Leaked source code of windows server 2003
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.

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