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.

2850 lines
72 KiB

  1. // Logon.cpp : Windows Logon application
  2. //
  3. #include "priv.h"
  4. using namespace DirectUI;
  5. // Logon.cpp : Windows Logon application
  6. //
  7. #include "logon.h"
  8. #include "Fx.h"
  9. #include "backend.h"
  10. #include "resource.h"
  11. #include "eballoon.h"
  12. #include "profileutil.h"
  13. #include "langicon.h"
  14. #include <passrec.h>
  15. BOOL RunningInWinlogon(); // from backend.cpp
  16. UsingDUIClass(Element);
  17. UsingDUIClass(Button);
  18. UsingDUIClass(ScrollBar);
  19. UsingDUIClass(Selector);
  20. UsingDUIClass(ScrollViewer);
  21. UsingDUIClass(Edit);
  22. // Globals
  23. LogonFrame* g_plf = NULL;
  24. ILogonStatusHost *g_pILogonStatusHost = NULL;
  25. CErrorBalloon g_pErrorBalloon;
  26. BOOL g_fNoAnimations = false;
  27. WCHAR szLastSelectedName[UNLEN + sizeof('\0')] = { L'\0' };
  28. HANDLE g_rgH[3] = {0};
  29. #define MAX_COMPUTERDESC_LENGTH 255
  30. #define RECTWIDTH(r) (r.right - r.left)
  31. // Resource string loading
  32. LPCWSTR LoadResString(UINT nID)
  33. {
  34. static WCHAR szRes[101];
  35. szRes[0] = NULL;
  36. LoadStringW(g_plf->GetHInstance(), nID, szRes, DUIARRAYSIZE(szRes) - 1);
  37. return szRes;
  38. }
  39. void SetButtonLabel(Button* pButton, LPCWSTR pszLabel)
  40. {
  41. Element *pLabel= (Element*)pButton->FindDescendent(StrToID(L"label"));
  42. DUIAssert(pLabel, "Cannot find button label, check the UI file");
  43. if (pLabel != NULL)
  44. {
  45. pLabel->SetContentString(pszLabel);
  46. }
  47. }
  48. ////////////////////////////////////////
  49. //
  50. // SetElementAccessability
  51. //
  52. // Set the accessibility information for an element.
  53. //
  54. /////////////////////////////////////////
  55. void inline SetElementAccessability(Element* pe, bool bAccessible, int iRole, LPCWSTR pszAccName)
  56. {
  57. if (pe)
  58. {
  59. pe->SetAccessible(bAccessible);
  60. pe->SetAccRole(iRole);
  61. pe->SetAccName(pszAccName);
  62. }
  63. }
  64. ////////////////////////////////////////
  65. //
  66. // RunningUnderWinlogon
  67. //
  68. // Check to see if the logon message window is available.
  69. //
  70. /////////////////////////////////////////
  71. BOOL RunningUnderWinlogon()
  72. {
  73. return (FindWindow(TEXT("Shell_TrayWnd"), NULL) == NULL);
  74. }
  75. // global storage of username associated with failed logon. Used for
  76. // restore wizard via ECSubClassProc
  77. WCHAR g_szUsername[UNLEN];
  78. ////////////////////////////////////////
  79. //
  80. // Support code for balloon tip launch of the Password Reset Wizard
  81. //
  82. // Code in support of subclassing the Password Panel edit control
  83. //
  84. // The control is displayed by InsertPasswordPanel and undisplayed
  85. // by RemovePasswordPanel. The control is subclassed when displayed
  86. // and unsubclassed when removed.
  87. //
  88. ////////////////////////////////////////
  89. // Entirely randomly selected magic number for the edit control subclass operation
  90. #define ECMAGICNUM 3212
  91. void ShowResetWizard(HWND hw)
  92. {
  93. // Show password restore wizard
  94. HMODULE hDll = LoadLibrary(L"keymgr.dll");
  95. if (hDll)
  96. {
  97. RUNDLLPROC PRShowRestoreWizard;
  98. PRShowRestoreWizard = (RUNDLLPROC) GetProcAddress(hDll,(LPCSTR)"PRShowRestoreWizardW");
  99. if (PRShowRestoreWizard)
  100. {
  101. PRShowRestoreWizard(hw,NULL,g_szUsername,0);
  102. }
  103. FreeLibrary(hDll);
  104. }
  105. return;
  106. }
  107. LRESULT CALLBACK ECSubClassProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,UINT_PTR uID, ULONG_PTR dwRefData)
  108. {
  109. UNREFERENCED_PARAMETER(uID);
  110. UNREFERENCED_PARAMETER(dwRefData);
  111. switch (uMsg)
  112. {
  113. case WM_NOTIFY:
  114. {
  115. LPNMHDR lph;
  116. lph = (LPNMHDR) lParam;
  117. if (TTN_LINKCLICK == lph->code)
  118. {
  119. g_pErrorBalloon.HideToolTip();
  120. ShowResetWizard(hwnd);
  121. return 0;
  122. }
  123. }
  124. default:
  125. break;
  126. }
  127. return DefSubclassProc(hwnd, uMsg, wParam, lParam);
  128. }
  129. BOOL SubClassTheEditBox(HWND he)
  130. {
  131. if (he)
  132. {
  133. SetWindowSubclass(he,ECSubClassProc,ECMAGICNUM,NULL);
  134. }
  135. return (he != NULL);
  136. }
  137. void UnSubClassTheEditBox(HWND he)
  138. {
  139. if (he)
  140. {
  141. RemoveWindowSubclass(he,ECSubClassProc,ECMAGICNUM);
  142. }
  143. }
  144. ////////////////////////////////////////
  145. //
  146. // BuildAccountList
  147. //
  148. // Add all user accounts.
  149. //
  150. // Out parameter ppla returns a user that should be selected automatically if there is one.
  151. // the caller should select this user.
  152. //
  153. // RETURNS
  154. // S_OK if everything works out. Failure HRESULT if not. You are pretty much hosed if this fails
  155. //
  156. /////////////////////////////////////////
  157. HRESULT BuildAccountList(LogonFrame* plf, OUT LogonAccount **ppla)
  158. {
  159. HRESULT hr;
  160. if (ppla)
  161. {
  162. *ppla = NULL;
  163. }
  164. hr = BuildUserListFromGina(plf, ppla);
  165. if (SUCCEEDED(hr))
  166. {
  167. g_plf->SetUserListAvailable(TRUE);
  168. }
  169. #ifdef GADGET_ENABLE_GDIPLUS
  170. plf->FxStartup();
  171. #endif
  172. return hr;
  173. }
  174. ////////////////////////////////////////
  175. //
  176. // PokeComCtl32
  177. //
  178. // Flush comctl32's notion of the atom table. This is so balloon tips will work correctly
  179. // after a logoff.
  180. //
  181. /////////////////////////////////////////
  182. void PokeComCtl32()
  183. {
  184. INITCOMMONCONTROLSEX iccex = { sizeof(INITCOMMONCONTROLSEX), ICC_WINLOGON_REINIT | ICC_STANDARD_CLASSES | ICC_TREEVIEW_CLASSES};
  185. InitCommonControlsEx(&iccex);
  186. }
  187. ////////////////////////////////////////////////////////
  188. //
  189. // LogonFrame
  190. //
  191. ////////////////////////////////////////////////////////
  192. int LogonFrame::_nDPI = 0;
  193. HRESULT LogonFrame::Create(OUT Element** ppElement)
  194. {
  195. UNREFERENCED_PARAMETER(ppElement);
  196. DUIAssertForce("Cannot instantiate an HWND host derived Element via parser. Must use substitution.");
  197. return E_NOTIMPL;
  198. }
  199. HRESULT LogonFrame::Create(HWND hParent, BOOL fDblBuffer, UINT nCreate, OUT Element** ppElement)
  200. {
  201. *ppElement = NULL;
  202. LogonFrame* plf = HNew<LogonFrame>();
  203. if (!plf)
  204. return E_OUTOFMEMORY;
  205. HRESULT hr = plf->Initialize(hParent, fDblBuffer, nCreate);
  206. if (FAILED(hr))
  207. {
  208. plf->Destroy();
  209. return hr;
  210. }
  211. *ppElement = plf;
  212. return S_OK;
  213. }
  214. void LogonFrame::ResetTheme(void)
  215. {
  216. Parser *pParser = NULL;
  217. Value *pvScrollerSheet;
  218. Element *peListScroller = NULL;
  219. if (g_rgH[SCROLLBARHTHEME])
  220. {
  221. CloseThemeData(g_rgH[SCROLLBARHTHEME]);
  222. g_rgH[SCROLLBARHTHEME] = NULL;
  223. }
  224. g_rgH[SCROLLBARHTHEME] = OpenThemeData(_pnhh->GetHWND(), L"Scrollbar");
  225. Parser::Create(IDR_LOGONUI, g_rgH, LogonParseError, &pParser);
  226. if (pParser && !pParser->WasParseError())
  227. {
  228. pvScrollerSheet = pParser->GetSheet(L"scroller");
  229. if (pvScrollerSheet)
  230. {
  231. peListScroller = (Selector*)FindDescendent(StrToID(L"scroller"));
  232. peListScroller->SetValue(SheetProp, PI_Local, pvScrollerSheet);
  233. pvScrollerSheet->Release();
  234. }
  235. pParser->Destroy();
  236. }
  237. }
  238. void LogonFrame::NextFlagAnimate(DWORD dwFrame)
  239. {
  240. #ifndef ANIMATE_FLAG
  241. UNREFERENCED_PARAMETER(dwFrame);
  242. #else
  243. Element* pe;
  244. if( dwFrame >= MAX_FLAG_FRAMES || g_fNoAnimations)
  245. {
  246. return;
  247. }
  248. pe = FindDescendent(StrToID(L"product"));
  249. DUIAssertNoMsg(pe);
  250. if (pe)
  251. {
  252. HBITMAP hbm = NULL;
  253. HDC hdc;
  254. Value *pv = NULL;
  255. hdc = CreateCompatibleDC(_hdcAnimation);
  256. if (hdc)
  257. {
  258. pv = pe->GetValue(Element::ContentProp, PI_Local);
  259. if (pv)
  260. {
  261. hbm = (HBITMAP)pv->GetImage(false);
  262. }
  263. if (hbm)
  264. {
  265. _dwFlagFrame = dwFrame;
  266. if (_dwFlagFrame >= MAX_FLAG_FRAMES)
  267. {
  268. _dwFlagFrame = 0;
  269. }
  270. HBITMAP hbmSave = (HBITMAP)SelectObject(hdc, hbm);
  271. BitBlt(hdc, 0, 0, 137, 86, _hdcAnimation, 0, 86 * _dwFlagFrame,SRCCOPY);
  272. SelectObject(hdc, hbmSave);
  273. HGADGET hGad = pe->GetDisplayNode();
  274. if (hGad)
  275. {
  276. InvalidateGadget(hGad);
  277. }
  278. }
  279. if (pv)
  280. {
  281. pv->Release();
  282. }
  283. DeleteDC(hdc);
  284. }
  285. }
  286. #endif
  287. }
  288. ////////////////////////////////////////
  289. //
  290. // LogonFrame::Initialize
  291. //
  292. // Initialize the LogonFrame, create the notification window that is used by SHGina for
  293. // sending messages to logonui. Set initial state, etc.
  294. //
  295. // RETURNS
  296. // S_OK if everything works out. Failure HRESULT if not. You are pretty much hosed if this fails
  297. //
  298. /////////////////////////////////////////
  299. HRESULT LogonFrame::Initialize(HWND hParent, BOOL fDblBuffer, UINT nCreate)
  300. {
  301. // Zero-init members
  302. _peAccountList = NULL;
  303. _peViewer = NULL;
  304. _peRightPanel = NULL;
  305. _peLeftPanel = NULL;
  306. _pbPower = NULL;
  307. _pbUndock = NULL;
  308. _peHelp = NULL;
  309. _peMsgArea = NULL;
  310. _peLogoArea = NULL;
  311. _pParser = NULL;
  312. _hwndNotification = NULL;
  313. _nStatusID = 0;
  314. _fPreStatusLock = FALSE;
  315. _nAppState = LAS_PreStatus;
  316. _pnhh = NULL;
  317. _fListAvailable = FALSE;
  318. _pvHotList = NULL;
  319. _pvList = NULL;
  320. _hdcAnimation = NULL;
  321. _dwFlagFrame = 0;
  322. _nColorDepth = 0;
  323. // Set up notification window
  324. _hwndNotification = CreateWindowEx(0,
  325. TEXT("LogonWnd"),
  326. TEXT("Logon"),
  327. WS_OVERLAPPED,
  328. 0, 0,
  329. 10,
  330. 10,
  331. HWND_MESSAGE,
  332. NULL,
  333. GetModuleHandleW(NULL),
  334. NULL);
  335. if (SUCCEEDED(CoCreateInstance(CLSID_ShellLogonStatusHost, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(ILogonStatusHost, &g_pILogonStatusHost))))
  336. {
  337. g_pILogonStatusHost->Initialize(GetModuleHandleW(NULL), _hwndNotification);
  338. }
  339. // In status (pre) state
  340. SetState(LAS_PreStatus);
  341. // Do base class initialization
  342. HRESULT hr;
  343. HDC hDC = NULL;
  344. hr = HWNDElement::Initialize(hParent, fDblBuffer ? true : false, nCreate);
  345. if (FAILED(hr))
  346. {
  347. return hr;
  348. goto Failure;
  349. }
  350. if (!g_fNoAnimations)
  351. {
  352. // Initialize
  353. hDC = GetDC(NULL);
  354. _nDPI = GetDeviceCaps(hDC, LOGPIXELSY);
  355. _nColorDepth = GetDeviceCaps(hDC, BITSPIXEL);
  356. ReleaseDC(NULL, hDC);
  357. #ifdef ANIMATE_FLAG
  358. hDC = GetDC(hParent);
  359. _hdcAnimation = CreateCompatibleDC(hDC);
  360. if (_hdcAnimation)
  361. {
  362. _hbmpFlags = (HBITMAP)LoadImage(GetModuleHandleW(NULL), MAKEINTRESOURCE(IDB_FLAGSTRIP), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
  363. if (_hbmpFlags)
  364. {
  365. HBITMAP hbmOld = (HBITMAP)SelectObject(_hdcAnimation, _hbmpFlags);
  366. DeleteObject(hbmOld);
  367. }
  368. else
  369. {
  370. DeleteDC(_hdcAnimation);
  371. _hdcAnimation = NULL;
  372. }
  373. }
  374. ReleaseDC(hParent, hDC);
  375. #endif
  376. }
  377. hr = SetActive(AE_MouseAndKeyboard);
  378. if (FAILED(hr))
  379. goto Failure;
  380. return S_OK;
  381. Failure:
  382. return hr;
  383. }
  384. LogonFrame::~LogonFrame()
  385. {
  386. if (_pvHotList)
  387. _pvHotList->Release();
  388. if (_pvList)
  389. _pvList->Release();
  390. if (_hdcAnimation)
  391. DeleteDC(_hdcAnimation);
  392. g_plf = NULL;
  393. }
  394. // Tree is ready. Upon failure, exit which will casuse the app to shutdown
  395. HRESULT LogonFrame::OnTreeReady(Parser* pParser)
  396. {
  397. HRESULT hr;
  398. // Cache
  399. _pParser = pParser;
  400. // Cache important descendents
  401. _peAccountList = (Selector*)FindDescendent(StrToID(L"accountlist"));
  402. DUIAssert(_peAccountList, "Cannot find account list, check the UI file");
  403. if (_peAccountList == NULL)
  404. {
  405. hr = E_OUTOFMEMORY;
  406. goto Failure;
  407. }
  408. _peLeftPanel = (Element*)FindDescendent(StrToID(L"leftpanel"));
  409. DUIAssert(_peLeftPanel, "Cannot find left panel, check the UI file");
  410. if (_peLeftPanel == NULL)
  411. {
  412. hr = E_OUTOFMEMORY;
  413. goto Failure;
  414. }
  415. _peViewer = (ScrollViewer*)FindDescendent(StrToID(L"scroller"));
  416. DUIAssert(_peViewer, "Cannot find scroller list, check the UI file");
  417. if (_peViewer == NULL)
  418. {
  419. hr = E_OUTOFMEMORY;
  420. goto Failure;
  421. }
  422. _peRightPanel = (Selector*)FindDescendent(StrToID(L"rightpanel"));
  423. DUIAssert(_peRightPanel, "Cannot find account list, check the UI file");
  424. if (_peRightPanel == NULL)
  425. {
  426. hr = E_OUTOFMEMORY;
  427. goto Failure;
  428. }
  429. _peLogoArea = (Element*)FindDescendent(StrToID(L"logoarea"));
  430. DUIAssert(_peLogoArea, "Cannot find logo area, check the UI file");
  431. if (_peLogoArea == NULL)
  432. {
  433. hr = E_OUTOFMEMORY;
  434. goto Failure;
  435. }
  436. _peMsgArea = (Element*)FindDescendent(StrToID(L"msgarea"));
  437. DUIAssert(_peMsgArea, "Cannot find welcome area, check the UI file");
  438. if (_peMsgArea == NULL)
  439. {
  440. hr = E_OUTOFMEMORY;
  441. goto Failure;
  442. }
  443. _pbPower = (Button*)FindDescendent(StrToID(L"power"));
  444. DUIAssert(_pbPower, "Cannot find power button, check the UI file");
  445. if (_pbPower == NULL)
  446. {
  447. hr = E_OUTOFMEMORY;
  448. goto Failure;
  449. }
  450. _pbUndock = (Button*)FindDescendent(StrToID(L"undock"));
  451. DUIAssert(_pbUndock, "Cannot find undock button, check the UI file");
  452. if (_pbUndock == NULL)
  453. {
  454. hr = E_OUTOFMEMORY;
  455. goto Failure;
  456. }
  457. _peHelp = (Button*)FindDescendent(StrToID(L"help"));
  458. DUIAssert(_peHelp, "Cannot find help text, check the UI file");
  459. if (_peHelp == NULL)
  460. {
  461. hr = E_OUTOFMEMORY;
  462. goto Failure;
  463. }
  464. _peOptions = FindDescendent(StrToID(L"options"));
  465. DUIAssert(_peOptions, "Cannot find account list, check the UI file");
  466. if (_peOptions == NULL)
  467. {
  468. hr = E_OUTOFMEMORY;
  469. goto Failure;
  470. }
  471. // check for small window or low color cases and hide some elements that will look bad then.
  472. HWND hwnd = _pnhh->GetHWND();
  473. RECT rcClient;
  474. Element *pEle;
  475. HDC hDC = GetDC(hwnd);
  476. _nColorDepth = GetDeviceCaps(hDC, BITSPIXEL);
  477. _pvHotList = _pParser->GetSheet(L"hotaccountlistss");
  478. _pvList = _pParser->GetSheet(L"accountlistss");
  479. ReleaseDC(hwnd, hDC);
  480. GetClientRect(hwnd, &rcClient);
  481. if (RECTWIDTH(rcClient) < 780 || _nColorDepth <= 8)
  482. {
  483. //no animations
  484. g_fNoAnimations = true;
  485. // remove the clouds
  486. pEle = FindDescendent(StrToID(L"contentcontainer"));
  487. if (pEle)
  488. {
  489. pEle->RemoveLocalValue(ContentProp);
  490. if (_nColorDepth <= 8)
  491. {
  492. pEle->SetBackgroundColor(ORGB (96,128,255));
  493. }
  494. }
  495. if (_nColorDepth <= 8)
  496. {
  497. pEle = FindDescendent(StrToID(L"product"));
  498. if (pEle)
  499. {
  500. pEle->SetBackgroundColor(ORGB (96,128,255));
  501. }
  502. }
  503. }
  504. _peViewer->AddListener(this);
  505. _peAccountList->AddListener(this);
  506. // Setup frame labels
  507. SetPowerButtonLabel(LoadResString(IDS_POWER));
  508. SetUndockButtonLabel(LoadResString(IDS_UNDOCK));
  509. ShowLogoArea();
  510. HideWelcomeArea();
  511. return S_OK;
  512. Failure:
  513. return hr;
  514. }
  515. // Set the title element (welcome, please wait..) by string resource id
  516. void LogonFrame::SetTitle(UINT uRCID)
  517. {
  518. WCHAR sz[1024];
  519. ZeroMemory(&sz, sizeof(sz));
  520. if (_nStatusID != uRCID)
  521. {
  522. #ifdef DBG
  523. int cRead = 0;
  524. cRead = LoadStringW(_pParser->GetHInstance(), uRCID, sz, DUIARRAYSIZE(sz));
  525. DUIAssert(cRead, "Could not locate string resource ID");
  526. #else
  527. LoadStringW(_pParser->GetHInstance(), uRCID, sz, ARRAYSIZE(sz));
  528. #endif
  529. SetTitle(sz);
  530. _nStatusID = uRCID;
  531. }
  532. }
  533. // Set the title element (welcome, please wait..)
  534. // slightly more involved because there is the shadow element that
  535. // needs to be changed as well
  536. void LogonFrame::SetTitle(LPCWSTR pszTitle)
  537. {
  538. Element *peTitle = NULL, *peShadow = NULL;
  539. peTitle= (Button*)FindDescendent(StrToID(L"welcome"));
  540. DUIAssert(peTitle, "Cannot find title text, check the UI file");
  541. if (peTitle)
  542. {
  543. peShadow= (Button*)FindDescendent(StrToID(L"welcomeshadow"));
  544. DUIAssert(peShadow, "Cannot find title shadow text, check the UI file");
  545. }
  546. if (peTitle && peShadow)
  547. {
  548. peTitle->SetContentString(pszTitle);
  549. peShadow->SetContentString(pszTitle);
  550. }
  551. }
  552. // Generic events
  553. void LogonFrame::OnEvent(Event* pEvent)
  554. {
  555. if (pEvent->nStage == GMF_BUBBLED) // Bubbled events
  556. {
  557. g_pErrorBalloon.HideToolTip();
  558. if (pEvent->uidType == Button::Click)
  559. {
  560. if (pEvent->peTarget == _pbPower)
  561. {
  562. // Power button pressed
  563. OnPower();
  564. pEvent->fHandled = true;
  565. return;
  566. }
  567. else if (pEvent->peTarget == _pbUndock)
  568. {
  569. // Undock button pressed
  570. OnUndock();
  571. pEvent->fHandled = true;
  572. return;
  573. }
  574. }
  575. }
  576. HWNDElement::OnEvent(pEvent);
  577. }
  578. // PropertyChanged listened events from various descendents
  579. // Swap out property sheets for account list based on state of the list
  580. void LogonFrame::OnListenedPropertyChanged(Element* peFrom, PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew)
  581. {
  582. UNREFERENCED_PARAMETER(pvOld);
  583. UNREFERENCED_PARAMETER(pvNew);
  584. {
  585. if (((peFrom == _peAccountList) && IsProp(Selector::Selection)) ||
  586. ((peFrom == _peViewer) && (IsProp(MouseWithin) || IsProp(KeyWithin))))
  587. {
  588. bool bHot = false;
  589. // Move to "hot" account list sheet if mouse or key is within viewer or an item is selected
  590. if (GetState() == LAS_PreStatus || GetState() == LAS_Logon)
  591. {
  592. bHot = _peViewer->GetMouseWithin() || _peAccountList->GetSelection();
  593. }
  594. if (!g_fNoAnimations)
  595. {
  596. KillFlagAnimation();
  597. _peAccountList->SetValue(SheetProp, PI_Local, bHot ? _pvHotList : _pvList);
  598. }
  599. }
  600. }
  601. }
  602. // System events
  603. // Watch for input events. If the frame receives them, unselect the list and set keyfocus to it
  604. void LogonFrame::OnInput(InputEvent* pEvent)
  605. {
  606. if (pEvent->nStage == GMF_DIRECT || pEvent->nStage == GMF_BUBBLED)
  607. {
  608. if (pEvent->nDevice == GINPUT_KEYBOARD)
  609. {
  610. KeyboardEvent* pke = (KeyboardEvent*)pEvent;
  611. if (pke->nCode == GKEY_DOWN)
  612. {
  613. switch (pke->ch)
  614. {
  615. case VK_ESCAPE:
  616. g_pErrorBalloon.HideToolTip();
  617. SetKeyFocus();
  618. _peAccountList->SetSelection(NULL);
  619. pEvent->fHandled = true;
  620. return;
  621. case VK_UP:
  622. case VK_DOWN:
  623. if (UserListAvailable())
  624. {
  625. if (_peAccountList->GetSelection() == NULL)
  626. {
  627. Value* pvChildren;
  628. ElementList* peList = _peAccountList->GetChildren(&pvChildren);
  629. if (peList)
  630. {
  631. LogonAccount* peAccount = (LogonAccount*)peList->GetItem(0);
  632. if (peAccount)
  633. {
  634. peAccount->SetKeyFocus();
  635. _peAccountList->SetSelection(peAccount);
  636. }
  637. }
  638. pvChildren->Release();
  639. pEvent->fHandled = true;
  640. return;
  641. }
  642. }
  643. break;
  644. }
  645. }
  646. }
  647. }
  648. HWNDElement::OnInput(pEvent);
  649. }
  650. void LogonFrame::OnPropertyChanged(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew)
  651. {
  652. if (IsProp(KeyFocused))
  653. {
  654. if (pvNew->GetBool())
  655. {
  656. // Unselect items from account list if pressed on background
  657. _peAccountList->SetSelection(NULL);
  658. }
  659. }
  660. HWNDElement::OnPropertyChanged(ppi, iIndex, pvOld, pvNew);
  661. }
  662. Element* LogonFrame::GetAdjacent(Element* peFrom, int iNavDir, NavReference const* pnr, bool bKeyable)
  663. {
  664. Element* peFound = HWNDElement::GetAdjacent(peFrom, iNavDir, pnr, bKeyable);
  665. if ((peFound == this))
  666. {
  667. // Don't let the frame show up in the tab order. Just repeat the search when we encounter the frame
  668. return HWNDElement::GetAdjacent(this, iNavDir, pnr, bKeyable);
  669. }
  670. return peFound;
  671. }
  672. // Add an account to the frame list
  673. HRESULT LogonFrame::AddAccount(LPCWSTR pszPicture, BOOL fPicRes, LPCWSTR pszName, LPCWSTR pszUsername, LPCWSTR pszHint,
  674. BOOL fPwdNeeded, BOOL fLoggedOn, OUT LogonAccount **ppla)
  675. {
  676. HRESULT hr;
  677. LogonAccount* pla = NULL;
  678. if (!_pParser)
  679. {
  680. hr = E_FAIL;
  681. goto Failure;
  682. }
  683. // Build up an account and insert into selection list
  684. hr = _pParser->CreateElement(L"accountitem", NULL, (Element**)&pla);
  685. if (FAILED(hr))
  686. goto Failure;
  687. hr = pla->OnTreeReady(pszPicture, fPicRes, pszName, pszUsername, pszHint, fPwdNeeded, fLoggedOn, GetHInstance());
  688. if (FAILED(hr))
  689. goto Failure;
  690. hr = _peAccountList->Add(pla);
  691. if (FAILED(hr))
  692. goto Failure;
  693. if (pla)
  694. {
  695. SetElementAccessability(pla, true, ROLE_SYSTEM_LISTITEM, pszUsername);
  696. }
  697. if (_nColorDepth <= 8)
  698. {
  699. pla->SetBackgroundColor(ORGB (96,128,255));
  700. Element *pEle;
  701. pEle = pla->FindDescendent(StrToID(L"userpane"));
  702. if (pEle)
  703. {
  704. pEle->SetBorderColor(ORGB (96,128,255));
  705. }
  706. }
  707. if (ppla)
  708. *ppla = pla;
  709. return S_OK;
  710. Failure:
  711. return hr;
  712. }
  713. // Passed authentication, log user on
  714. HRESULT LogonFrame::OnLogUserOn(LogonAccount* pla)
  715. {
  716. StartDefer();
  717. #ifdef GADGET_ENABLE_GDIPLUS
  718. // Disable status so that it can't be clicked on anymore
  719. pla->DisableStatus(0);
  720. pla->DisableStatus(1);
  721. // Clear list of logon accounts except the one logging on
  722. Value* pvChildren;
  723. ElementList* peList = _peAccountList->GetChildren(&pvChildren);
  724. if (peList)
  725. {
  726. LogonAccount* peAccount;
  727. for (UINT i = 0; i < peList->GetSize(); i++)
  728. {
  729. peAccount = (LogonAccount*)peList->GetItem(i);
  730. if (peAccount != pla)
  731. {
  732. peAccount->SetLogonState(LS_Denied);
  733. }
  734. else
  735. {
  736. peAccount->SetLogonState(LS_Granted);
  737. peAccount->InsertStatus(0);
  738. peAccount->RemoveStatus(1);
  739. }
  740. // Account account items are disabled
  741. peAccount->SetEnabled(false);
  742. }
  743. }
  744. pvChildren->Release();
  745. FxLogUserOn(pla);
  746. // Set frame status
  747. SetStatus(LoadResString(IDS_LOGGINGON));
  748. #else
  749. // Set keyfocus back to frame so it isn't pushed anywhere when controls are removed.
  750. // This will also cause a remove of the password panel from the current account
  751. SetKeyFocus();
  752. // Disable status so that it can't be clicked on anymore
  753. pla->DisableStatus(0);
  754. pla->DisableStatus(1);
  755. // Clear list of logon accounts except the one logging on
  756. Value* pvChildren;
  757. ElementList* peList = _peAccountList->GetChildren(&pvChildren);
  758. if (peList)
  759. {
  760. LogonAccount* peAccount;
  761. for (UINT i = 0; i < peList->GetSize(); i++)
  762. {
  763. peAccount = (LogonAccount*)peList->GetItem(i);
  764. if (peAccount != pla)
  765. {
  766. peAccount->SetLayoutPos(LP_None);
  767. peAccount->SetLogonState(LS_Denied);
  768. }
  769. else
  770. {
  771. peAccount->SetLogonState(LS_Granted);
  772. peAccount->InsertStatus(0);
  773. peAccount->RemoveStatus(1);
  774. }
  775. // Account account items are disabled
  776. peAccount->SetEnabled(false);
  777. }
  778. }
  779. pvChildren->Release();
  780. // Hide option buttons
  781. HidePowerButton();
  782. HideUndockButton();
  783. // Set frame status
  784. SetStatus(LoadResString(IDS_LOGGINGON));
  785. _peViewer->RemoveListener(this);
  786. _peAccountList->RemoveListener(this);
  787. #endif
  788. EndDefer();
  789. return S_OK;
  790. }
  791. HRESULT LogonFrame::OnPower()
  792. {
  793. DUITrace("LogonUI: LogonFrame::OnPower()\n");
  794. TurnOffComputer();
  795. return S_OK;
  796. }
  797. HRESULT LogonFrame::OnUndock()
  798. {
  799. DUITrace("LogonUI: LogonFrame::OnUndock()\n");
  800. UndockComputer();
  801. return S_OK;
  802. }
  803. ////////////////////////////////////////
  804. //
  805. // LogonFrame::SetButtonLabels
  806. //
  807. // If there is a friendly name of the computer stored in the computer name description,
  808. // grab it and change the "Turn off" and "Undock" options to include the compute rname
  809. //
  810. // RETURNS
  811. // nothing
  812. //
  813. /////////////////////////////////////////
  814. void LogonFrame::SetButtonLabels()
  815. {
  816. WCHAR szComputerName[MAX_COMPUTERDESC_LENGTH + 1] = {0};
  817. DWORD cchComputerName = MAX_COMPUTERDESC_LENGTH + 1;
  818. if ( _pbPower && SUCCEEDED(SHGetComputerDisplayName(NULL, SGCDNF_DESCRIPTIONONLY, szComputerName, cchComputerName)))
  819. {
  820. WCHAR szCommand[MAX_COMPUTERDESC_LENGTH + 50], szRes[50];
  821. LoadStringW(g_plf->GetHInstance(), IDS_POWERNAME, szRes, DUIARRAYSIZE(szRes));
  822. wsprintf(szCommand, szRes, szComputerName);
  823. SetPowerButtonLabel(szCommand);
  824. LoadStringW(g_plf->GetHInstance(), IDS_UNDOCKNAME, szRes, DUIARRAYSIZE(szRes));
  825. wsprintf(szCommand, szRes, szComputerName);
  826. SetUndockButtonLabel(szCommand);
  827. }
  828. }
  829. ////////////////////////////////////////////////////////
  830. // Logon Application State Transitions
  831. ////////////////////////////////////////
  832. //
  833. // LogonFrame::EnterPreStatusMode
  834. //
  835. // SHGina has sent a message telling logonui to enter the pre-status
  836. // mode or we are starting up in status mode. Hide items that should
  837. // not be displayed when in this state (power off, account list, user
  838. // instructions, etc).
  839. //
  840. // RETURNS
  841. // nothing
  842. //
  843. /////////////////////////////////////////
  844. void LogonFrame::EnterPreStatusMode(BOOL fLock)
  845. {
  846. // If currently locked, ignore call
  847. if (IsPreStatusLock())
  848. {
  849. DUIAssert(!fLock, "Receiving a lock while already within pre-Status lock");
  850. return;
  851. }
  852. if (fLock)
  853. {
  854. LogonAccount *pAccount;
  855. // Entering pre-Status mode with "lock", cannot exit to logon state without an unlock
  856. _fPreStatusLock = TRUE;
  857. pAccount = static_cast<LogonAccount*>(_peAccountList->GetSelection());
  858. if (pAccount != NULL)
  859. {
  860. lstrcpynW(szLastSelectedName, pAccount->GetUsername(), ARRAYSIZE(szLastSelectedName));
  861. }
  862. }
  863. if (GetState() == LAS_Hide)
  864. {
  865. _pnhh->ShowWindow();
  866. SetWindowPos(_pnhh->GetHWND(), NULL, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SWP_NOMOVE | SWP_NOZORDER );
  867. }
  868. StartDefer();
  869. SetKeyFocus(); // Removes selection
  870. HidePowerButton();
  871. HideUndockButton();
  872. ShowLogoArea();
  873. HideWelcomeArea();
  874. HideAccountPanel();
  875. Element *pe;
  876. pe = FindDescendent(StrToID(L"instruct"));
  877. DUIAssertNoMsg(pe);
  878. pe->SetVisible(FALSE);
  879. SetStatus(LoadResString(IDS_WINDOWSNAME));
  880. EndDefer();
  881. // Set state
  882. SetState(LAS_PreStatus);
  883. }
  884. ////////////////////////////////////////
  885. //
  886. // LogonFrame::EnterLogonMode
  887. //
  888. // SHGina has sent a message telling logonui to enter the logon mode.
  889. // this means to build and display the user list. If we are re-entering
  890. // logon mode from another mode, the user list will already exist and we
  891. // should just set everything back to the pending state.
  892. //
  893. // EnterLogonMode also sets up the undock and power off buttons based on
  894. // whether those options are allowed.
  895. //
  896. //
  897. // RETURNS
  898. // nothing
  899. //
  900. /////////////////////////////////////////
  901. void LogonFrame::EnterLogonMode(BOOL fUnLock)
  902. {
  903. // If currently locked, ignore call if not to unlock
  904. if (IsPreStatusLock())
  905. {
  906. if (fUnLock)
  907. {
  908. // Exiting pre-Status mode lock
  909. _fPreStatusLock = FALSE;
  910. }
  911. else
  912. return;
  913. }
  914. else
  915. {
  916. DUIAssert(!fUnLock, "Receiving an unlock while not within pre-Status lock");
  917. }
  918. DUIAssert(GetState() != LAS_Hide, "Cannot enter logon state from hidden state");
  919. ResetTheme();
  920. Element* pe;
  921. LogonAccount* plaAutoSelect = NULL;
  922. StartDefer();
  923. PokeComCtl32();
  924. // Retrieve data from backend if not populated
  925. if (UserListAvailable())
  926. {
  927. ResetUserList();
  928. }
  929. else
  930. {
  931. // Cache password field atoms for quicker identification (static)
  932. LogonAccount::idPwdGo = AddAtomW(L"go");
  933. LogonAccount::idPwdInfo = AddAtomW(L"info");
  934. // Create password panel
  935. Element* pePwdPanel;
  936. _pParser->CreateElement(L"passwordpanel", NULL, &pePwdPanel);
  937. DUIAssert(pePwdPanel, "Can't create password panel");
  938. // Cache password panel edit control
  939. Edit* pePwdEdit = (Edit*)pePwdPanel->FindDescendent(StrToID(L"password"));
  940. DUIAssert(pePwdPanel, "Can't create password edit control");
  941. // Cache password panel info button
  942. Button* pbPwdInfo = (Button*)pePwdPanel->FindDescendent(StrToID(L"info"));
  943. DUIAssert(pePwdPanel, "Can't create password info button");
  944. // Cache password panel keyboard element
  945. Element* peKbdIcon = (Button*)pePwdPanel->FindDescendent(StrToID(L"keyboard"));
  946. DUIAssert(pePwdPanel, "Can't create password keyboard icon");
  947. LogonAccount::InitPasswordPanel(pePwdPanel, pePwdEdit, pbPwdInfo, peKbdIcon );
  948. }
  949. BuildAccountList(this, &plaAutoSelect);
  950. if (szLastSelectedName[0] != L'\0')
  951. {
  952. LogonAccount *pAccount;
  953. pAccount = InternalFindNamedUser(szLastSelectedName);
  954. if (pAccount != NULL)
  955. {
  956. plaAutoSelect = pAccount;
  957. }
  958. szLastSelectedName[0] = L'\0';
  959. }
  960. if (IsShutdownAllowed())
  961. {
  962. ShowPowerButton();
  963. }
  964. else
  965. {
  966. HidePowerButton();
  967. }
  968. if (IsUndockAllowed())
  969. {
  970. ShowUndockButton();
  971. }
  972. else
  973. {
  974. HideUndockButton();
  975. }
  976. pe = FindDescendent(StrToID(L"instruct"));
  977. DUIAssertNoMsg(pe);
  978. pe->SetVisible(TRUE);
  979. pe = FindDescendent(StrToID(L"product"));
  980. DUIAssertNoMsg(pe);
  981. pe->StopAnimation(ANI_AlphaType);
  982. pe->RemoveLocalValue(BackgroundProp);
  983. // Account list viewer
  984. ShowAccountPanel();
  985. SetTitle(IDS_WELCOME);
  986. SetStatus(LoadResString(IDS_BEGIN));
  987. if (!plaAutoSelect)
  988. {
  989. SetKeyFocus();
  990. }
  991. EndDefer();
  992. // Set state
  993. SetState(LAS_Logon);
  994. // Set auto-select item, if exists
  995. if (plaAutoSelect)
  996. {
  997. plaAutoSelect->SetKeyFocus();
  998. _peAccountList->SetSelection(plaAutoSelect);
  999. }
  1000. SetButtonLabels();
  1001. SetForegroundWindow(_pnhh->GetHWND());
  1002. }
  1003. ////////////////////////////////////////
  1004. //
  1005. // LogonFrame::EnterPostStatusMode
  1006. //
  1007. // SHGina has sent a message telling logonui that the authentication has succeeded
  1008. // and we should now go into the post status mode. LogonFrame::OnLogUserOn has already
  1009. // started the animations for this.
  1010. //
  1011. // RETURNS
  1012. // nothing
  1013. //
  1014. /////////////////////////////////////////
  1015. void LogonFrame::EnterPostStatusMode()
  1016. {
  1017. // Set state
  1018. SetState(LAS_PostStatus);
  1019. Element *pe;
  1020. pe = FindDescendent(StrToID(L"instruct"));
  1021. DUIAssertNoMsg(pe);
  1022. pe->SetVisible(FALSE);
  1023. //animation was started in OnLogUserOn
  1024. ShowWelcomeArea();
  1025. HideLogoArea();
  1026. }
  1027. ////////////////////////////////////////
  1028. //
  1029. // LogonFrame::EnterHideMode
  1030. //
  1031. // SHGina has sent a message telling logonui to hide.
  1032. //
  1033. // RETURNS
  1034. // nothing
  1035. //
  1036. /////////////////////////////////////////
  1037. void LogonFrame::EnterHideMode()
  1038. {
  1039. // Set state
  1040. SetState(LAS_Hide);
  1041. if (_pnhh)
  1042. {
  1043. _pnhh->HideWindow();
  1044. }
  1045. }
  1046. ////////////////////////////////////////
  1047. //
  1048. // LogonFrame::EnterDoneMode
  1049. //
  1050. // SHGina has sent a message telling logonui to exit.
  1051. //
  1052. // RETURNS
  1053. // nothing
  1054. //
  1055. /////////////////////////////////////////
  1056. void LogonFrame::EnterDoneMode()
  1057. {
  1058. // Set state
  1059. SetState(LAS_Done);
  1060. if (_pnhh)
  1061. {
  1062. _pnhh->DestroyWindow();
  1063. }
  1064. }
  1065. ////////////////////////////////////////
  1066. //
  1067. // LogonFrame::ResetUserList
  1068. //
  1069. // Delete all of the users in the user list so that it can be rebuilt
  1070. //
  1071. // RETURNS
  1072. // nothing
  1073. //
  1074. /////////////////////////////////////////
  1075. void LogonFrame::ResetUserList()
  1076. {
  1077. if (UserListAvailable())
  1078. {
  1079. // reset the candidate to NULL
  1080. LogonAccount::ClearCandidate();
  1081. // remove of the password panel from the current account (if any)
  1082. SetKeyFocus();
  1083. //fix up the existing list to get us back into logon mode
  1084. Value* pvChildren;
  1085. ElementList* peList = _peAccountList->GetChildren(&pvChildren);
  1086. if (peList)
  1087. {
  1088. LogonAccount* peAccount;
  1089. for (int i = peList->GetSize() - 1; i >= 0; i--)
  1090. {
  1091. peAccount = (LogonAccount*)peList->GetItem(i);
  1092. peAccount->Destroy();
  1093. }
  1094. }
  1095. pvChildren->Release();
  1096. }
  1097. }
  1098. ////////////////////////////////////////
  1099. //
  1100. // LogonFrame::InteractiveLogonRequest
  1101. //
  1102. // SHGina has sent an InteractiveLogonRequest. We should look for the user
  1103. // that was passed in and if found, try to log them in.
  1104. //
  1105. // RETURNS
  1106. // LRESULT indicating success or failure of finding htem and logging them in.
  1107. //
  1108. /////////////////////////////////////////
  1109. LRESULT LogonFrame::InteractiveLogonRequest(LPCWSTR pszUsername, LPCWSTR pszPassword)
  1110. {
  1111. LRESULT lResult = 0;
  1112. LogonAccount *pla;
  1113. pla = FindNamedUser(pszUsername);
  1114. if (pla)
  1115. {
  1116. if (pla->OnAuthenticateUser(pszPassword))
  1117. {
  1118. lResult = ERROR_SUCCESS;
  1119. }
  1120. else
  1121. {
  1122. lResult = ERROR_ACCESS_DENIED;
  1123. }
  1124. }
  1125. return(lResult);
  1126. }
  1127. ////////////////////////////////////////
  1128. //
  1129. // LogonFrame::InternalFindNamedUser
  1130. //
  1131. // Find a user in the LogonAccount list with the
  1132. // provided username (logon name).
  1133. //
  1134. // RETURNS
  1135. // The LogonAccount* for the indicated user or NULL if
  1136. // not found
  1137. //
  1138. /////////////////////////////////////////
  1139. LogonAccount* LogonFrame::InternalFindNamedUser(LPCWSTR pszUsername)
  1140. {
  1141. LogonAccount *plaResult = NULL;
  1142. Value* pvChildren;
  1143. ElementList* peList = _peAccountList->GetChildren(&pvChildren);
  1144. if (peList)
  1145. {
  1146. for (UINT i = 0; i < peList->GetSize(); i++)
  1147. {
  1148. DUIAssert(peList->GetItem(i)->GetClassInfo() == LogonAccount::Class, "Account list must contain LogonAccount objects");
  1149. LogonAccount* pla = (LogonAccount*)peList->GetItem(i);
  1150. if (pla)
  1151. {
  1152. if (lstrcmpi(pla->GetUsername(), pszUsername) == 0)
  1153. {
  1154. plaResult = pla;
  1155. break;
  1156. }
  1157. }
  1158. }
  1159. }
  1160. pvChildren->Release();
  1161. return plaResult;
  1162. }
  1163. ////////////////////////////////////////
  1164. //
  1165. // LogonFrame::FindNamedUser
  1166. //
  1167. // Find a user in the LogonAccount list with the
  1168. // provided username (logon name).
  1169. //
  1170. // RETURNS
  1171. // The LogonAccount* for the indicated user or NULL if
  1172. // not found
  1173. //
  1174. /////////////////////////////////////////
  1175. LogonAccount *LogonFrame::FindNamedUser(LPCWSTR pszUsername)
  1176. {
  1177. // Early out if: no user list available
  1178. // not in logon mode (showing user list)
  1179. if (!UserListAvailable() || (GetState() != LAS_Logon))
  1180. {
  1181. return NULL;
  1182. }
  1183. else
  1184. {
  1185. return(InternalFindNamedUser(pszUsername));
  1186. }
  1187. }
  1188. ////////////////////////////////////////
  1189. //
  1190. // LogonFrame::UpdateUserStatus
  1191. //
  1192. // Iterate the list of user accounts and call LogonAccount::UpdateNotifications
  1193. // for each one. This will result in them updating the unread mail count and
  1194. // logon status for each of the logon accounts.
  1195. // Pass fRefreshAll through to UpdateApplications
  1196. //
  1197. /////////////////////////////////////////
  1198. void LogonFrame::UpdateUserStatus(BOOL fRefreshAll)
  1199. {
  1200. Value* pvChildren;
  1201. static fUpdating = false;
  1202. // Early out if: no user list available
  1203. // not in logon mode (showing user list)
  1204. if (!UserListAvailable() || (GetState() != LAS_Logon) || fUpdating)
  1205. return;
  1206. fUpdating = true;
  1207. StartDefer();
  1208. ElementList* peList = _peAccountList->GetChildren(&pvChildren);
  1209. if (peList)
  1210. {
  1211. for (UINT i = 0; i < peList->GetSize(); i++)
  1212. {
  1213. DUIAssert(peList->GetItem(i)->GetClassInfo() == LogonAccount::Class, "Account list must contain LogonAccount objects");
  1214. LogonAccount* pla = (LogonAccount*)peList->GetItem(i);
  1215. if (pla)
  1216. {
  1217. pla->UpdateNotifications(fRefreshAll);
  1218. }
  1219. }
  1220. }
  1221. if (IsUndockAllowed())
  1222. {
  1223. ShowUndockButton();
  1224. }
  1225. else
  1226. {
  1227. HideUndockButton();
  1228. }
  1229. pvChildren->Release();
  1230. EndDefer();
  1231. fUpdating = false;
  1232. }
  1233. ////////////////////////////////////////
  1234. //
  1235. // LogonFrame::SelectUser
  1236. //
  1237. //
  1238. //
  1239. /////////////////////////////////////////
  1240. void LogonFrame::SelectUser(LPCWSTR pszUsername)
  1241. {
  1242. LogonAccount *pla;
  1243. pla = FindNamedUser(pszUsername);
  1244. if (pla != NULL)
  1245. {
  1246. pla->OnAuthenticatedUser();
  1247. }
  1248. else
  1249. {
  1250. LogonAccount::ClearCandidate();
  1251. EnterPostStatusMode();
  1252. HidePowerButton();
  1253. HideUndockButton();
  1254. HideAccountPanel();
  1255. }
  1256. }
  1257. ////////////////////////////////////////
  1258. //
  1259. // LogonFrame::Resize
  1260. //
  1261. //
  1262. //
  1263. /////////////////////////////////////////
  1264. void LogonFrame::Resize(BOOL fWorkArea)
  1265. {
  1266. RECT rc;
  1267. SIZE size;
  1268. static BOOL fWorkAreaChanged = FALSE;
  1269. if (fWorkArea)
  1270. {
  1271. fWorkAreaChanged = TRUE;
  1272. }
  1273. if (fWorkAreaChanged)
  1274. {
  1275. SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
  1276. size.cx = rc.right - rc.left;
  1277. size.cy = rc.bottom - rc.top;
  1278. }
  1279. else
  1280. {
  1281. rc.left = 0;
  1282. rc.top = 0;
  1283. size.cx = GetSystemMetrics(SM_CXSCREEN);
  1284. size.cy = GetSystemMetrics(SM_CYSCREEN);
  1285. }
  1286. SetWindowPos(_pnhh->GetHWND(),
  1287. NULL,
  1288. rc.left,
  1289. rc.top,
  1290. size.cx,
  1291. size.cy,
  1292. SWP_NOACTIVATE | SWP_NOZORDER | SWP_ASYNCWINDOWPOS);
  1293. }
  1294. ////////////////////////////////////////
  1295. //
  1296. // LogonFrame::SetAnimations
  1297. //
  1298. //
  1299. //
  1300. /////////////////////////////////////////
  1301. void LogonFrame::SetAnimations(BOOL fAnimations)
  1302. {
  1303. g_fNoAnimations = !fAnimations;
  1304. if (fAnimations)
  1305. {
  1306. EnableAnimations();
  1307. }
  1308. else
  1309. {
  1310. DisableAnimations();
  1311. }
  1312. }
  1313. ////////////////////////////////////////////////////////
  1314. // Property definitions
  1315. ////////////////////////////////////////////////////////
  1316. // ClassInfo (must appear after property definitions)
  1317. // Define class info with type and base type, set static class pointer
  1318. IClassInfo* LogonFrame::Class = NULL;
  1319. HRESULT LogonFrame::Register()
  1320. {
  1321. return ClassInfo<LogonFrame,HWNDElement>::Register(L"LogonFrame", NULL, 0);
  1322. }
  1323. ////////////////////////////////////////////////////////
  1324. //
  1325. HRESULT LogonAccountList::Create(OUT Element** ppElement)
  1326. {
  1327. *ppElement = NULL;
  1328. LogonAccountList* plal = HNew<LogonAccountList>();
  1329. if (!plal)
  1330. return E_OUTOFMEMORY;
  1331. HRESULT hr = plal->Initialize();
  1332. if (FAILED(hr))
  1333. {
  1334. plal->Destroy();
  1335. return hr;
  1336. }
  1337. *ppElement = plal;
  1338. return S_OK;
  1339. }
  1340. void LogonAccountList::OnPropertyChanged(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew)
  1341. {
  1342. #ifdef GADGET_ENABLE_GDIPLUS
  1343. if (IsProp(MouseWithin))
  1344. {
  1345. if (pvNew->GetBool())
  1346. FxMouseWithin(fdIn);
  1347. else
  1348. FxMouseWithin(fdOut);
  1349. }
  1350. #endif // GADGET_ENABLE_GDIPLUS
  1351. Selector::OnPropertyChanged(ppi, iIndex, pvOld, pvNew);
  1352. }
  1353. ////////////////////////////////////////////////////////
  1354. // Property definitions
  1355. ////////////////////////////////////////////////////////
  1356. // ClassInfo (must appear after property definitions)
  1357. // Define class info with type and base type, set static class pointer
  1358. IClassInfo* LogonAccountList::Class = NULL;
  1359. HRESULT LogonAccountList::Register()
  1360. {
  1361. return ClassInfo<LogonAccountList,Selector>::Register(L"LogonAccountList", NULL, 0);
  1362. }
  1363. ////////////////////////////////////////////////////////
  1364. //
  1365. // LogonAccount
  1366. //
  1367. ////////////////////////////////////////////////////////
  1368. ATOM LogonAccount::idPwdGo = NULL;
  1369. ATOM LogonAccount::idPwdInfo = NULL;
  1370. Element* LogonAccount::_pePwdPanel = NULL;
  1371. Edit* LogonAccount::_pePwdEdit = NULL;
  1372. Button* LogonAccount::_pbPwdInfo = NULL;
  1373. Element* LogonAccount::_peKbdIcon = NULL;
  1374. LogonAccount* LogonAccount::_peCandidate = NULL;
  1375. HRESULT LogonAccount::Create(OUT Element** ppElement)
  1376. {
  1377. *ppElement = NULL;
  1378. LogonAccount* pla = HNew<LogonAccount>();
  1379. if (!pla)
  1380. return E_OUTOFMEMORY;
  1381. HRESULT hr = pla->Initialize();
  1382. if (FAILED(hr))
  1383. {
  1384. pla->Destroy();
  1385. return hr;
  1386. }
  1387. *ppElement = pla;
  1388. return S_OK;
  1389. }
  1390. HRESULT LogonAccount::Initialize()
  1391. {
  1392. // Zero-init members
  1393. _pbStatus[0] = NULL;
  1394. _pbStatus[1] = NULL;
  1395. _pvUsername = NULL;
  1396. _pvHint = NULL;
  1397. _fPwdNeeded = (BOOL)-1; // uninitialized
  1398. _fLoggedOn = FALSE;
  1399. _fHasPwdPanel = FALSE;
  1400. // Do base class initialization
  1401. HRESULT hr = Button::Initialize(AE_MouseAndKeyboard);
  1402. if (FAILED(hr))
  1403. goto Failure;
  1404. // Initialize
  1405. // TODO: Additional LogonAccount initialization code here
  1406. return S_OK;
  1407. Failure:
  1408. return hr;
  1409. }
  1410. LogonAccount::~LogonAccount()
  1411. {
  1412. // Free resources
  1413. if (_pvUsername)
  1414. {
  1415. _pvUsername->Release();
  1416. _pvUsername = NULL;
  1417. }
  1418. if (_pvHint)
  1419. {
  1420. _pvHint->Release();
  1421. _pvHint = NULL;
  1422. }
  1423. // TODO: Account destruction cleanup
  1424. }
  1425. void LogonAccount::SetStatus(UINT nLine, LPCWSTR psz)
  1426. {
  1427. if (psz)
  1428. {
  1429. _pbStatus[nLine]->SetContentString(psz);
  1430. SetElementAccessability(_pbStatus[nLine], true, ROLE_SYSTEM_LINK, psz);
  1431. }
  1432. }
  1433. // Tree is ready
  1434. HRESULT LogonAccount::OnTreeReady(LPCWSTR pszPicture, BOOL fPicRes, LPCWSTR pszName, LPCWSTR pszUsername, LPCWSTR pszHint,
  1435. BOOL fPwdNeeded, BOOL fLoggedOn, HINSTANCE hInst)
  1436. {
  1437. HRESULT hr;
  1438. Element* pePicture = NULL;
  1439. Element* peName = NULL;
  1440. Value* pv = NULL;
  1441. UNREFERENCED_PARAMETER(fPwdNeeded);
  1442. StartDefer();
  1443. // Cache important descendents
  1444. _pbStatus[0] = (Button*)FindDescendent(StrToID(L"status0"));
  1445. DUIAssert(_pbStatus[0], "Cannot find account list, check the UI file");
  1446. if (_pbStatus[0] == NULL)
  1447. {
  1448. hr = E_OUTOFMEMORY;
  1449. goto Failure;
  1450. }
  1451. _pbStatus[1] = (Button*)FindDescendent(StrToID(L"status1"));
  1452. DUIAssert(_pbStatus[1], "Cannot find account list, check the UI file");
  1453. if (_pbStatus[1] == NULL)
  1454. {
  1455. hr = E_OUTOFMEMORY;
  1456. goto Failure;
  1457. }
  1458. // Locate descendents and populate
  1459. pePicture = FindDescendent(StrToID(L"picture"));
  1460. DUIAssert(pePicture, "Cannot find account list, check the UI file");
  1461. if (pePicture == NULL)
  1462. {
  1463. hr = E_OUTOFMEMORY;
  1464. goto Failure;
  1465. }
  1466. // CreateGraphic handles NULL bitmaps
  1467. pv = Value::CreateGraphic(pszPicture, GRAPHIC_NoBlend, 0, 0, 0, (fPicRes) ? hInst : 0);
  1468. if (pv)
  1469. {
  1470. // Our preferred size is 1/2 inch (36pt) square.
  1471. USHORT cx = (USHORT)LogonFrame::PointToPixel(36);
  1472. USHORT cy = cx;
  1473. Graphic* pg = pv->GetGraphic();
  1474. // If it's not square, scale the smaller dimension
  1475. // to maintain the aspect ratio.
  1476. if (pg->cx > pg->cy)
  1477. {
  1478. cy = (USHORT)MulDiv(cx, pg->cy, pg->cx);
  1479. }
  1480. else if (pg->cy > pg->cx)
  1481. {
  1482. cx = (USHORT)MulDiv(cy, pg->cx, pg->cy);
  1483. }
  1484. // Did anything change?
  1485. if (cx != pg->cx || cy != pg->cy)
  1486. {
  1487. // Reload the graphic
  1488. pv->Release();
  1489. pv = Value::CreateGraphic(pszPicture, GRAPHIC_NoBlend, 0, cx, cy, (fPicRes) ? hInst : 0);
  1490. }
  1491. }
  1492. if (!pv)
  1493. {
  1494. // if we can't get the picture, use a default one
  1495. pv = Value::CreateGraphic(MAKEINTRESOURCEW(IDB_USER0), GRAPHIC_NoBlend, 0, (USHORT)LogonFrame::PointToPixel(36), (USHORT)LogonFrame::PointToPixel(36), hInst);
  1496. if (!pv)
  1497. {
  1498. hr = E_OUTOFMEMORY;
  1499. goto Failure;
  1500. }
  1501. }
  1502. hr = pePicture->SetValue(Element::ContentProp, PI_Local, pv);
  1503. if (FAILED(hr))
  1504. goto Failure;
  1505. pv->Release();
  1506. pv = NULL;
  1507. // Name
  1508. peName = FindDescendent(StrToID(L"username"));
  1509. DUIAssert(peName, "Cannot find account list, check the UI file");
  1510. if (peName == NULL)
  1511. {
  1512. hr = E_OUTOFMEMORY;
  1513. goto Failure;
  1514. }
  1515. hr = peName->SetContentString(pszName);
  1516. if (FAILED(hr))
  1517. goto Failure;
  1518. // Store members, will be released in destructor
  1519. if (pszUsername)
  1520. {
  1521. _pvUsername = Value::CreateString(pszUsername);
  1522. if (!_pvUsername)
  1523. {
  1524. hr = E_OUTOFMEMORY;
  1525. goto Failure;
  1526. }
  1527. }
  1528. if (pszHint)
  1529. {
  1530. _pvHint = Value::CreateString(pszHint);
  1531. if (!_pvHint)
  1532. {
  1533. hr = E_OUTOFMEMORY;
  1534. goto Failure;
  1535. }
  1536. }
  1537. _fLoggedOn = fLoggedOn;
  1538. EndDefer();
  1539. return S_OK;
  1540. Failure:
  1541. EndDefer();
  1542. if (pv)
  1543. pv->Release();
  1544. return hr;
  1545. }
  1546. // Generic events
  1547. void LogonAccount::OnEvent(Event* pEvent)
  1548. {
  1549. if (pEvent->nStage == GMF_DIRECT) // Direct events
  1550. {
  1551. // Watch for click events initiated by LogonAccounts only
  1552. // if we are not logging someone on
  1553. if (pEvent->uidType == Button::Click)
  1554. {
  1555. if (pEvent->peTarget == this)
  1556. {
  1557. if (IsPasswordBlank())
  1558. {
  1559. // No password needed, attempt logon
  1560. OnAuthenticateUser();
  1561. }
  1562. pEvent->fHandled = true;
  1563. return;
  1564. }
  1565. }
  1566. }
  1567. else if (pEvent->nStage == GMF_BUBBLED) // Bubbled events
  1568. {
  1569. if (pEvent->uidType == Button::Click)
  1570. {
  1571. if (idPwdGo && (pEvent->peTarget->GetID() == idPwdGo))
  1572. {
  1573. // Attempt logon
  1574. OnAuthenticateUser();
  1575. pEvent->fHandled = true;
  1576. return;
  1577. }
  1578. else if (idPwdInfo && (pEvent->peTarget->GetID() == idPwdInfo))
  1579. {
  1580. // Retrieve hint
  1581. OnHintSelect();
  1582. pEvent->fHandled = true;
  1583. return;
  1584. }
  1585. else if (pEvent->peTarget == _pbStatus[0])
  1586. {
  1587. // Retrieve status info
  1588. OnStatusSelect(0);
  1589. pEvent->fHandled = true;
  1590. return;
  1591. }
  1592. else if (pEvent->peTarget == _pbStatus[1])
  1593. {
  1594. // Retrieve status info
  1595. OnStatusSelect(1);
  1596. pEvent->fHandled = true;
  1597. return;
  1598. }
  1599. }
  1600. else if (pEvent->uidType == Edit::Enter)
  1601. {
  1602. if (_pePwdEdit && pEvent->peTarget == _pePwdEdit)
  1603. {
  1604. // Attempt logon
  1605. OnAuthenticateUser();
  1606. pEvent->fHandled = true;
  1607. return;
  1608. }
  1609. }
  1610. }
  1611. Button::OnEvent(pEvent);
  1612. }
  1613. // System events
  1614. void LogonAccount::OnInput(InputEvent* pEvent)
  1615. {
  1616. KeyboardEvent* pke = (KeyboardEvent*)pEvent;
  1617. if (pke->nDevice == GINPUT_KEYBOARD && pke->nCode == GKEY_DOWN)
  1618. {
  1619. g_pErrorBalloon.HideToolTip();
  1620. }
  1621. LayoutCheckHandler(LAYOUT_DEF_USER);
  1622. Button::OnInput(pEvent);
  1623. }
  1624. void LogonAccount::OnPropertyChanged(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew)
  1625. {
  1626. #ifdef GADGET_ENABLE_GDIPLUS
  1627. // MouseWithin must be before Selected
  1628. if (IsProp(MouseWithin))
  1629. {
  1630. if (pvNew->GetBool())
  1631. FxMouseWithin(fdIn);
  1632. else
  1633. FxMouseWithin(fdOut);
  1634. }
  1635. #endif
  1636. if (IsProp(Selected))
  1637. {
  1638. if (pvNew->GetBool())
  1639. InsertPasswordPanel();
  1640. else
  1641. RemovePasswordPanel();
  1642. }
  1643. Button::OnPropertyChanged(ppi, iIndex, pvOld, pvNew);
  1644. }
  1645. BOOL LogonAccount::IsPasswordBlank()
  1646. {
  1647. if (_fPwdNeeded == (BOOL)-1)
  1648. {
  1649. // assume a password is needed
  1650. _fPwdNeeded = TRUE;
  1651. if (_pvUsername)
  1652. {
  1653. LPTSTR pszUsername;
  1654. pszUsername = _pvUsername->GetString();
  1655. if (pszUsername)
  1656. {
  1657. ILogonUser* pUser;
  1658. if (SUCCEEDED(GetLogonUserByLogonName(pszUsername, &pUser)))
  1659. {
  1660. VARIANT_BOOL vbPwdNeeded;
  1661. if (RunningInWinlogon() &&
  1662. SUCCEEDED(pUser->get_passwordRequired(&vbPwdNeeded)) &&
  1663. (vbPwdNeeded == VARIANT_FALSE))
  1664. {
  1665. _fPwdNeeded = FALSE;
  1666. }
  1667. pUser->Release();
  1668. }
  1669. }
  1670. }
  1671. }
  1672. return (_fPwdNeeded == FALSE);
  1673. }
  1674. HRESULT LogonAccount::InsertPasswordPanel()
  1675. {
  1676. HRESULT hr;
  1677. // If already have it, or no password is available, or logon state is not pending
  1678. if (_fHasPwdPanel || IsPasswordBlank() || (GetLogonState() != LS_Pending))
  1679. goto Done;
  1680. StartDefer();
  1681. // Add password panel
  1682. hr = Add(_pePwdPanel);
  1683. if (FAILED(hr))
  1684. {
  1685. EndDefer();
  1686. goto Failure;
  1687. }
  1688. SetElementAccessability(_pePwdEdit, true, ROLE_SYSTEM_STATICTEXT, _pvUsername->GetString());
  1689. _fHasPwdPanel = TRUE;
  1690. #ifdef GADGET_ENABLE_GDIPLUS
  1691. // Ensure that the Edit control is visible
  1692. ShowEdit();
  1693. #endif
  1694. // Hide hint button if no hint provided
  1695. if (_pvHint && *(_pvHint->GetString()) != NULL)
  1696. _pbPwdInfo->SetVisible(true);
  1697. else
  1698. _pbPwdInfo->SetVisible(false);
  1699. // Hide status text (do not remove or insert)
  1700. HideStatus(0);
  1701. HideStatus(1);
  1702. LayoutCheckHandler(LAYOUT_DEF_USER);
  1703. // Push focus to edit control
  1704. _pePwdEdit->SetKeyFocus();
  1705. EndDefer();
  1706. Done:
  1707. return S_OK;
  1708. Failure:
  1709. return hr;
  1710. }
  1711. HRESULT LogonAccount::RemovePasswordPanel()
  1712. {
  1713. HRESULT hr;
  1714. if (!_fHasPwdPanel)
  1715. goto Done;
  1716. StartDefer();
  1717. // Remove password panel
  1718. hr = Remove(_pePwdPanel);
  1719. if (FAILED(hr))
  1720. {
  1721. EndDefer();
  1722. goto Failure;
  1723. }
  1724. // Clear out edit control
  1725. _pePwdEdit->SetContentString(L"");
  1726. UnSubClassTheEditBox(_pePwdEdit->GetHWND()); // Provide for trap of the TTN_LINKCLICK event
  1727. // Unhide status text
  1728. ShowStatus(0);
  1729. ShowStatus(1);
  1730. _fHasPwdPanel = FALSE;
  1731. EndDefer();
  1732. Done:
  1733. return S_OK;
  1734. Failure:
  1735. return hr;
  1736. }
  1737. // User has authenticated
  1738. void LogonAccount::OnAuthenticatedUser()
  1739. {
  1740. // On success, log user on
  1741. _peCandidate = this;
  1742. g_plf->OnLogUserOn(this);
  1743. g_plf->EnterPostStatusMode();
  1744. }
  1745. // User is attempting to log on
  1746. BOOL LogonAccount::OnAuthenticateUser(LPCWSTR pszInPassword)
  1747. {
  1748. HRESULT hr;
  1749. // Logon requested on this account
  1750. LPCWSTR pszPassword = L"";
  1751. Value* pv = NULL;
  1752. ILogonUser *pobjUser;
  1753. VARIANT_BOOL vbLogonSucceeded = VARIANT_FALSE;
  1754. WCHAR *pszUsername = _pvUsername->GetString();
  1755. if (pszUsername)
  1756. {
  1757. if (SUCCEEDED(hr = GetLogonUserByLogonName(pszUsername, &pobjUser)))
  1758. {
  1759. if (!IsPasswordBlank())
  1760. {
  1761. if (pszInPassword)
  1762. {
  1763. pszPassword = pszInPassword;
  1764. }
  1765. else
  1766. {
  1767. if (_pePwdEdit)
  1768. {
  1769. pszPassword = _pePwdEdit->GetContentString(&pv);
  1770. if (!pszPassword)
  1771. pszPassword = L"";
  1772. if (pv)
  1773. {
  1774. pv->Release();
  1775. }
  1776. }
  1777. }
  1778. BSTR bstr = SysAllocString(pszPassword);
  1779. pobjUser->logon(bstr, &vbLogonSucceeded);
  1780. SysFreeString(bstr);
  1781. }
  1782. else
  1783. {
  1784. pobjUser->logon(L"", &vbLogonSucceeded);
  1785. }
  1786. pobjUser->Release();
  1787. }
  1788. }
  1789. if (vbLogonSucceeded == VARIANT_TRUE)
  1790. {
  1791. OnAuthenticatedUser();
  1792. }
  1793. else
  1794. {
  1795. if (pszInPassword == NULL)
  1796. {
  1797. ShowPasswordIncorrectMessage();
  1798. }
  1799. }
  1800. return (vbLogonSucceeded == VARIANT_TRUE);
  1801. }
  1802. ////////////////////////////////////////
  1803. //
  1804. // LogonAccount::ShowPasswordIncorrectMessage
  1805. //
  1806. // Put up the balloon message that says that the password is incorrect.
  1807. //
  1808. /////////////////////////////////////////
  1809. void LogonAccount::ShowPasswordIncorrectMessage()
  1810. {
  1811. TCHAR szError[512], szTitle[128], szAccessible[640];
  1812. BOOL fBackupAvailable = false;
  1813. BOOL fHint = false;
  1814. DWORD dwResult;
  1815. g_szUsername[0] = 0;
  1816. SubClassTheEditBox(_pePwdEdit->GetHWND()); // Provide for trap of the TTN_LINKCLICK event
  1817. if (0 < lstrlen(_pvUsername->GetString()))
  1818. {
  1819. wcscpy(g_szUsername,_pvUsername->GetString());
  1820. if (0 == PRQueryStatus(NULL,_pvUsername->GetString(),&dwResult))
  1821. {
  1822. if (0 == dwResult)
  1823. {
  1824. fBackupAvailable = TRUE;
  1825. }
  1826. }
  1827. }
  1828. if (NULL != _pvHint && 0 < lstrlen(_pvHint->GetString()))
  1829. {
  1830. fHint = true;
  1831. }
  1832. LoadStringW(g_plf->GetHInstance(), IDS_BADPWDTITLE, szTitle, DUIARRAYSIZE(szTitle));
  1833. if (!fBackupAvailable & fHint)
  1834. LoadStringW(g_plf->GetHInstance(), IDS_BADPWDHINT, szError, DUIARRAYSIZE(szError));
  1835. else if (fBackupAvailable & !fHint)
  1836. LoadStringW(g_plf->GetHInstance(), IDS_BADPWDREST, szError, DUIARRAYSIZE(szError));
  1837. else if (fBackupAvailable & fHint)
  1838. LoadStringW(g_plf->GetHInstance(), IDS_BADPWDHINTREST, szError, DUIARRAYSIZE(szError));
  1839. else
  1840. LoadStringW(g_plf->GetHInstance(), IDS_BADPWD, szError, DUIARRAYSIZE(szError));
  1841. g_pErrorBalloon.ShowToolTip(GetModuleHandleW(NULL), _pePwdEdit->GetHWND(), szError, szTitle, TTI_ERROR, EB_WARNINGCENTERED | EB_MARKUP, 10000);
  1842. lstrcpy(szAccessible, szTitle);
  1843. lstrcat(szAccessible, szError);
  1844. SetElementAccessability(_pePwdEdit, true, ROLE_SYSTEM_STATICTEXT, szAccessible);
  1845. _pePwdEdit->RemoveLocalValue(ContentProp);
  1846. _pePwdEdit->SetKeyFocus();
  1847. }
  1848. ////////////////////////////////////////
  1849. //
  1850. // LogonAccount::OnHintSelect
  1851. //
  1852. // Put up the balloon message that contains the user's password hint.
  1853. //
  1854. /////////////////////////////////////////
  1855. void LogonAccount::OnHintSelect()
  1856. {
  1857. TCHAR szTitle[128];
  1858. DUIAssertNoMsg(_pbPwdInfo);
  1859. // get the position of the link so we can target the balloon tip correctly
  1860. POINT pt = {0,0};
  1861. CalcBalloonTargetLocation(g_plf->GetNativeHost()->GetHWND(), _pbPwdInfo, &pt);
  1862. LoadStringW(g_plf->GetHInstance(), IDS_PASSWORDHINTTITLE, szTitle, DUIARRAYSIZE(szTitle));
  1863. g_pErrorBalloon.ShowToolTip(GetModuleHandleW(NULL), g_plf->GetHWND(), &pt, _pvHint->GetString(), szTitle, TTI_INFO, EB_WARNINGCENTERED, 10000);
  1864. SetElementAccessability(_pePwdEdit, true, ROLE_SYSTEM_STATICTEXT, _pvHint->GetString());
  1865. _pePwdEdit->SetKeyFocus();
  1866. }
  1867. ////////////////////////////////////////
  1868. //
  1869. // LogonAccount::OnStatusSelect
  1870. //
  1871. // The user clicked one of the notification links (unread mail, running programs, etc).
  1872. // Dispatch that click to the right balloon tip display procs
  1873. //
  1874. /////////////////////////////////////////
  1875. void LogonAccount::OnStatusSelect(UINT nLine)
  1876. {
  1877. if (nLine == LASS_Email)
  1878. {
  1879. UnreadMailTip();
  1880. }
  1881. else if (nLine == LASS_LoggedOn)
  1882. {
  1883. AppRunningTip();
  1884. }
  1885. }
  1886. ////////////////////////////////////////
  1887. //
  1888. // LogonAccount::AppRunningTip
  1889. //
  1890. // The user activated the link that shows how many programs are running. Show the tip that
  1891. // basically says that running lots of programs can show the machine down
  1892. //
  1893. /////////////////////////////////////////
  1894. void LogonAccount::AppRunningTip()
  1895. {
  1896. TCHAR szTitle[256], szTemp[512];
  1897. Element* pe = FindDescendent(StrToID(L"username"));
  1898. DUIAssertNoMsg(pe);
  1899. Value* pv;
  1900. LPCWSTR pszDisplayName = pe->GetContentString(&pv);
  1901. if (!pszDisplayName)
  1902. pszDisplayName = L"";
  1903. if (_dwRunningApps == 0)
  1904. {
  1905. LoadStringW(g_plf->GetHInstance(), IDS_USERISLOGGEDON, szTemp, DUIARRAYSIZE(szTemp));
  1906. wsprintf(szTitle, szTemp, pszDisplayName, _dwRunningApps);
  1907. }
  1908. else
  1909. {
  1910. LoadStringW(g_plf->GetHInstance(), (_dwRunningApps == 1 ? IDS_USERRUNNINGPROGRAM : IDS_USERRUNNINGPROGRAMS), szTemp, DUIARRAYSIZE(szTemp));
  1911. wsprintf(szTitle, szTemp, pszDisplayName, _dwRunningApps);
  1912. }
  1913. pv->Release();
  1914. // get the position of the link so we can target the balloon tip correctly
  1915. POINT pt = {0,0};
  1916. CalcBalloonTargetLocation(g_plf->GetNativeHost()->GetHWND(), _pbStatus[LASS_LoggedOn], &pt);
  1917. LoadStringW(g_plf->GetHInstance(), (_dwRunningApps > 0 ? IDS_TOOMANYPROGRAMS : IDS_TOOMANYUSERS), szTemp, DUIARRAYSIZE(szTemp));
  1918. g_pErrorBalloon.ShowToolTip(GetModuleHandleW(NULL), g_plf->GetHWND(), &pt, szTemp, szTitle, TTI_INFO, EB_WARNINGCENTERED, 10000);
  1919. }
  1920. ////////////////////////////////////////
  1921. //
  1922. // LogonAccount::UnreadMailTip
  1923. //
  1924. // The user activated the link that shows how many unread email messages they have.
  1925. // Show the tip that says how many messages each of their email accounts has.
  1926. //
  1927. // TODO -- speed this up. its really slow now because each call to SHGina's
  1928. // ILogonUser::getMailAccountInfo load's the users' hive to get the next account from
  1929. // the registry.
  1930. //
  1931. /////////////////////////////////////////
  1932. void LogonAccount::UnreadMailTip()
  1933. {
  1934. TCHAR szTitle[128], szMsg[1024], szTemp[512], szRes[128];
  1935. HRESULT hr = E_FAIL;
  1936. ILogonUser *pobjUser = NULL;
  1937. szMsg[0] = TEXT('\0');
  1938. Element* pe = FindDescendent(StrToID(L"username"));
  1939. DUIAssertNoMsg(pe);
  1940. Value* pv;
  1941. LPCWSTR pszDisplayName = pe->GetContentString(&pv);
  1942. if (!pszDisplayName)
  1943. pszDisplayName = L"";
  1944. WCHAR *pszUsername = _pvUsername->GetString();
  1945. DWORD dwAccountsAdded = 0;
  1946. if (pszUsername)
  1947. {
  1948. if (SUCCEEDED(hr = GetLogonUserByLogonName(pszUsername, &pobjUser)) && pobjUser)
  1949. {
  1950. DWORD i, cMailAccounts;
  1951. cMailAccounts = 5;
  1952. for (i = 0; i < cMailAccounts; i++)
  1953. {
  1954. UINT cUnread;
  1955. VARIANT varAcctName = {0};
  1956. hr = pobjUser->getMailAccountInfo(i, &varAcctName, &cUnread);
  1957. if (FAILED(hr))
  1958. {
  1959. break;
  1960. }
  1961. if (varAcctName.bstrVal && cUnread > 0)
  1962. {
  1963. if (dwAccountsAdded > 0)
  1964. {
  1965. lstrcat(szMsg, TEXT("\r\n"));
  1966. }
  1967. dwAccountsAdded++;
  1968. LoadStringW(g_plf->GetHInstance(), IDS_UNREADMAILACCOUNT, szRes, DUIARRAYSIZE(szRes));
  1969. wsprintf(szTemp, szRes, varAcctName.bstrVal, cUnread);
  1970. lstrcat(szMsg, szTemp);
  1971. }
  1972. VariantClear(&varAcctName);
  1973. }
  1974. pobjUser->Release();
  1975. }
  1976. }
  1977. LoadStringW(g_plf->GetHInstance(), (_dwUnreadMail == 1 ? IDS_USERUNREADEMAIL : IDS_USERUNREADEMAILS), szTemp, DUIARRAYSIZE(szTemp));
  1978. wsprintf(szTitle, szTemp, pszDisplayName, _dwUnreadMail);
  1979. pv->Release();
  1980. // get the position of the link so we can target the balloon tip correctly
  1981. POINT pt = {0,0};
  1982. CalcBalloonTargetLocation(g_plf->GetNativeHost()->GetHWND(), _pbStatus[LASS_Email], &pt);
  1983. if (szMsg[0] == 0)
  1984. {
  1985. LoadStringW(g_plf->GetHInstance(), IDS_UNREADMAILTEMP, szMsg, DUIARRAYSIZE(szMsg));
  1986. }
  1987. g_pErrorBalloon.ShowToolTip(GetModuleHandleW(NULL), g_plf->GetHWND(), &pt, szMsg, szTitle, TTI_INFO, EB_WARNINGCENTERED, 10000);
  1988. }
  1989. ////////////////////////////////////////
  1990. //
  1991. // LogonAccount::UpdateNotifications
  1992. //
  1993. // Update the notification links for this user. Check to see if they are logged on and
  1994. // if so, find out how many applications they had open when they last switched away.
  1995. //
  1996. // Check the unread mail count for users who are logged on or for everyone if fCheckEverything is
  1997. // true. Checking unread mail counts is slow because it has to load the user's registry hive.
  1998. // Since no applications will update this value when the user is not logged on, there is no
  1999. // need to check this when they are not logged on. The exception to this is when we are first
  2000. // building the list since we need to always load it then, hence the fCheckEverything flag.
  2001. //
  2002. /////////////////////////////////////////
  2003. void LogonAccount::UpdateNotifications(BOOL fCheckEverything)
  2004. {
  2005. HRESULT hr = E_FAIL;
  2006. ILogonUser *pobjUser = NULL;
  2007. WCHAR szTemp[1024], sz[1024];
  2008. if (_fHasPwdPanel)
  2009. return;
  2010. WCHAR *pszUsername = _pvUsername->GetString();
  2011. if (pszUsername)
  2012. {
  2013. if (SUCCEEDED(hr = GetLogonUserByLogonName(pszUsername, &pobjUser)) && pobjUser)
  2014. {
  2015. VARIANT_BOOL vbLoggedOn;
  2016. VARIANT varUnreadMail;
  2017. BOOL fLoggedOn;
  2018. int iUnreadMailCount = 0;
  2019. DWORD dwProgramsRunning = 0;
  2020. if (FAILED(pobjUser->get_isLoggedOn(&vbLoggedOn)))
  2021. {
  2022. vbLoggedOn = VARIANT_FALSE;
  2023. }
  2024. fLoggedOn = (vbLoggedOn == VARIANT_TRUE);
  2025. if (fLoggedOn)
  2026. {
  2027. HKEY hKey;
  2028. CUserProfile userProfile(pszUsername, NULL);
  2029. if (ERROR_SUCCESS == RegOpenKeyEx(userProfile, TEXT("SessionInformation"), 0, KEY_QUERY_VALUE, &hKey))
  2030. {
  2031. DWORD dwProgramsRunningSize = sizeof(dwProgramsRunning);
  2032. RegQueryValueEx(hKey, TEXT("ProgramCount"), NULL, NULL, reinterpret_cast<LPBYTE>(&dwProgramsRunning), &dwProgramsRunningSize);
  2033. RegCloseKey(hKey);
  2034. }
  2035. }
  2036. SetRunningApps(dwProgramsRunning);
  2037. if (fLoggedOn)
  2038. {
  2039. InsertStatus(LASS_LoggedOn);
  2040. if (dwProgramsRunning != 0)
  2041. {
  2042. LoadStringW(g_plf->GetHInstance(), (dwProgramsRunning == 1 ? IDS_RUNNINGPROGRAM : IDS_RUNNINGPROGRAMS), szTemp, ARRAYSIZE(szTemp));
  2043. wsprintf(sz, szTemp, dwProgramsRunning);
  2044. SetStatus(LASS_LoggedOn, sz);
  2045. ShowStatus(LASS_LoggedOn);
  2046. }
  2047. else
  2048. {
  2049. LoadStringW(g_plf->GetHInstance(), IDS_USERLOGGEDON, szTemp, ARRAYSIZE(szTemp));
  2050. SetStatus(LASS_LoggedOn, szTemp);
  2051. }
  2052. }
  2053. else
  2054. {
  2055. // if they are not logged on, clean up the logged on text and remove any padding
  2056. RemoveStatus(LASS_LoggedOn);
  2057. }
  2058. if (fLoggedOn || fCheckEverything)
  2059. {
  2060. varUnreadMail.uintVal = 0;
  2061. if (FAILED(pobjUser->get_setting(L"UnreadMail", &varUnreadMail)))
  2062. {
  2063. varUnreadMail.uintVal = 0;
  2064. }
  2065. iUnreadMailCount = varUnreadMail.uintVal;
  2066. SetUnreadMail((DWORD)iUnreadMailCount);
  2067. if (iUnreadMailCount != 0)
  2068. {
  2069. InsertStatus(LASS_Email);
  2070. LoadStringW(g_plf->GetHInstance(), (iUnreadMailCount == 1 ? IDS_UNREADMAIL : IDS_UNREADMAILS), szTemp, ARRAYSIZE(szTemp));
  2071. wsprintf(sz, szTemp, iUnreadMailCount);
  2072. SetStatus(LASS_Email, sz);
  2073. ShowStatus(LASS_Email);
  2074. }
  2075. else
  2076. {
  2077. RemoveStatus(LASS_Email);
  2078. }
  2079. }
  2080. pobjUser->Release();
  2081. }
  2082. }
  2083. }
  2084. #ifdef GADGET_ENABLE_GDIPLUS
  2085. void
  2086. LogonAccount::ShowEdit()
  2087. {
  2088. HWND hwndEdit = _pePwdEdit->GetHWND();
  2089. HWND hwndHost = ::GetParent(hwndEdit);
  2090. SetWindowPos(hwndHost, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
  2091. EnableWindow(hwndEdit, TRUE);
  2092. SetFocus(hwndEdit);
  2093. }
  2094. void
  2095. LogonAccount::HideEdit()
  2096. {
  2097. HWND hwndEdit = _pePwdEdit->GetHWND();
  2098. HWND hwndHost = ::GetParent(hwndEdit);
  2099. EnableWindow(hwndEdit, FALSE);
  2100. SetWindowPos(hwndHost, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_HIDEWINDOW);
  2101. }
  2102. #endif // GADGET_ENABLE_GDIPLUS
  2103. ////////////////////////////////////////////////////////
  2104. // Property definitions
  2105. ////////////////////////////////////////////////////////
  2106. // ClassInfo (must appear after property definitions)
  2107. // LogonState property
  2108. static int vvLogonState[] = { DUIV_INT, -1 };
  2109. static PropertyInfo impLogonStateProp = { L"LogonState", PF_Normal, 0, vvLogonState, NULL, Value::pvIntZero /*LS_Pending*/ };
  2110. PropertyInfo* LogonAccount::LogonStateProp = &impLogonStateProp;
  2111. ////////////////////////////////////////////////////////
  2112. // ClassInfo (must appear after property definitions)
  2113. // Class properties
  2114. static PropertyInfo* _aPI[] = {
  2115. LogonAccount::LogonStateProp,
  2116. };
  2117. // Define class info with type and base type, set static class pointer
  2118. IClassInfo* LogonAccount::Class = NULL;
  2119. HRESULT LogonAccount::Register()
  2120. {
  2121. return ClassInfo<LogonAccount,Button>::Register(L"LogonAccount", _aPI, DUIARRAYSIZE(_aPI));
  2122. }
  2123. ////////////////////////////////////////////////////////
  2124. // Logon Parser
  2125. void CALLBACK LogonParseError(LPCWSTR pszError, LPCWSTR pszToken, int dLine)
  2126. {
  2127. WCHAR buf[201];
  2128. if (dLine != -1)
  2129. swprintf(buf, L"%s '%s' at line %d", pszError, pszToken, dLine);
  2130. else
  2131. swprintf(buf, L"%s '%s'", pszError, pszToken);
  2132. MessageBoxW(NULL, buf, L"Parser Message", MB_OK);
  2133. }
  2134. void DoFadeWindow(HWND hwnd)
  2135. {
  2136. HDC hdc;
  2137. int i;
  2138. RECT rcFrame;
  2139. COLORREF rgbFinal = RGB(90,126,220);
  2140. hdc = GetDC(hwnd);
  2141. GetClientRect(hwnd, &rcFrame);
  2142. COLORREF crCurr;
  2143. HBRUSH hbrFill;
  2144. crCurr = RGB(0,0,0);
  2145. // draw the left bar
  2146. for (i = 0; i < 16; i++)
  2147. {
  2148. RECT rcCurrFrame;
  2149. rcCurrFrame = rcFrame;
  2150. crCurr = RGB((GetRValue(rgbFinal) / 16)*i,
  2151. (GetGValue(rgbFinal) / 16)*i,
  2152. (GetBValue(rgbFinal) / 16)*i);
  2153. hbrFill = CreateSolidBrush(crCurr);
  2154. if (hbrFill)
  2155. {
  2156. FillRect(hdc, &rcCurrFrame, hbrFill);
  2157. DeleteObject(hbrFill);
  2158. }
  2159. GdiFlush();
  2160. }
  2161. ReleaseDC(hwnd, hdc);
  2162. }
  2163. ////////////////////////////////////////////////////////
  2164. // Logon entry point
  2165. int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow)
  2166. {
  2167. UNREFERENCED_PARAMETER(hPrevInstance);
  2168. UNREFERENCED_PARAMETER(pCmdLine);
  2169. UNREFERENCED_PARAMETER(nCmdShow);
  2170. WNDCLASSEX wcx = {0};
  2171. BOOL fStatusLaunch = false;
  2172. BOOL fShutdownLaunch = false;
  2173. BOOL fWait = false;
  2174. CBackgroundWindow backgroundWindow(hInst);
  2175. ZeroMemory(g_rgH, sizeof(g_rgH));
  2176. SetErrorHandler();
  2177. InitCommonControls();
  2178. // Register logon notification window
  2179. wcx.cbSize = sizeof(WNDCLASSEX);
  2180. wcx.lpfnWndProc = LogonWindowProc;
  2181. wcx.hInstance = GetModuleHandleW(NULL);
  2182. wcx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  2183. wcx.lpszClassName = TEXT("LogonWnd");
  2184. wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
  2185. RegisterClassEx(&wcx);
  2186. fStatusLaunch = (StrStrIA(pCmdLine, "/status") != NULL);
  2187. fShutdownLaunch = (StrStrIA(pCmdLine, "/shutdown") != NULL);
  2188. fWait = (StrStrIA(pCmdLine, "/wait") != NULL);
  2189. g_fNoAnimations = (StrStrIA(pCmdLine, "/noanim") != NULL);
  2190. // Create frame
  2191. Parser* pParser = NULL;
  2192. NativeHWNDHost* pnhh = NULL;
  2193. // DirectUI init process
  2194. if (FAILED(InitProcess()))
  2195. goto Failure;
  2196. // Register classes
  2197. if (FAILED(LogonFrame::Register()))
  2198. goto Failure;
  2199. if (FAILED(LogonAccountList::Register()))
  2200. goto Failure;
  2201. if (FAILED(LogonAccount::Register()))
  2202. goto Failure;
  2203. // DirectUI init thread
  2204. if (FAILED(InitThread()))
  2205. goto Failure;
  2206. if (FAILED(CoInitialize(NULL)))
  2207. goto Failure;
  2208. #ifdef GADGET_ENABLE_GDIPLUS
  2209. if (FAILED(FxInitGuts()))
  2210. goto Failure;
  2211. #endif
  2212. #ifndef DEBUG
  2213. if (!RunningUnderWinlogon())
  2214. goto Failure;
  2215. #endif
  2216. DisableAnimations();
  2217. // Create host
  2218. HMONITOR hMonitor;
  2219. POINT pt;
  2220. MONITORINFO monitorInfo;
  2221. // Determine initial size of the host. This is desired to be the entire
  2222. // primary monitor resolution because the host always runs on the secure
  2223. // desktop. If magnifier is brought up it will call SHAppBarMessage which
  2224. // will change the work area and we will respond to it appropriately from
  2225. // the listener in shgina that sends us HM_DISPLAYRESIZE messages.
  2226. pt.x = pt.y = 0;
  2227. hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
  2228. DUIAssert(hMonitor != NULL, "NULL HMONITOR returned from MonitorFromPoint");
  2229. monitorInfo.cbSize = sizeof(monitorInfo);
  2230. if (GetMonitorInfo(hMonitor, &monitorInfo) == FALSE)
  2231. {
  2232. SystemParametersInfo(SPI_GETWORKAREA, 0, &monitorInfo.rcMonitor, 0);
  2233. }
  2234. NativeHWNDHost::Create(L"Windows Logon", backgroundWindow.Create(), NULL, monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top,
  2235. monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top, 0, WS_POPUP, NHHO_IgnoreClose, &pnhh);
  2236. // NativeHWNDHost::Create(L"Windows Logon", NULL, NULL, monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top,
  2237. // 800, 600, 0, WS_POPUP, NHHO_IgnoreClose, &pnhh);
  2238. if (!pnhh)
  2239. goto Failure;
  2240. // Populate handle list for theme style parsing
  2241. g_rgH[0] = hInst; // Default HINSTANCE
  2242. g_rgH[SCROLLBARHTHEME] = OpenThemeData(pnhh->GetHWND(), L"Scrollbar");
  2243. // Frame creation
  2244. Parser::Create(IDR_LOGONUI, g_rgH, LogonParseError, &pParser);
  2245. if (!pParser)
  2246. goto Failure;
  2247. if (!pParser->WasParseError())
  2248. {
  2249. Element::StartDefer();
  2250. // Always double buffer
  2251. LogonFrame::Create(pnhh->GetHWND(), true, 0, (Element**)&g_plf);
  2252. if (!g_plf)
  2253. {
  2254. Element::EndDefer();
  2255. goto Failure;
  2256. }
  2257. g_plf->SetNativeHost(pnhh);
  2258. Element* pe;
  2259. pParser->CreateElement(L"main", g_plf, &pe);
  2260. if (pe) // Fill contents using substitution
  2261. {
  2262. // Frame tree is built
  2263. if (FAILED(g_plf->OnTreeReady(pParser)))
  2264. {
  2265. Element::EndDefer();
  2266. goto Failure;
  2267. }
  2268. if (fShutdownLaunch || fWait)
  2269. {
  2270. g_plf->SetTitle(IDS_PLEASEWAIT);
  2271. }
  2272. if (!fStatusLaunch)
  2273. {
  2274. // Build contents of account list
  2275. g_plf->EnterLogonMode(false);
  2276. }
  2277. else
  2278. {
  2279. g_plf->EnterPreStatusMode(false);
  2280. }
  2281. // Host
  2282. pnhh->Host(g_plf);
  2283. g_plf->SetButtonLabels();
  2284. Element *peLogoArea = g_plf->FindDescendent(StrToID(L"product"));
  2285. if (!g_fNoAnimations)
  2286. {
  2287. pnhh->ShowWindow();
  2288. DoFadeWindow(pnhh->GetHWND());
  2289. if (peLogoArea)
  2290. {
  2291. peLogoArea->SetAlpha(0);
  2292. }
  2293. }
  2294. // Set visible and focus
  2295. g_plf->SetVisible(true);
  2296. g_plf->SetKeyFocus();
  2297. Element::EndDefer();
  2298. // Do initial show
  2299. pnhh->ShowWindow();
  2300. if (!g_fNoAnimations)
  2301. {
  2302. EnableAnimations();
  2303. }
  2304. if (peLogoArea)
  2305. {
  2306. peLogoArea->SetAlpha(255);
  2307. }
  2308. StartMessagePump();
  2309. // psf will be deleted by native HWND host when destroyed
  2310. }
  2311. else
  2312. Element::EndDefer();
  2313. }
  2314. Failure:
  2315. if (pnhh)
  2316. pnhh->Destroy();
  2317. if (pParser)
  2318. pParser->Destroy();
  2319. ReleaseStatusHost();
  2320. FreeLayoutInfo(LAYOUT_DEF_USER);
  2321. if (g_rgH[SCROLLBARHTHEME]) // Scrollbar
  2322. {
  2323. CloseThemeData(g_rgH[SCROLLBARHTHEME]);
  2324. }
  2325. CoUninitialize();
  2326. UnInitThread();
  2327. UnInitProcess();
  2328. // Free cached atom list
  2329. if (LogonAccount::idPwdGo)
  2330. DeleteAtom(LogonAccount::idPwdGo);
  2331. if (LogonAccount::idPwdInfo)
  2332. DeleteAtom(LogonAccount::idPwdInfo);
  2333. EndHostProcess(0);
  2334. return 0;
  2335. }
  2336. void LogonAccount::SetKeyboardIcon(HICON hIcon)
  2337. {
  2338. HICON hIconCopy = NULL;
  2339. if (hIcon)
  2340. {
  2341. hIconCopy = CopyIcon(hIcon);
  2342. }
  2343. if (_peKbdIcon && hIconCopy)
  2344. {
  2345. Value* pvIcon = Value::CreateGraphic(hIconCopy);
  2346. _peKbdIcon->SetValue(Element::ContentProp, PI_Local, pvIcon); // Element takes owners
  2347. _peKbdIcon->SetPadding(0, 5, 0, 7);
  2348. pvIcon->Release();
  2349. }
  2350. }