Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1532 lines
41 KiB

  1. //Copyright (c) 1998 - 1999 Microsoft Corporation
  2. /*******************************************************************************
  3. *
  4. * server.cpp
  5. *
  6. * implementation of the CServer class
  7. *
  8. *
  9. *******************************************************************************/
  10. #include "stdafx.h"
  11. #include "winadmin.h"
  12. #include "admindoc.h"
  13. #include "dialogs.h"
  14. #include <malloc.h> // for alloca used by Unicode conversion macros
  15. #include <afxconv.h> // for Unicode conversion macros
  16. static int _convert;
  17. #include <winsta.h>
  18. #include <regapi.h>
  19. #include "..\..\inc\utilsub.h"
  20. #include "procs.h"
  21. #ifdef _DEBUG
  22. #define new DEBUG_NEW
  23. #undef THIS_FILE
  24. static char THIS_FILE[] = __FILE__;
  25. #endif
  26. //////////////////////////////////////////////////////////////////////////////////////////
  27. //
  28. // CServer Member Functions
  29. //
  30. //////////////////////////////////////////////////////////////////////////////////////////
  31. /////////////////////////////////////////////////////////////////////////////
  32. // CServer::CServer
  33. //
  34. // Constructor for the server class
  35. CServer::CServer(CDomain *pDomain, TCHAR *name, BOOL bFoundLater, BOOL bConnect)
  36. {
  37. ASSERT(name);
  38. m_ServerFlags = ULONG(0);
  39. m_pDomain = pDomain;
  40. if(bFoundLater) SetFoundLater();
  41. //m_State = SS_NONE;
  42. m_PreviousState = SS_NONE;
  43. m_hTreeItem = NULL;
  44. m_hThisServer = NULL;
  45. m_hFavTree = NULL;
  46. m_pBackgroundThread = NULL;
  47. m_bThreadAlive = FALSE;
  48. m_pExtensionInfo = NULL;
  49. m_pExtServerInfo = NULL;
  50. m_pRegistryInfo = NULL;
  51. m_fManualFind = FALSE;
  52. // Don't call SetState because we don't want to send a message to the views
  53. m_State = SS_NOT_CONNECTED;
  54. // save off the server name
  55. wcscpy(m_Name, name);
  56. // Dummy up an ExtServerInfo structure
  57. // This is to make it easier for code that tries
  58. // to access this structure before the extension DLL
  59. // has provided it
  60. m_pExtServerInfo = ((CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument())->GetDefaultExtServerInfo();
  61. if(bConnect) Connect();
  62. } // end CServer::CServer
  63. /////////////////////////////////////////////////////////////////////////////
  64. // CServer::~CServer
  65. //
  66. // Destructor for the server class
  67. CServer::~CServer()
  68. {
  69. // Disconnect();
  70. m_hTreeItem = NULL;
  71. m_hFavTree = NULL;
  72. m_hThisServer = NULL;
  73. } // end CServer::~CServer
  74. /////////////////////////////////////////////////////////////////////////////
  75. // CServer::RemoveWinStationProcesses
  76. //
  77. // remove all the processes for a given WinStation
  78. void CServer::RemoveWinStationProcesses(CWinStation *pWinStation)
  79. {
  80. ASSERT(pWinStation);
  81. CWinAdminDoc *pDoc = (CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument();
  82. CObList TempList;
  83. LockProcessList();
  84. POSITION pos = m_ProcessList.GetHeadPosition();
  85. while(pos) {
  86. POSITION pos2 = pos;
  87. CProcess *pProcess = (CProcess*)m_ProcessList.GetNext(pos);
  88. if(pProcess->GetWinStation() == pWinStation) {
  89. // Add the process to our temporary list
  90. TempList.AddTail(pProcess);
  91. // Remove the process from the list of processes
  92. pProcess = (CProcess*)m_ProcessList.GetAt(pos2);
  93. m_ProcessList.RemoveAt(pos2);
  94. }
  95. }
  96. UnlockProcessList();
  97. pos = TempList.GetHeadPosition();
  98. while(pos) {
  99. POSITION pos2 = pos;
  100. CProcess *pProcess = (CProcess*)TempList.GetNext(pos);
  101. // Send a message to remove the Process from the view
  102. CFrameWnd *p = (CFrameWnd*)pDoc->GetMainWnd();
  103. if(p && ::IsWindow(p->GetSafeHwnd())) {
  104. p->SendMessage(WM_ADMIN_REMOVE_PROCESS, 0, (LPARAM)pProcess);
  105. }
  106. delete pProcess;
  107. }
  108. TempList.RemoveAll();
  109. } // end CServer::RemoveWinStationProcesses
  110. /////////////////////////////////////////////////////////////////////////////
  111. // CServer::ClearAllSelected
  112. //
  113. // Clears the WAF_SELECTED bit in all of this server's lists
  114. //
  115. void CServer::ClearAllSelected()
  116. {
  117. // Clear the WinStation list WAF_SELECTED flags
  118. // Iterate through the WinStation list
  119. LockWinStationList( );
  120. POSITION pos = m_WinStationList.GetHeadPosition();
  121. while(pos) {
  122. CWinStation *pWinStation = (CWinStation*)m_WinStationList.GetNext(pos);
  123. pWinStation->ClearSelected();
  124. }
  125. m_NumWinStationsSelected = 0;
  126. UnlockWinStationList( );
  127. LockProcessList();
  128. // Clear the Process list PF_SELECTED flags
  129. // Iterate through the Process list
  130. pos = m_ProcessList.GetHeadPosition();
  131. while(pos) {
  132. CProcess *pProcess = (CProcess*)m_ProcessList.GetNext(pos);
  133. pProcess->ClearSelected();
  134. }
  135. m_NumProcessesSelected = 0;
  136. UnlockProcessList( );
  137. } // end CServer::ClearAllSelected
  138. //Function - htol - start
  139. //===========================================================================
  140. //
  141. //Description: converts a hex string to a uLONG, handles "0x..."
  142. //
  143. //
  144. //Parameters:
  145. //
  146. //Return Value:
  147. //
  148. //Global Variables Affected:
  149. //
  150. //Remarks: (Side effects, Assumptions, Warnings...)
  151. //
  152. //
  153. //---------------------------------------------------------------------------
  154. WCHAR hextable[] = L"0123456789ABCDEF";
  155. ULONG htol(WCHAR *hexString)
  156. {
  157. ULONG retValue = 0L;
  158. // convert the string to upper case
  159. _wcsupr(hexString);
  160. WCHAR *p = hexString;
  161. while (*p == L' ')
  162. p++;
  163. while(*p)
  164. {
  165. if(*p == L'X')
  166. {
  167. retValue = 0L;
  168. } else if ((*p == L' ') || (*p == L'\n') || (*p == L'\r'))
  169. break;
  170. else if(*p == L'.') {
  171. // skip over a decimal point
  172. }
  173. else
  174. {
  175. retValue <<= 4;
  176. for(int i = 0; i < 16; i++)
  177. {
  178. if(hextable[i] == *p)
  179. {
  180. retValue += i;
  181. break;
  182. }
  183. }
  184. }
  185. *p++;
  186. }
  187. return retValue;
  188. }
  189. static TCHAR szMicrosoftKey[] = TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion");
  190. static TCHAR szInstallDate[] = TEXT("InstallDate");
  191. static TCHAR szCSDVersion[] = TEXT("CSDVersion");
  192. static TCHAR szCurrentVersion[] = TEXT("CurrentVersion");
  193. static TCHAR szCurrentBuildNumber[] = TEXT("CurrentBuildNumber");
  194. static TCHAR szCurrentProductName[] = TEXT("ProductName");
  195. static TCHAR szHotfixKey[] = TEXT("HOTFIX");
  196. static TCHAR szValid[] = TEXT("Valid");
  197. static TCHAR szInstalledOn[] = TEXT("Installed On");
  198. static TCHAR szInstalledBy[] = TEXT("Installed By");
  199. #define REG_CONTROL_CITRIX REG_CONTROL L"\\Citrix"
  200. /////////////////////////////////////////////////////////////////////////////
  201. // CServer::BuildRegistryInfo
  202. //
  203. // Go out and fill in the registry info structure
  204. BOOL CServer::BuildRegistryInfo()
  205. {
  206. DWORD dwType, dwSize;
  207. HKEY hKeyServer;
  208. HKEY hKey;
  209. if(!IsServerSane()) return FALSE;
  210. m_pRegistryInfo = new ServerRegistryInfo;
  211. if(!m_pRegistryInfo) return FALSE;
  212. memset(m_pRegistryInfo, 0, sizeof(ServerRegistryInfo));
  213. TCHAR Buffer[128];
  214. Buffer[0] = TEXT('\\');
  215. Buffer[1] = TEXT('\\');
  216. Buffer[2] = TEXT('\0');
  217. wcscpy(Buffer+2, m_Name);
  218. /*
  219. * Connect to the server's registry
  220. * (avoid using RPC when the server is the local machine.)
  221. */
  222. if(RegConnectRegistry(IsCurrentServer() ? NULL : Buffer, HKEY_LOCAL_MACHINE, &hKeyServer) != ERROR_SUCCESS)
  223. return FALSE;
  224. /*
  225. * Fetch MS information.
  226. */
  227. if(RegOpenKeyEx(hKeyServer, szMicrosoftKey, 0, KEY_READ, &hKey) != ERROR_SUCCESS) {
  228. RegCloseKey(hKeyServer);
  229. return FALSE;
  230. }
  231. dwSize = sizeof(m_pRegistryInfo->InstallDate);
  232. if(RegQueryValueEx(hKey, szInstallDate, NULL, &dwType, (LPBYTE)&m_pRegistryInfo->InstallDate,
  233. &dwSize) != ERROR_SUCCESS) {
  234. m_pRegistryInfo->InstallDate = 0xFFFFFFFF;
  235. }
  236. // REMARK: we should check the returned codes for every RegQueryValueEx
  237. dwSize = sizeof(m_pRegistryInfo->ServicePackLevel);
  238. RegQueryValueEx(hKey, szCSDVersion, NULL, &dwType, (LPBYTE)&m_pRegistryInfo->ServicePackLevel, &dwSize);
  239. dwSize = sizeof(m_pRegistryInfo->MSVersion);
  240. RegQueryValueEx(hKey, szCurrentVersion, NULL, &dwType, (LPBYTE)&m_pRegistryInfo->MSVersion, &dwSize);
  241. m_pRegistryInfo->MSVersionNum = _wtol(m_pRegistryInfo->MSVersion);
  242. dwSize = sizeof(m_pRegistryInfo->MSBuild);
  243. RegQueryValueEx(hKey, szCurrentBuildNumber, NULL, &dwType, (LPBYTE)&m_pRegistryInfo->MSBuild, &dwSize);
  244. dwSize = sizeof(m_pRegistryInfo->MSProductName);
  245. RegQueryValueEx(hKey, szCurrentProductName, NULL, &dwType, (LPBYTE)&m_pRegistryInfo->MSProductName, &dwSize);
  246. HKEY hKeyHotfix;
  247. if(RegOpenKeyEx(hKey, szHotfixKey, 0, KEY_READ, &hKeyHotfix) == ERROR_SUCCESS) {
  248. DWORD Index = 0;
  249. FILETIME LastWriteTime;
  250. dwSize = sizeof(Buffer) / sizeof( TCHAR );
  251. while(RegEnumKeyEx(hKeyHotfix, Index, Buffer, &dwSize, NULL, NULL, NULL,
  252. &LastWriteTime) == ERROR_SUCCESS) {
  253. HKEY hKeySingleHotfix;
  254. if(RegOpenKeyEx(hKeyHotfix, Buffer, 0, KEY_READ, &hKeySingleHotfix) == ERROR_SUCCESS) {
  255. // Create a CHotFix object
  256. CHotfix *pHotfix = new CHotfix;
  257. if(pHotfix) {
  258. // Copy the Hotfix name
  259. // Get rid of the WF: if it's there
  260. if(wcsncmp(Buffer, TEXT("WF:"), 3) == 0) {
  261. wcscpy(pHotfix->m_Name, &Buffer[3]);
  262. }
  263. else wcscpy(pHotfix->m_Name, Buffer);
  264. // Get the Valid entry
  265. dwSize = sizeof(&pHotfix->m_Valid);
  266. if(RegQueryValueEx(hKeySingleHotfix, szValid, NULL, &dwType, (LPBYTE)&pHotfix->m_Valid,
  267. &dwSize) != ERROR_SUCCESS) {
  268. pHotfix->m_Valid = 0L;
  269. }
  270. // Get the Installed On entry
  271. dwSize = sizeof(&pHotfix->m_InstalledOn);
  272. if(RegQueryValueEx(hKeySingleHotfix, szInstalledOn, NULL, &dwType, (LPBYTE)&pHotfix->m_InstalledOn,
  273. &dwSize) != ERROR_SUCCESS) {
  274. pHotfix->m_InstalledOn = 0xFFFFFFFF;
  275. }
  276. // Get the Installed By entry
  277. dwSize = sizeof(pHotfix->m_InstalledBy);
  278. if(RegQueryValueEx(hKeySingleHotfix, szInstalledBy, NULL, &dwType, (LPBYTE)pHotfix->m_InstalledBy,
  279. &dwSize) != ERROR_SUCCESS) {
  280. pHotfix->m_InstalledBy[0] = '\0';
  281. }
  282. pHotfix->m_pServer = this;
  283. m_HotfixList.AddTail(pHotfix);
  284. RegCloseKey(hKeySingleHotfix);
  285. }
  286. }
  287. dwSize = sizeof(Buffer) / sizeof( TCHAR );
  288. Index++;
  289. }
  290. RegCloseKey(hKeyHotfix);
  291. }
  292. RegCloseKey(hKey);
  293. if (m_pRegistryInfo->MSVersionNum < 5) // only for TS 4.0
  294. {
  295. /*
  296. * Fetch Citrix information.
  297. */
  298. // Look in the new location
  299. LONG result = RegOpenKeyEx(hKeyServer, REG_CONTROL_TSERVER, 0, KEY_READ, &hKey);
  300. if(result != ERROR_SUCCESS) {
  301. // Look in the old location
  302. result = RegOpenKeyEx(hKeyServer, REG_CONTROL_CITRIX, 0, KEY_READ, &hKey);
  303. }
  304. if(result != ERROR_SUCCESS) {
  305. RegCloseKey(hKeyServer);
  306. return FALSE;
  307. }
  308. dwSize = sizeof(m_pRegistryInfo->CTXProductName);
  309. RegQueryValueEx(hKey, REG_CITRIX_PRODUCTNAME, NULL, &dwType, (LPBYTE)m_pRegistryInfo->CTXProductName, &dwSize);
  310. dwSize = sizeof(m_pRegistryInfo->CTXVersion);
  311. RegQueryValueEx(hKey, REG_CITRIX_PRODUCTVERSION, NULL, &dwType, (LPBYTE)m_pRegistryInfo->CTXVersion, &dwSize);
  312. m_pRegistryInfo->CTXVersionNum = htol(m_pRegistryInfo->CTXVersion);
  313. dwSize = sizeof(m_pRegistryInfo->CTXBuild);
  314. RegQueryValueEx(hKey, REG_CITRIX_PRODUCTBUILD, NULL, &dwType, (LPBYTE)m_pRegistryInfo->CTXBuild, &dwSize);
  315. RegCloseKey(hKey);
  316. }
  317. else // for NT 5.0 and beyond, do not query the registry
  318. {
  319. //REMARK: we should get rid of all this.
  320. wcscpy(m_pRegistryInfo->CTXProductName, m_pRegistryInfo->MSProductName);
  321. wcscpy(m_pRegistryInfo->CTXVersion, m_pRegistryInfo->MSVersion);
  322. m_pRegistryInfo->CTXVersionNum = m_pRegistryInfo->MSVersionNum;
  323. wcscpy(m_pRegistryInfo->CTXBuild, m_pRegistryInfo->MSBuild);
  324. }
  325. RegCloseKey(hKeyServer);
  326. // Set the flag to say the info is valid
  327. SetRegistryInfoValid();
  328. return TRUE;
  329. } // end CServer::BuildRegistryInfo
  330. /////////////////////////////////////////////////////////////////////////////
  331. // CServer::AddWinStation
  332. //
  333. // Add a WinStation to the Server's WinStationList in
  334. // sorted order
  335. // NOTE: The list should be NOT be locked by the caller
  336. //
  337. void CServer::AddWinStation(CWinStation *pNewWinStation)
  338. {
  339. ASSERT(pNewWinStation);
  340. LockWinStationList();
  341. ODS( L"CServer!AddWinStation\n" );
  342. BOOLEAN bAdded = FALSE;
  343. POSITION pos, oldpos;
  344. int Index;
  345. // Traverse the WinStationList and insert this new WinStation,
  346. // keeping the list sorted by Sort Order, then Protocol.
  347. for(Index = 0, pos = m_WinStationList.GetHeadPosition(); pos != NULL; Index++) {
  348. oldpos = pos;
  349. CWinStation *pWinStation = (CWinStation*)m_WinStationList.GetNext(pos);
  350. if((pWinStation->GetSortOrder() > pNewWinStation->GetSortOrder())
  351. || ((pWinStation->GetSortOrder() == pNewWinStation->GetSortOrder()) &&
  352. (pWinStation->GetSdClass() > pNewWinStation->GetSdClass()))) {
  353. // The new object belongs before the current list object.
  354. m_WinStationList.InsertBefore(oldpos, pNewWinStation);
  355. bAdded = TRUE;
  356. break;
  357. }
  358. }
  359. // If we haven't yet added the WinStation, add it now to the tail
  360. // of the list.
  361. if(!bAdded) {
  362. m_WinStationList.AddTail(pNewWinStation);
  363. }
  364. UnlockWinStationList();
  365. } // end CServer::AddWinStation
  366. /////////////////////////////////////////////////////////////////////////////
  367. // CServer::Connect
  368. //
  369. // Connect to the server
  370. //
  371. BOOL CServer::Connect()
  372. {
  373. m_NumProcessesSelected = 0;
  374. m_NumWinStationsSelected = 0;
  375. m_pExtServerInfo = NULL;
  376. BOOL bResult = FALSE;
  377. if(m_State != SS_NOT_CONNECTED )
  378. {
  379. return FALSE;
  380. }
  381. // Fire off the background thread for this server
  382. LockThreadAlive();
  383. if(m_pBackgroundThread == NULL)
  384. {
  385. ServerProcInfo *pProcInfo = new ServerProcInfo;
  386. if(pProcInfo)
  387. {
  388. pProcInfo->pServer = this;
  389. pProcInfo->pDoc = (CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument();
  390. m_BackgroundContinue = TRUE;
  391. m_bThreadAlive = FALSE;
  392. m_pBackgroundThread = AfxBeginThread((AFX_THREADPROC)CServer::BackgroundThreadProc,
  393. pProcInfo,
  394. THREAD_PRIORITY_NORMAL,
  395. 0,
  396. CREATE_SUSPENDED,
  397. NULL
  398. );
  399. if( m_pBackgroundThread == NULL )
  400. {
  401. ODS( L"CServer!Connect possibly low resources no thread created\n" );
  402. delete pProcInfo;
  403. return FALSE;
  404. }
  405. m_pBackgroundThread->m_bAutoDelete = FALSE;
  406. if (m_pBackgroundThread->ResumeThread() <= 1)
  407. {
  408. bResult = TRUE;
  409. }
  410. }
  411. }
  412. UnlockThreadAlive();
  413. return TRUE;
  414. }
  415. /////////////////////////////////////////////////////////////////////////////
  416. // CServer::Disconnect
  417. //
  418. // Disconnect from the server
  419. //
  420. void CServer::Disconnect()
  421. {
  422. // not a good idea for an ods
  423. CWinAdminDoc *pDoc = (CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument();
  424. SetState(SS_DISCONNECTING);
  425. // If there is an extension DLL, let it cleanup anything it added to this Server
  426. LPFNEXSERVERCLEANUPPROC CleanupProc = ((CWinAdminApp*)AfxGetApp())->GetExtServerCleanupProc();
  427. if(CleanupProc && m_pExtensionInfo) {
  428. (*CleanupProc)(m_pExtensionInfo);
  429. m_pExtensionInfo = NULL;
  430. }
  431. // Tell the background thread to terminate and
  432. // wait for it to do so.
  433. LockThreadAlive();
  434. ClearBackgroundContinue();
  435. if( !m_pBackgroundThread )
  436. {
  437. // Either there is no background thread at all,
  438. // or some other thread is taking care of terminating it.
  439. // Just do nothing.
  440. //ODS( L"TSADMIN:CServer::Disconnect UnlockThreadAlive\n" );
  441. UnlockThreadAlive();
  442. }
  443. else
  444. {
  445. if( m_bThreadAlive )
  446. {
  447. // the thread is alive. Tell him to exit.
  448. // keep temporary pointer and handle
  449. CWinThread *pBackgroundThread = m_pBackgroundThread;
  450. HANDLE hThread = m_pBackgroundThread->m_hThread;
  451. // Clear the pointer before releasing the lock
  452. m_pBackgroundThread = NULL;
  453. // Give the thread a chance to exit
  454. UnlockThreadAlive();
  455. // Force him out of waiting for an event if he is
  456. ULONG WSEventFlags;
  457. if(IsHandleGood())
  458. {
  459. ODS( L"TSADMIN:CServer::Disconnect Handle is good flush events\n" );
  460. WinStationWaitSystemEvent(m_Handle, WEVENT_FLUSH, &WSEventFlags);
  461. }
  462. if( hThread ) // It should always be TRUE
  463. {
  464. // If this server object is waiting for RPC to timeout,
  465. // just kill the thread
  466. if( m_PreviousState == SS_NOT_CONNECTED )
  467. {
  468. ODS( L"TSADMIN:CServer::Disconnect Previous state not connected termthread\n" );
  469. if( WaitForSingleObject( hThread , 100 ) == WAIT_TIMEOUT )
  470. {
  471. TerminateThread(hThread, 0);
  472. }
  473. }
  474. // For all other threads, wait a second and then kill it
  475. else if( WaitForSingleObject( hThread , 1000 ) == WAIT_TIMEOUT )
  476. {
  477. ODS( L"TSADMIN CServer!Disconnect prevstate was !not_connected termthread\n" );
  478. TerminateThread(hThread, 0);
  479. }
  480. WaitForSingleObject(hThread, INFINITE);
  481. }
  482. else
  483. {
  484. ASSERT(FALSE);
  485. }
  486. // delete the CWinThread object
  487. ODS( L"TSADMIN:CServer::Disconnect delete CWinThread Object m_bThread == TRUE\n" );
  488. delete pBackgroundThread;
  489. }
  490. else
  491. {
  492. // the thread is dead or will be dead very soon. Just do the cleanup.
  493. ODS( L"TSADMIN:CServer::Disconnect delete CWinThread Object m_bThread == FALSE\n" );
  494. delete m_pBackgroundThread;
  495. m_pBackgroundThread = NULL;
  496. UnlockThreadAlive();
  497. }
  498. }
  499. if(IsHandleGood())
  500. {
  501. ODS( L"TSADMIN:CServer::Disconnect WinStationCloseServer\n" );
  502. WinStationCloseServer(m_Handle);
  503. m_Handle = NULL;
  504. }
  505. LockWinStationList();
  506. CObList TempList;
  507. // Iterate through the WinStation list
  508. // Move all the WinStations to a temporary list so that
  509. // we don't have to have the WinStationList locked while
  510. // sending the WM_ADMIN_REMOVE_WINSTATION message to the views.
  511. POSITION pos = m_WinStationList.GetHeadPosition();
  512. while(pos)
  513. {
  514. CWinStation *pWinStation = (CWinStation*)m_WinStationList.GetNext(pos);
  515. TempList.AddTail(pWinStation);
  516. }
  517. m_WinStationList.RemoveAll();
  518. UnlockWinStationList();
  519. CFrameWnd *p = (CFrameWnd*)pDoc->GetMainWnd();
  520. pos = TempList.GetHeadPosition();
  521. while(pos)
  522. {
  523. CWinStation *pWinStation = (CWinStation*)TempList.GetNext(pos);
  524. if(p && ::IsWindow(p->GetSafeHwnd()))
  525. {
  526. ODS( L"TSADMIN:CServer::Disconnect Remove WinStation\n" );
  527. p->SendMessage(WM_ADMIN_REMOVE_WINSTATION, 0, (LPARAM)pWinStation);
  528. }
  529. delete pWinStation;
  530. }
  531. TempList.RemoveAll();
  532. LockProcessList();
  533. pos = m_ProcessList.GetHeadPosition();
  534. while(pos)
  535. {
  536. CProcess *pProcess = (CProcess*)m_ProcessList.GetNext(pos);
  537. ODS( L"TSADMIN:CServer::Disconnect Delete process\n" );
  538. delete pProcess;
  539. }
  540. m_ProcessList.RemoveAll();
  541. UnlockProcessList();
  542. LockLicenseList();
  543. pos = m_LicenseList.GetHeadPosition();
  544. while(pos)
  545. {
  546. CLicense *pLicense = (CLicense*)m_LicenseList.GetNext(pos);
  547. ODS( L"TSADMIN:CServer::Disconnect remove license\n" );
  548. delete pLicense;
  549. }
  550. m_LicenseList.RemoveAll();
  551. UnlockLicenseList();
  552. //
  553. pos = m_UserSidList.GetHeadPosition();
  554. while(pos)
  555. {
  556. CUserSid *pUserSid = (CUserSid*)m_UserSidList.GetNext(pos);
  557. ODS( L"TSADMIN:CServer::Disconnect remove sids\n" );
  558. delete pUserSid;
  559. }
  560. m_UserSidList.RemoveAll();
  561. pos = m_HotfixList.GetHeadPosition();
  562. while(pos)
  563. {
  564. CHotfix *pHotfix = (CHotfix*)m_HotfixList.GetNext(pos);
  565. ODS( L"TSADMIN:CServer::Disconnect Remove hotfixes\n" );
  566. delete pHotfix;
  567. }
  568. m_HotfixList.RemoveAll();
  569. if( m_pRegistryInfo )
  570. {
  571. delete m_pRegistryInfo;
  572. ODS( L"TSADMIN:CServer::Disconnect delete reginfo\n" );
  573. m_pRegistryInfo = NULL;
  574. }
  575. // ODS( L"TSADMIN:CServer::Disconnect Set state not connected\n" );
  576. SetState(SS_NOT_CONNECTED);
  577. }
  578. /////////////////////////////////////////////////////////////////////////////
  579. // CServer::DoDetail
  580. //
  581. // Go get detailed information about this server
  582. //
  583. void CServer::DoDetail()
  584. {
  585. CWinAdminDoc *pDoc = (CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument();
  586. SetState(SS_GETTING_INFO);
  587. ULONG Entries;
  588. PLOGONID pLogonId;
  589. if(!ShouldBackgroundContinue()) return;
  590. // We need to access the registry information for the server
  591. // at this time because we must not administer WF 2.00 servers
  592. // (RPC structures are incompatible). If we cannot access the
  593. // server's registry, or the multi-user version is 2.00, we bail
  594. // from this server.
  595. if ( !BuildRegistryInfo() || (GetCTXVersionNum() == 0x200) || (GetCTXVersionNum() == 0) )
  596. {
  597. ClearHandleGood();
  598. SetLostConnection();
  599. SetState(SS_BAD);
  600. ODS( L"CServer::DoDetail - Setting to lost connection\n" );
  601. CFrameWnd *pFrameWnd = (CFrameWnd*)pDoc->GetMainWnd();
  602. if(pFrameWnd && ::IsWindow(pFrameWnd->GetSafeHwnd())) pFrameWnd->SendMessage(WM_ADMIN_REMOVE_SERVER, 0, (LPARAM)this);
  603. ClearBackgroundContinue();
  604. return;
  605. }
  606. // Find all the WinStations
  607. BOOL fWinEnum;
  608. fWinEnum = WinStationEnumerate(m_Handle, &pLogonId, &Entries);
  609. DBGMSG( L"CServer!DoDetail WinEnum last reported error 0x%x\n", GetLastError( ) );
  610. if(!fWinEnum )
  611. {
  612. ClearHandleGood();
  613. SetLostConnection();
  614. SetState(SS_BAD);
  615. ClearBackgroundContinue();
  616. return;
  617. }
  618. if(!ShouldBackgroundContinue()) {
  619. if(pLogonId) WinStationFreeMemory(pLogonId);
  620. return;
  621. }
  622. // Get information about the WinStations
  623. if(pLogonId)
  624. {
  625. for(ULONG i = 0; i < Entries; i++)
  626. {
  627. // Create a new WinStation object
  628. CWinStation *pWinStation = new CWinStation(this, &pLogonId[i]);
  629. if(pWinStation)
  630. {
  631. // If the queries weren't successful, ignore this WinStation
  632. if(!pWinStation->QueriesSuccessful())
  633. {
  634. ODS( L"CServer::DoDetail!QueriesSuccessful failed\n" );
  635. delete pWinStation;
  636. }
  637. else
  638. {
  639. AddWinStation(pWinStation);
  640. pWinStation->SetNew();
  641. }
  642. }
  643. if( !ShouldBackgroundContinue() )
  644. {
  645. if(pLogonId) WinStationFreeMemory(pLogonId);
  646. return;
  647. }
  648. }
  649. WinStationFreeMemory(pLogonId);
  650. }
  651. if(!ShouldBackgroundContinue()) return;
  652. // If there is an extension DLL loaded, allow it to add it's own info for this Server
  653. LPFNEXSERVERINITPROC InitProc = ((CWinAdminApp*)AfxGetApp())->GetExtServerInitProc();
  654. if(InitProc) {
  655. m_pExtensionInfo = (*InitProc)(m_Name, m_Handle);
  656. if(m_pExtensionInfo) {
  657. LPFNEXGETSERVERINFOPROC GetInfoProc = ((CWinAdminApp*)AfxGetApp())->GetExtGetServerInfoProc();
  658. if(GetInfoProc) {
  659. m_pExtServerInfo = (*GetInfoProc)(m_pExtensionInfo);
  660. // If this server is running WinFrame or Picasso, set flag
  661. if(m_pExtServerInfo->Flags & ESF_WINFRAME) SetWinFrame();
  662. }
  663. }
  664. }
  665. QueryLicenses();
  666. SetState(SS_GOOD);
  667. // Send a message to the views to tell it the state of this
  668. // server has changed
  669. CFrameWnd *p = (CFrameWnd*)pDoc->GetMainWnd();
  670. if(p && ::IsWindow(p->GetSafeHwnd())) {
  671. p->SendMessage(WM_ADMIN_UPDATE_SERVER_INFO, 0, (LPARAM)this);
  672. p->SendMessage(WM_ADMIN_UPDATE_WINSTATIONS, 0, (LPARAM)this);
  673. }
  674. } // end CServer::DoDetail
  675. /////////////////////////////////////////////////////////////////////////////
  676. // CServer::FindProcessByPID
  677. //
  678. // returns a pointer to a CProcess from m_ProcessList given a PID
  679. CProcess* CServer::FindProcessByPID(ULONG Pid)
  680. {
  681. LockProcessList();
  682. POSITION pos = m_ProcessList.GetHeadPosition();
  683. while(pos) {
  684. CProcess *pProcess = (CProcess*)m_ProcessList.GetNext(pos);
  685. if(pProcess->GetPID() == Pid) {
  686. UnlockProcessList();
  687. return pProcess;
  688. }
  689. }
  690. UnlockProcessList();
  691. return NULL;
  692. } // end CServer::FindProcessByPID
  693. /////////////////////////////////////////////////////////////////////////////
  694. // CServer::EnumerateProcesses
  695. //
  696. // Enumerate this server's processes
  697. BOOL CServer::EnumerateProcesses()
  698. {
  699. ENUMTOKEN EnumToken;
  700. ULONG PID;
  701. ULONG LogonId;
  702. TCHAR ImageName[MAX_PROCESSNAME+1];
  703. PSID pSID;
  704. EnumToken.Current = 0;
  705. EnumToken.NumberOfProcesses = 0;
  706. EnumToken.ProcessArray = NULL;
  707. EnumToken.bGAP = TRUE;
  708. if(!IsHandleGood()) return 0;
  709. CWinAdminDoc *pDoc = (CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument();
  710. LockProcessList();
  711. // Loop processes through and turn off current flag and new flag
  712. // Delete any processes that aren't current
  713. POSITION pos = m_ProcessList.GetHeadPosition();
  714. while(pos) {
  715. POSITION pos2 = pos;
  716. CProcess *pProcess = (CProcess*)m_ProcessList.GetNext(pos);
  717. if(!pProcess->IsCurrent()) {
  718. pProcess = (CProcess*)m_ProcessList.GetAt(pos2);
  719. m_ProcessList.RemoveAt(pos2);
  720. delete pProcess;
  721. } else {
  722. pProcess->ClearCurrent();
  723. pProcess->ClearNew();
  724. pProcess->ClearChanged(); // !
  725. }
  726. }
  727. UnlockProcessList();
  728. // Should we quit?
  729. if(!pDoc->ShouldProcessContinue()) {
  730. return FALSE;
  731. }
  732. while(ProcEnumerateProcesses(m_Handle,
  733. &EnumToken,
  734. ImageName,
  735. &LogonId,
  736. &PID,
  737. &pSID )) {
  738. CProcess *pProcess = new CProcess(PID,
  739. LogonId,
  740. this,
  741. pSID,
  742. FindWinStationById(LogonId),
  743. ImageName);
  744. if(pProcess) {
  745. // If this process is in the list, we need to see if it has changed
  746. CProcess *pOldProcess = FindProcessByPID(PID);
  747. if(pOldProcess && pProcess->GetWinStation()) {
  748. // Flag the process as current
  749. pOldProcess->SetCurrent();
  750. // Update any info that has changed
  751. pOldProcess->Update(pProcess);
  752. // We don't need this process object anymore
  753. delete pProcess;
  754. }
  755. // It is a new process, add it to the list
  756. else if(pProcess->GetWinStation()) {
  757. pProcess->SetNew();
  758. LockProcessList();
  759. m_ProcessList.AddTail(pProcess);
  760. UnlockProcessList();
  761. }
  762. // This process doesn't have a WinStation, delete it
  763. else {
  764. delete pProcess;
  765. }
  766. }
  767. // Should we quit?
  768. if(!pDoc->ShouldProcessContinue()) {
  769. // We have to call this one last time with an offset of -1 to
  770. // make the function free up the memory allocated by the client side stub.
  771. EnumToken.Current = (ULONG)-1;
  772. ProcEnumerateProcesses(m_Handle,
  773. &EnumToken,
  774. ImageName,
  775. &LogonId,
  776. &PID,
  777. &pSID );
  778. return FALSE;
  779. }
  780. }
  781. return TRUE;
  782. } // end CServer::EnumerateProcesses
  783. /////////////////////////////////////////////////////////////////////////////
  784. // CServer::ClearProcesses
  785. //
  786. // Clear out the list of processes
  787. void CServer::ClearProcesses()
  788. {
  789. LockProcessList();
  790. POSITION pos = m_ProcessList.GetHeadPosition();
  791. while(pos) {
  792. CProcess *pProcess = (CProcess*)m_ProcessList.GetNext(pos);
  793. delete pProcess;
  794. }
  795. m_ProcessList.RemoveAll();
  796. UnlockProcessList();
  797. } // end CServer::ClearProcesses
  798. /////////////////////////////////////////////////////////////////////////////
  799. // CServer::FindWinStationById
  800. //
  801. CWinStation* CServer::FindWinStationById(ULONG Id)
  802. {
  803. LockWinStationList();
  804. POSITION pos = m_WinStationList.GetHeadPosition();
  805. while(pos) {
  806. CWinStation *pWinStation = (CWinStation*)m_WinStationList.GetNext(pos);
  807. if(pWinStation->GetLogonId() == Id) {
  808. UnlockWinStationList();
  809. return pWinStation;
  810. }
  811. }
  812. UnlockWinStationList();
  813. return NULL;
  814. } // end CServer::FindWinStationById
  815. /////////////////////////////////////////////////////////////////////////////
  816. // CServer::BackgroundThreadProc
  817. //
  818. UINT CServer::BackgroundThreadProc(LPVOID pParam)
  819. {
  820. ASSERT(pParam);
  821. ODS( L"CServer::BackgroundThreadProc\n" );
  822. // We need a pointer to the document so we can make
  823. // calls to member functions
  824. CWinAdminDoc *pDoc = (CWinAdminDoc*)((ServerProcInfo*)pParam)->pDoc;
  825. CServer *pServer = ((ServerProcInfo*)pParam)->pServer;
  826. HANDLE hServer;
  827. delete (ServerProcInfo*)pParam;
  828. // Make sure we don't have to quit
  829. if(!pServer->ShouldBackgroundContinue()) {
  830. return 0;
  831. }
  832. pServer->SetThreadAlive();
  833. // In case the server is disconnected we wait uselessly here
  834. while(!pDoc->AreAllViewsReady()) Sleep(500);
  835. // Make sure we don't have to quit
  836. if(!pServer->ShouldBackgroundContinue())
  837. {
  838. pServer->ClearThreadAlive();
  839. return 0;
  840. }
  841. if(!pServer->IsCurrentServer())
  842. {
  843. // open the server and save the handle
  844. hServer = WinStationOpenServer(pServer->GetName());
  845. pServer->SetHandle(hServer);
  846. // Make sure we don't have to quit
  847. if(!pServer->ShouldBackgroundContinue())
  848. {
  849. pServer->ClearThreadAlive();
  850. return 0;
  851. }
  852. if(hServer == NULL)
  853. {
  854. DWORD Error = GetLastError();
  855. DBGMSG( L"CServer!BackgroundThreadProc WinStationOpenServer failed with 0x%x\n", Error );
  856. if(Error == RPC_S_SERVER_UNAVAILABLE)
  857. {
  858. pServer->ClearBackgroundFound();
  859. pServer->SetLostConnection();
  860. pServer->ClearManualFind( );
  861. CFrameWnd *pFrameWnd = (CFrameWnd*)pDoc->GetMainWnd();
  862. if(pFrameWnd && ::IsWindow(pFrameWnd->GetSafeHwnd()))
  863. {
  864. ODS( L"Server backgrnd thread declares this server RPC_S_SERVER_UNAVAILABLE\n" );
  865. pFrameWnd->SendMessage(WM_ADMIN_REMOVE_SERVER, 0, (LPARAM)pServer);
  866. if( pServer->GetTreeItemFromFav() != NULL )
  867. {
  868. pFrameWnd->SendMessage( WM_ADMIN_REMOVESERVERFROMFAV , 0 , ( LPARAM )pServer );
  869. }
  870. }
  871. }
  872. else
  873. {
  874. pServer->SetState(SS_BAD);
  875. }
  876. pServer->ClearThreadAlive();
  877. return 0;
  878. }
  879. pServer->SetHandleGood();
  880. pServer->SetState(SS_OPENED);
  881. }
  882. else
  883. {
  884. hServer = SERVERNAME_CURRENT;
  885. pServer->SetHandle(SERVERNAME_CURRENT);
  886. pServer->SetHandleGood();
  887. pServer->SetState(SS_OPENED);
  888. }
  889. // Make sure we don't have to quit
  890. if(!pServer->ShouldBackgroundContinue()) {
  891. pServer->ClearThreadAlive();
  892. return 0;
  893. }
  894. // If we found this server after initial enum,
  895. // we need to add it to the views now
  896. CFrameWnd *pFrameWnd = (CFrameWnd*)pDoc->GetMainWnd();
  897. if(pServer->WasFoundLater())
  898. {
  899. if(pFrameWnd && ::IsWindow(pFrameWnd->GetSafeHwnd()))
  900. {
  901. pFrameWnd->SendMessage(WM_ADMIN_ADD_SERVER, ( WPARAM )TVI_SORT, (LPARAM)pServer);
  902. }
  903. }
  904. // Make sure we don't have to quit
  905. if(!pServer->ShouldBackgroundContinue()) {
  906. pServer->ClearThreadAlive();
  907. return 0;
  908. }
  909. pServer->DoDetail();
  910. // Now go into our loop waiting for WinStation Events
  911. while(1) {
  912. ULONG WSEventFlags;
  913. ULONG Entries;
  914. PLOGONID pLogonId;
  915. // Make sure we don't have to quit
  916. if(!pServer->ShouldBackgroundContinue()) {
  917. pServer->ClearThreadAlive();
  918. return 0;
  919. }
  920. // Wait for the browser to tell us something happened
  921. if(!WinStationWaitSystemEvent(hServer, WEVENT_ALL, &WSEventFlags))
  922. {
  923. if(GetLastError() != ERROR_OPERATION_ABORTED)
  924. {
  925. ODS( L"CServer::BackgroundThreadProc ERROR_OPERATION_ABORTED\n" );
  926. pServer->ClearHandleGood();
  927. pServer->SetState(SS_BAD);
  928. pServer->SetLostConnection();
  929. pServer->ClearThreadAlive();
  930. pServer->ClearManualFind( );
  931. return 1;
  932. }
  933. }
  934. ODS( L"CServer::BackgroundThreadProc -- some system event has taken place\n" );
  935. // Make sure we don't have to quit
  936. if(!pServer->ShouldBackgroundContinue()) {
  937. pServer->ClearThreadAlive();
  938. ODS( L"CServer::BackgroundThreadProc -* backgrnd thread should not continue\n" );
  939. return 0;
  940. }
  941. // Loop through this Server's WinStations and clear the current flag
  942. pServer->LockWinStationList();
  943. CObList *pWinStationList = pServer->GetWinStationList();
  944. POSITION pos = pWinStationList->GetHeadPosition();
  945. while(pos) {
  946. CWinStation *pWinStation = (CWinStation*)pWinStationList->GetNext(pos);
  947. pWinStation->ClearCurrent();
  948. pWinStation->ClearNew();
  949. pWinStation->ClearChanged();
  950. }
  951. pServer->UnlockWinStationList();
  952. // Find all the WinStations
  953. BOOL fWinEnum = WinStationEnumerate(hServer, &pLogonId, &Entries);
  954. DBGMSG( L"CServer!BackgroundThread WinEnum last reported error 0x%x\n", GetLastError( ) );
  955. if(!fWinEnum )
  956. {
  957. ODS( L"CServer!BackgroundThread -- server is no longer valid\n" );
  958. pServer->ClearHandleGood();
  959. pServer->SetLostConnection();
  960. pServer->SetState(SS_BAD);
  961. pServer->ClearThreadAlive();
  962. pServer->ClearManualFind( );
  963. return 1;
  964. }
  965. // Make sure we don't have to quit
  966. if(!pServer->ShouldBackgroundContinue()) {
  967. if(pLogonId) WinStationFreeMemory(pLogonId);
  968. pServer->ClearThreadAlive();
  969. ODS( L"CServer!BackgroundThreadProc -# backgrnd thread should not continue\n" );
  970. return 0;
  971. }
  972. if(pLogonId)
  973. {
  974. // Get information about the WinStations
  975. for(ULONG i = 0; i < Entries; i++)
  976. {
  977. // Look for this WinStation in the list
  978. CWinStation *pWinStation = pServer->FindWinStationById(pLogonId[i].LogonId);
  979. if(pWinStation)
  980. {
  981. // Mark this WinStation as current
  982. pWinStation->SetCurrent();
  983. // We found the WinStation in the list
  984. // Create a new CWinStation object - he will get his information
  985. CWinStation *pTempWinStation = new CWinStation(pServer, &pLogonId[i]);
  986. if(pTempWinStation)
  987. {
  988. // If any information has changed, send a message to update the views
  989. if(pWinStation->Update(pTempWinStation))
  990. {
  991. CFrameWnd *pFrameWnd = (CFrameWnd*)pDoc->GetMainWnd();
  992. if(pFrameWnd && ::IsWindow(pFrameWnd->GetSafeHwnd()))
  993. {
  994. pFrameWnd->SendMessage(WM_ADMIN_UPDATE_WINSTATION, 0, (LPARAM)pWinStation);
  995. }
  996. }
  997. // We don't need the temporary CWinStation object anymore
  998. delete pTempWinStation;
  999. }
  1000. }
  1001. else
  1002. {
  1003. // We didn't find it in our list
  1004. // We don't want to add it to our list if the WinStation is down
  1005. if(pLogonId[i].State != State_Down && pLogonId[i].State != State_Init)
  1006. {
  1007. // Create a new CWinStation object
  1008. CWinStation *pNewWinStation = new CWinStation(pServer, &pLogonId[i]);
  1009. if(pNewWinStation)
  1010. {
  1011. pServer->AddWinStation(pNewWinStation);
  1012. pNewWinStation->SetNew();
  1013. CFrameWnd *pFrameWnd = (CFrameWnd*)pDoc->GetMainWnd();
  1014. if(pFrameWnd && ::IsWindow(pFrameWnd->GetSafeHwnd()))
  1015. {
  1016. pFrameWnd->SendMessage(WM_ADMIN_ADD_WINSTATION, 0, (LPARAM)pNewWinStation);
  1017. }
  1018. }
  1019. }
  1020. }
  1021. }
  1022. WinStationFreeMemory(pLogonId);
  1023. // Send a message to the views to update their WinStations
  1024. CFrameWnd *pFrameWnd = (CFrameWnd*)pDoc->GetMainWnd();
  1025. if(pFrameWnd && ::IsWindow(pFrameWnd->GetSafeHwnd()))
  1026. {
  1027. pFrameWnd->SendMessage(WM_ADMIN_UPDATE_WINSTATIONS, 0, (LPARAM)pServer);
  1028. }
  1029. // Loop through the WinStations for this server and move
  1030. // any that aren't current to a temporary list
  1031. CObList TempList;
  1032. pServer->LockWinStationList();
  1033. CObList *pWinStationList = pServer->GetWinStationList();
  1034. POSITION pos = pWinStationList->GetHeadPosition();
  1035. while(pos)
  1036. {
  1037. POSITION pos2 = pos;
  1038. CWinStation *pWinStation = (CWinStation*)pWinStationList->GetNext(pos);
  1039. if(!pWinStation->IsCurrent())
  1040. {
  1041. // Add the WinStation to our temporary list
  1042. TempList.AddTail(pWinStation);
  1043. // Remove the WinStation from the list of WinStations
  1044. pWinStation = (CWinStation*)pWinStationList->GetAt(pos2);
  1045. pWinStationList->RemoveAt(pos2);
  1046. }
  1047. }
  1048. pServer->UnlockWinStationList();
  1049. pos = TempList.GetHeadPosition();
  1050. while(pos)
  1051. {
  1052. POSITION pos2 = pos;
  1053. CWinStation *pWinStation = (CWinStation*)TempList.GetNext(pos);
  1054. // Send a message to remove the WinStation from the tree view
  1055. CFrameWnd *pFrameWnd = (CFrameWnd*)pDoc->GetMainWnd();
  1056. if(pFrameWnd && ::IsWindow(pFrameWnd->GetSafeHwnd()))
  1057. {
  1058. pFrameWnd->SendMessage(WM_ADMIN_REMOVE_WINSTATION, 0, (LPARAM)pWinStation);
  1059. }
  1060. delete pWinStation;
  1061. }
  1062. TempList.RemoveAll();
  1063. } // end if(pLogonId)
  1064. // If there is an extension DLL loaded, allow it to update info for this Server
  1065. LPFNEXSERVEREVENTPROC EventProc = ((CWinAdminApp*)AfxGetApp())->GetExtServerEventProc();
  1066. if(EventProc) {
  1067. // Returns TRUE if anything changed
  1068. if((*EventProc)(pServer->GetExtensionInfo(), WSEventFlags)) {
  1069. pServer->QueryLicenses();
  1070. CFrameWnd *pFrameWnd = (CFrameWnd*)pDoc->GetMainWnd();
  1071. if(pFrameWnd && ::IsWindow(pFrameWnd->GetSafeHwnd()))
  1072. {
  1073. pFrameWnd->SendMessage(WM_ADMIN_REDISPLAY_LICENSES, 0, (LPARAM)pServer);
  1074. }
  1075. }
  1076. }
  1077. // Tell the Server view to show the new load and license counts
  1078. CFrameWnd *pFrameWnd = (CFrameWnd*)pDoc->GetMainWnd();
  1079. if(pFrameWnd && ::IsWindow(pFrameWnd->GetSafeHwnd()))
  1080. {
  1081. pFrameWnd->SendMessage(WM_ADMIN_UPDATE_SERVER_INFO, 0, (LPARAM)pServer);
  1082. }
  1083. // Make sure we don't have to quit
  1084. if(!pServer->ShouldBackgroundContinue())
  1085. {
  1086. pServer->ClearThreadAlive();
  1087. ODS( L"CServer::BackgroundThreadProc -@ backgrnd thread should not continue\n" );
  1088. return 0;
  1089. }
  1090. } // end while(1)
  1091. } // end CServer::BackgroundThreadProc
  1092. /////////////////////////////////////////////////////////////////////////////
  1093. // CServer::QueryLicenses
  1094. //
  1095. void CServer::QueryLicenses()
  1096. {
  1097. ULONG NumLicenses;
  1098. ExtLicenseInfo *pExtLicenseInfo = NULL;
  1099. // If there is an extension DLL loaded, get this server's list of licenses
  1100. LPFNEXGETSERVERLICENSESPROC LicenseProc = ((CWinAdminApp*)AfxGetApp())->GetExtGetServerLicensesProc();
  1101. if(LicenseProc && m_pExtensionInfo) {
  1102. LockLicenseList();
  1103. // Iterate through the License list
  1104. POSITION pos = m_LicenseList.GetHeadPosition();
  1105. while(pos) {
  1106. CLicense *pLicense = (CLicense*)m_LicenseList.GetNext(pos);
  1107. delete pLicense;
  1108. }
  1109. m_LicenseList.RemoveAll();
  1110. UnlockLicenseList();
  1111. pExtLicenseInfo = (*LicenseProc)(m_pExtensionInfo, &NumLicenses);
  1112. if(pExtLicenseInfo) {
  1113. ExtLicenseInfo *pExtLicense = pExtLicenseInfo;
  1114. for(ULONG lic = 0; lic < NumLicenses; lic++) {
  1115. CLicense *pLicense = new CLicense(this, pExtLicense);
  1116. if(pLicense) {
  1117. AddLicense(pLicense);
  1118. }
  1119. pExtLicense++;
  1120. }
  1121. // Get the extension DLL's function to free the license info
  1122. LPFNEXFREESERVERLICENSESPROC LicenseFreeProc = ((CWinAdminApp*)AfxGetApp())->GetExtFreeServerLicensesProc();
  1123. if(LicenseFreeProc) {
  1124. (*LicenseFreeProc)(pExtLicenseInfo);
  1125. } else {
  1126. TRACE0("WAExGetServerLicenses exists without WAExFreeServerLicenseInfo\n");
  1127. ASSERT(0);
  1128. }
  1129. }
  1130. }
  1131. } // end CServer::QueryLicenses
  1132. /////////////////////////////////////////////////////////////////////////////
  1133. // CServer::AddLicense
  1134. //
  1135. // Add a License to the Server's LicenseList in
  1136. // sorted order
  1137. // NOTE: The list should be NOT be locked by the caller
  1138. //
  1139. void CServer::AddLicense(CLicense *pNewLicense)
  1140. {
  1141. ASSERT(pNewLicense);
  1142. LockLicenseList();
  1143. BOOLEAN bAdded = FALSE;
  1144. POSITION pos, oldpos;
  1145. int Index;
  1146. // Traverse the LicenseList and insert this new License,
  1147. // keeping the list sorted by Class, then Name.
  1148. for(Index = 0, pos = m_LicenseList.GetHeadPosition(); pos != NULL; Index++) {
  1149. oldpos = pos;
  1150. CLicense *pLicense = (CLicense*)m_LicenseList.GetNext(pos);
  1151. if((pLicense->GetClass() > pNewLicense->GetClass())
  1152. || ((pLicense->GetClass() == pNewLicense->GetClass()) &&
  1153. lstrcmpi(pLicense->GetSerialNumber(), pNewLicense->GetSerialNumber()) > 0)) {
  1154. // The new object belongs before the current list object.
  1155. m_LicenseList.InsertBefore(oldpos, pNewLicense);
  1156. bAdded = TRUE;
  1157. break;
  1158. }
  1159. }
  1160. // If we haven't yet added the License, add it now to the tail
  1161. // of the list.
  1162. if(!bAdded) {
  1163. m_LicenseList.AddTail(pNewLicense);
  1164. }
  1165. UnlockLicenseList();
  1166. } // end CServer::AddLicense
  1167. /////////////////////////////////////////////////////////////////////////////
  1168. // CServer::SetState
  1169. //
  1170. void CServer::SetState(SERVER_STATE State)
  1171. {
  1172. m_PreviousState = m_State;
  1173. m_State = State;
  1174. if(m_State != m_PreviousState)
  1175. {
  1176. CWinAdminDoc *pDoc = (CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument();
  1177. CFrameWnd *pFrameWnd = (CFrameWnd*)pDoc->GetMainWnd();
  1178. if(pFrameWnd && ::IsWindow(pFrameWnd->GetSafeHwnd()))
  1179. {
  1180. pFrameWnd->SendMessage(WM_ADMIN_UPDATE_SERVER, 0, (LPARAM)this);
  1181. }
  1182. }
  1183. } // end CServer::SetState