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.

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