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.

936 lines
30 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: CLogonStatusHost.cpp
  3. //
  4. // Copyright (c) 2000, Microsoft Corporation
  5. //
  6. // File that contains implementation for ILogonStatusHost for use by UI host
  7. // executables.
  8. //
  9. // History: 2000-05-10 vtan created
  10. // --------------------------------------------------------------------------
  11. #include "priv.h"
  12. #include <wtsapi32.h>
  13. #include <winsta.h>
  14. #include "UserOM.h"
  15. #include "GinaIPC.h"
  16. #include "CInteractiveLogon.h"
  17. const WCHAR CLogonStatusHost::s_szTermSrvReadyEventName[] = TEXT("TermSrvReadyEvent");
  18. //
  19. // IUnknown Interface
  20. //
  21. ULONG CLogonStatusHost::AddRef (void)
  22. {
  23. return(++_cRef);
  24. }
  25. ULONG CLogonStatusHost::Release (void)
  26. {
  27. ULONG ulResult;
  28. ASSERTMSG(_cRef > 0, "Invalid reference count in CLogonStatusHost::Release");
  29. ulResult = --_cRef;
  30. if (ulResult <= 0)
  31. {
  32. delete this;
  33. ulResult = 0;
  34. }
  35. return(ulResult);
  36. }
  37. HRESULT CLogonStatusHost::QueryInterface (REFIID riid, void **ppvObj)
  38. {
  39. static const QITAB qit[] =
  40. {
  41. QITABENT(CLogonStatusHost, IDispatch),
  42. QITABENT(CLogonStatusHost, ILogonStatusHost),
  43. {0},
  44. };
  45. return(QISearch(this, qit, riid, ppvObj));
  46. }
  47. //
  48. // IDispatch Interface
  49. //
  50. STDMETHODIMP CLogonStatusHost::GetTypeInfoCount (UINT* pctinfo)
  51. {
  52. return(CIDispatchHelper::GetTypeInfoCount(pctinfo));
  53. }
  54. STDMETHODIMP CLogonStatusHost::GetTypeInfo (UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
  55. {
  56. return(CIDispatchHelper::GetTypeInfo(itinfo, lcid, pptinfo));
  57. }
  58. STDMETHODIMP CLogonStatusHost::GetIDsOfNames (REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid)
  59. {
  60. return(CIDispatchHelper::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid));
  61. }
  62. STDMETHODIMP CLogonStatusHost::Invoke (DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr)
  63. {
  64. return(CIDispatchHelper::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr));
  65. }
  66. //
  67. // ILogonStatusHost Interface
  68. //
  69. // --------------------------------------------------------------------------
  70. // CLogonStatusHost::Initialize
  71. //
  72. // Arguments: hInstance = HINSTANCE of hosting process.
  73. // hwndHost = HWND of UI host process.
  74. //
  75. // Returns: HRESULT
  76. //
  77. // Purpose: Registers the StatusWindowClass and creates an invisible
  78. // window of this class to receive messages from GINA to pass
  79. // through to the UI host.
  80. //
  81. // History: 2000-05-10 vtan created
  82. // --------------------------------------------------------------------------
  83. STDMETHODIMP CLogonStatusHost::Initialize (HINSTANCE hInstance, HWND hwndHost)
  84. {
  85. HRESULT hr;
  86. HANDLE hEvent;
  87. WNDCLASSEX wndClassEx;
  88. ASSERTMSG(_hInstance == NULL, "CLogonStatusHost::Initialized already invoked by caller.");
  89. // Save parameters to member variables.
  90. _hInstance = hInstance;
  91. _hwndHost = hwndHost;
  92. // Register this window class.
  93. ZeroMemory(&wndClassEx, sizeof(wndClassEx));
  94. wndClassEx.cbSize = sizeof(WNDCLASSEX);
  95. wndClassEx.lpfnWndProc = StatusWindowProc;
  96. wndClassEx.hInstance = hInstance;
  97. wndClassEx.lpszClassName = STATUS_WINDOW_CLASS_NAME;
  98. _atom = RegisterClassEx(&wndClassEx);
  99. // Create the window to receive messages from msgina.
  100. _hwnd = CreateWindow(MAKEINTRESOURCE(_atom),
  101. TEXT("GINA UI"),
  102. WS_OVERLAPPED,
  103. 0, 0,
  104. 0, 0,
  105. NULL,
  106. NULL,
  107. _hInstance,
  108. this);
  109. // Signal msgina that we're ready.
  110. hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, TEXT("msgina: StatusHostReadyEvent"));
  111. if (hEvent != NULL)
  112. {
  113. TBOOL(SetEvent(hEvent));
  114. TBOOL(CloseHandle(hEvent));
  115. }
  116. // If we have a window then set the host window in, start waiting
  117. // for terminal services to be ready and a wait on the parent process.
  118. if (_hwnd != NULL)
  119. {
  120. _interactiveLogon.SetHostWindow(_hwndHost);
  121. StartWaitForParentProcess();
  122. StartWaitForTermService();
  123. hr = S_OK;
  124. }
  125. else
  126. {
  127. hr = E_OUTOFMEMORY;
  128. }
  129. return(hr);
  130. }
  131. // --------------------------------------------------------------------------
  132. // CLogonStatusHost::UnInitialize
  133. //
  134. // Arguments: <none>
  135. //
  136. // Returns: HRESULT
  137. //
  138. // Purpose: Cleans up resources and memory allocated in Initialize.
  139. //
  140. // History: 2001-01-03 vtan created
  141. // --------------------------------------------------------------------------
  142. STDMETHODIMP CLogonStatusHost::UnInitialize (void)
  143. {
  144. ASSERTMSG(_hInstance != NULL, "CLogonStatusHost::UnInitialized invoked without Initialize.");
  145. if (_hwnd != NULL)
  146. {
  147. EndWaitForTermService();
  148. EndWaitForParentProcess();
  149. if (_fRegisteredNotification != FALSE)
  150. {
  151. TBOOL(WinStationUnRegisterConsoleNotification(SERVERNAME_CURRENT, _hwnd));
  152. _fRegisteredNotification = FALSE;
  153. }
  154. TBOOL(DestroyWindow(_hwnd));
  155. _hwnd = NULL;
  156. }
  157. if (_atom != 0)
  158. {
  159. TBOOL(UnregisterClass(MAKEINTRESOURCE(_atom), _hInstance));
  160. _atom = 0;
  161. }
  162. _hwndHost = NULL;
  163. _hInstance = NULL;
  164. return(S_OK);
  165. }
  166. // --------------------------------------------------------------------------
  167. // CLogonStatusHost::WindowProcedureHelper
  168. //
  169. // Arguments: See the platform SDK under WindowProc.
  170. //
  171. // Returns: HRESULT
  172. //
  173. // Purpose: Handles certain messages for the status UI host. This allows
  174. // things like ALT-F4 to be discarded or power messages to be
  175. // responded to correctly.
  176. //
  177. // History: 2000-05-10 vtan created
  178. // --------------------------------------------------------------------------
  179. STDMETHODIMP CLogonStatusHost::WindowProcedureHelper (HWND hwnd, UINT uMsg, VARIANT wParam, VARIANT lParam)
  180. {
  181. UNREFERENCED_PARAMETER(hwnd);
  182. UNREFERENCED_PARAMETER(lParam);
  183. HRESULT hr;
  184. hr = E_NOTIMPL;
  185. switch (uMsg)
  186. {
  187. case WM_SYSCOMMAND:
  188. if (SC_CLOSE == wParam.uintVal) // Blow off ALT-F4
  189. {
  190. hr = S_OK;
  191. }
  192. break;
  193. default:
  194. break;
  195. }
  196. return(hr);
  197. }
  198. // --------------------------------------------------------------------------
  199. // CLogonStatusHost::Handle_WM_UISERVICEREQUEST
  200. //
  201. // Arguments: wParam = WPARAM sent from GINA.
  202. // lParam = LPARAM sent from GINA.
  203. //
  204. // Returns: LRESULT
  205. //
  206. // Purpose: Receives messages from GINA bound for the UI host. Turns
  207. // around and passes the messages to the UI host. This allows
  208. // the actual implementation to change without having to
  209. // rebuild the UI host.
  210. //
  211. // History: 2000-05-10 vtan created
  212. // --------------------------------------------------------------------------
  213. LRESULT CLogonStatusHost::Handle_WM_UISERVICEREQUEST (WPARAM wParam, LPARAM lParam)
  214. {
  215. LRESULT lResult;
  216. WPARAM wParamSend;
  217. void *pV;
  218. lResult = 0;
  219. pV = NULL;
  220. wParamSend = HM_NOACTION;
  221. switch (wParam)
  222. {
  223. case UI_TERMINATE:
  224. ExitProcess(0);
  225. break;
  226. case UI_STATE_STATUS:
  227. _interactiveLogon.Stop();
  228. wParamSend = HM_SWITCHSTATE_STATUS;
  229. break;
  230. case UI_STATE_LOGON:
  231. _interactiveLogon.Start();
  232. wParamSend = HM_SWITCHSTATE_LOGON;
  233. break;
  234. case UI_STATE_LOGGEDON:
  235. _interactiveLogon.Stop();
  236. wParamSend = HM_SWITCHSTATE_LOGGEDON;
  237. break;
  238. case UI_STATE_HIDE:
  239. _interactiveLogon.Stop();
  240. TBOOL(SetProcessWorkingSetSize(GetCurrentProcess(), static_cast<SIZE_T>(-1), static_cast<SIZE_T>(-1)));
  241. wParamSend = HM_SWITCHSTATE_HIDE;
  242. break;
  243. case UI_STATE_END:
  244. EndWaitForTermService();
  245. EndWaitForParentProcess();
  246. wParamSend = HM_SWITCHSTATE_DONE;
  247. break;
  248. case UI_NOTIFY_WAIT:
  249. wParamSend = HM_NOTIFY_WAIT;
  250. break;
  251. case UI_SELECT_USER:
  252. pV = LocalAlloc(LPTR, sizeof(SELECT_USER));
  253. if (pV != NULL)
  254. {
  255. (WCHAR*)lstrcpyW(static_cast<SELECT_USER*>(pV)->szUsername, reinterpret_cast<LOGONIPC_USERID*>(lParam)->wszUsername);
  256. (WCHAR*)lstrcpyW(static_cast<SELECT_USER*>(pV)->szDomain, reinterpret_cast<LOGONIPC_USERID*>(lParam)->wszDomain);
  257. wParamSend = HM_SELECT_USER;
  258. lParam = reinterpret_cast<LPARAM>(pV);
  259. }
  260. break;
  261. case UI_SET_ANIMATIONS:
  262. wParamSend = HM_SET_ANIMATIONS;
  263. break;
  264. case UI_INTERACTIVE_LOGON:
  265. pV = LocalAlloc(LPTR, sizeof(INTERACTIVE_LOGON_REQUEST));
  266. if (pV != NULL)
  267. {
  268. (WCHAR*)lstrcpyW(static_cast<INTERACTIVE_LOGON_REQUEST*>(pV)->szUsername, reinterpret_cast<LOGONIPC_CREDENTIALS*>(lParam)->userID.wszUsername);
  269. (WCHAR*)lstrcpyW(static_cast<INTERACTIVE_LOGON_REQUEST*>(pV)->szDomain, reinterpret_cast<LOGONIPC_CREDENTIALS*>(lParam)->userID.wszDomain);
  270. (WCHAR*)lstrcpyW(static_cast<INTERACTIVE_LOGON_REQUEST*>(pV)->szPassword, reinterpret_cast<LOGONIPC_CREDENTIALS*>(lParam)->wszPassword);
  271. ZeroMemory(&reinterpret_cast<LOGONIPC_CREDENTIALS*>(lParam)->wszPassword, (lstrlenW(reinterpret_cast<LOGONIPC_CREDENTIALS*>(lParam)->wszPassword) + sizeof('\0')) * sizeof(WCHAR));
  272. wParamSend = HM_INTERACTIVE_LOGON_REQUEST;
  273. lParam = reinterpret_cast<LPARAM>(pV);
  274. }
  275. break;
  276. case UI_DISPLAY_STATUS:
  277. wParamSend = HM_DISPLAYSTATUS;
  278. break;
  279. default:
  280. break;
  281. }
  282. if (wParam != HM_NOACTION)
  283. {
  284. lResult = SendMessage(_hwndHost, WM_UIHOSTMESSAGE, wParamSend, lParam);
  285. }
  286. else
  287. {
  288. lResult = 0;
  289. }
  290. if (pV != NULL)
  291. {
  292. (HLOCAL)LocalFree(pV);
  293. }
  294. return(lResult);
  295. }
  296. // --------------------------------------------------------------------------
  297. // CLogonStatusHost::Handle_WM_WTSSESSION_CHANGE
  298. //
  299. // Arguments: wParam =
  300. // lParam =
  301. //
  302. // Returns: LRESULT
  303. //
  304. // Purpose: Receives messages from GINA bound for the UI host. Turns
  305. // around and passes the messages to the UI host. This allows
  306. // the actual implementation to change without having to
  307. // rebuild the UI host.
  308. //
  309. // History: 2000-05-10 vtan created
  310. // --------------------------------------------------------------------------
  311. LRESULT CLogonStatusHost::Handle_WM_WTSSESSION_CHANGE (WPARAM wParam, LPARAM lParam)
  312. {
  313. UNREFERENCED_PARAMETER(lParam);
  314. LRESULT lResult;
  315. lResult = 0;
  316. switch (wParam)
  317. {
  318. case WTS_CONSOLE_CONNECT:
  319. case WTS_CONSOLE_DISCONNECT:
  320. case WTS_REMOTE_CONNECT:
  321. case WTS_REMOTE_DISCONNECT:
  322. break;
  323. case WTS_SESSION_LOGON:
  324. case WTS_SESSION_LOGOFF:
  325. lResult = SendMessage(_hwndHost, WM_UIHOSTMESSAGE, HM_DISPLAYREFRESH, 0);
  326. break;
  327. default:
  328. break;
  329. }
  330. return(lResult);
  331. }
  332. // --------------------------------------------------------------------------
  333. // CLogonStatusHost::StatusWindowProc
  334. //
  335. // Arguments: See the platform SDK under WindowProc.
  336. //
  337. // Returns: <none>
  338. //
  339. // Purpose: Window procedure for StatusWindowClass.
  340. //
  341. // History: 2000-05-10 vtan created
  342. // --------------------------------------------------------------------------
  343. LRESULT CALLBACK CLogonStatusHost::StatusWindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  344. {
  345. LRESULT lResult;
  346. CLogonStatusHost *pThis;
  347. static bool fDisplayChange = false;
  348. pThis = reinterpret_cast<CLogonStatusHost*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
  349. switch (uMsg)
  350. {
  351. case WM_CREATE:
  352. {
  353. CREATESTRUCT *pCreateStruct;
  354. pCreateStruct = reinterpret_cast<CREATESTRUCT*>(lParam);
  355. (LONG_PTR)SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pCreateStruct->lpCreateParams));
  356. lResult = 0;
  357. break;
  358. }
  359. case WM_UISERVICEREQUEST:
  360. lResult = pThis->Handle_WM_UISERVICEREQUEST(wParam, lParam);
  361. break;
  362. case WM_WTSSESSION_CHANGE:
  363. lResult = pThis->Handle_WM_WTSSESSION_CHANGE(wParam, lParam);
  364. break;
  365. case WM_SETTINGCHANGE:
  366. if (wParam == SPI_SETWORKAREA)
  367. {
  368. lResult = SendMessage(pThis->_hwndHost, WM_UIHOSTMESSAGE, HM_DISPLAYRESIZE, TRUE);
  369. }
  370. else
  371. {
  372. lResult = 0;
  373. }
  374. break;
  375. case WM_DISPLAYCHANGE:
  376. fDisplayChange = true;
  377. lResult = PostMessage(pThis->_hwndHost, WM_UIHOSTMESSAGE, HM_DISPLAYRESIZE, FALSE);
  378. break;
  379. case WM_WINDOWPOSCHANGING:
  380. if (fDisplayChange)
  381. {
  382. fDisplayChange = false;
  383. lResult = PostMessage(pThis->_hwndHost, WM_UIHOSTMESSAGE, HM_DISPLAYRESIZE, FALSE);
  384. }
  385. else
  386. {
  387. lResult = 0;
  388. }
  389. break;
  390. default:
  391. lResult = DefWindowProc(hwnd, uMsg, wParam, lParam);
  392. break;
  393. }
  394. return(lResult);
  395. }
  396. // --------------------------------------------------------------------------
  397. // CLogonStatusHost::IsTermServiceDisabled
  398. //
  399. // Arguments: <none>
  400. //
  401. // Returns: bool
  402. //
  403. // Purpose: Determines from the service control manager whether terminal
  404. // services is disabled.
  405. //
  406. // History: 2001-01-04 vtan created
  407. // --------------------------------------------------------------------------
  408. bool CLogonStatusHost::IsTermServiceDisabled (void)
  409. {
  410. bool fResult;
  411. SC_HANDLE hSCManager;
  412. fResult = false;
  413. hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  414. if (hSCManager != NULL)
  415. {
  416. SC_HANDLE hSCTermService;
  417. hSCTermService = OpenService(hSCManager, TEXT("TermService"), SERVICE_QUERY_CONFIG);
  418. if (hSCTermService != NULL)
  419. {
  420. DWORD dwBytesNeeded;
  421. QUERY_SERVICE_CONFIG *pServiceConfig;
  422. (BOOL)QueryServiceConfig(hSCTermService, NULL, 0, &dwBytesNeeded);
  423. pServiceConfig = static_cast<QUERY_SERVICE_CONFIG*>(LocalAlloc(LMEM_FIXED, dwBytesNeeded));
  424. if (pServiceConfig != NULL)
  425. {
  426. if (QueryServiceConfig(hSCTermService, pServiceConfig, dwBytesNeeded, &dwBytesNeeded) != FALSE)
  427. {
  428. fResult = (pServiceConfig->dwStartType == SERVICE_DISABLED);
  429. }
  430. (HLOCAL)LocalFree(pServiceConfig);
  431. }
  432. TBOOL(CloseServiceHandle(hSCTermService));
  433. }
  434. TBOOL(CloseServiceHandle(hSCManager));
  435. }
  436. return(fResult);
  437. }
  438. // --------------------------------------------------------------------------
  439. // CLogonStatusHost::StartWaitForTermService
  440. //
  441. // Arguments: <none>
  442. //
  443. // Returns: <none>
  444. //
  445. // Purpose: Register for console notifications with terminal services. If
  446. // the service is disabled don't bother. If the service hasn't
  447. // started then create a thread to wait for it and re-perform the
  448. // registration.
  449. //
  450. // History: 2001-01-03 vtan created
  451. // --------------------------------------------------------------------------
  452. void CLogonStatusHost::StartWaitForTermService (void)
  453. {
  454. // Don't do anything if terminal services is disabled.
  455. if (!IsTermServiceDisabled())
  456. {
  457. // Try to register the notification first.
  458. _fRegisteredNotification = WinStationRegisterConsoleNotification(SERVERNAME_CURRENT, _hwnd, NOTIFY_FOR_ALL_SESSIONS);
  459. if (_fRegisteredNotification == FALSE)
  460. {
  461. DWORD dwThreadID;
  462. (ULONG)AddRef();
  463. _hThreadWaitForTermService = CreateThread(NULL,
  464. 0,
  465. CB_WaitForTermService,
  466. this,
  467. 0,
  468. &dwThreadID);
  469. if (_hThreadWaitForTermService == NULL)
  470. {
  471. (ULONG)Release();
  472. }
  473. }
  474. }
  475. }
  476. // --------------------------------------------------------------------------
  477. // CLogonStatusHost::EndWaitForTermService
  478. //
  479. // Arguments: <none>
  480. //
  481. // Returns: <none>
  482. //
  483. // Purpose: If a thread has been created and the thread is still executing
  484. // then wake it up and force it to exit. If the thread cannot be
  485. // woken up then terminate it. Release handles.
  486. //
  487. // History: 2001-01-03 vtan created
  488. // --------------------------------------------------------------------------
  489. void CLogonStatusHost::EndWaitForTermService (void)
  490. {
  491. HANDLE hThread;
  492. // Grab the _hThreadWaitForTermService now. This will indicate to the
  493. // thread should it decide to finish executing that it shouldn't release
  494. // the reference on itself.
  495. hThread = InterlockedExchangePointer(&_hThreadWaitForTermService, NULL);
  496. if (hThread != NULL)
  497. {
  498. // Queue an APC to the wait thread. If the queue succeeds then
  499. // wait for the thread to finish executing. If the queue fails
  500. // the thread probably finished between the time we executed the
  501. // InterlockedExchangePointer above and the QueueUserAPC.
  502. if (QueueUserAPC(CB_WakeupThreadAPC, hThread, PtrToUlong(this)) != FALSE)
  503. {
  504. (DWORD)WaitForSingleObject(hThread, INFINITE);
  505. }
  506. TBOOL(CloseHandle(hThread));
  507. (ULONG)Release();
  508. }
  509. }
  510. // --------------------------------------------------------------------------
  511. // CLogonStatusHost::WaitForTermService
  512. //
  513. // Arguments: <none>
  514. //
  515. // Returns: <none>
  516. //
  517. // Purpose: Simple thread that waits for terminal services to signal that
  518. // it's ready and then registers for notifications. This is
  519. // required because this DLL initializes before terminal services
  520. // has had a chance to start up.
  521. //
  522. // History: 2000-10-20 vtan created
  523. // 2001-01-04 vtan allow premature exit
  524. // --------------------------------------------------------------------------
  525. void CLogonStatusHost::WaitForTermService (void)
  526. {
  527. DWORD dwWaitResult;
  528. int iCounter;
  529. HANDLE hTermSrvReadyEvent, hThread;
  530. dwWaitResult = 0;
  531. iCounter = 0;
  532. hTermSrvReadyEvent = OpenEvent(SYNCHRONIZE, FALSE, s_szTermSrvReadyEventName);
  533. while ((dwWaitResult == 0) && (hTermSrvReadyEvent == NULL) && (iCounter < 60))
  534. {
  535. ++iCounter;
  536. dwWaitResult = SleepEx(1000, TRUE);
  537. if (dwWaitResult == 0)
  538. {
  539. hTermSrvReadyEvent = OpenEvent(SYNCHRONIZE, FALSE, s_szTermSrvReadyEventName);
  540. }
  541. }
  542. if (hTermSrvReadyEvent != NULL)
  543. {
  544. dwWaitResult = WaitForSingleObjectEx(hTermSrvReadyEvent, 60000, TRUE);
  545. if (dwWaitResult == WAIT_OBJECT_0)
  546. {
  547. _fRegisteredNotification = WinStationRegisterConsoleNotification(SERVERNAME_CURRENT, _hwnd, NOTIFY_FOR_ALL_SESSIONS);
  548. }
  549. TBOOL(CloseHandle(hTermSrvReadyEvent));
  550. }
  551. // Grab the _hThreadWaitForTermService now. This will indicate to the
  552. // EndWaitForTermService function that we've reached the point of no
  553. // return and we're going to release ourselves. If we can't grab the
  554. // handle then EndWaitForTermService must be telling us to stop now.
  555. hThread = InterlockedExchangePointer(&_hThreadWaitForTermService, NULL);
  556. if (hThread != NULL)
  557. {
  558. TBOOL(CloseHandle(hThread));
  559. (ULONG)Release();
  560. }
  561. }
  562. // --------------------------------------------------------------------------
  563. // CLogonStatusHost::CB_WaitForTermService
  564. //
  565. // Arguments: pParameter = User defined data.
  566. //
  567. // Returns: DWORD
  568. //
  569. // Purpose: Stub to call member function.
  570. //
  571. // History: 2001-01-04 vtan created
  572. // --------------------------------------------------------------------------
  573. DWORD WINAPI CLogonStatusHost::CB_WaitForTermService (void *pParameter)
  574. {
  575. static_cast<CLogonStatusHost*>(pParameter)->WaitForTermService();
  576. return(0);
  577. }
  578. // --------------------------------------------------------------------------
  579. // CLogonStatusHost::StartWaitForParentProcess
  580. //
  581. // Arguments: <none>
  582. //
  583. // Returns: <none>
  584. //
  585. // Purpose: Create a thread to wait on the parent process. Terminal
  586. // services will terminate a non-session 0 winlogon which will
  587. // leave us dangling. Detect this case and exit cleanly. This
  588. // will allow csrss and win32k to clean up and release resources.
  589. //
  590. // History: 2001-01-03 vtan created
  591. // --------------------------------------------------------------------------
  592. void CLogonStatusHost::StartWaitForParentProcess (void)
  593. {
  594. ULONG ulReturnLength;
  595. PROCESS_BASIC_INFORMATION processBasicInformation;
  596. // Open a handle to our parent process. This will be winlogon.
  597. // If the parent dies then so do we.
  598. if (NT_SUCCESS(NtQueryInformationProcess(GetCurrentProcess(),
  599. ProcessBasicInformation,
  600. &processBasicInformation,
  601. sizeof(processBasicInformation),
  602. &ulReturnLength)))
  603. {
  604. _hProcessParent = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
  605. FALSE,
  606. static_cast<DWORD>(processBasicInformation.InheritedFromUniqueProcessId));
  607. #ifdef DEBUG
  608. if (IsDebuggerPresent())
  609. {
  610. if (NT_SUCCESS(NtQueryInformationProcess(_hProcessParent,
  611. ProcessBasicInformation,
  612. &processBasicInformation,
  613. sizeof(processBasicInformation),
  614. &ulReturnLength)))
  615. {
  616. TBOOL(CloseHandle(_hProcessParent));
  617. _hProcessParent = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
  618. FALSE,
  619. static_cast<DWORD>(processBasicInformation.InheritedFromUniqueProcessId));
  620. }
  621. }
  622. #endif /* DEBUG */
  623. if (_hProcessParent != NULL)
  624. {
  625. DWORD dwThreadID;
  626. (ULONG)AddRef();
  627. _hThreadWaitForParentProcess = CreateThread(NULL,
  628. 0,
  629. CB_WaitForParentProcess,
  630. this,
  631. 0,
  632. &dwThreadID);
  633. if (_hThreadWaitForParentProcess == NULL)
  634. {
  635. (ULONG)Release();
  636. }
  637. }
  638. }
  639. }
  640. // --------------------------------------------------------------------------
  641. // CLogonStatusHost::EndWaitForParentProcess
  642. //
  643. // Arguments: <none>
  644. //
  645. // Returns: <none>
  646. //
  647. // Purpose: If a thread waiting on the parent process is executing then
  648. // wake it up and force it to exit. If the thread cannot be woken
  649. // then terminate it. Release the handles used.
  650. //
  651. // History: 2000-12-11 vtan created
  652. // --------------------------------------------------------------------------
  653. void CLogonStatusHost::EndWaitForParentProcess (void)
  654. {
  655. HANDLE hThread;
  656. // Do exactly the same thing that EndWaitForTermService does to correctly
  657. // control the reference count on the "this" object. Whoever grabs the
  658. // _hThreadWaitForParentProcess is the guy who releases the reference.
  659. hThread = InterlockedExchangePointer(&_hThreadWaitForParentProcess, NULL);
  660. if (hThread != NULL)
  661. {
  662. if (QueueUserAPC(CB_WakeupThreadAPC, hThread, PtrToUlong(this)) != FALSE)
  663. {
  664. (DWORD)WaitForSingleObject(hThread, INFINITE);
  665. }
  666. TBOOL(CloseHandle(hThread));
  667. (ULONG)Release();
  668. }
  669. // Always release this handle the callback doesn't do this.
  670. if (_hProcessParent != NULL)
  671. {
  672. TBOOL(CloseHandle(_hProcessParent));
  673. _hProcessParent = NULL;
  674. }
  675. }
  676. // --------------------------------------------------------------------------
  677. // CLogonStatusHost::ParentProcessTerminated
  678. //
  679. // Arguments: <none>
  680. //
  681. // Returns: <none>
  682. //
  683. // Purpose: Handles parent process termination. Terminate process on us.
  684. //
  685. // History: 2000-12-11 vtan created
  686. // --------------------------------------------------------------------------
  687. void CLogonStatusHost::WaitForParentProcess (void)
  688. {
  689. DWORD dwWaitResult;
  690. HANDLE hThread;
  691. // Make a Win32 API call now so that the thread is converted to
  692. // a GUI thread. This will allow the PostMessage call to work
  693. // once the parent process is terminated. If the thread isn't
  694. // a GUI thread the system will not convert it to one in the
  695. // state when the callback is executed.
  696. TBOOL(PostMessage(_hwndHost, WM_NULL, 0, 0));
  697. dwWaitResult = WaitForSingleObjectEx(_hProcessParent, INFINITE, TRUE);
  698. if (dwWaitResult == WAIT_OBJECT_0)
  699. {
  700. TBOOL(PostMessage(_hwndHost, WM_UIHOSTMESSAGE, HM_SWITCHSTATE_DONE, 0));
  701. }
  702. hThread = InterlockedExchangePointer(&_hThreadWaitForParentProcess, NULL);
  703. if (hThread != NULL)
  704. {
  705. TBOOL(CloseHandle(hThread));
  706. (ULONG)Release();
  707. }
  708. }
  709. // --------------------------------------------------------------------------
  710. // CLogonStatusHost::CB_WaitForParentProcess
  711. //
  712. // Arguments: pParameter = User defined data.
  713. //
  714. // Returns: DWORD
  715. //
  716. // Purpose: Stub to call member function.
  717. //
  718. // History: 2001-01-04 vtan created
  719. // --------------------------------------------------------------------------
  720. DWORD WINAPI CLogonStatusHost::CB_WaitForParentProcess (void *pParameter)
  721. {
  722. static_cast<CLogonStatusHost*>(pParameter)->WaitForParentProcess();
  723. return(0);
  724. }
  725. // --------------------------------------------------------------------------
  726. // CLogonStatusHost::CB_WakeupThreadAPC
  727. //
  728. // Arguments: dwParam = User defined data.
  729. //
  730. // Returns: <none>
  731. //
  732. // Purpose: APCProc to wake up a thread waiting in an alertable state.
  733. //
  734. // History: 2001-01-04 vtan created
  735. // --------------------------------------------------------------------------
  736. void CALLBACK CLogonStatusHost::CB_WakeupThreadAPC (ULONG_PTR dwParam)
  737. {
  738. UNREFERENCED_PARAMETER(dwParam);
  739. }
  740. // --------------------------------------------------------------------------
  741. // CLogonStatusHost::CLogonStatusHost
  742. //
  743. // Arguments: <none>
  744. //
  745. // Returns: <none>
  746. //
  747. // Purpose: Constructor for CLogonStatusHost.
  748. //
  749. // History: 2000-05-10 vtan created
  750. // --------------------------------------------------------------------------
  751. CLogonStatusHost::CLogonStatusHost (void) :
  752. CIDispatchHelper(&IID_ILogonStatusHost, &LIBID_SHGINALib),
  753. _cRef(1),
  754. _hInstance(NULL),
  755. _hwnd(NULL),
  756. _hwndHost(NULL),
  757. _atom(0),
  758. _fRegisteredNotification(FALSE),
  759. _hThreadWaitForTermService(NULL),
  760. _hThreadWaitForParentProcess(NULL),
  761. _hProcessParent(NULL)
  762. {
  763. DllAddRef();
  764. }
  765. // --------------------------------------------------------------------------
  766. // CLogonStatusHost::~CLogonStatusHost
  767. //
  768. // Arguments: <none>
  769. //
  770. // Returns: <none>
  771. //
  772. // Purpose: Destructor for CLogonStatusHost.
  773. //
  774. // History: 2000-05-10 vtan created
  775. // --------------------------------------------------------------------------
  776. CLogonStatusHost::~CLogonStatusHost (void)
  777. {
  778. ASSERTMSG((_hProcessParent == NULL) &&
  779. (_hThreadWaitForParentProcess == NULL) &&
  780. (_hThreadWaitForTermService == NULL) &&
  781. (_fRegisteredNotification == FALSE) &&
  782. (_atom == 0) &&
  783. (_hwndHost == NULL) &&
  784. (_hwnd == NULL) &&
  785. (_hInstance == NULL), "Must UnIniitialize object before destroying in CLogonStatusHost::~CLogonStatusHost");
  786. ASSERTMSG(_cRef == 0, "Reference count expected to be zero in CLogonStatusHost::~CLogonStatusHost");
  787. DllRelease();
  788. }
  789. // --------------------------------------------------------------------------
  790. // CLogonStatusHost_Create
  791. //
  792. // Arguments: riid = Class GUID to QI to return.
  793. // ppv = Interface returned.
  794. //
  795. // Returns: HRESULT
  796. //
  797. // Purpose: Creates the CLogonStatusHost class and returns the specified
  798. // interface supported by the class to the caller.
  799. //
  800. // History: 2000-05-10 vtan created
  801. // --------------------------------------------------------------------------
  802. STDAPI CLogonStatusHost_Create (REFIID riid, void** ppvObj)
  803. {
  804. HRESULT hr;
  805. CLogonStatusHost* pLogonStatusHost;
  806. hr = E_OUTOFMEMORY;
  807. pLogonStatusHost = new CLogonStatusHost;
  808. if (pLogonStatusHost != NULL)
  809. {
  810. hr = pLogonStatusHost->QueryInterface(riid, ppvObj);
  811. pLogonStatusHost->Release();
  812. }
  813. return(hr);
  814. }