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.

1010 lines
32 KiB

  1. // backend.cpp : Windows Logon application
  2. //
  3. // backend logic for communicating with SHGina and winlogon
  4. #include "priv.h"
  5. using namespace DirectUI;
  6. #include "resource.h"
  7. #include "backend.h"
  8. #include "shgina.h"
  9. #include "profileutil.h"
  10. #include "uihostipc.h"
  11. ////////////////////////////////
  12. #include "eballoon.h"
  13. #define MAX_COMPUTERDESC_LENGTH 255
  14. static WCHAR g_szGuestName[UNLEN + sizeof('\0')] = L"Guest";
  15. #define TIMER_REFRESHTIPS 1014
  16. #define TIMER_ANIMATEFLAG 1015
  17. #define TOTAL_FLAG_FRAMES (FLAG_ANIMATION_COUNT * MAX_FLAG_FRAMES)
  18. UINT_PTR g_puTimerId = 0;
  19. UINT_PTR g_puFlagTimerId = 0;
  20. DWORD sTimerCount = 0;
  21. extern CErrorBalloon g_pErrorBalloon;
  22. extern LogonFrame* g_plf;
  23. extern ILogonStatusHost *g_pILogonStatusHost;
  24. const TCHAR CBackgroundWindow::s_szWindowClassName[] = TEXT("LogonUIBackgroundWindowClass");
  25. // --------------------------------------------------------------------------
  26. // CBackgroundWindow::CBackgroundWindow
  27. //
  28. // Arguments: hInstance = HINSTANCE of the process.
  29. //
  30. // Returns: <none>
  31. //
  32. // Purpose: Constructor for CBackgroundWindow. This registers the window
  33. // class.
  34. //
  35. // History: 2001-03-27 vtan created
  36. // --------------------------------------------------------------------------
  37. CBackgroundWindow::CBackgroundWindow (HINSTANCE hInstance) :
  38. _hInstance(hInstance),
  39. _hwnd(NULL)
  40. {
  41. WNDCLASSEX wndClassEx;
  42. ZeroMemory(&wndClassEx, sizeof(wndClassEx));
  43. wndClassEx.cbSize = sizeof(wndClassEx);
  44. wndClassEx.lpfnWndProc = WndProc;
  45. wndClassEx.hInstance = hInstance;
  46. wndClassEx.lpszClassName = s_szWindowClassName;
  47. wndClassEx.hCursor = LoadCursor(NULL, IDC_ARROW);
  48. _atom = RegisterClassEx(&wndClassEx);
  49. }
  50. // --------------------------------------------------------------------------
  51. // CBackgroundWindow::~CBackgroundWindow
  52. //
  53. // Arguments: <none>
  54. //
  55. // Returns: <none>
  56. //
  57. // Purpose: Destructor for CBackgroundWindow. This destroys the window
  58. // and unregisters the window class.
  59. //
  60. // History: 2001-03-27 vtan created
  61. // --------------------------------------------------------------------------
  62. CBackgroundWindow::~CBackgroundWindow (void)
  63. {
  64. if (_hwnd != NULL)
  65. {
  66. (BOOL)DestroyWindow(_hwnd);
  67. }
  68. if (_atom != 0)
  69. {
  70. TBOOL(UnregisterClass(MAKEINTRESOURCE(_atom), _hInstance));
  71. }
  72. }
  73. // --------------------------------------------------------------------------
  74. // CBackgroundWindow::Create
  75. //
  76. // Arguments: <none>
  77. //
  78. // Returns: HWND
  79. //
  80. // Purpose: Creates the window. It's created WS_EX_TOPMOST and covers the
  81. // entire screen. It's not created on CHK builds of logonui.exe
  82. //
  83. // History: 2001-03-27 vtan created
  84. // --------------------------------------------------------------------------
  85. HWND CBackgroundWindow::Create (void)
  86. {
  87. HWND hwnd;
  88. #if DEBUG
  89. hwnd = NULL;
  90. #else
  91. hwnd = CreateWindowEx(0,
  92. s_szWindowClassName,
  93. NULL,
  94. WS_POPUP,
  95. GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN),
  96. GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN),
  97. NULL, NULL, _hInstance, this);
  98. if (hwnd != NULL)
  99. {
  100. (BOOL)ShowWindow(hwnd, SW_SHOW);
  101. TBOOL(SetForegroundWindow(hwnd));
  102. (BOOL)EnableWindow(hwnd, FALSE);
  103. }
  104. #endif
  105. return(hwnd);
  106. }
  107. // --------------------------------------------------------------------------
  108. // CBackgroundWindow::WndProc
  109. //
  110. // Arguments: See the platform SDK under WindowProc.
  111. //
  112. // Returns: See the platform SDK under WindowProc.
  113. //
  114. // Purpose: WindowProc for the background window. This just passes the
  115. // messages thru to DefWindowProc.
  116. //
  117. // History: 2001-03-27 vtan created
  118. // --------------------------------------------------------------------------
  119. LRESULT CALLBACK CBackgroundWindow::WndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  120. {
  121. LRESULT lResult;
  122. CBackgroundWindow *pThis;
  123. pThis = reinterpret_cast<CBackgroundWindow*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
  124. switch (uMsg)
  125. {
  126. case WM_CREATE:
  127. {
  128. CREATESTRUCT *pCreateStruct;
  129. pCreateStruct = reinterpret_cast<CREATESTRUCT*>(lParam);
  130. pThis = reinterpret_cast<CBackgroundWindow*>(pCreateStruct->lpCreateParams);
  131. (LONG_PTR)SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis));
  132. lResult = 0;
  133. break;
  134. }
  135. case WM_PAINT:
  136. {
  137. HDC hdcPaint;
  138. PAINTSTRUCT ps;
  139. hdcPaint = BeginPaint(hwnd, &ps);
  140. TBOOL(FillRect(ps.hdc, &ps.rcPaint, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH))));
  141. TBOOL(EndPaint(hwnd, &ps));
  142. lResult = 0;
  143. break;
  144. }
  145. default:
  146. lResult = DefWindowProc(hwnd, uMsg, wParam, lParam);
  147. break;
  148. }
  149. return(lResult);
  150. }
  151. ////////////////////////////////////////////////////////
  152. // Logon Utilities
  153. ////////////////////////////////////////////////////////
  154. ////////////////////////////////////////
  155. //
  156. // TurnOffComputer
  157. //
  158. // Call SHGina to bring up the "Turn Off Computer" dialog and handle the request.
  159. // In debug builds, holding down the shift key and clicking the turn off button
  160. // will exit logonui.
  161. //
  162. // RETURNS
  163. // HRESULT indicating whether it worked or not.
  164. //
  165. /////////////////////////////////////////
  166. HRESULT TurnOffComputer()
  167. {
  168. ILocalMachine *pobjLocalMachine;
  169. HRESULT hr = CoCreateInstance(CLSID_ShellLocalMachine, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(ILocalMachine, &pobjLocalMachine));
  170. if (SUCCEEDED(hr))
  171. {
  172. hr = pobjLocalMachine->TurnOffComputer();
  173. pobjLocalMachine->Release();
  174. }
  175. return hr;
  176. }
  177. ////////////////////////////////////////
  178. //
  179. // UndockComputer
  180. //
  181. // Tell SHGina to undock the computer
  182. //
  183. // RETURNS
  184. // HRESULT indicating whether it worked or not.
  185. //
  186. /////////////////////////////////////////
  187. HRESULT UndockComputer()
  188. {
  189. ILocalMachine *pobjLocalMachine;
  190. HRESULT hr = CoCreateInstance(CLSID_ShellLocalMachine, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(ILocalMachine, &pobjLocalMachine));
  191. if (SUCCEEDED(hr))
  192. {
  193. hr = pobjLocalMachine->UndockComputer();
  194. pobjLocalMachine->Release();
  195. }
  196. return hr;
  197. }
  198. ////////////////////////////////////////
  199. //
  200. // CalcBalloonTargetLocation
  201. //
  202. // Given a DirectUI element, figure out a good place to have a balloon tip pointed to
  203. // in parent window coordinates.
  204. //
  205. // RETURNS
  206. // nothing
  207. //
  208. /////////////////////////////////////////
  209. void CalcBalloonTargetLocation(HWND hwndParent, Element *pe, POINT *ppt)
  210. {
  211. Value* pv;
  212. BOOL fIsRTL = (GetWindowLong(hwndParent, GWL_EXSTYLE) & WS_EX_LAYOUTRTL) != 0;
  213. DUIAssertNoMsg(pe);
  214. DUIAssertNoMsg(ppt);
  215. // get the position of the link so we can target the balloon tip correctly
  216. POINT pt = {0,0};
  217. const SIZE *psize = pe->GetExtent(&pv);
  218. pt.y += psize->cy / 2;
  219. if (psize->cx < 100)
  220. {
  221. pt.x += psize->cx / 2;
  222. }
  223. else
  224. {
  225. if (fIsRTL)
  226. {
  227. pt.x = (pt.x + psize->cx) - 50;
  228. }
  229. else
  230. {
  231. pt.x += 50;
  232. }
  233. }
  234. pv->Release();
  235. while (pe)
  236. {
  237. const POINT* ppt = pe->GetLocation(&pv);
  238. pt.x += ppt->x;
  239. pt.y += ppt->y;
  240. pv->Release();
  241. pe = pe->GetParent();
  242. }
  243. *ppt = pt;
  244. }
  245. ////////////////////////////////////////
  246. //
  247. // DetermineGuestAccountName
  248. //
  249. //
  250. // Get the localized guest account name by matching the
  251. // local list of user account SIDs for the guest RID.
  252. // This code is lifted directly from msgina\userlist.cpp
  253. // In the event of failure this is initialized to the english "Guest".
  254. //
  255. //
  256. // RETURNS
  257. // nothing.
  258. //
  259. /////////////////////////////////////////
  260. void DetermineGuestAccountName()
  261. {
  262. NET_API_STATUS nasCode;
  263. DWORD dwPreferredSize, dwEntriesRead;
  264. NET_DISPLAY_USER *pNDU;
  265. static const int iMaximumUserCount = 100;
  266. dwPreferredSize = (sizeof(NET_DISPLAY_USER) + (3 * UNLEN) * iMaximumUserCount);
  267. pNDU = NULL;
  268. nasCode = NetQueryDisplayInformation(NULL,
  269. 1,
  270. 0,
  271. iMaximumUserCount,
  272. dwPreferredSize,
  273. &dwEntriesRead,
  274. reinterpret_cast<void**>(&pNDU));
  275. if ((ERROR_SUCCESS == nasCode) || (ERROR_MORE_DATA == nasCode))
  276. {
  277. int iIndex;
  278. for (iIndex = static_cast<int>(dwEntriesRead - 1); iIndex >= 0; --iIndex)
  279. {
  280. BOOL fResult;
  281. DWORD dwSIDSize, dwDomainSize;
  282. SID_NAME_USE eUse;
  283. PSID pSID;
  284. WCHAR wszDomain[DNLEN + sizeof('\0')];
  285. // Iterate the user list and look up the SID for each user in the
  286. // list regardless of whether they are disabled or not.
  287. dwSIDSize = dwDomainSize = 0;
  288. fResult = LookupAccountNameW(NULL,
  289. pNDU[iIndex].usri1_name,
  290. NULL,
  291. &dwSIDSize,
  292. NULL,
  293. &dwDomainSize,
  294. &eUse);
  295. pSID = static_cast<PSID>(LocalAlloc(LMEM_FIXED, dwSIDSize));
  296. if (pSID != NULL)
  297. {
  298. dwDomainSize = DUIARRAYSIZE(wszDomain);
  299. fResult = LookupAccountNameW(NULL,
  300. pNDU[iIndex].usri1_name,
  301. pSID,
  302. &dwSIDSize,
  303. wszDomain,
  304. &dwDomainSize,
  305. &eUse);
  306. // Ensure that only user SIDs are checked.
  307. if ((fResult != FALSE) && (SidTypeUser == eUse))
  308. {
  309. unsigned char ucSubAuthorityCount;
  310. int iSubAuthorityIndex;
  311. ucSubAuthorityCount = *GetSidSubAuthorityCount(pSID);
  312. for (iSubAuthorityIndex = 0; iSubAuthorityIndex < ucSubAuthorityCount; ++iSubAuthorityIndex)
  313. {
  314. DWORD dwSubAuthority;
  315. dwSubAuthority = *GetSidSubAuthority(pSID, iSubAuthorityIndex);
  316. if (DOMAIN_USER_RID_GUEST == dwSubAuthority)
  317. {
  318. lstrcpyW(g_szGuestName, pNDU[iIndex].usri1_name);
  319. }
  320. }
  321. }
  322. (HLOCAL)LocalFree(pSID);
  323. }
  324. }
  325. }
  326. (NET_API_STATUS)NetApiBufferFree(pNDU);
  327. }
  328. ////////////////////////////////////////
  329. //
  330. // GetLogonUserByLogonName
  331. //
  332. // Given a username, CoCreate the ILogonUser for that name.
  333. //
  334. // RETURNS
  335. // HRESULT -- failure if the user could not be created.
  336. //
  337. /////////////////////////////////////////
  338. HRESULT GetLogonUserByLogonName(LPWSTR pszUsername, ILogonUser **ppobjUser)
  339. {
  340. VARIANT var;
  341. ILogonEnumUsers *pobjEnum;
  342. if (ppobjUser)
  343. {
  344. *ppobjUser = NULL;
  345. }
  346. var.vt = VT_BSTR;
  347. var.bstrVal = pszUsername;
  348. HRESULT hr = CoCreateInstance(CLSID_ShellLogonEnumUsers, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(ILogonEnumUsers, &pobjEnum));
  349. if (SUCCEEDED(hr))
  350. {
  351. hr = pobjEnum->item(var, ppobjUser);
  352. pobjEnum->Release();
  353. }
  354. return hr;
  355. }
  356. ////////////////////////////////////////
  357. //
  358. // ReleaseStatusHost
  359. //
  360. // Clean up the logon status host object.
  361. //
  362. // RETURNS
  363. // nothing
  364. //
  365. /////////////////////////////////////////
  366. void ReleaseStatusHost()
  367. {
  368. if (g_pILogonStatusHost != NULL)
  369. {
  370. g_pILogonStatusHost->UnInitialize();
  371. g_pILogonStatusHost->Release();
  372. g_pILogonStatusHost = NULL;
  373. }
  374. }
  375. ////////////////////////////////////////
  376. //
  377. // EndHostProcess
  378. //
  379. // Clean up the logon status host object and if uiExitCode is anything other than 0,
  380. // then terminate the process immediately.
  381. //
  382. // RETURNS
  383. // nothing
  384. //
  385. /////////////////////////////////////////
  386. void EndHostProcess(UINT uiExitCode)
  387. {
  388. ReleaseStatusHost();
  389. if (uiExitCode != 0)
  390. {
  391. ExitProcess(uiExitCode);
  392. }
  393. }
  394. ////////////////////////////////////////
  395. //
  396. // GetRegistryNumericValue
  397. //
  398. // Given a registry HKEY and a value return the numeric value
  399. //
  400. // RETURNS
  401. // the numeric value from the registry
  402. //
  403. /////////////////////////////////////////
  404. int GetRegistryNumericValue(HKEY hKey, LPCTSTR pszValueName)
  405. {
  406. int iResult;
  407. DWORD dwType, dwDataSize;
  408. iResult = 0;
  409. if (ERROR_SUCCESS == RegQueryValueEx(hKey,
  410. pszValueName,
  411. NULL,
  412. &dwType,
  413. NULL,
  414. NULL))
  415. {
  416. if (REG_DWORD == dwType)
  417. {
  418. DWORD dwData;
  419. dwDataSize = sizeof(dwData);
  420. if (ERROR_SUCCESS == RegQueryValueEx(hKey,
  421. pszValueName,
  422. NULL,
  423. NULL,
  424. reinterpret_cast<LPBYTE>(&dwData),
  425. &dwDataSize))
  426. {
  427. iResult = static_cast<int>(dwData);
  428. }
  429. }
  430. else if (REG_SZ == dwType)
  431. {
  432. TCHAR szData[1024];
  433. dwDataSize = sizeof(szData);
  434. if (ERROR_SUCCESS == RegQueryValueEx(hKey,
  435. pszValueName,
  436. NULL,
  437. NULL,
  438. reinterpret_cast<LPBYTE>(szData),
  439. &dwDataSize))
  440. {
  441. char szAnsiData[1024];
  442. (int)WideCharToMultiByte(CP_ACP,
  443. 0,
  444. (LPCWSTR)szData,
  445. -1,
  446. szAnsiData,
  447. sizeof(szAnsiData),
  448. NULL,
  449. NULL);
  450. iResult = atoi(szAnsiData);
  451. }
  452. }
  453. }
  454. return(iResult);
  455. }
  456. ////////////////////////////////////////
  457. //
  458. // IsShutdownAllowed
  459. //
  460. // Firstly (firstly??)... if the machine is remote then don't allow shut down.
  461. // Determine the local machine policy for shutdown from the logon screen.
  462. // This is stored in two places as two different types (REG_DWORD and REG_SZ).
  463. // Always check the policy location AFTER the normal location to ensure that
  464. // policy overrides normal settings.
  465. //
  466. // RETURNS
  467. // TRUE if the machine is allowed to be shut down from logonui. FALSE otherwise
  468. //
  469. /////////////////////////////////////////
  470. BOOL IsShutdownAllowed()
  471. {
  472. BOOL fResult = FALSE;
  473. ILocalMachine *pobjLocalMachine;
  474. HRESULT hr = CoCreateInstance(CLSID_ShellLocalMachine, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(ILocalMachine, &pobjLocalMachine));
  475. if (SUCCEEDED(hr))
  476. {
  477. VARIANT_BOOL vbCanShutdown = VARIANT_FALSE;
  478. hr = pobjLocalMachine->get_isShutdownAllowed(&vbCanShutdown);
  479. if (SUCCEEDED(hr))
  480. {
  481. fResult = (vbCanShutdown == VARIANT_TRUE);
  482. }
  483. pobjLocalMachine->Release();
  484. }
  485. return fResult;
  486. }
  487. ////////////////////////////////////////
  488. //
  489. // IsUndockAllowed
  490. //
  491. // Check with SHGina to see if we are allowed to undock the PC.
  492. //
  493. // RETURNS
  494. // TRUE if the machine is allowed to be undocked from logonui. FALSE otherwise
  495. //
  496. /////////////////////////////////////////
  497. BOOL IsUndockAllowed()
  498. {
  499. BOOL fResult = FALSE;
  500. #if 0
  501. ILocalMachine *pobjLocalMachine;
  502. HRESULT hr = CoCreateInstance(CLSID_ShellLocalMachine, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(ILocalMachine, &pobjLocalMachine));
  503. if (SUCCEEDED(hr))
  504. {
  505. VARIANT_BOOL vbCanUndock = VARIANT_FALSE;
  506. hr = pobjLocalMachine->get_isUndockEnabled(&vbCanUndock);
  507. if (SUCCEEDED(hr))
  508. {
  509. fResult = (vbCanUndock == VARIANT_TRUE);
  510. }
  511. pobjLocalMachine->Release();
  512. }
  513. #endif
  514. return fResult;
  515. }
  516. #ifndef TESTDATA
  517. LONG WINAPI LogonUIUnhandledExceptionFilter (struct _EXCEPTION_POINTERS *ExceptionInfo)
  518. {
  519. return(RtlUnhandledExceptionFilter(ExceptionInfo));
  520. }
  521. #endif // !TESTDATA
  522. void SetErrorHandler (void)
  523. {
  524. #ifndef TESTDATA
  525. SYSTEM_KERNEL_DEBUGGER_INFORMATION kdInfo;
  526. (NTSTATUS)NtQuerySystemInformation(SystemKernelDebuggerInformation,
  527. &kdInfo,
  528. sizeof(kdInfo),
  529. NULL);
  530. if (kdInfo.KernelDebuggerEnabled || NtCurrentPeb()->BeingDebugged)
  531. {
  532. (LPTOP_LEVEL_EXCEPTION_FILTER)SetUnhandledExceptionFilter(LogonUIUnhandledExceptionFilter);
  533. }
  534. #endif // !TESTDATA
  535. }
  536. ////////////////////////////////////////
  537. //
  538. // RunningInWinlogon
  539. //
  540. // Checks to see if logonui is running in the winlogon context. There are some things
  541. // that don't work well when we are not in winlogon so this makes debugging easier.
  542. //
  543. // RETURNS
  544. // TRUE if the running in winlogon (actually if it can find the GINA Logon window). FALSE otherwise
  545. //
  546. /////////////////////////////////////////
  547. BOOL RunningInWinlogon()
  548. {
  549. #if DEBUG
  550. return (FindWindow(NULL, TEXT("GINA Logon")) != NULL);
  551. #else
  552. return true;
  553. #endif
  554. }
  555. ////////////////////////////////////////
  556. //
  557. // BuildUserListFromGina
  558. //
  559. // Enumerate all of the users that SHGina tells us we care about and add them to the accounts list.
  560. // Find out of they require a password and their current state for notifications.
  561. //
  562. // If there is only 1 user or if there are 2 users, but one of them is guest, then ppAccount will
  563. // contain a pointer to the only user on this machine. The caller can then automatically select
  564. // that user to avoid them from having to click that user given that there is no one else to click.
  565. //
  566. //
  567. // RETURNS
  568. // HRESULT -- if not a success code, we are hosed.
  569. //
  570. /////////////////////////////////////////
  571. HRESULT BuildUserListFromGina(LogonFrame* plf, OUT LogonAccount** ppAccount)
  572. {
  573. if (ppAccount)
  574. {
  575. *ppAccount = NULL;
  576. }
  577. DetermineGuestAccountName();
  578. int iGuestId = -1;
  579. WCHAR szPicturePath[MAX_PATH];
  580. ILogonEnumUsers *pobjEnum;
  581. LogonAccount* plaLastNormal = NULL;
  582. // load the ILogonEnumUsers object from SHGina.dll
  583. HRESULT hr = CoCreateInstance(CLSID_ShellLogonEnumUsers, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(ILogonEnumUsers, &pobjEnum));
  584. if (SUCCEEDED(hr))
  585. {
  586. int iUser,cUsers;
  587. UINT uiUsers;
  588. ILogonUser *pobjUser;
  589. // get the number of users
  590. hr = pobjEnum->get_length(&uiUsers);
  591. if (FAILED(hr))
  592. goto done;
  593. cUsers = (int)uiUsers;
  594. for (iUser = 0; iUser < cUsers; iUser++)
  595. {
  596. VARIANT var, varUnreadMail, varPicture = {0}, varUsername = {0}, varHint = {0};
  597. VARIANT_BOOL vbLoggedOn, vbInteractiveLogonAllowed;
  598. var.vt = VT_I4;
  599. var.lVal = iUser;
  600. hr = pobjEnum->item( var, &pobjUser);
  601. if (SUCCEEDED(hr) && pobjUser)
  602. {
  603. if (SUCCEEDED(pobjUser->get_interactiveLogonAllowed(&vbInteractiveLogonAllowed)) &&
  604. (vbInteractiveLogonAllowed != VARIANT_FALSE))
  605. {
  606. // get the display name for the user
  607. pobjUser->get_setting(L"DisplayName" ,&var);
  608. pobjUser->get_setting(L"LoginName", &varUsername);
  609. // if the display name is blank, we will use the login name. This is the case for Guest
  610. if (var.bstrVal && lstrlenW(var.bstrVal) == 0)
  611. {
  612. VariantClear(&var);
  613. pobjUser->get_setting(L"LoginName" ,&var);
  614. }
  615. if (FAILED(pobjUser->get_isLoggedOn(&vbLoggedOn)))
  616. {
  617. vbLoggedOn = VARIANT_FALSE;
  618. }
  619. if (FAILED(pobjUser->get_setting(L"UnreadMail", &varUnreadMail)))
  620. {
  621. varUnreadMail.uintVal = 0;
  622. }
  623. lstrcpyW(szPicturePath, L"");
  624. // get the path to their picture
  625. if (SUCCEEDED(pobjUser->get_setting(L"Picture" ,&varPicture)))
  626. {
  627. if (lstrlenW(varPicture.bstrVal) != 0) // in the case of defaultUser, lets just use the user icons we have.
  628. {
  629. lstrcpynW(szPicturePath, &(varPicture.bstrVal[7]), MAX_PATH);
  630. }
  631. VariantClear(&varPicture);
  632. }
  633. VariantClear(&varHint);
  634. hr = pobjUser->get_setting(L"Hint", &varHint);
  635. if (FAILED(hr) || varHint.vt != VT_BSTR)
  636. {
  637. VariantClear(&varHint);
  638. }
  639. if (lstrcmpi(g_szGuestName, var.bstrVal) == 0)
  640. {
  641. iGuestId = iUser;
  642. }
  643. LogonAccount* pla = NULL;
  644. // If no picture is available, default to one
  645. hr = plf->AddAccount(*szPicturePath ? szPicturePath : MAKEINTRESOURCEW(IDB_USER0),
  646. *szPicturePath == NULL,
  647. var.bstrVal,
  648. varUsername.bstrVal,
  649. varHint.bstrVal,
  650. (vbLoggedOn == VARIANT_TRUE),
  651. &pla);
  652. // pla->UpdateNotifications(true);
  653. if (SUCCEEDED(hr) && (iGuestId != iUser))
  654. {
  655. plaLastNormal = pla;
  656. }
  657. VariantClear(&var);
  658. VariantClear(&varHint);
  659. VariantClear(&varUsername);
  660. }
  661. pobjUser->Release();
  662. }
  663. }
  664. // if there is only one user, select them by default. Ignore guest.
  665. if (ppAccount && plaLastNormal && (cUsers == 1 ||
  666. (cUsers == 2 && iGuestId != -1)))
  667. {
  668. *ppAccount = plaLastNormal;
  669. }
  670. done:
  671. pobjEnum->Release();
  672. }
  673. // User logon list is now available
  674. plf->SetUserListAvailable(true);
  675. //DUITrace("LOGONUI: UserList is now available\n");
  676. return hr;
  677. }
  678. ////////////////////////////////////////
  679. //
  680. // KillFlagAnimation
  681. //
  682. // Stop the flag from animating immediately. What it actually does is check to
  683. // see if we are still animating the flag and if we are, then set the frame
  684. // counter to the end and set the bitmap to the first frame in the animation.
  685. // The next time the timer fires, it will see that we are done and actually
  686. // kill the timer.
  687. //
  688. /////////////////////////////////////////
  689. void KillFlagAnimation()
  690. {
  691. #ifdef ANIMATE_FLAG
  692. if (sTimerCount > 0 && sTimerCount < TOTAL_FLAG_FRAMES)
  693. {
  694. sTimerCount = TOTAL_FLAG_FRAMES + 1;
  695. if (g_plf != NULL)
  696. {
  697. g_plf->NextFlagAnimate(0);
  698. }
  699. }
  700. #endif
  701. }
  702. ////////////////////////////////////////
  703. //
  704. // LogonWindowProc
  705. //
  706. // This is the notification window that SHGina uses to communicate with logonui.
  707. // Send all messages through the helper in logonstatushost and check for our
  708. // own messages on this window. This is where all of the SHGina notifications come.
  709. //
  710. ////////////////////////////////////////
  711. LRESULT CALLBACK LogonWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  712. {
  713. static BOOL sResetTimer = false;
  714. LogonFrame *pLogonFrame;
  715. pLogonFrame = g_plf;
  716. if (g_pILogonStatusHost != NULL)
  717. {
  718. VARIANT varWParam, varLParam;
  719. varWParam.uintVal = static_cast<UINT>(wParam);
  720. varLParam.lVal = static_cast<LONG>(lParam);
  721. if (SUCCEEDED(g_pILogonStatusHost->WindowProcedureHelper(hwnd, uMsg, varWParam, varLParam)))
  722. {
  723. return 0;
  724. }
  725. }
  726. switch (uMsg)
  727. {
  728. case WM_TIMER:
  729. if ((pLogonFrame != NULL) && (pLogonFrame->GetState() == LAS_Logon) && (wParam == TIMER_REFRESHTIPS))
  730. {
  731. BOOL fRefreshAll = false;
  732. if (!sResetTimer)
  733. {
  734. fRefreshAll = true;
  735. sResetTimer = true;
  736. KillTimer(hwnd, g_puTimerId);
  737. g_puTimerId = SetTimer(hwnd, TIMER_REFRESHTIPS, 15000, NULL); // update the values 15 seconds
  738. #ifdef ANIMATE_FLAG
  739. g_puFlagTimerId = SetTimer(hwnd, TIMER_ANIMATEFLAG, 20, NULL); // start the flag animation
  740. #endif
  741. }
  742. pLogonFrame->UpdateUserStatus(fRefreshAll);
  743. return 0;
  744. }
  745. #ifdef ANIMATE_FLAG
  746. if (wParam == TIMER_ANIMATEFLAG)
  747. {
  748. if (sTimerCount > TOTAL_FLAG_FRAMES)
  749. {
  750. sTimerCount = 0;
  751. KillTimer(hwnd, g_puFlagTimerId);
  752. pLogonFrame->NextFlagAnimate(0);
  753. }
  754. else
  755. {
  756. sTimerCount ++;
  757. pLogonFrame->NextFlagAnimate(sTimerCount % MAX_FLAG_FRAMES);
  758. }
  759. return 0;
  760. }
  761. #endif
  762. break;
  763. case WM_UIHOSTMESSAGE:
  764. switch (wParam)
  765. {
  766. case HM_SWITCHSTATE_STATUS: // LAS_PreStatus
  767. if (pLogonFrame != NULL)
  768. {
  769. pLogonFrame->EnterPreStatusMode(lParam != 0);
  770. }
  771. break;
  772. case HM_SWITCHSTATE_LOGON: // LAS_Logon
  773. if (pLogonFrame != NULL)
  774. {
  775. pLogonFrame->EnterLogonMode(lParam != 0);
  776. }
  777. if (g_puTimerId != 0)
  778. {
  779. sResetTimer = false;
  780. KillTimer(hwnd, g_puTimerId);
  781. }
  782. g_puTimerId = SetTimer(hwnd, TIMER_REFRESHTIPS, 250, NULL); // update the values in 1 second
  783. break;
  784. case HM_SWITCHSTATE_LOGGEDON: // LAS_PostStatus
  785. if (pLogonFrame != NULL)
  786. {
  787. pLogonFrame->EnterPostStatusMode();
  788. }
  789. break;
  790. case HM_SWITCHSTATE_HIDE: // LAS_Hide
  791. if (pLogonFrame != NULL)
  792. {
  793. if (LogonAccount::GetCandidate())
  794. {
  795. LogonAccount* pla = LogonAccount::GetCandidate();
  796. pla->InsertStatus(0);
  797. pla->SetStatus(0, L"");
  798. pla->ShowStatus(0);
  799. }
  800. else
  801. {
  802. pLogonFrame->SetStatus(L"");
  803. }
  804. pLogonFrame->EnterHideMode();
  805. }
  806. goto killTimer;
  807. break;
  808. case HM_SWITCHSTATE_DONE: // LAS_Done
  809. if (pLogonFrame != NULL)
  810. {
  811. pLogonFrame->EnterDoneMode();
  812. }
  813. killTimer:
  814. if (g_puTimerId != 0)
  815. {
  816. KillTimer(hwnd, g_puTimerId);
  817. g_puTimerId = 0;
  818. }
  819. break;
  820. case HM_NOTIFY_WAIT:
  821. if (pLogonFrame != NULL)
  822. {
  823. pLogonFrame->SetTitle(IDS_PLEASEWAIT);
  824. }
  825. break;
  826. case HM_SELECT_USER:
  827. if (pLogonFrame != NULL)
  828. {
  829. pLogonFrame->SelectUser(reinterpret_cast<SELECT_USER*>(lParam)->szUsername);
  830. }
  831. break;
  832. case HM_SET_ANIMATIONS:
  833. if (pLogonFrame != NULL)
  834. {
  835. pLogonFrame->SetAnimations(lParam != 0);
  836. }
  837. break;
  838. case HM_DISPLAYSTATUS:
  839. if ((pLogonFrame != NULL) && (lParam != NULL))
  840. {
  841. if (pLogonFrame->GetState() == LAS_PostStatus)
  842. {
  843. if (LogonAccount::GetCandidate())
  844. {
  845. LogonAccount* pla = LogonAccount::GetCandidate();
  846. pla->InsertStatus(0);
  847. pla->SetStatus(0, (WCHAR*)lParam);
  848. pla->ShowStatus(0);
  849. }
  850. else
  851. {
  852. pLogonFrame->SetStatus((WCHAR*)lParam);
  853. }
  854. }
  855. else
  856. {
  857. pLogonFrame->SetStatus((WCHAR*)lParam);
  858. }
  859. }
  860. break;
  861. case HM_DISPLAYREFRESH:
  862. if (pLogonFrame != NULL)
  863. {
  864. pLogonFrame->UpdateUserStatus(true);
  865. }
  866. break;
  867. case HM_DISPLAYRESIZE:
  868. if (pLogonFrame != NULL)
  869. {
  870. pLogonFrame->Resize();
  871. }
  872. break;
  873. case HM_INTERACTIVE_LOGON_REQUEST:
  874. return((pLogonFrame != NULL) && pLogonFrame->InteractiveLogonRequest(reinterpret_cast<INTERACTIVE_LOGON_REQUEST*>(lParam)->szUsername, reinterpret_cast<INTERACTIVE_LOGON_REQUEST*>(lParam)->szPassword));
  875. }
  876. break;
  877. }
  878. return DefWindowProc(hwnd, uMsg,wParam, lParam);
  879. }