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.

908 lines
24 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: Monitor.cpp
  4. //
  5. // Module: CMMON32.EXE
  6. //
  7. // Synopsis: Implement class CMonitor
  8. //
  9. // Copyright (c) 1998-1999 Microsoft Corporation
  10. //
  11. // Author: fengsun Created 01/22/98
  12. //
  13. //+----------------------------------------------------------------------------
  14. #include "cmmaster.h"
  15. #include "Monitor.h"
  16. #include "Connection.h"
  17. // The following blocks are copied from winuser.h and wtsapi32.h (we compile with
  18. // _WIN32_WINNT set to less than 5.01, so we can't get these values via a #include)
  19. //
  20. #include "winuser.h"
  21. #define WM_WTSSESSION_CHANGE 0x02B1
  22. //
  23. #include "WtsApi32.h"
  24. #define WTS_CONSOLE_CONNECT 0x1
  25. #define WTS_CONSOLE_DISCONNECT 0x2
  26. #define WTS_REMOTE_CONNECT 0x3
  27. #define WTS_REMOTE_DISCONNECT 0x4
  28. #define WTS_SESSION_LOGON 0x5
  29. #define WTS_SESSION_LOGOFF 0x6
  30. #define WTS_SESSION_LOCK 0x7
  31. #define WTS_SESSION_UNLOCK 0x8
  32. #include "shelldll.cpp" // for common source
  33. //
  34. // The monitor invisible window class name
  35. //
  36. static const TCHAR* const c_pszCmMonWndClass = TEXT("CM Monitor Window");
  37. //
  38. // static class data members
  39. //
  40. HINSTANCE CMonitor::m_hInst = NULL;
  41. CMonitor* CMonitor::m_pThis = NULL;
  42. inline CMonitor::CMonitor()
  43. {
  44. MYDBGASSERT(m_pThis == NULL);
  45. m_pThis = this;
  46. m_hProcess = NULL;
  47. }
  48. inline CMonitor::~CMonitor()
  49. {
  50. MYDBGASSERT(m_InternalConnArray.GetSize() == 0);
  51. MYDBGASSERT(m_ReconnectConnArray.GetSize() == 0);
  52. MYDBGASSERT(m_hProcess == NULL);
  53. };
  54. //+----------------------------------------------------------------------------
  55. //
  56. // Function: WinMain
  57. //
  58. // Synopsis: WinMain of the exe
  59. //
  60. //
  61. // History: Created Header 1/22/98
  62. //
  63. //+----------------------------------------------------------------------------
  64. int WINAPI WinMain(HINSTANCE , HINSTANCE hPrevInst, LPSTR pszCmdLine, int iCmdShow)
  65. {
  66. //
  67. // First Things First, lets initialize the U Api's
  68. //
  69. if (!InitUnicodeAPI())
  70. {
  71. //
  72. // Without our U api's we are going no where. Bail. Don't show the message if
  73. // we are running in the system account since we might be running without a user
  74. // present.
  75. //
  76. if (!IsLogonAsSystem())
  77. {
  78. MessageBox(NULL, TEXT("Cmmon32.exe Initialization Error: Unable to initialize Unicode to ANSI conversion layer, exiting."),
  79. TEXT("Connection Manager"), MB_OK | MB_ICONERROR);
  80. }
  81. return FALSE;
  82. }
  83. DWORD cb = 0;
  84. HWINSTA hWSta = GetProcessWindowStation();
  85. HDESK hDesk = GetThreadDesktop(GetCurrentThreadId());
  86. TCHAR szWinStation[MAX_PATH] = {0};
  87. TCHAR szDesktopName[MAX_PATH] = {0};
  88. GetUserObjectInformation(hDesk, UOI_NAME, szDesktopName, sizeof(szDesktopName), &cb);
  89. GetUserObjectInformation(hWSta, UOI_NAME, szWinStation, sizeof(szWinStation), &cb);
  90. CMTRACE(TEXT("====================================================="));
  91. CMTRACE1(TEXT(" CMMON32.EXE - LOADING - Process ID is 0x%x "), GetCurrentProcessId());
  92. CMTRACE1(TEXT(" WindowStation Name = %s"), szWinStation);
  93. CMTRACE1(TEXT(" Desktop Name = %s"), szDesktopName);
  94. CMTRACE(TEXT("====================================================="));
  95. int iRet = CMonitor::WinMain(GetModuleHandleA(NULL), hPrevInst, pszCmdLine, iCmdShow);
  96. CMTRACE(TEXT("====================================================="));
  97. CMTRACE1(TEXT(" CMMON32.EXE - UNLOADING - Process ID is 0x%x "), GetCurrentProcessId());
  98. CMTRACE(TEXT("====================================================="));
  99. if (!UnInitUnicodeAPI())
  100. {
  101. CMASSERTMSG(FALSE, TEXT("cmmon32.exe WinMain, UnInitUnicodeAPI failed - we are probably leaking a handle"));
  102. }
  103. //
  104. // that's what C runtime does to exit.
  105. //
  106. ExitProcess(iRet);
  107. return iRet;
  108. }
  109. //+----------------------------------------------------------------------------
  110. //
  111. // Function: CMonitor::WinMain
  112. //
  113. // Synopsis: Called by ::WinMain
  114. //
  115. // Arguments: Same as WinMain
  116. //
  117. //
  118. // Returns: int - return value of the process
  119. //
  120. // History: Created Header 1/22/98
  121. //
  122. //+----------------------------------------------------------------------------
  123. int CMonitor::WinMain(HINSTANCE hInst, HINSTANCE /*hPrevInst*/, LPSTR /*pszCmdLine*/, int /*iCmdShow*/)
  124. {
  125. m_hInst = hInst;
  126. //
  127. // The only Monitor object exist during the life time of WinMain
  128. //
  129. CMonitor theMonitor;
  130. if (!theMonitor.Initialize())
  131. {
  132. CMTRACE(TEXT("theMonitor.Initialize failed"));
  133. return 0;
  134. }
  135. MSG msg;
  136. //
  137. // Loop until PostQuitMessage is called,
  138. // This happens when both connected and reconnecting array are down to 0
  139. //
  140. while(GetMessageU(&msg, NULL,0,0))
  141. {
  142. TranslateMessage(&msg);
  143. DispatchMessageU(&msg);
  144. }
  145. theMonitor.Terminate();
  146. CMTRACE(TEXT("The Monitor is terminated"));
  147. return 0;
  148. }
  149. //+----------------------------------------------------------------------------
  150. //
  151. // Function: CMonitor::Initialize
  152. //
  153. // Synopsis: Initialize before the monitor start the message loop
  154. //
  155. // Arguments: None
  156. //
  157. // Returns: BOOL - Whether successfully initialized
  158. //
  159. // History: fengsun Created Header 2/17/98
  160. //
  161. //+----------------------------------------------------------------------------
  162. BOOL CMonitor::Initialize()
  163. {
  164. DWORD dwProcessId = GetCurrentProcessId();
  165. m_hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
  166. MYDBGASSERT(m_hProcess);
  167. #ifdef DEBUG
  168. BOOL fStandAlone = FALSE; // whether cmmon is lauched directly instead of through cmdial
  169. #endif
  170. if (FAILED(m_SharedTable.Open()))
  171. {
  172. #ifdef DEBUG
  173. if ( MessageBox(NULL, TEXT("CMMON32.exe has to be launched by CMDIAL. \nContinue testing?"),
  174. TEXT("CmMon32 ERROR"), MB_YESNO|MB_ICONQUESTION|MB_SYSTEMMODAL)
  175. == IDNO)
  176. {
  177. return FALSE;
  178. }
  179. fStandAlone = TRUE;
  180. if (FAILED(m_SharedTable.Create()))
  181. #endif
  182. return FALSE;
  183. }
  184. #ifdef DEBUG
  185. //
  186. // No other CMMON running
  187. //
  188. HWND hwndMonitor;
  189. m_SharedTable.GetMonitorWnd(&hwndMonitor);
  190. MYDBGASSERT(hwndMonitor == NULL);
  191. #endif
  192. if ((m_hwndMonitor = CreateMonitorWindow()) == NULL)
  193. {
  194. CMTRACE(TEXT("CreateMonitorWindow failed"));
  195. return FALSE;
  196. }
  197. MYVERIFY(SUCCEEDED(m_SharedTable.SetMonitorWnd(m_hwndMonitor)));
  198. //
  199. // Register for user changes (XP onwards only)
  200. //
  201. if (OS_NT51)
  202. {
  203. HINSTANCE hInstLib = LoadLibrary(TEXT("WTSAPI32.DLL"));
  204. if (hInstLib)
  205. {
  206. BOOL (WINAPI *pfnWTSRegisterSessionNotification)(HWND, DWORD);
  207. pfnWTSRegisterSessionNotification = (BOOL(WINAPI *)(HWND, DWORD)) GetProcAddress(hInstLib, "WTSRegisterSessionNotification") ;
  208. if (pfnWTSRegisterSessionNotification)
  209. {
  210. pfnWTSRegisterSessionNotification(m_hwndMonitor, NOTIFY_FOR_THIS_SESSION);
  211. }
  212. FreeLibrary(hInstLib);
  213. }
  214. else
  215. {
  216. MYDBGASSERT(0);
  217. }
  218. }
  219. //
  220. // Tell CmDial32.dll, CmMon is ready to receive message
  221. //
  222. HANDLE hEvent = OpenEventU(EVENT_ALL_ACCESS, FALSE, c_pszCmMonReadyEvent);
  223. #ifdef DEBUG
  224. if (!fStandAlone && !hEvent)
  225. {
  226. DWORD dw = GetLastError();
  227. CMTRACE1(TEXT("CreateMonitorWindow -- OpenEvent failed %d"), dw);
  228. //
  229. // CmDial have the event opened
  230. //
  231. MYDBGASSERT(hEvent);
  232. }
  233. #endif
  234. SetEvent(hEvent);
  235. CloseHandle(hEvent);
  236. return TRUE;
  237. }
  238. //+----------------------------------------------------------------------------
  239. //
  240. // Function: CMonitor::Terminate
  241. //
  242. // Synopsis: Cleanup, before exit
  243. //
  244. // Arguments: None
  245. //
  246. // Returns: Nothing
  247. //
  248. // History: Created Header 2/17/98
  249. //
  250. //+----------------------------------------------------------------------------
  251. void CMonitor::Terminate()
  252. {
  253. //
  254. // All the thread should exited at this point
  255. //
  256. if (m_ReconnectConnArray.GetSize() != 0)
  257. {
  258. MYDBGASSERT(FALSE);
  259. }
  260. if (m_InternalConnArray.GetSize() != 0)
  261. {
  262. MYDBGASSERT(FALSE);
  263. }
  264. //
  265. // Unregister for user changes (XP onwards only)
  266. //
  267. if (OS_NT51)
  268. {
  269. HINSTANCE hInstLib = LoadLibrary(TEXT("WTSAPI32.DLL"));
  270. if (hInstLib)
  271. {
  272. BOOL (WINAPI *pfnWTSUnRegisterSessionNotification)(HWND);
  273. pfnWTSUnRegisterSessionNotification = (BOOL(WINAPI *)(HWND)) GetProcAddress(hInstLib, "WTSUnRegisterSessionNotification") ;
  274. if (pfnWTSUnRegisterSessionNotification)
  275. {
  276. pfnWTSUnRegisterSessionNotification(m_hwndMonitor);
  277. }
  278. FreeLibrary(hInstLib);
  279. }
  280. else
  281. {
  282. MYDBGASSERT(0);
  283. }
  284. }
  285. #ifdef DEBUG
  286. HWND hwndMonitor;
  287. m_SharedTable.GetMonitorWnd(&hwndMonitor);
  288. MYDBGASSERT(hwndMonitor == m_hwndMonitor);
  289. #endif
  290. MYVERIFY(SUCCEEDED(m_SharedTable.SetMonitorWnd(NULL)));
  291. m_SharedTable.Close();
  292. CloseHandle(m_hProcess);
  293. m_hProcess = NULL;
  294. }
  295. //+----------------------------------------------------------------------------
  296. //
  297. // Function: CMonitor::CreateMonitorWindow
  298. //
  299. // Synopsis: Register and create the invisible monitor window
  300. //
  301. // Arguments: None
  302. //
  303. // Returns: HWND - The monitor window handle
  304. //
  305. // History: Created Header 2/17/98
  306. //
  307. //+----------------------------------------------------------------------------
  308. HWND CMonitor::CreateMonitorWindow()
  309. {
  310. //
  311. // Register a window class and create the window
  312. //
  313. WNDCLASSEX wc;
  314. ZeroMemory(&wc, sizeof(wc));
  315. wc.lpszClassName = c_pszCmMonWndClass;
  316. wc.lpfnWndProc = MonitorWindowProc;
  317. wc.cbSize = sizeof(wc);
  318. if (!RegisterClassExU( &wc ))
  319. {
  320. CMTRACE(TEXT("RegisterClassEx failed"));
  321. return NULL;
  322. }
  323. return CreateWindowExU(0, c_pszCmMonWndClass, TEXT(""), 0, 0,
  324. 0, 0, 0, 0, 0, m_hInst, 0);
  325. }
  326. //+----------------------------------------------------------------------------
  327. //
  328. // Function: CMonitor::HandleFastUserSwitch
  329. //
  330. // Synopsis: Does any disconnects required when XP does a fast user switch
  331. //
  332. // Arguments: dwAction - a WTS_ value indicating how the user's state has changed
  333. //
  334. // Returns: BOOL - success or failure
  335. //
  336. // History: 10-Jul-2001 SumitC Created
  337. //
  338. //+----------------------------------------------------------------------------
  339. BOOL
  340. CMonitor::HandleFastUserSwitch(IN DWORD dwAction)
  341. {
  342. BOOL bRet = TRUE;
  343. BOOL fDisconnecting = FALSE;
  344. MYDBGASSERT(OS_NT51);
  345. if (!OS_NT51)
  346. {
  347. goto Cleanup;
  348. }
  349. if ((WTS_SESSION_LOCK == dwAction) || (WTS_SESSION_UNLOCK == dwAction))
  350. {
  351. // don't do anything for lock and unlock
  352. goto Cleanup;
  353. }
  354. //
  355. // See if we are disconnecting
  356. //
  357. if ((WTS_CONSOLE_DISCONNECT == dwAction) ||
  358. (WTS_REMOTE_DISCONNECT == dwAction) ||
  359. (WTS_SESSION_LOGOFF == dwAction))
  360. {
  361. fDisconnecting = TRUE;
  362. }
  363. //
  364. // If a session is being disconnected, find out if any of the connected
  365. // connectoids are single-user, and disconnect them if so.
  366. //
  367. if (fDisconnecting)
  368. {
  369. CMTRACE(TEXT("CMonitor::HandleFastUserSwitch -- see if theres anything to disconnect"));
  370. for (INT i = 0; i < m_InternalConnArray.GetSize(); ++i)
  371. {
  372. CCmConnection* pConnection = (CCmConnection*)m_InternalConnArray[i];
  373. ASSERT_VALID(pConnection);
  374. if (pConnection && (FALSE == pConnection->m_fGlobalGlobal))
  375. {
  376. CMTRACE1(TEXT("CMonitor::HandleFastUserSwitch -- found one, disconnecting %s"), pConnection->GetServiceName());
  377. MYVERIFY(TRUE == pConnection->OnEndSession(TRUE, FALSE));
  378. }
  379. }
  380. }
  381. Cleanup:
  382. return bRet;
  383. }
  384. //+----------------------------------------------------------------------------
  385. //
  386. // Function: CMonitor::MonitorWindowProc
  387. //
  388. // Synopsis: The window procedure of the invisible monitor window
  389. //
  390. // Arguments: HWND hWnd - Window Proc parameters
  391. // UINT uMsg -
  392. // WPARAM wParam -
  393. // LPARAM lParam -
  394. //
  395. // Returns: LRESULT -
  396. //
  397. // History: Created Header 2/3/98
  398. //
  399. //+----------------------------------------------------------------------------
  400. LRESULT CALLBACK CMonitor::MonitorWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  401. {
  402. switch (uMsg)
  403. {
  404. case WM_COPYDATA:
  405. {
  406. ASSERT_VALID(m_pThis);
  407. COPYDATASTRUCT* pCopyData = (COPYDATASTRUCT*) lParam;
  408. MYDBGASSERT(pCopyData);
  409. switch(pCopyData->dwData)
  410. {
  411. case CMMON_CONNECTED_INFO:
  412. MYDBGASSERT(pCopyData->cbData >= sizeof(CM_CONNECTED_INFO));
  413. m_pThis->OnConnected((CM_CONNECTED_INFO*)pCopyData->lpData);
  414. return TRUE;
  415. case CMMON_HANGUP_INFO:
  416. MYDBGASSERT(pCopyData->cbData == sizeof(CM_HANGUP_INFO));
  417. m_pThis->OnHangup((CM_HANGUP_INFO*)pCopyData->lpData);
  418. return TRUE;
  419. default:
  420. MYDBGASSERT(FALSE);
  421. return FALSE;
  422. }
  423. }
  424. break;
  425. case WM_REMOVE_CONNECTION:
  426. ASSERT_VALID(m_pThis);
  427. m_pThis->OnRemoveConnection((DWORD)wParam, (CCmConnection*)lParam);
  428. return TRUE;
  429. break;
  430. case WM_QUERYENDSESSION:
  431. CMTRACE(TEXT("CMonitor::MonitorWindowProc -- Got WM_QUERYENDSESSION message"));
  432. return m_pThis->OnQueryEndSession((BOOL)lParam);
  433. break;
  434. case WM_ENDSESSION:
  435. CMTRACE(TEXT("CMonitor::MonitorWindowProc -- Got WM_ENDSESSION message"));
  436. break;
  437. case WM_WTSSESSION_CHANGE:
  438. CMTRACE1(TEXT("CMonitor::MonitorWindowProc -- Got WM_WTSSESSION_CHANGE message with %d"), wParam);
  439. if (OS_NT51)
  440. {
  441. MYVERIFY(m_pThis->HandleFastUserSwitch((DWORD)wParam));
  442. }
  443. break;
  444. default:
  445. break;
  446. }
  447. return DefWindowProcU(hWnd, uMsg, wParam, lParam);
  448. }
  449. //+----------------------------------------------------------------------------
  450. //
  451. // Function: CMonitor::OnConnected
  452. //
  453. // Synopsis: Called upon CMMON_CONNECTED_INFO received from cmdial
  454. //
  455. // Arguments: const CONNECTED_INFO* pConnectedInfo - Info from CmDial
  456. //
  457. // Returns: Nothing
  458. //
  459. // History: fengsun Created Header 2/3/98
  460. //
  461. //+----------------------------------------------------------------------------
  462. void CMonitor::OnConnected(const CM_CONNECTED_INFO* pConnectedInfo)
  463. {
  464. ASSERT_VALID(this);
  465. CMTRACE(TEXT("CMonitor::OnConnected"));
  466. RestoreWorkingSet();
  467. MYDBGASSERT(pConnectedInfo);
  468. //
  469. // Not in the connected table
  470. //
  471. MYDBGASSERT(!LookupConnection(m_InternalConnArray, pConnectedInfo->szEntryName));
  472. // ASSERT in the shared table
  473. CM_CONNECTION ConnectionEntry;
  474. if (FAILED(m_SharedTable.GetEntry(pConnectedInfo->szEntryName, &ConnectionEntry)))
  475. {
  476. MYDBGASSERT(!"CMonitor::OnConnected: Can not find the connection");
  477. return;
  478. }
  479. CCmConnection* pConnection = new CCmConnection(pConnectedInfo, &ConnectionEntry);
  480. MYDBGASSERT(pConnection);
  481. if (pConnection)
  482. {
  483. m_InternalConnArray.Add(pConnection);
  484. pConnection->StartConnectionThread();
  485. }
  486. }
  487. //+----------------------------------------------------------------------------
  488. //
  489. // Function: CMonitor::OnHangup
  490. //
  491. // Synopsis: Upon CMMON_HANGUP_INFO request from CMDIAL
  492. // Post the request to the thread
  493. //
  494. // Arguments: const CM_HANGUP_INFO* pHangupInfo - Info from CmDial
  495. //
  496. // Returns: Nothing
  497. //
  498. // History: fengsun Created Header 2/12/98
  499. //
  500. //+----------------------------------------------------------------------------
  501. void CMonitor::OnHangup(const CM_HANGUP_INFO* pHangupInfo)
  502. {
  503. ASSERT_VALID(this);
  504. RestoreWorkingSet();
  505. MYDBGASSERT(pHangupInfo);
  506. MYDBGASSERT(pHangupInfo->szEntryName[0]);
  507. //
  508. // Upon hangup request from CMDIAL.DLL
  509. // Look up the InternalConnArray for the connection
  510. //
  511. CCmConnection* pConnection = LookupConnection(m_InternalConnArray,pHangupInfo->szEntryName);
  512. //
  513. // CMDIAL post this message regardless whether there is a connection
  514. //
  515. if (!pConnection)
  516. {
  517. return;
  518. }
  519. pConnection->PostHangupMsg();
  520. //
  521. // The connection thread will post a REMOVE_CONNECTION message back when finished
  522. //
  523. }
  524. //+----------------------------------------------------------------------------
  525. //
  526. // Function: CMonitor::LookupConnection
  527. //
  528. // Synopsis: Look up a connection from connection array by service name
  529. //
  530. // Arguments: const CPtrArray& ConnArray - The array to lookup
  531. // const TCHAR* pServiceName - The servicename of the connection
  532. //
  533. // Returns: CCmConnection* - the connection found or NULL
  534. //
  535. // History: fengsun Created Header 2/17/98
  536. //
  537. //+----------------------------------------------------------------------------
  538. CCmConnection* CMonitor::LookupConnection(const CPtrArray& ConnArray, const TCHAR* pServiceName) const
  539. {
  540. for (int i =0; i<ConnArray.GetSize(); i++)
  541. {
  542. CCmConnection* pConnection = (CCmConnection*)ConnArray[i];
  543. ASSERT_VALID(pConnection);
  544. if (lstrcmpiU(pServiceName, pConnection->GetServiceName()) == 0)
  545. {
  546. return pConnection;
  547. }
  548. }
  549. return NULL;
  550. }
  551. //+----------------------------------------------------------------------------
  552. //
  553. // Function: CMonitor::LookupConnection
  554. //
  555. // Synopsis: Look up a connection from connection array by connection pointer
  556. //
  557. // Arguments: const CPtrArray& ConnArray - The array to lookup
  558. // const CCmConnection* pConnection - The connection pointer
  559. //
  560. // Returns: int - the index to the array, or -1 if not found
  561. //
  562. // History: Created Header 2/17/98
  563. //
  564. //+----------------------------------------------------------------------------
  565. int CMonitor::LookupConnection(const CPtrArray& ConnArray, const CCmConnection* pConnection) const
  566. {
  567. ASSERT_VALID(pConnection);
  568. for (int i =0; i<ConnArray.GetSize(); i++)
  569. {
  570. if ((CCmConnection*)ConnArray[i] == pConnection )
  571. {
  572. return i;
  573. }
  574. }
  575. return -1;
  576. }
  577. //+----------------------------------------------------------------------------
  578. //
  579. // Function: CMonitor::RemoveConnection
  580. //
  581. // Synopsis: Called by connection thread to remove a connection from
  582. // connected/reconnecting array
  583. //
  584. // Arguments: CCmConnection* pConnection - The connection to remove
  585. // BOOL fClearTable - Whter to remove the connection from shared table
  586. //
  587. // Returns: Nothing
  588. //
  589. // History: fengsun Created Header 2/23/98
  590. //
  591. //+----------------------------------------------------------------------------
  592. void CMonitor::RemoveConnection(CCmConnection* pConnection, BOOL fClearTable)
  593. {
  594. if (fClearTable)
  595. {
  596. //
  597. // Called in Connection thread. Operation on m_SharedTable is multi-thread safe
  598. //
  599. m_pThis->m_SharedTable.ClearEntry(pConnection->GetServiceName());
  600. }
  601. //
  602. // The internal connection list is not safe to be accessed by multiple thread
  603. // Message will be processed in monitor thread OnRemoveConnection
  604. //
  605. PostMessageU(GetMonitorWindow(), WM_REMOVE_CONNECTION,
  606. REMOVE_CONNECTION, (LPARAM)pConnection);
  607. }
  608. //+----------------------------------------------------------------------------
  609. //
  610. // Function: CMonitor::MoveToReconnectingConn
  611. //
  612. // Synopsis: Called by connection thread. Move a connection from connected
  613. // array to reconnecting array
  614. //
  615. // Arguments: CCmConnection* pConnection - The connectio to move
  616. //
  617. // Returns: Nothing
  618. //
  619. // History: fengsun Created Header 2/23/98
  620. //
  621. //+----------------------------------------------------------------------------
  622. void CMonitor::MoveToReconnectingConn(CCmConnection* pConnection)
  623. {
  624. //
  625. // Message will be processed in OnRemoveConnection
  626. // Note: SendMessage to another thread can cause deadlock, if the reveiving
  627. // thread also SendMessage back to this thread.
  628. // Use SendMessageTimeout if that is the case
  629. //
  630. PostMessageU(GetMonitorWindow(), WM_REMOVE_CONNECTION,
  631. MOVE_TO_RECONNECTING, (LPARAM)pConnection);
  632. }
  633. //+----------------------------------------------------------------------------
  634. //
  635. // Function: CMonitor::OnRemoveConnection
  636. //
  637. // Synopsis: Called whether a remove connection request is received from
  638. // connection thread.
  639. // Remove the connection from connected array or reconnecting array
  640. // Delete it from the shared connectio table
  641. // If both array are down to 0, exit cmmon
  642. //
  643. // Arguments: DWORD dwRequestType -
  644. // REMOVE_CONNECTION remove the connection from either array
  645. // MOVE_TO_RECONNECTING move the connection from connected array
  646. // to reconnecting array
  647. //
  648. // CCmConnection* pConnection - The connetion to remove or move
  649. //
  650. // Returns: Nothing
  651. //
  652. // History: fengsun Created Header 2/3/98
  653. //
  654. //+----------------------------------------------------------------------------
  655. void CMonitor::OnRemoveConnection(DWORD dwRequestType, CCmConnection* pConnection)
  656. {
  657. ASSERT_VALID(this);
  658. ASSERT_VALID(pConnection);
  659. switch(dwRequestType)
  660. {
  661. case REMOVE_CONNECTION:
  662. {
  663. int nIndex = LookupConnection(m_InternalConnArray, pConnection);
  664. if (nIndex != -1)
  665. {
  666. //
  667. // Remove the entry from connected array
  668. //
  669. m_InternalConnArray.RemoveAt(nIndex);
  670. }
  671. else
  672. {
  673. //
  674. // Remove the entry from reconnecting array
  675. //
  676. nIndex = LookupConnection(m_ReconnectConnArray, pConnection);
  677. MYDBGASSERT(nIndex != -1);
  678. if (nIndex == -1)
  679. {
  680. break;
  681. }
  682. m_ReconnectConnArray.RemoveAt(nIndex);
  683. }
  684. delete pConnection;
  685. }
  686. break;
  687. case MOVE_TO_RECONNECTING:
  688. {
  689. //
  690. // Move from connected array to reconnecting array
  691. //
  692. int nIndex = LookupConnection(m_InternalConnArray, pConnection);
  693. MYDBGASSERT(nIndex != -1);
  694. if (nIndex == -1)
  695. {
  696. break;
  697. }
  698. m_InternalConnArray.RemoveAt(nIndex);
  699. m_ReconnectConnArray.Add(pConnection);
  700. }
  701. break;
  702. default:
  703. MYDBGASSERT(FALSE);
  704. break;
  705. }
  706. //
  707. // If there are no connections, quit CmMon
  708. //
  709. if (m_ReconnectConnArray.GetSize() == 0 && m_InternalConnArray.GetSize() == 0)
  710. {
  711. PostQuitMessage(0);
  712. }
  713. }
  714. //+----------------------------------------------------------------------------
  715. //
  716. // Function: CMonitor::OnQueryEndSession
  717. //
  718. // Synopsis: This message processes the WM_QUERYENDSESSION message by passing
  719. // it to all the connection threads.
  720. //
  721. // Arguments: Nothing
  722. //
  723. // Returns: TRUE if successful, FALSE otherwise
  724. //
  725. // History: quintinb Created 3/18/99
  726. //
  727. //+----------------------------------------------------------------------------
  728. BOOL CMonitor::OnQueryEndSession(BOOL fLogOff) const
  729. {
  730. BOOL bOkayToEndSession = TRUE;
  731. BOOL bReturn;
  732. for (int i = 0; i < m_InternalConnArray.GetSize(); i++)
  733. {
  734. ASSERT_VALID((CCmConnection*)m_InternalConnArray[i]);
  735. bReturn = ((CCmConnection*)m_InternalConnArray[i])->OnEndSession(TRUE, fLogOff); // fEndSession == TRUE
  736. bOkayToEndSession = bOkayToEndSession && bReturn;
  737. }
  738. return bOkayToEndSession;
  739. }
  740. #ifdef DEBUG
  741. //+----------------------------------------------------------------------------
  742. //
  743. // Function: CMonitor::AssertValid
  744. //
  745. // Synopsis: Helper function for debug. Assert the object is in a valid state
  746. //
  747. // Arguments: None
  748. //
  749. // Returns: Nothing
  750. //
  751. // History: Created Header 2/17/98
  752. //
  753. //+----------------------------------------------------------------------------
  754. void CMonitor::AssertValid() const
  755. {
  756. MYDBGASSERT(IsWindow(m_hwndMonitor));
  757. MYDBGASSERT(m_pThis == this);
  758. ASSERT_VALID(&m_InternalConnArray);
  759. ASSERT_VALID(&m_ReconnectConnArray);
  760. }
  761. #endif