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.

2826 lines
74 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, BOOL fLoggedOn, OUT LogonAccount **ppla)
  674. {
  675. HRESULT hr;
  676. LogonAccount* pla = NULL;
  677. if (!_pParser)
  678. {
  679. hr = E_FAIL;
  680. goto Failure;
  681. }
  682. // Build up an account and insert into selection list
  683. hr = _pParser->CreateElement(L"accountitem", NULL, (Element**)&pla);
  684. if (FAILED(hr))
  685. goto Failure;
  686. hr = pla->OnTreeReady(pszPicture, fPicRes, pszName, pszUsername, pszHint, fLoggedOn, GetHInstance());
  687. if (FAILED(hr))
  688. goto Failure;
  689. hr = _peAccountList->Add(pla);
  690. if (FAILED(hr))
  691. goto Failure;
  692. if (pla)
  693. {
  694. SetElementAccessability(pla, true, ROLE_SYSTEM_LISTITEM, pszUsername);
  695. }
  696. if (_nColorDepth <= 8)
  697. {
  698. pla->SetBackgroundColor(ORGB (96,128,255));
  699. Element *pEle;
  700. pEle = pla->FindDescendent(StrToID(L"userpane"));
  701. if (pEle)
  702. {
  703. pEle->SetBorderColor(ORGB (96,128,255));
  704. }
  705. }
  706. if (ppla)
  707. *ppla = pla;
  708. return S_OK;
  709. Failure:
  710. return hr;
  711. }
  712. // Passed authentication, log user on
  713. HRESULT LogonFrame::OnLogUserOn(LogonAccount* pla)
  714. {
  715. StartDefer();
  716. #ifdef GADGET_ENABLE_GDIPLUS
  717. // Disable status so that it can't be clicked on anymore
  718. pla->DisableStatus(0);
  719. pla->DisableStatus(1);
  720. // Clear list of logon accounts except the one logging on
  721. Value* pvChildren;
  722. ElementList* peList = _peAccountList->GetChildren(&pvChildren);
  723. if (peList)
  724. {
  725. LogonAccount* peAccount;
  726. for (UINT i = 0; i < peList->GetSize(); i++)
  727. {
  728. peAccount = (LogonAccount*)peList->GetItem(i);
  729. if (peAccount != pla)
  730. {
  731. peAccount->SetLogonState(LS_Denied);
  732. }
  733. else
  734. {
  735. peAccount->SetLogonState(LS_Granted);
  736. peAccount->InsertStatus(0);
  737. peAccount->RemoveStatus(1);
  738. }
  739. // Account account items are disabled
  740. peAccount->SetEnabled(false);
  741. }
  742. }
  743. pvChildren->Release();
  744. FxLogUserOn(pla);
  745. // Set frame status
  746. SetStatus(LoadResString(IDS_LOGGINGON));
  747. #else
  748. // Set keyfocus back to frame so it isn't pushed anywhere when controls are removed.
  749. // This will also cause a remove of the password panel from the current account
  750. SetKeyFocus();
  751. // Disable status so that it can't be clicked on anymore
  752. pla->DisableStatus(0);
  753. pla->DisableStatus(1);
  754. // Clear list of logon accounts except the one logging on
  755. Value* pvChildren;
  756. ElementList* peList = _peAccountList->GetChildren(&pvChildren);
  757. if (peList)
  758. {
  759. LogonAccount* peAccount;
  760. for (UINT i = 0; i < peList->GetSize(); i++)
  761. {
  762. peAccount = (LogonAccount*)peList->GetItem(i);
  763. if (peAccount != pla)
  764. {
  765. peAccount->SetLayoutPos(LP_None);
  766. peAccount->SetLogonState(LS_Denied);
  767. }
  768. else
  769. {
  770. peAccount->SetLogonState(LS_Granted);
  771. peAccount->InsertStatus(0);
  772. peAccount->RemoveStatus(1);
  773. }
  774. // Account account items are disabled
  775. peAccount->SetEnabled(false);
  776. }
  777. }
  778. pvChildren->Release();
  779. // Hide option buttons
  780. HidePowerButton();
  781. HideUndockButton();
  782. // Set frame status
  783. SetStatus(LoadResString(IDS_LOGGINGON));
  784. _peViewer->RemoveListener(this);
  785. _peAccountList->RemoveListener(this);
  786. #endif
  787. EndDefer();
  788. return S_OK;
  789. }
  790. HRESULT LogonFrame::OnPower()
  791. {
  792. DUITrace("LogonUI: LogonFrame::OnPower()\n");
  793. TurnOffComputer();
  794. return S_OK;
  795. }
  796. HRESULT LogonFrame::OnUndock()
  797. {
  798. DUITrace("LogonUI: LogonFrame::OnUndock()\n");
  799. UndockComputer();
  800. return S_OK;
  801. }
  802. ////////////////////////////////////////
  803. //
  804. // LogonFrame::SetButtonLabels
  805. //
  806. // If there is a friendly name of the computer stored in the computer name description,
  807. // grab it and change the "Turn off" and "Undock" options to include the compute rname
  808. //
  809. // RETURNS
  810. // nothing
  811. //
  812. /////////////////////////////////////////
  813. void LogonFrame::SetButtonLabels()
  814. {
  815. WCHAR szComputerName[MAX_COMPUTERDESC_LENGTH + 1] = {0};
  816. DWORD cchComputerName = MAX_COMPUTERDESC_LENGTH + 1;
  817. if ( _pbPower && SUCCEEDED(SHGetComputerDisplayName(NULL, SGCDNF_DESCRIPTIONONLY, szComputerName, cchComputerName)))
  818. {
  819. WCHAR szCommand[MAX_COMPUTERDESC_LENGTH + 50], szRes[50];
  820. LoadStringW(g_plf->GetHInstance(), IDS_POWERNAME, szRes, DUIARRAYSIZE(szRes));
  821. wsprintf(szCommand, szRes, szComputerName);
  822. SetPowerButtonLabel(szCommand);
  823. LoadStringW(g_plf->GetHInstance(), IDS_UNDOCKNAME, szRes, DUIARRAYSIZE(szRes));
  824. wsprintf(szCommand, szRes, szComputerName);
  825. SetUndockButtonLabel(szCommand);
  826. }
  827. }
  828. ////////////////////////////////////////////////////////
  829. // Logon Application State Transitions
  830. ////////////////////////////////////////
  831. //
  832. // LogonFrame::EnterPreStatusMode
  833. //
  834. // SHGina has sent a message telling logonui to enter the pre-status
  835. // mode or we are starting up in status mode. Hide items that should
  836. // not be displayed when in this state (power off, account list, user
  837. // instructions, etc).
  838. //
  839. // RETURNS
  840. // nothing
  841. //
  842. /////////////////////////////////////////
  843. void LogonFrame::EnterPreStatusMode(BOOL fLock)
  844. {
  845. // If currently locked, ignore call
  846. if (IsPreStatusLock())
  847. {
  848. DUIAssert(!fLock, "Receiving a lock while already within pre-Status lock");
  849. return;
  850. }
  851. if (fLock)
  852. {
  853. LogonAccount *pAccount;
  854. // Entering pre-Status mode with "lock", cannot exit to logon state without an unlock
  855. _fPreStatusLock = TRUE;
  856. pAccount = static_cast<LogonAccount*>(_peAccountList->GetSelection());
  857. if (pAccount != NULL)
  858. {
  859. lstrcpynW(szLastSelectedName, pAccount->GetUsername(), ARRAYSIZE(szLastSelectedName));
  860. }
  861. }
  862. if (GetState() == LAS_Hide)
  863. {
  864. _pnhh->ShowWindow();
  865. SetWindowPos(_pnhh->GetHWND(), NULL, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SWP_NOMOVE | SWP_NOZORDER );
  866. }
  867. StartDefer();
  868. SetKeyFocus(); // Removes selection
  869. HidePowerButton();
  870. HideUndockButton();
  871. ShowLogoArea();
  872. HideWelcomeArea();
  873. HideAccountPanel();
  874. Element *pe;
  875. pe = FindDescendent(StrToID(L"instruct"));
  876. DUIAssertNoMsg(pe);
  877. pe->SetVisible(FALSE);
  878. SetStatus(LoadResString(IDS_WINDOWSNAME));
  879. EndDefer();
  880. // Set state
  881. SetState(LAS_PreStatus);
  882. }
  883. ////////////////////////////////////////
  884. //
  885. // LogonFrame::EnterLogonMode
  886. //
  887. // SHGina has sent a message telling logonui to enter the logon mode.
  888. // this means to build and display the user list. If we are re-entering
  889. // logon mode from another mode, the user list will already exist and we
  890. // should just set everything back to the pending state.
  891. //
  892. // EnterLogonMode also sets up the undock and power off buttons based on
  893. // whether those options are allowed.
  894. //
  895. //
  896. // RETURNS
  897. // nothing
  898. //
  899. /////////////////////////////////////////
  900. void LogonFrame::EnterLogonMode(BOOL fUnLock)
  901. {
  902. // If currently locked, ignore call if not to unlock
  903. if (IsPreStatusLock())
  904. {
  905. if (fUnLock)
  906. {
  907. // Exiting pre-Status mode lock
  908. _fPreStatusLock = FALSE;
  909. }
  910. else
  911. return;
  912. }
  913. else
  914. {
  915. DUIAssert(!fUnLock, "Receiving an unlock while not within pre-Status lock");
  916. }
  917. DUIAssert(GetState() != LAS_Hide, "Cannot enter logon state from hidden state");
  918. ResetTheme();
  919. Element* pe;
  920. LogonAccount* plaAutoSelect = NULL;
  921. StartDefer();
  922. PokeComCtl32();
  923. // Retrieve data from backend if not populated
  924. if (UserListAvailable())
  925. {
  926. ResetUserList();
  927. }
  928. else
  929. {
  930. // Cache password field atoms for quicker identification (static)
  931. LogonAccount::idPwdGo = AddAtomW(L"go");
  932. LogonAccount::idPwdInfo = AddAtomW(L"info");
  933. // Create password panel
  934. Element* pePwdPanel;
  935. _pParser->CreateElement(L"passwordpanel", NULL, &pePwdPanel);
  936. DUIAssert(pePwdPanel, "Can't create password panel");
  937. // Cache password panel edit control
  938. Edit* pePwdEdit = (Edit*)pePwdPanel->FindDescendent(StrToID(L"password"));
  939. DUIAssert(pePwdPanel, "Can't create password edit control");
  940. // Cache password panel info button
  941. Button* pbPwdInfo = (Button*)pePwdPanel->FindDescendent(StrToID(L"info"));
  942. DUIAssert(pePwdPanel, "Can't create password info button");
  943. // Cache password panel keyboard element
  944. Element* peKbdIcon = (Button*)pePwdPanel->FindDescendent(StrToID(L"keyboard"));
  945. DUIAssert(pePwdPanel, "Can't create password keyboard icon");
  946. LogonAccount::InitPasswordPanel(pePwdPanel, pePwdEdit, pbPwdInfo, peKbdIcon );
  947. }
  948. BuildAccountList(this, &plaAutoSelect);
  949. if (szLastSelectedName[0] != L'\0')
  950. {
  951. LogonAccount *pAccount;
  952. pAccount = InternalFindNamedUser(szLastSelectedName);
  953. if (pAccount != NULL)
  954. {
  955. plaAutoSelect = pAccount;
  956. }
  957. szLastSelectedName[0] = L'\0';
  958. }
  959. if (IsShutdownAllowed())
  960. {
  961. ShowPowerButton();
  962. }
  963. else
  964. {
  965. HidePowerButton();
  966. }
  967. if (IsUndockAllowed())
  968. {
  969. ShowUndockButton();
  970. }
  971. else
  972. {
  973. HideUndockButton();
  974. }
  975. pe = FindDescendent(StrToID(L"instruct"));
  976. DUIAssertNoMsg(pe);
  977. pe->SetVisible(TRUE);
  978. pe = FindDescendent(StrToID(L"product"));
  979. DUIAssertNoMsg(pe);
  980. pe->StopAnimation(ANI_AlphaType);
  981. pe->RemoveLocalValue(BackgroundProp);
  982. // Account list viewer
  983. ShowAccountPanel();
  984. SetTitle(IDS_WELCOME);
  985. SetStatus(LoadResString(IDS_BEGIN));
  986. if (!plaAutoSelect)
  987. {
  988. SetKeyFocus();
  989. }
  990. EndDefer();
  991. // Set state
  992. SetState(LAS_Logon);
  993. // Set auto-select item, if exists
  994. if (plaAutoSelect)
  995. {
  996. plaAutoSelect->SetKeyFocus();
  997. _peAccountList->SetSelection(plaAutoSelect);
  998. }
  999. SetButtonLabels();
  1000. SetForegroundWindow(_pnhh->GetHWND());
  1001. }
  1002. ////////////////////////////////////////
  1003. //
  1004. // LogonFrame::EnterPostStatusMode
  1005. //
  1006. // SHGina has sent a message telling logonui that the authentication has succeeded
  1007. // and we should now go into the post status mode. LogonFrame::OnLogUserOn has already
  1008. // started the animations for this.
  1009. //
  1010. // RETURNS
  1011. // nothing
  1012. //
  1013. /////////////////////////////////////////
  1014. void LogonFrame::EnterPostStatusMode()
  1015. {
  1016. // Set state
  1017. SetState(LAS_PostStatus);
  1018. Element *pe;
  1019. pe = FindDescendent(StrToID(L"instruct"));
  1020. DUIAssertNoMsg(pe);
  1021. pe->SetVisible(FALSE);
  1022. //animation was started in OnLogUserOn
  1023. ShowWelcomeArea();
  1024. HideLogoArea();
  1025. }
  1026. ////////////////////////////////////////
  1027. //
  1028. // LogonFrame::EnterHideMode
  1029. //
  1030. // SHGina has sent a message telling logonui to hide.
  1031. //
  1032. // RETURNS
  1033. // nothing
  1034. //
  1035. /////////////////////////////////////////
  1036. void LogonFrame::EnterHideMode()
  1037. {
  1038. // Set state
  1039. SetState(LAS_Hide);
  1040. if (_pnhh)
  1041. {
  1042. _pnhh->HideWindow();
  1043. }
  1044. }
  1045. ////////////////////////////////////////
  1046. //
  1047. // LogonFrame::EnterDoneMode
  1048. //
  1049. // SHGina has sent a message telling logonui to exit.
  1050. //
  1051. // RETURNS
  1052. // nothing
  1053. //
  1054. /////////////////////////////////////////
  1055. void LogonFrame::EnterDoneMode()
  1056. {
  1057. // Set state
  1058. SetState(LAS_Done);
  1059. if (_pnhh)
  1060. {
  1061. _pnhh->DestroyWindow();
  1062. }
  1063. }
  1064. ////////////////////////////////////////
  1065. //
  1066. // LogonFrame::ResetUserList
  1067. //
  1068. // Delete all of the users in the user list so that it can be rebuilt
  1069. //
  1070. // RETURNS
  1071. // nothing
  1072. //
  1073. /////////////////////////////////////////
  1074. void LogonFrame::ResetUserList()
  1075. {
  1076. if (UserListAvailable())
  1077. {
  1078. // reset the candidate to NULL
  1079. LogonAccount::ClearCandidate();
  1080. // remove of the password panel from the current account (if any)
  1081. SetKeyFocus();
  1082. //fix up the existing list to get us back into logon mode
  1083. Value* pvChildren;
  1084. ElementList* peList = _peAccountList->GetChildren(&pvChildren);
  1085. if (peList)
  1086. {
  1087. LogonAccount* peAccount;
  1088. for (int i = peList->GetSize() - 1; i >= 0; i--)
  1089. {
  1090. peAccount = (LogonAccount*)peList->GetItem(i);
  1091. peAccount->Destroy();
  1092. }
  1093. }
  1094. pvChildren->Release();
  1095. }
  1096. }
  1097. ////////////////////////////////////////
  1098. //
  1099. // LogonFrame::InteractiveLogonRequest
  1100. //
  1101. // SHGina has sent an InteractiveLogonRequest. We should look for the user
  1102. // that was passed in and if found, try to log them in.
  1103. //
  1104. // RETURNS
  1105. // LRESULT indicating success or failure of finding htem and logging them in.
  1106. //
  1107. /////////////////////////////////////////
  1108. LRESULT LogonFrame::InteractiveLogonRequest(LPCWSTR pszUsername, LPCWSTR pszPassword)
  1109. {
  1110. LRESULT lResult = 0;
  1111. LogonAccount *pla;
  1112. pla = FindNamedUser(pszUsername);
  1113. if (pla)
  1114. {
  1115. if (pla->OnAuthenticateUser(pszPassword))
  1116. {
  1117. lResult = ERROR_SUCCESS;
  1118. }
  1119. else
  1120. {
  1121. lResult = ERROR_ACCESS_DENIED;
  1122. }
  1123. }
  1124. return(lResult);
  1125. }
  1126. ////////////////////////////////////////
  1127. //
  1128. // LogonFrame::InternalFindNamedUser
  1129. //
  1130. // Find a user in the LogonAccount list with the
  1131. // provided username (logon name).
  1132. //
  1133. // RETURNS
  1134. // The LogonAccount* for the indicated user or NULL if
  1135. // not found
  1136. //
  1137. /////////////////////////////////////////
  1138. LogonAccount* LogonFrame::InternalFindNamedUser(LPCWSTR pszUsername)
  1139. {
  1140. LogonAccount *plaResult = NULL;
  1141. Value* pvChildren;
  1142. ElementList* peList = _peAccountList->GetChildren(&pvChildren);
  1143. if (peList)
  1144. {
  1145. for (UINT i = 0; i < peList->GetSize(); i++)
  1146. {
  1147. DUIAssert(peList->GetItem(i)->GetClassInfo() == LogonAccount::Class, "Account list must contain LogonAccount objects");
  1148. LogonAccount* pla = (LogonAccount*)peList->GetItem(i);
  1149. if (pla)
  1150. {
  1151. if (lstrcmpi(pla->GetUsername(), pszUsername) == 0)
  1152. {
  1153. plaResult = pla;
  1154. break;
  1155. }
  1156. }
  1157. }
  1158. }
  1159. pvChildren->Release();
  1160. return plaResult;
  1161. }
  1162. ////////////////////////////////////////
  1163. //
  1164. // LogonFrame::FindNamedUser
  1165. //
  1166. // Find a user in the LogonAccount list with the
  1167. // provided username (logon name).
  1168. //
  1169. // RETURNS
  1170. // The LogonAccount* for the indicated user or NULL if
  1171. // not found
  1172. //
  1173. /////////////////////////////////////////
  1174. LogonAccount *LogonFrame::FindNamedUser(LPCWSTR pszUsername)
  1175. {
  1176. // Early out if: no user list available
  1177. // not in logon mode (showing user list)
  1178. if (!UserListAvailable() || (GetState() != LAS_Logon))
  1179. {
  1180. return NULL;
  1181. }
  1182. else
  1183. {
  1184. return(InternalFindNamedUser(pszUsername));
  1185. }
  1186. }
  1187. ////////////////////////////////////////
  1188. //
  1189. // LogonFrame::UpdateUserStatus
  1190. //
  1191. // Iterate the list of user accounts and call LogonAccount::UpdateNotifications
  1192. // for each one. This will result in them updating the unread mail count and
  1193. // logon status for each of the logon accounts.
  1194. // Pass fRefreshAll through to UpdateApplications
  1195. //
  1196. /////////////////////////////////////////
  1197. void LogonFrame::UpdateUserStatus(BOOL fRefreshAll)
  1198. {
  1199. Value* pvChildren;
  1200. static fUpdating = false;
  1201. // Early out if: no user list available
  1202. // not in logon mode (showing user list)
  1203. if (!UserListAvailable() || (GetState() != LAS_Logon) || fUpdating)
  1204. return;
  1205. fUpdating = true;
  1206. StartDefer();
  1207. ElementList* peList = _peAccountList->GetChildren(&pvChildren);
  1208. if (peList)
  1209. {
  1210. for (UINT i = 0; i < peList->GetSize(); i++)
  1211. {
  1212. DUIAssert(peList->GetItem(i)->GetClassInfo() == LogonAccount::Class, "Account list must contain LogonAccount objects");
  1213. LogonAccount* pla = (LogonAccount*)peList->GetItem(i);
  1214. if (pla)
  1215. {
  1216. pla->UpdateNotifications(fRefreshAll);
  1217. }
  1218. }
  1219. }
  1220. if (IsUndockAllowed())
  1221. {
  1222. ShowUndockButton();
  1223. }
  1224. else
  1225. {
  1226. HideUndockButton();
  1227. }
  1228. pvChildren->Release();
  1229. EndDefer();
  1230. fUpdating = false;
  1231. }
  1232. ////////////////////////////////////////
  1233. //
  1234. // LogonFrame::SelectUser
  1235. //
  1236. //
  1237. //
  1238. /////////////////////////////////////////
  1239. void LogonFrame::SelectUser(LPCWSTR pszUsername)
  1240. {
  1241. LogonAccount *pla;
  1242. pla = FindNamedUser(pszUsername);
  1243. if (pla != NULL)
  1244. {
  1245. pla->OnAuthenticatedUser();
  1246. }
  1247. else
  1248. {
  1249. LogonAccount::ClearCandidate();
  1250. EnterPostStatusMode();
  1251. HidePowerButton();
  1252. HideUndockButton();
  1253. HideAccountPanel();
  1254. }
  1255. }
  1256. ////////////////////////////////////////
  1257. //
  1258. // LogonFrame::Resize
  1259. //
  1260. //
  1261. //
  1262. /////////////////////////////////////////
  1263. void LogonFrame::Resize()
  1264. {
  1265. RECT rc;
  1266. SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
  1267. SetWindowPos(_pnhh->GetHWND(),
  1268. NULL,
  1269. rc.left,
  1270. rc.top,
  1271. rc.right - rc.left,
  1272. rc.bottom - rc.top,
  1273. SWP_NOACTIVATE | SWP_NOZORDER);
  1274. }
  1275. ////////////////////////////////////////
  1276. //
  1277. // LogonFrame::SetAnimations
  1278. //
  1279. //
  1280. //
  1281. /////////////////////////////////////////
  1282. void LogonFrame::SetAnimations(BOOL fAnimations)
  1283. {
  1284. g_fNoAnimations = !fAnimations;
  1285. if (fAnimations)
  1286. {
  1287. EnableAnimations();
  1288. }
  1289. else
  1290. {
  1291. DisableAnimations();
  1292. }
  1293. }
  1294. ////////////////////////////////////////////////////////
  1295. // Property definitions
  1296. ////////////////////////////////////////////////////////
  1297. // ClassInfo (must appear after property definitions)
  1298. // Define class info with type and base type, set static class pointer
  1299. IClassInfo* LogonFrame::Class = NULL;
  1300. HRESULT LogonFrame::Register()
  1301. {
  1302. return ClassInfo<LogonFrame,HWNDElement>::Register(L"LogonFrame", NULL, 0);
  1303. }
  1304. ////////////////////////////////////////////////////////
  1305. //
  1306. HRESULT LogonAccountList::Create(OUT Element** ppElement)
  1307. {
  1308. *ppElement = NULL;
  1309. LogonAccountList* plal = HNew<LogonAccountList>();
  1310. if (!plal)
  1311. return E_OUTOFMEMORY;
  1312. HRESULT hr = plal->Initialize();
  1313. if (FAILED(hr))
  1314. {
  1315. plal->Destroy();
  1316. return hr;
  1317. }
  1318. *ppElement = plal;
  1319. return S_OK;
  1320. }
  1321. void LogonAccountList::OnPropertyChanged(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew)
  1322. {
  1323. #ifdef GADGET_ENABLE_GDIPLUS
  1324. if (IsProp(MouseWithin))
  1325. {
  1326. if (pvNew->GetBool())
  1327. FxMouseWithin(fdIn);
  1328. else
  1329. FxMouseWithin(fdOut);
  1330. }
  1331. #endif // GADGET_ENABLE_GDIPLUS
  1332. Selector::OnPropertyChanged(ppi, iIndex, pvOld, pvNew);
  1333. }
  1334. ////////////////////////////////////////////////////////
  1335. // Property definitions
  1336. ////////////////////////////////////////////////////////
  1337. // ClassInfo (must appear after property definitions)
  1338. // Define class info with type and base type, set static class pointer
  1339. IClassInfo* LogonAccountList::Class = NULL;
  1340. HRESULT LogonAccountList::Register()
  1341. {
  1342. return ClassInfo<LogonAccountList,Selector>::Register(L"LogonAccountList", NULL, 0);
  1343. }
  1344. ////////////////////////////////////////////////////////
  1345. //
  1346. // LogonAccount
  1347. //
  1348. ////////////////////////////////////////////////////////
  1349. ATOM LogonAccount::idPwdGo = NULL;
  1350. ATOM LogonAccount::idPwdInfo = NULL;
  1351. Element* LogonAccount::_pePwdPanel = NULL;
  1352. Edit* LogonAccount::_pePwdEdit = NULL;
  1353. Button* LogonAccount::_pbPwdInfo = NULL;
  1354. Element* LogonAccount::_peKbdIcon = NULL;
  1355. LogonAccount* LogonAccount::_peCandidate = NULL;
  1356. HRESULT LogonAccount::Create(OUT Element** ppElement)
  1357. {
  1358. *ppElement = NULL;
  1359. LogonAccount* pla = HNew<LogonAccount>();
  1360. if (!pla)
  1361. return E_OUTOFMEMORY;
  1362. HRESULT hr = pla->Initialize();
  1363. if (FAILED(hr))
  1364. {
  1365. pla->Destroy();
  1366. return hr;
  1367. }
  1368. *ppElement = pla;
  1369. return S_OK;
  1370. }
  1371. HRESULT LogonAccount::Initialize()
  1372. {
  1373. // Zero-init members
  1374. _pbStatus[0] = NULL;
  1375. _pbStatus[1] = NULL;
  1376. _pvUsername = NULL;
  1377. _pvHint = NULL;
  1378. _fPwdNeeded = (BOOL)-1; // uninitialized
  1379. _fLoggedOn = FALSE;
  1380. _fHasPwdPanel = FALSE;
  1381. // Do base class initialization
  1382. HRESULT hr = Button::Initialize(AE_MouseAndKeyboard);
  1383. if (FAILED(hr))
  1384. goto Failure;
  1385. // Initialize
  1386. // TODO: Additional LogonAccount initialization code here
  1387. return S_OK;
  1388. Failure:
  1389. return hr;
  1390. }
  1391. LogonAccount::~LogonAccount()
  1392. {
  1393. // Free resources
  1394. if (_pvUsername)
  1395. {
  1396. _pvUsername->Release();
  1397. _pvUsername = NULL;
  1398. }
  1399. if (_pvHint)
  1400. {
  1401. _pvHint->Release();
  1402. _pvHint = NULL;
  1403. }
  1404. // TODO: Account destruction cleanup
  1405. }
  1406. void LogonAccount::SetStatus(UINT nLine, LPCWSTR psz)
  1407. {
  1408. if (psz)
  1409. {
  1410. _pbStatus[nLine]->SetContentString(psz);
  1411. SetElementAccessability(_pbStatus[nLine], true, ROLE_SYSTEM_LINK, psz);
  1412. }
  1413. }
  1414. // Tree is ready
  1415. HRESULT LogonAccount::OnTreeReady(LPCWSTR pszPicture, BOOL fPicRes, LPCWSTR pszName, LPCWSTR pszUsername, LPCWSTR pszHint, BOOL fLoggedOn, HINSTANCE hInst)
  1416. {
  1417. HRESULT hr;
  1418. Element* pePicture = NULL;
  1419. Element* peName = NULL;
  1420. Value* pv = NULL;
  1421. StartDefer();
  1422. // Cache important descendents
  1423. _pbStatus[0] = (Button*)FindDescendent(StrToID(L"status0"));
  1424. DUIAssert(_pbStatus[0], "Cannot find account list, check the UI file");
  1425. if (_pbStatus[0] == NULL)
  1426. {
  1427. hr = E_OUTOFMEMORY;
  1428. goto Failure;
  1429. }
  1430. _pbStatus[1] = (Button*)FindDescendent(StrToID(L"status1"));
  1431. DUIAssert(_pbStatus[1], "Cannot find account list, check the UI file");
  1432. if (_pbStatus[1] == NULL)
  1433. {
  1434. hr = E_OUTOFMEMORY;
  1435. goto Failure;
  1436. }
  1437. // Locate descendents and populate
  1438. pePicture = FindDescendent(StrToID(L"picture"));
  1439. DUIAssert(pePicture, "Cannot find account list, check the UI file");
  1440. if (pePicture == NULL)
  1441. {
  1442. hr = E_OUTOFMEMORY;
  1443. goto Failure;
  1444. }
  1445. // CreateGraphic handles NULL bitmaps
  1446. pv = Value::CreateGraphic(pszPicture, GRAPHIC_NoBlend, 0, 0, 0, (fPicRes) ? hInst : 0);
  1447. if (pv)
  1448. {
  1449. // Our preferred size is 1/2 inch (36pt) square.
  1450. USHORT cx = (USHORT)LogonFrame::PointToPixel(36);
  1451. USHORT cy = cx;
  1452. Graphic* pg = pv->GetGraphic();
  1453. // If it's not square, scale the smaller dimension
  1454. // to maintain the aspect ratio.
  1455. if (pg->cx > pg->cy)
  1456. {
  1457. cy = (USHORT)MulDiv(cx, pg->cy, pg->cx);
  1458. }
  1459. else if (pg->cy > pg->cx)
  1460. {
  1461. cx = (USHORT)MulDiv(cy, pg->cx, pg->cy);
  1462. }
  1463. // Did anything change?
  1464. if (cx != pg->cx || cy != pg->cy)
  1465. {
  1466. // Reload the graphic
  1467. pv->Release();
  1468. pv = Value::CreateGraphic(pszPicture, GRAPHIC_NoBlend, 0, cx, cy, (fPicRes) ? hInst : 0);
  1469. }
  1470. }
  1471. if (!pv)
  1472. {
  1473. // if we can't get the picture, use a default one
  1474. pv = Value::CreateGraphic(MAKEINTRESOURCEW(IDB_USER0), GRAPHIC_NoBlend, 0, (USHORT)LogonFrame::PointToPixel(36), (USHORT)LogonFrame::PointToPixel(36), hInst);
  1475. if (!pv)
  1476. {
  1477. hr = E_OUTOFMEMORY;
  1478. goto Failure;
  1479. }
  1480. }
  1481. hr = pePicture->SetValue(Element::ContentProp, PI_Local, pv);
  1482. if (FAILED(hr))
  1483. goto Failure;
  1484. pv->Release();
  1485. pv = NULL;
  1486. // Name
  1487. peName = FindDescendent(StrToID(L"username"));
  1488. DUIAssert(peName, "Cannot find account list, check the UI file");
  1489. if (peName == NULL)
  1490. {
  1491. hr = E_OUTOFMEMORY;
  1492. goto Failure;
  1493. }
  1494. hr = peName->SetContentString(pszName);
  1495. if (FAILED(hr))
  1496. goto Failure;
  1497. // Store members, will be released in destructor
  1498. if (pszUsername)
  1499. {
  1500. _pvUsername = Value::CreateString(pszUsername);
  1501. if (!_pvUsername)
  1502. {
  1503. hr = E_OUTOFMEMORY;
  1504. goto Failure;
  1505. }
  1506. }
  1507. if (pszHint)
  1508. {
  1509. _pvHint = Value::CreateString(pszHint);
  1510. if (!_pvHint)
  1511. {
  1512. hr = E_OUTOFMEMORY;
  1513. goto Failure;
  1514. }
  1515. }
  1516. _fLoggedOn = fLoggedOn;
  1517. EndDefer();
  1518. return S_OK;
  1519. Failure:
  1520. EndDefer();
  1521. if (pv)
  1522. pv->Release();
  1523. return hr;
  1524. }
  1525. // Generic events
  1526. void LogonAccount::OnEvent(Event* pEvent)
  1527. {
  1528. if (pEvent->nStage == GMF_DIRECT) // Direct events
  1529. {
  1530. // Watch for click events initiated by LogonAccounts only
  1531. // if we are not logging someone on
  1532. if (pEvent->uidType == Button::Click)
  1533. {
  1534. if (pEvent->peTarget == this)
  1535. {
  1536. if (IsPasswordBlank())
  1537. {
  1538. // No password needed, attempt logon
  1539. OnAuthenticateUser();
  1540. }
  1541. pEvent->fHandled = true;
  1542. return;
  1543. }
  1544. }
  1545. }
  1546. else if (pEvent->nStage == GMF_BUBBLED) // Bubbled events
  1547. {
  1548. if (pEvent->uidType == Button::Click)
  1549. {
  1550. if (idPwdGo && (pEvent->peTarget->GetID() == idPwdGo))
  1551. {
  1552. // Attempt logon
  1553. OnAuthenticateUser();
  1554. pEvent->fHandled = true;
  1555. return;
  1556. }
  1557. else if (idPwdInfo && (pEvent->peTarget->GetID() == idPwdInfo))
  1558. {
  1559. // Retrieve hint
  1560. OnHintSelect();
  1561. pEvent->fHandled = true;
  1562. return;
  1563. }
  1564. else if (pEvent->peTarget == _pbStatus[0])
  1565. {
  1566. // Retrieve status info
  1567. OnStatusSelect(0);
  1568. pEvent->fHandled = true;
  1569. return;
  1570. }
  1571. else if (pEvent->peTarget == _pbStatus[1])
  1572. {
  1573. // Retrieve status info
  1574. OnStatusSelect(1);
  1575. pEvent->fHandled = true;
  1576. return;
  1577. }
  1578. }
  1579. else if (pEvent->uidType == Edit::Enter)
  1580. {
  1581. if (_pePwdEdit && pEvent->peTarget == _pePwdEdit)
  1582. {
  1583. // Attempt logon
  1584. OnAuthenticateUser();
  1585. pEvent->fHandled = true;
  1586. return;
  1587. }
  1588. }
  1589. }
  1590. Button::OnEvent(pEvent);
  1591. }
  1592. // System events
  1593. void LogonAccount::OnInput(InputEvent* pEvent)
  1594. {
  1595. KeyboardEvent* pke = (KeyboardEvent*)pEvent;
  1596. if (pke->nDevice == GINPUT_KEYBOARD && pke->nCode == GKEY_DOWN)
  1597. {
  1598. g_pErrorBalloon.HideToolTip();
  1599. }
  1600. LayoutCheckHandler(LAYOUT_DEF_USER);
  1601. Button::OnInput(pEvent);
  1602. }
  1603. void LogonAccount::OnPropertyChanged(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew)
  1604. {
  1605. #ifdef GADGET_ENABLE_GDIPLUS
  1606. // MouseWithin must be before Selected
  1607. if (IsProp(MouseWithin))
  1608. {
  1609. if (pvNew->GetBool())
  1610. FxMouseWithin(fdIn);
  1611. else
  1612. FxMouseWithin(fdOut);
  1613. }
  1614. #endif
  1615. if (IsProp(Selected))
  1616. {
  1617. if (pvNew->GetBool())
  1618. InsertPasswordPanel();
  1619. else
  1620. RemovePasswordPanel();
  1621. }
  1622. Button::OnPropertyChanged(ppi, iIndex, pvOld, pvNew);
  1623. }
  1624. BOOL LogonAccount::IsPasswordBlank()
  1625. {
  1626. if (_fPwdNeeded == (BOOL)-1)
  1627. {
  1628. // assume a password is needed
  1629. _fPwdNeeded = TRUE;
  1630. if (_pvUsername)
  1631. {
  1632. LPTSTR pszUsername;
  1633. pszUsername = _pvUsername->GetString();
  1634. if (pszUsername)
  1635. {
  1636. ILogonUser* pUser;
  1637. if (SUCCEEDED(GetLogonUserByLogonName(pszUsername, &pUser)))
  1638. {
  1639. VARIANT_BOOL vbPwdNeeded;
  1640. if (RunningInWinlogon() &&
  1641. SUCCEEDED(pUser->get_passwordRequired(&vbPwdNeeded)) &&
  1642. (vbPwdNeeded == VARIANT_FALSE))
  1643. {
  1644. _fPwdNeeded = FALSE;
  1645. }
  1646. pUser->Release();
  1647. }
  1648. }
  1649. }
  1650. }
  1651. return (_fPwdNeeded == FALSE);
  1652. }
  1653. HRESULT LogonAccount::InsertPasswordPanel()
  1654. {
  1655. HRESULT hr;
  1656. // If already have it, or no password is available, or logon state is not pending
  1657. if (_fHasPwdPanel || IsPasswordBlank() || (GetLogonState() != LS_Pending))
  1658. goto Done;
  1659. StartDefer();
  1660. // Add password panel
  1661. hr = Add(_pePwdPanel);
  1662. if (FAILED(hr))
  1663. {
  1664. EndDefer();
  1665. goto Failure;
  1666. }
  1667. SetElementAccessability(_pePwdEdit, true, ROLE_SYSTEM_STATICTEXT, _pvUsername->GetString());
  1668. _fHasPwdPanel = TRUE;
  1669. #ifdef GADGET_ENABLE_GDIPLUS
  1670. // Ensure that the Edit control is visible
  1671. ShowEdit();
  1672. #endif
  1673. // Hide hint button if no hint provided
  1674. if (_pvHint && *(_pvHint->GetString()) != NULL)
  1675. _pbPwdInfo->SetVisible(true);
  1676. else
  1677. _pbPwdInfo->SetVisible(false);
  1678. // Hide status text (do not remove or insert)
  1679. HideStatus(0);
  1680. HideStatus(1);
  1681. LayoutCheckHandler(LAYOUT_DEF_USER);
  1682. // Push focus to edit control
  1683. _pePwdEdit->SetKeyFocus();
  1684. EndDefer();
  1685. Done:
  1686. return S_OK;
  1687. Failure:
  1688. return hr;
  1689. }
  1690. HRESULT LogonAccount::RemovePasswordPanel()
  1691. {
  1692. HRESULT hr;
  1693. if (!_fHasPwdPanel)
  1694. goto Done;
  1695. StartDefer();
  1696. // Remove password panel
  1697. hr = Remove(_pePwdPanel);
  1698. if (FAILED(hr))
  1699. {
  1700. EndDefer();
  1701. goto Failure;
  1702. }
  1703. // Clear out edit control
  1704. _pePwdEdit->SetContentString(L"");
  1705. UnSubClassTheEditBox(_pePwdEdit->GetHWND()); // Provide for trap of the TTN_LINKCLICK event
  1706. // Unhide status text
  1707. ShowStatus(0);
  1708. ShowStatus(1);
  1709. _fHasPwdPanel = FALSE;
  1710. EndDefer();
  1711. Done:
  1712. return S_OK;
  1713. Failure:
  1714. return hr;
  1715. }
  1716. // User has authenticated
  1717. void LogonAccount::OnAuthenticatedUser()
  1718. {
  1719. // On success, log user on
  1720. _peCandidate = this;
  1721. g_plf->OnLogUserOn(this);
  1722. g_plf->EnterPostStatusMode();
  1723. }
  1724. // User is attempting to log on
  1725. BOOL LogonAccount::OnAuthenticateUser(LPCWSTR pszInPassword)
  1726. {
  1727. HRESULT hr;
  1728. // Logon requested on this account
  1729. LPCWSTR pszPassword = L"";
  1730. Value* pv = NULL;
  1731. ILogonUser *pobjUser;
  1732. VARIANT_BOOL vbLogonSucceeded = VARIANT_FALSE;
  1733. WCHAR *pszUsername = _pvUsername->GetString();
  1734. if (pszUsername)
  1735. {
  1736. if (SUCCEEDED(hr = GetLogonUserByLogonName(pszUsername, &pobjUser)))
  1737. {
  1738. if (!IsPasswordBlank())
  1739. {
  1740. if (pszInPassword)
  1741. {
  1742. pszPassword = pszInPassword;
  1743. }
  1744. else
  1745. {
  1746. if (_pePwdEdit)
  1747. {
  1748. pszPassword = _pePwdEdit->GetContentString(&pv);
  1749. if (!pszPassword)
  1750. pszPassword = L"";
  1751. if (pv)
  1752. {
  1753. pv->Release();
  1754. }
  1755. }
  1756. }
  1757. BSTR bstr = SysAllocString(pszPassword);
  1758. pobjUser->logon(bstr, &vbLogonSucceeded);
  1759. SysFreeString(bstr);
  1760. }
  1761. else
  1762. {
  1763. pobjUser->logon(L"", &vbLogonSucceeded);
  1764. }
  1765. pobjUser->Release();
  1766. }
  1767. }
  1768. if (vbLogonSucceeded == VARIANT_TRUE)
  1769. {
  1770. OnAuthenticatedUser();
  1771. }
  1772. else
  1773. {
  1774. if (pszInPassword == NULL)
  1775. {
  1776. ShowPasswordIncorrectMessage();
  1777. }
  1778. }
  1779. return (vbLogonSucceeded == VARIANT_TRUE);
  1780. }
  1781. ////////////////////////////////////////
  1782. //
  1783. // LogonAccount::ShowPasswordIncorrectMessage
  1784. //
  1785. // Put up the balloon message that says that the password is incorrect.
  1786. //
  1787. /////////////////////////////////////////
  1788. void LogonAccount::ShowPasswordIncorrectMessage()
  1789. {
  1790. TCHAR szError[512], szTitle[128], szAccessible[640];
  1791. BOOL fBackupAvailable = false;
  1792. BOOL fHint = false;
  1793. DWORD dwResult;
  1794. g_szUsername[0] = 0;
  1795. SubClassTheEditBox(_pePwdEdit->GetHWND()); // Provide for trap of the TTN_LINKCLICK event
  1796. if (0 < lstrlen(_pvUsername->GetString()))
  1797. {
  1798. wcscpy(g_szUsername,_pvUsername->GetString());
  1799. if (0 == PRQueryStatus(NULL,_pvUsername->GetString(),&dwResult))
  1800. {
  1801. if (0 == dwResult)
  1802. {
  1803. fBackupAvailable = TRUE;
  1804. }
  1805. }
  1806. }
  1807. if (NULL != _pvHint && 0 < lstrlen(_pvHint->GetString()))
  1808. {
  1809. fHint = true;
  1810. }
  1811. LoadStringW(g_plf->GetHInstance(), IDS_BADPWDTITLE, szTitle, DUIARRAYSIZE(szTitle));
  1812. if (!fBackupAvailable && fHint)
  1813. LoadStringW(g_plf->GetHInstance(), IDS_BADPWDHINT, szError, DUIARRAYSIZE(szError));
  1814. else if (fBackupAvailable && !fHint)
  1815. LoadStringW(g_plf->GetHInstance(), IDS_BADPWDREST, szError, DUIARRAYSIZE(szError));
  1816. else if (fBackupAvailable && fHint)
  1817. LoadStringW(g_plf->GetHInstance(), IDS_BADPWDHINTREST, szError, DUIARRAYSIZE(szError));
  1818. else
  1819. LoadStringW(g_plf->GetHInstance(), IDS_BADPWD, szError, DUIARRAYSIZE(szError));
  1820. g_pErrorBalloon.ShowToolTip(GetModuleHandleW(NULL), _pePwdEdit->GetHWND(), szError, szTitle, TTI_ERROR, EB_WARNINGCENTERED | EB_MARKUP, 10000);
  1821. lstrcpy(szAccessible, szTitle);
  1822. lstrcat(szAccessible, szError);
  1823. SetElementAccessability(_pePwdEdit, true, ROLE_SYSTEM_STATICTEXT, szAccessible);
  1824. _pePwdEdit->RemoveLocalValue(ContentProp);
  1825. _pePwdEdit->SetKeyFocus();
  1826. }
  1827. ////////////////////////////////////////
  1828. //
  1829. // LogonAccount::OnHintSelect
  1830. //
  1831. // Put up the balloon message that contains the user's password hint.
  1832. //
  1833. /////////////////////////////////////////
  1834. void LogonAccount::OnHintSelect()
  1835. {
  1836. TCHAR szTitle[128];
  1837. DUIAssertNoMsg(_pbPwdInfo);
  1838. // get the position of the link so we can target the balloon tip correctly
  1839. POINT pt = {0,0};
  1840. CalcBalloonTargetLocation(g_plf->GetNativeHost()->GetHWND(), _pbPwdInfo, &pt);
  1841. LoadStringW(g_plf->GetHInstance(), IDS_PASSWORDHINTTITLE, szTitle, DUIARRAYSIZE(szTitle));
  1842. g_pErrorBalloon.ShowToolTip(GetModuleHandleW(NULL), g_plf->GetHWND(), &pt, _pvHint->GetString(), szTitle, TTI_INFO, EB_WARNINGCENTERED, 10000);
  1843. SetElementAccessability(_pePwdEdit, true, ROLE_SYSTEM_STATICTEXT, _pvHint->GetString());
  1844. _pePwdEdit->SetKeyFocus();
  1845. }
  1846. ////////////////////////////////////////
  1847. //
  1848. // LogonAccount::OnStatusSelect
  1849. //
  1850. // The user clicked one of the notification links (unread mail, running programs, etc).
  1851. // Dispatch that click to the right balloon tip display procs
  1852. //
  1853. /////////////////////////////////////////
  1854. void LogonAccount::OnStatusSelect(UINT nLine)
  1855. {
  1856. if (nLine == LASS_Email)
  1857. {
  1858. UnreadMailTip();
  1859. }
  1860. else if (nLine == LASS_LoggedOn)
  1861. {
  1862. AppRunningTip();
  1863. }
  1864. }
  1865. ////////////////////////////////////////
  1866. //
  1867. // LogonAccount::AppRunningTip
  1868. //
  1869. // The user activated the link that shows how many programs are running. Show the tip that
  1870. // basically says that running lots of programs can show the machine down
  1871. //
  1872. /////////////////////////////////////////
  1873. void LogonAccount::AppRunningTip()
  1874. {
  1875. TCHAR szTitle[256], szTemp[512];
  1876. Element* pe = FindDescendent(StrToID(L"username"));
  1877. DUIAssertNoMsg(pe);
  1878. Value* pv;
  1879. LPCWSTR pszDisplayName = pe->GetContentString(&pv);
  1880. if (!pszDisplayName)
  1881. pszDisplayName = L"";
  1882. if (_dwRunningApps == 0)
  1883. {
  1884. LoadStringW(g_plf->GetHInstance(), IDS_USERISLOGGEDON, szTemp, DUIARRAYSIZE(szTemp));
  1885. wsprintf(szTitle, szTemp, pszDisplayName, _dwRunningApps);
  1886. }
  1887. else
  1888. {
  1889. LoadStringW(g_plf->GetHInstance(), (_dwRunningApps == 1 ? IDS_USERRUNNINGPROGRAM : IDS_USERRUNNINGPROGRAMS), szTemp, DUIARRAYSIZE(szTemp));
  1890. wsprintf(szTitle, szTemp, pszDisplayName, _dwRunningApps);
  1891. }
  1892. pv->Release();
  1893. // get the position of the link so we can target the balloon tip correctly
  1894. POINT pt = {0,0};
  1895. CalcBalloonTargetLocation(g_plf->GetNativeHost()->GetHWND(), _pbStatus[LASS_LoggedOn], &pt);
  1896. LoadStringW(g_plf->GetHInstance(), (_dwRunningApps > 0 ? IDS_TOOMANYPROGRAMS : IDS_TOOMANYUSERS), szTemp, DUIARRAYSIZE(szTemp));
  1897. g_pErrorBalloon.ShowToolTip(GetModuleHandleW(NULL), g_plf->GetHWND(), &pt, szTemp, szTitle, TTI_INFO, EB_WARNINGCENTERED, 10000);
  1898. }
  1899. ////////////////////////////////////////
  1900. //
  1901. // LogonAccount::UnreadMailTip
  1902. //
  1903. // The user activated the link that shows how many unread email messages they have.
  1904. // Show the tip that says how many messages each of their email accounts has.
  1905. //
  1906. // TODO -- speed this up. its really slow now because each call to SHGina's
  1907. // ILogonUser::getMailAccountInfo load's the users' hive to get the next account from
  1908. // the registry.
  1909. //
  1910. /////////////////////////////////////////
  1911. void LogonAccount::UnreadMailTip()
  1912. {
  1913. TCHAR szTitle[128], szMsg[1024], szTemp[512], szRes[128];
  1914. HRESULT hr = E_FAIL;
  1915. ILogonUser *pobjUser = NULL;
  1916. szMsg[0] = TEXT('\0');
  1917. Element* pe = FindDescendent(StrToID(L"username"));
  1918. DUIAssertNoMsg(pe);
  1919. Value* pv;
  1920. LPCWSTR pszDisplayName = pe->GetContentString(&pv);
  1921. if (!pszDisplayName)
  1922. pszDisplayName = L"";
  1923. WCHAR *pszUsername = _pvUsername->GetString();
  1924. DWORD dwAccountsAdded = 0;
  1925. if (pszUsername)
  1926. {
  1927. if (SUCCEEDED(hr = GetLogonUserByLogonName(pszUsername, &pobjUser)) && pobjUser)
  1928. {
  1929. DWORD i, cMailAccounts;
  1930. cMailAccounts = 5;
  1931. for (i = 0; i < cMailAccounts; i++)
  1932. {
  1933. UINT cUnread;
  1934. VARIANT varAcctName = {0};
  1935. hr = pobjUser->getMailAccountInfo(i, &varAcctName, &cUnread);
  1936. if (FAILED(hr))
  1937. {
  1938. break;
  1939. }
  1940. if (varAcctName.bstrVal && cUnread > 0)
  1941. {
  1942. if (dwAccountsAdded > 0)
  1943. {
  1944. lstrcat(szMsg, TEXT("\r\n"));
  1945. }
  1946. dwAccountsAdded++;
  1947. LoadStringW(g_plf->GetHInstance(), IDS_UNREADMAILACCOUNT, szRes, DUIARRAYSIZE(szRes));
  1948. wsprintf(szTemp, szRes, varAcctName.bstrVal, cUnread);
  1949. lstrcat(szMsg, szTemp);
  1950. }
  1951. VariantClear(&varAcctName);
  1952. }
  1953. pobjUser->Release();
  1954. }
  1955. }
  1956. LoadStringW(g_plf->GetHInstance(), (_dwUnreadMail == 1 ? IDS_USERUNREADEMAIL : IDS_USERUNREADEMAILS), szTemp, DUIARRAYSIZE(szTemp));
  1957. wsprintf(szTitle, szTemp, pszDisplayName, _dwUnreadMail);
  1958. pv->Release();
  1959. // get the position of the link so we can target the balloon tip correctly
  1960. POINT pt = {0,0};
  1961. CalcBalloonTargetLocation(g_plf->GetNativeHost()->GetHWND(), _pbStatus[LASS_Email], &pt);
  1962. if (szMsg[0] == 0)
  1963. {
  1964. LoadStringW(g_plf->GetHInstance(), IDS_UNREADMAILTEMP, szMsg, DUIARRAYSIZE(szMsg));
  1965. }
  1966. g_pErrorBalloon.ShowToolTip(GetModuleHandleW(NULL), g_plf->GetHWND(), &pt, szMsg, szTitle, TTI_INFO, EB_WARNINGCENTERED, 10000);
  1967. }
  1968. ////////////////////////////////////////
  1969. //
  1970. // LogonAccount::UpdateNotifications
  1971. //
  1972. // Update the notification links for this user. Check to see if they are logged on and
  1973. // if so, find out how many applications they had open when they last switched away.
  1974. //
  1975. // Check the unread mail count for users who are logged on or for everyone if fCheckEverything is
  1976. // true. Checking unread mail counts is slow because it has to load the user's registry hive.
  1977. // Since no applications will update this value when the user is not logged on, there is no
  1978. // need to check this when they are not logged on. The exception to this is when we are first
  1979. // building the list since we need to always load it then, hence the fCheckEverything flag.
  1980. //
  1981. /////////////////////////////////////////
  1982. void LogonAccount::UpdateNotifications(BOOL fCheckEverything)
  1983. {
  1984. HRESULT hr = E_FAIL;
  1985. ILogonUser *pobjUser = NULL;
  1986. WCHAR szTemp[1024], sz[1024];
  1987. if (_fHasPwdPanel)
  1988. return;
  1989. WCHAR *pszUsername = _pvUsername->GetString();
  1990. if (pszUsername)
  1991. {
  1992. if (SUCCEEDED(hr = GetLogonUserByLogonName(pszUsername, &pobjUser)) && pobjUser)
  1993. {
  1994. VARIANT_BOOL vbLoggedOn;
  1995. VARIANT varUnreadMail;
  1996. BOOL fLoggedOn;
  1997. int iUnreadMailCount = 0;
  1998. DWORD dwProgramsRunning = 0;
  1999. if (FAILED(pobjUser->get_isLoggedOn(&vbLoggedOn)))
  2000. {
  2001. vbLoggedOn = VARIANT_FALSE;
  2002. }
  2003. fLoggedOn = (vbLoggedOn == VARIANT_TRUE);
  2004. if (fLoggedOn)
  2005. {
  2006. HKEY hKey;
  2007. CUserProfile userProfile(pszUsername, NULL);
  2008. if (ERROR_SUCCESS == RegOpenKeyEx(userProfile, TEXT("SessionInformation"), 0, KEY_QUERY_VALUE, &hKey))
  2009. {
  2010. DWORD dwProgramsRunningSize = sizeof(dwProgramsRunning);
  2011. RegQueryValueEx(hKey, TEXT("ProgramCount"), NULL, NULL, reinterpret_cast<LPBYTE>(&dwProgramsRunning), &dwProgramsRunningSize);
  2012. RegCloseKey(hKey);
  2013. }
  2014. }
  2015. SetRunningApps(dwProgramsRunning);
  2016. if (fLoggedOn)
  2017. {
  2018. InsertStatus(LASS_LoggedOn);
  2019. if (dwProgramsRunning != 0)
  2020. {
  2021. LoadStringW(g_plf->GetHInstance(), (dwProgramsRunning == 1 ? IDS_RUNNINGPROGRAM : IDS_RUNNINGPROGRAMS), szTemp, ARRAYSIZE(szTemp));
  2022. wsprintf(sz, szTemp, dwProgramsRunning);
  2023. SetStatus(LASS_LoggedOn, sz);
  2024. ShowStatus(LASS_LoggedOn);
  2025. }
  2026. else
  2027. {
  2028. LoadStringW(g_plf->GetHInstance(), IDS_USERLOGGEDON, szTemp, ARRAYSIZE(szTemp));
  2029. SetStatus(LASS_LoggedOn, szTemp);
  2030. }
  2031. }
  2032. else
  2033. {
  2034. // if they are not logged on, clean up the logged on text and remove any padding
  2035. RemoveStatus(LASS_LoggedOn);
  2036. }
  2037. if (fLoggedOn || fCheckEverything)
  2038. {
  2039. varUnreadMail.uintVal = 0;
  2040. if (FAILED(pobjUser->get_setting(L"UnreadMail", &varUnreadMail)))
  2041. {
  2042. varUnreadMail.uintVal = 0;
  2043. }
  2044. iUnreadMailCount = varUnreadMail.uintVal;
  2045. SetUnreadMail((DWORD)iUnreadMailCount);
  2046. if (iUnreadMailCount != 0)
  2047. {
  2048. InsertStatus(LASS_Email);
  2049. LoadStringW(g_plf->GetHInstance(), (iUnreadMailCount == 1 ? IDS_UNREADMAIL : IDS_UNREADMAILS), szTemp, ARRAYSIZE(szTemp));
  2050. wsprintf(sz, szTemp, iUnreadMailCount);
  2051. SetStatus(LASS_Email, sz);
  2052. ShowStatus(LASS_Email);
  2053. }
  2054. else
  2055. {
  2056. RemoveStatus(LASS_Email);
  2057. }
  2058. }
  2059. pobjUser->Release();
  2060. }
  2061. }
  2062. }
  2063. #ifdef GADGET_ENABLE_GDIPLUS
  2064. void
  2065. LogonAccount::ShowEdit()
  2066. {
  2067. HWND hwndEdit = _pePwdEdit->GetHWND();
  2068. HWND hwndHost = ::GetParent(hwndEdit);
  2069. SetWindowPos(hwndHost, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
  2070. EnableWindow(hwndEdit, TRUE);
  2071. SetFocus(hwndEdit);
  2072. }
  2073. void
  2074. LogonAccount::HideEdit()
  2075. {
  2076. HWND hwndEdit = _pePwdEdit->GetHWND();
  2077. HWND hwndHost = ::GetParent(hwndEdit);
  2078. EnableWindow(hwndEdit, FALSE);
  2079. SetWindowPos(hwndHost, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_HIDEWINDOW);
  2080. }
  2081. #endif // GADGET_ENABLE_GDIPLUS
  2082. ////////////////////////////////////////////////////////
  2083. // Property definitions
  2084. ////////////////////////////////////////////////////////
  2085. // ClassInfo (must appear after property definitions)
  2086. // LogonState property
  2087. static int vvLogonState[] = { DUIV_INT, -1 };
  2088. static PropertyInfo impLogonStateProp = { L"LogonState", PF_Normal, 0, vvLogonState, NULL, Value::pvIntZero /*LS_Pending*/ };
  2089. PropertyInfo* LogonAccount::LogonStateProp = &impLogonStateProp;
  2090. ////////////////////////////////////////////////////////
  2091. // ClassInfo (must appear after property definitions)
  2092. // Class properties
  2093. static PropertyInfo* _aPI[] = {
  2094. LogonAccount::LogonStateProp,
  2095. };
  2096. // Define class info with type and base type, set static class pointer
  2097. IClassInfo* LogonAccount::Class = NULL;
  2098. HRESULT LogonAccount::Register()
  2099. {
  2100. return ClassInfo<LogonAccount,Button>::Register(L"LogonAccount", _aPI, DUIARRAYSIZE(_aPI));
  2101. }
  2102. ////////////////////////////////////////////////////////
  2103. // Logon Parser
  2104. void CALLBACK LogonParseError(LPCWSTR pszError, LPCWSTR pszToken, int dLine)
  2105. {
  2106. WCHAR buf[201];
  2107. if (dLine != -1)
  2108. swprintf(buf, L"%s '%s' at line %d", pszError, pszToken, dLine);
  2109. else
  2110. swprintf(buf, L"%s '%s'", pszError, pszToken);
  2111. MessageBoxW(NULL, buf, L"Parser Message", MB_OK);
  2112. }
  2113. void DoFadeWindow(HWND hwnd)
  2114. {
  2115. HDC hdc;
  2116. int i;
  2117. RECT rcFrame;
  2118. COLORREF rgbFinal = RGB(90,126,220);
  2119. hdc = GetDC(hwnd);
  2120. GetClientRect(hwnd, &rcFrame);
  2121. COLORREF crCurr;
  2122. HBRUSH hbrFill;
  2123. crCurr = RGB(0,0,0);
  2124. // draw the left bar
  2125. for (i = 0; i < 16; i++)
  2126. {
  2127. RECT rcCurrFrame;
  2128. rcCurrFrame = rcFrame;
  2129. crCurr = RGB((GetRValue(rgbFinal) / 16)*i,
  2130. (GetGValue(rgbFinal) / 16)*i,
  2131. (GetBValue(rgbFinal) / 16)*i);
  2132. hbrFill = CreateSolidBrush(crCurr);
  2133. if (hbrFill)
  2134. {
  2135. FillRect(hdc, &rcCurrFrame, hbrFill);
  2136. DeleteObject(hbrFill);
  2137. }
  2138. GdiFlush();
  2139. }
  2140. ReleaseDC(hwnd, hdc);
  2141. }
  2142. ////////////////////////////////////////////////////////
  2143. // Logon entry point
  2144. int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow)
  2145. {
  2146. UNREFERENCED_PARAMETER(hPrevInstance);
  2147. UNREFERENCED_PARAMETER(pCmdLine);
  2148. UNREFERENCED_PARAMETER(nCmdShow);
  2149. WNDCLASSEX wcx = {0};
  2150. BOOL fStatusLaunch = false;
  2151. BOOL fShutdownLaunch = false;
  2152. BOOL fWait = false;
  2153. CBackgroundWindow backgroundWindow(hInst);
  2154. ZeroMemory(g_rgH, sizeof(g_rgH));
  2155. SetErrorHandler();
  2156. InitCommonControls();
  2157. // Register logon notification window
  2158. wcx.cbSize = sizeof(WNDCLASSEX);
  2159. wcx.lpfnWndProc = LogonWindowProc;
  2160. wcx.hInstance = GetModuleHandleW(NULL);
  2161. wcx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  2162. wcx.lpszClassName = TEXT("LogonWnd");
  2163. wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
  2164. RegisterClassEx(&wcx);
  2165. fStatusLaunch = (StrStrIA(pCmdLine, "/status") != NULL);
  2166. fShutdownLaunch = (StrStrIA(pCmdLine, "/shutdown") != NULL);
  2167. fWait = (StrStrIA(pCmdLine, "/wait") != NULL);
  2168. g_fNoAnimations = (StrStrIA(pCmdLine, "/noanim") != NULL);
  2169. // Create frame
  2170. Parser* pParser = NULL;
  2171. NativeHWNDHost* pnhh = NULL;
  2172. // DirectUI init process
  2173. if (FAILED(InitProcess()))
  2174. goto Failure;
  2175. // Register classes
  2176. if (FAILED(LogonFrame::Register()))
  2177. goto Failure;
  2178. if (FAILED(LogonAccountList::Register()))
  2179. goto Failure;
  2180. if (FAILED(LogonAccount::Register()))
  2181. goto Failure;
  2182. // DirectUI init thread
  2183. if (FAILED(InitThread()))
  2184. goto Failure;
  2185. if (FAILED(CoInitialize(NULL)))
  2186. goto Failure;
  2187. #ifdef GADGET_ENABLE_GDIPLUS
  2188. if (FAILED(FxInitGuts()))
  2189. goto Failure;
  2190. #endif
  2191. #ifndef DEBUG
  2192. if (!RunningUnderWinlogon())
  2193. goto Failure;
  2194. #endif
  2195. DisableAnimations();
  2196. // Create host
  2197. HMONITOR hMonitor;
  2198. POINT pt;
  2199. MONITORINFO monitorInfo;
  2200. // Determine initial size of the host. This is desired to be the entire
  2201. // primary monitor resolution because the host always runs on the secure
  2202. // desktop. If magnifier is brought up it will call SHAppBarMessage which
  2203. // will change the work area and we will respond to it appropriately from
  2204. // the listener in shgina that sends us HM_DISPLAYRESIZE messages.
  2205. pt.x = pt.y = 0;
  2206. hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
  2207. DUIAssert(hMonitor != NULL, "NULL HMONITOR returned from MonitorFromPoint");
  2208. monitorInfo.cbSize = sizeof(monitorInfo);
  2209. if (GetMonitorInfo(hMonitor, &monitorInfo) == FALSE)
  2210. {
  2211. SystemParametersInfo(SPI_GETWORKAREA, 0, &monitorInfo.rcMonitor, 0);
  2212. }
  2213. NativeHWNDHost::Create(L"Windows Logon", backgroundWindow.Create(), NULL, monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top,
  2214. monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top, 0, WS_POPUP, NHHO_IgnoreClose, &pnhh);
  2215. // NativeHWNDHost::Create(L"Windows Logon", NULL, NULL, monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top,
  2216. // 800, 600, 0, WS_POPUP, NHHO_IgnoreClose, &pnhh);
  2217. if (!pnhh)
  2218. goto Failure;
  2219. // Populate handle list for theme style parsing
  2220. g_rgH[0] = hInst; // Default HINSTANCE
  2221. g_rgH[SCROLLBARHTHEME] = OpenThemeData(pnhh->GetHWND(), L"Scrollbar");
  2222. // Frame creation
  2223. Parser::Create(IDR_LOGONUI, g_rgH, LogonParseError, &pParser);
  2224. if (!pParser)
  2225. goto Failure;
  2226. if (!pParser->WasParseError())
  2227. {
  2228. Element::StartDefer();
  2229. // Always double buffer
  2230. LogonFrame::Create(pnhh->GetHWND(), true, 0, (Element**)&g_plf);
  2231. if (!g_plf)
  2232. {
  2233. Element::EndDefer();
  2234. goto Failure;
  2235. }
  2236. g_plf->SetNativeHost(pnhh);
  2237. Element* pe;
  2238. pParser->CreateElement(L"main", g_plf, &pe);
  2239. if (pe) // Fill contents using substitution
  2240. {
  2241. // Frame tree is built
  2242. if (FAILED(g_plf->OnTreeReady(pParser)))
  2243. {
  2244. Element::EndDefer();
  2245. goto Failure;
  2246. }
  2247. if (fShutdownLaunch || fWait)
  2248. {
  2249. g_plf->SetTitle(IDS_PLEASEWAIT);
  2250. }
  2251. if (!fStatusLaunch)
  2252. {
  2253. // Build contents of account list
  2254. g_plf->EnterLogonMode(false);
  2255. }
  2256. else
  2257. {
  2258. g_plf->EnterPreStatusMode(false);
  2259. }
  2260. // Host
  2261. pnhh->Host(g_plf);
  2262. g_plf->SetButtonLabels();
  2263. Element *peLogoArea = g_plf->FindDescendent(StrToID(L"product"));
  2264. if (!g_fNoAnimations)
  2265. {
  2266. pnhh->ShowWindow();
  2267. DoFadeWindow(pnhh->GetHWND());
  2268. if (peLogoArea)
  2269. {
  2270. peLogoArea->SetAlpha(0);
  2271. }
  2272. }
  2273. // Set visible and focus
  2274. g_plf->SetVisible(true);
  2275. g_plf->SetKeyFocus();
  2276. Element::EndDefer();
  2277. // Do initial show
  2278. pnhh->ShowWindow();
  2279. if (!g_fNoAnimations)
  2280. {
  2281. EnableAnimations();
  2282. }
  2283. if (peLogoArea)
  2284. {
  2285. peLogoArea->SetAlpha(255);
  2286. }
  2287. StartMessagePump();
  2288. // psf will be deleted by native HWND host when destroyed
  2289. }
  2290. else
  2291. Element::EndDefer();
  2292. }
  2293. Failure:
  2294. if (pnhh)
  2295. pnhh->Destroy();
  2296. if (pParser)
  2297. pParser->Destroy();
  2298. ReleaseStatusHost();
  2299. FreeLayoutInfo(LAYOUT_DEF_USER);
  2300. if (g_rgH[SCROLLBARHTHEME]) // Scrollbar
  2301. {
  2302. CloseThemeData(g_rgH[SCROLLBARHTHEME]);
  2303. }
  2304. CoUninitialize();
  2305. UnInitThread();
  2306. UnInitProcess();
  2307. // Free cached atom list
  2308. if (LogonAccount::idPwdGo)
  2309. DeleteAtom(LogonAccount::idPwdGo);
  2310. if (LogonAccount::idPwdInfo)
  2311. DeleteAtom(LogonAccount::idPwdInfo);
  2312. EndHostProcess(0);
  2313. return 0;
  2314. }
  2315. void LogonAccount::SetKeyboardIcon(HICON hIcon)
  2316. {
  2317. HICON hIconCopy = NULL;
  2318. if (hIcon)
  2319. {
  2320. hIconCopy = CopyIcon(hIcon);
  2321. }
  2322. if (_peKbdIcon && hIconCopy)
  2323. {
  2324. Value* pvIcon = Value::CreateGraphic(hIconCopy);
  2325. _peKbdIcon->SetValue(Element::ContentProp, PI_Local, pvIcon); // Element takes owners
  2326. _peKbdIcon->SetPadding(0, 5, 0, 7);
  2327. pvIcon->Release();
  2328. }
  2329. }