2851 lines
72 KiB
C++
2851 lines
72 KiB
C++
// Logon.cpp : Windows Logon application
|
|
//
|
|
|
|
#include "priv.h"
|
|
|
|
using namespace DirectUI;
|
|
// Logon.cpp : Windows Logon application
|
|
//
|
|
|
|
#include "logon.h"
|
|
#include "Fx.h"
|
|
#include "backend.h"
|
|
#include "resource.h"
|
|
#include "eballoon.h"
|
|
#include "profileutil.h"
|
|
#include "langicon.h"
|
|
#include <passrec.h>
|
|
|
|
BOOL RunningInWinlogon(); // from backend.cpp
|
|
|
|
UsingDUIClass(Element);
|
|
UsingDUIClass(Button);
|
|
UsingDUIClass(ScrollBar);
|
|
UsingDUIClass(Selector);
|
|
UsingDUIClass(ScrollViewer);
|
|
UsingDUIClass(Edit);
|
|
|
|
// Globals
|
|
|
|
LogonFrame* g_plf = NULL;
|
|
ILogonStatusHost *g_pILogonStatusHost = NULL;
|
|
CErrorBalloon g_pErrorBalloon;
|
|
BOOL g_fNoAnimations = false;
|
|
WCHAR szLastSelectedName[UNLEN + sizeof('\0')] = { L'\0' };
|
|
HANDLE g_rgH[3] = {0};
|
|
|
|
#define MAX_COMPUTERDESC_LENGTH 255
|
|
#define RECTWIDTH(r) (r.right - r.left)
|
|
|
|
|
|
// Resource string loading
|
|
LPCWSTR LoadResString(UINT nID)
|
|
{
|
|
static WCHAR szRes[101];
|
|
szRes[0] = NULL;
|
|
LoadStringW(g_plf->GetHInstance(), nID, szRes, DUIARRAYSIZE(szRes) - 1);
|
|
return szRes;
|
|
}
|
|
|
|
void SetButtonLabel(Button* pButton, LPCWSTR pszLabel)
|
|
{
|
|
Element *pLabel= (Element*)pButton->FindDescendent(StrToID(L"label"));
|
|
DUIAssert(pLabel, "Cannot find button label, check the UI file");
|
|
if (pLabel != NULL)
|
|
{
|
|
pLabel->SetContentString(pszLabel);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// SetElementAccessability
|
|
//
|
|
// Set the accessibility information for an element.
|
|
//
|
|
/////////////////////////////////////////
|
|
void inline SetElementAccessability(Element* pe, bool bAccessible, int iRole, LPCWSTR pszAccName)
|
|
{
|
|
if (pe)
|
|
{
|
|
pe->SetAccessible(bAccessible);
|
|
pe->SetAccRole(iRole);
|
|
pe->SetAccName(pszAccName);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// RunningUnderWinlogon
|
|
//
|
|
// Check to see if the logon message window is available.
|
|
//
|
|
/////////////////////////////////////////
|
|
BOOL RunningUnderWinlogon()
|
|
{
|
|
return (FindWindow(TEXT("Shell_TrayWnd"), NULL) == NULL);
|
|
}
|
|
|
|
// global storage of username associated with failed logon. Used for
|
|
// restore wizard via ECSubClassProc
|
|
WCHAR g_szUsername[UNLEN];
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// Support code for balloon tip launch of the Password Reset Wizard
|
|
//
|
|
// Code in support of subclassing the Password Panel edit control
|
|
//
|
|
// The control is displayed by InsertPasswordPanel and undisplayed
|
|
// by RemovePasswordPanel. The control is subclassed when displayed
|
|
// and unsubclassed when removed.
|
|
//
|
|
////////////////////////////////////////
|
|
|
|
// Entirely randomly selected magic number for the edit control subclass operation
|
|
#define ECMAGICNUM 3212
|
|
|
|
void ShowResetWizard(HWND hw)
|
|
{
|
|
// Show password restore wizard
|
|
HMODULE hDll = LoadLibrary(L"keymgr.dll");
|
|
if (hDll)
|
|
{
|
|
RUNDLLPROC PRShowRestoreWizard;
|
|
PRShowRestoreWizard = (RUNDLLPROC) GetProcAddress(hDll,(LPCSTR)"PRShowRestoreWizardW");
|
|
if (PRShowRestoreWizard)
|
|
{
|
|
PRShowRestoreWizard(hw,NULL,g_szUsername,0);
|
|
}
|
|
FreeLibrary(hDll);
|
|
}
|
|
return;
|
|
}
|
|
|
|
LRESULT CALLBACK ECSubClassProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,UINT_PTR uID, ULONG_PTR dwRefData)
|
|
{
|
|
UNREFERENCED_PARAMETER(uID);
|
|
UNREFERENCED_PARAMETER(dwRefData);
|
|
switch (uMsg)
|
|
{
|
|
case WM_NOTIFY:
|
|
{
|
|
LPNMHDR lph;
|
|
lph = (LPNMHDR) lParam;
|
|
if (TTN_LINKCLICK == lph->code)
|
|
{
|
|
g_pErrorBalloon.HideToolTip();
|
|
ShowResetWizard(hwnd);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
BOOL SubClassTheEditBox(HWND he)
|
|
{
|
|
if (he)
|
|
{
|
|
SetWindowSubclass(he,ECSubClassProc,ECMAGICNUM,NULL);
|
|
}
|
|
return (he != NULL);
|
|
}
|
|
|
|
void UnSubClassTheEditBox(HWND he)
|
|
{
|
|
if (he)
|
|
{
|
|
RemoveWindowSubclass(he,ECSubClassProc,ECMAGICNUM);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// BuildAccountList
|
|
//
|
|
// Add all user accounts.
|
|
//
|
|
// Out parameter ppla returns a user that should be selected automatically if there is one.
|
|
// the caller should select this user.
|
|
//
|
|
// RETURNS
|
|
// S_OK if everything works out. Failure HRESULT if not. You are pretty much hosed if this fails
|
|
//
|
|
/////////////////////////////////////////
|
|
HRESULT BuildAccountList(LogonFrame* plf, OUT LogonAccount **ppla)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (ppla)
|
|
{
|
|
*ppla = NULL;
|
|
}
|
|
|
|
hr = BuildUserListFromGina(plf, ppla);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
g_plf->SetUserListAvailable(TRUE);
|
|
}
|
|
#ifdef GADGET_ENABLE_GDIPLUS
|
|
plf->FxStartup();
|
|
#endif
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// PokeComCtl32
|
|
//
|
|
// Flush comctl32's notion of the atom table. This is so balloon tips will work correctly
|
|
// after a logoff.
|
|
//
|
|
/////////////////////////////////////////
|
|
|
|
void PokeComCtl32()
|
|
{
|
|
INITCOMMONCONTROLSEX iccex = { sizeof(INITCOMMONCONTROLSEX), ICC_WINLOGON_REINIT | ICC_STANDARD_CLASSES | ICC_TREEVIEW_CLASSES};
|
|
InitCommonControlsEx(&iccex);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////
|
|
//
|
|
// LogonFrame
|
|
//
|
|
////////////////////////////////////////////////////////
|
|
|
|
|
|
int LogonFrame::_nDPI = 0;
|
|
|
|
HRESULT LogonFrame::Create(OUT Element** ppElement)
|
|
{
|
|
UNREFERENCED_PARAMETER(ppElement);
|
|
DUIAssertForce("Cannot instantiate an HWND host derived Element via parser. Must use substitution.");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT LogonFrame::Create(HWND hParent, BOOL fDblBuffer, UINT nCreate, OUT Element** ppElement)
|
|
{
|
|
*ppElement = NULL;
|
|
|
|
LogonFrame* plf = HNew<LogonFrame>();
|
|
if (!plf)
|
|
return E_OUTOFMEMORY;
|
|
|
|
HRESULT hr = plf->Initialize(hParent, fDblBuffer, nCreate);
|
|
if (FAILED(hr))
|
|
{
|
|
plf->Destroy();
|
|
return hr;
|
|
}
|
|
|
|
*ppElement = plf;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void LogonFrame::ResetTheme(void)
|
|
{
|
|
Parser *pParser = NULL;
|
|
Value *pvScrollerSheet;
|
|
Element *peListScroller = NULL;
|
|
if (g_rgH[SCROLLBARHTHEME])
|
|
{
|
|
CloseThemeData(g_rgH[SCROLLBARHTHEME]);
|
|
g_rgH[SCROLLBARHTHEME] = NULL;
|
|
}
|
|
|
|
g_rgH[SCROLLBARHTHEME] = OpenThemeData(_pnhh->GetHWND(), L"Scrollbar");
|
|
|
|
Parser::Create(IDR_LOGONUI, g_rgH, LogonParseError, &pParser);
|
|
if (pParser && !pParser->WasParseError())
|
|
{
|
|
pvScrollerSheet = pParser->GetSheet(L"scroller");
|
|
|
|
if (pvScrollerSheet)
|
|
{
|
|
peListScroller = (Selector*)FindDescendent(StrToID(L"scroller"));
|
|
|
|
peListScroller->SetValue(SheetProp, PI_Local, pvScrollerSheet);
|
|
|
|
pvScrollerSheet->Release();
|
|
}
|
|
|
|
pParser->Destroy();
|
|
}
|
|
}
|
|
|
|
|
|
void LogonFrame::NextFlagAnimate(DWORD dwFrame)
|
|
{
|
|
|
|
#ifndef ANIMATE_FLAG
|
|
UNREFERENCED_PARAMETER(dwFrame);
|
|
#else
|
|
Element* pe;
|
|
|
|
if( dwFrame >= MAX_FLAG_FRAMES || g_fNoAnimations)
|
|
{
|
|
return;
|
|
}
|
|
|
|
pe = FindDescendent(StrToID(L"product"));
|
|
DUIAssertNoMsg(pe);
|
|
|
|
if (pe)
|
|
{
|
|
HBITMAP hbm = NULL;
|
|
HDC hdc;
|
|
Value *pv = NULL;
|
|
|
|
hdc = CreateCompatibleDC(_hdcAnimation);
|
|
|
|
if (hdc)
|
|
{
|
|
pv = pe->GetValue(Element::ContentProp, PI_Local);
|
|
if (pv)
|
|
{
|
|
hbm = (HBITMAP)pv->GetImage(false);
|
|
}
|
|
|
|
if (hbm)
|
|
{
|
|
_dwFlagFrame = dwFrame;
|
|
if (_dwFlagFrame >= MAX_FLAG_FRAMES)
|
|
{
|
|
_dwFlagFrame = 0;
|
|
}
|
|
|
|
|
|
HBITMAP hbmSave = (HBITMAP)SelectObject(hdc, hbm);
|
|
BitBlt(hdc, 0, 0, 137, 86, _hdcAnimation, 0, 86 * _dwFlagFrame,SRCCOPY);
|
|
SelectObject(hdc, hbmSave);
|
|
|
|
HGADGET hGad = pe->GetDisplayNode();
|
|
if (hGad)
|
|
{
|
|
InvalidateGadget(hGad);
|
|
}
|
|
}
|
|
|
|
if (pv)
|
|
{
|
|
pv->Release();
|
|
}
|
|
DeleteDC(hdc);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// LogonFrame::Initialize
|
|
//
|
|
// Initialize the LogonFrame, create the notification window that is used by SHGina for
|
|
// sending messages to logonui. Set initial state, etc.
|
|
//
|
|
// RETURNS
|
|
// S_OK if everything works out. Failure HRESULT if not. You are pretty much hosed if this fails
|
|
//
|
|
/////////////////////////////////////////
|
|
HRESULT LogonFrame::Initialize(HWND hParent, BOOL fDblBuffer, UINT nCreate)
|
|
{
|
|
// Zero-init members
|
|
_peAccountList = NULL;
|
|
_peViewer = NULL;
|
|
_peRightPanel = NULL;
|
|
_peLeftPanel = NULL;
|
|
_pbPower = NULL;
|
|
_pbUndock = NULL;
|
|
_peHelp = NULL;
|
|
_peMsgArea = NULL;
|
|
_peLogoArea = NULL;
|
|
_pParser = NULL;
|
|
_hwndNotification = NULL;
|
|
_nStatusID = 0;
|
|
_fPreStatusLock = FALSE;
|
|
_nAppState = LAS_PreStatus;
|
|
_pnhh = NULL;
|
|
_fListAvailable = FALSE;
|
|
_pvHotList = NULL;
|
|
_pvList = NULL;
|
|
_hdcAnimation = NULL;
|
|
_dwFlagFrame = 0;
|
|
_nColorDepth = 0;
|
|
|
|
|
|
// Set up notification window
|
|
_hwndNotification = CreateWindowEx(0,
|
|
TEXT("LogonWnd"),
|
|
TEXT("Logon"),
|
|
WS_OVERLAPPED,
|
|
0, 0,
|
|
10,
|
|
10,
|
|
HWND_MESSAGE,
|
|
NULL,
|
|
GetModuleHandleW(NULL),
|
|
NULL);
|
|
|
|
if (SUCCEEDED(CoCreateInstance(CLSID_ShellLogonStatusHost, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(ILogonStatusHost, &g_pILogonStatusHost))))
|
|
{
|
|
g_pILogonStatusHost->Initialize(GetModuleHandleW(NULL), _hwndNotification);
|
|
}
|
|
|
|
// In status (pre) state
|
|
SetState(LAS_PreStatus);
|
|
|
|
// Do base class initialization
|
|
HRESULT hr;
|
|
HDC hDC = NULL;
|
|
|
|
hr = HWNDElement::Initialize(hParent, fDblBuffer ? true : false, nCreate);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
goto Failure;
|
|
}
|
|
|
|
if (!g_fNoAnimations)
|
|
{
|
|
// Initialize
|
|
hDC = GetDC(NULL);
|
|
_nDPI = GetDeviceCaps(hDC, LOGPIXELSY);
|
|
_nColorDepth = GetDeviceCaps(hDC, BITSPIXEL);
|
|
ReleaseDC(NULL, hDC);
|
|
|
|
#ifdef ANIMATE_FLAG
|
|
hDC = GetDC(hParent);
|
|
_hdcAnimation = CreateCompatibleDC(hDC);
|
|
if (_hdcAnimation)
|
|
{
|
|
_hbmpFlags = (HBITMAP)LoadImage(GetModuleHandleW(NULL), MAKEINTRESOURCE(IDB_FLAGSTRIP), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
|
|
if (_hbmpFlags)
|
|
{
|
|
HBITMAP hbmOld = (HBITMAP)SelectObject(_hdcAnimation, _hbmpFlags);
|
|
DeleteObject(hbmOld);
|
|
}
|
|
else
|
|
{
|
|
DeleteDC(_hdcAnimation);
|
|
_hdcAnimation = NULL;
|
|
}
|
|
}
|
|
ReleaseDC(hParent, hDC);
|
|
#endif
|
|
}
|
|
|
|
hr = SetActive(AE_MouseAndKeyboard);
|
|
if (FAILED(hr))
|
|
goto Failure;
|
|
|
|
return S_OK;
|
|
|
|
|
|
Failure:
|
|
|
|
return hr;
|
|
}
|
|
|
|
LogonFrame::~LogonFrame()
|
|
{
|
|
if (_pvHotList)
|
|
_pvHotList->Release();
|
|
if (_pvList)
|
|
_pvList->Release();
|
|
if (_hdcAnimation)
|
|
DeleteDC(_hdcAnimation);
|
|
g_plf = NULL;
|
|
}
|
|
|
|
// Tree is ready. Upon failure, exit which will casuse the app to shutdown
|
|
HRESULT LogonFrame::OnTreeReady(Parser* pParser)
|
|
{
|
|
HRESULT hr;
|
|
|
|
// Cache
|
|
_pParser = pParser;
|
|
|
|
// Cache important descendents
|
|
_peAccountList = (Selector*)FindDescendent(StrToID(L"accountlist"));
|
|
DUIAssert(_peAccountList, "Cannot find account list, check the UI file");
|
|
if (_peAccountList == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
_peLeftPanel = (Element*)FindDescendent(StrToID(L"leftpanel"));
|
|
DUIAssert(_peLeftPanel, "Cannot find left panel, check the UI file");
|
|
if (_peLeftPanel == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
_peViewer = (ScrollViewer*)FindDescendent(StrToID(L"scroller"));
|
|
DUIAssert(_peViewer, "Cannot find scroller list, check the UI file");
|
|
if (_peViewer == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
_peRightPanel = (Selector*)FindDescendent(StrToID(L"rightpanel"));
|
|
DUIAssert(_peRightPanel, "Cannot find account list, check the UI file");
|
|
if (_peRightPanel == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
_peLogoArea = (Element*)FindDescendent(StrToID(L"logoarea"));
|
|
DUIAssert(_peLogoArea, "Cannot find logo area, check the UI file");
|
|
if (_peLogoArea == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
_peMsgArea = (Element*)FindDescendent(StrToID(L"msgarea"));
|
|
DUIAssert(_peMsgArea, "Cannot find welcome area, check the UI file");
|
|
if (_peMsgArea == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
_pbPower = (Button*)FindDescendent(StrToID(L"power"));
|
|
DUIAssert(_pbPower, "Cannot find power button, check the UI file");
|
|
if (_pbPower == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
_pbUndock = (Button*)FindDescendent(StrToID(L"undock"));
|
|
DUIAssert(_pbUndock, "Cannot find undock button, check the UI file");
|
|
if (_pbUndock == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
_peHelp = (Button*)FindDescendent(StrToID(L"help"));
|
|
DUIAssert(_peHelp, "Cannot find help text, check the UI file");
|
|
if (_peHelp == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
_peOptions = FindDescendent(StrToID(L"options"));
|
|
DUIAssert(_peOptions, "Cannot find account list, check the UI file");
|
|
if (_peOptions == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
// check for small window or low color cases and hide some elements that will look bad then.
|
|
HWND hwnd = _pnhh->GetHWND();
|
|
RECT rcClient;
|
|
Element *pEle;
|
|
HDC hDC = GetDC(hwnd);
|
|
_nColorDepth = GetDeviceCaps(hDC, BITSPIXEL);
|
|
_pvHotList = _pParser->GetSheet(L"hotaccountlistss");
|
|
_pvList = _pParser->GetSheet(L"accountlistss");
|
|
|
|
ReleaseDC(hwnd, hDC);
|
|
|
|
GetClientRect(hwnd, &rcClient);
|
|
if (RECTWIDTH(rcClient) < 780 || _nColorDepth <= 8)
|
|
{
|
|
//no animations
|
|
g_fNoAnimations = true;
|
|
|
|
// remove the clouds
|
|
pEle = FindDescendent(StrToID(L"contentcontainer"));
|
|
if (pEle)
|
|
{
|
|
pEle->RemoveLocalValue(ContentProp);
|
|
if (_nColorDepth <= 8)
|
|
{
|
|
pEle->SetBackgroundColor(ORGB (96,128,255));
|
|
}
|
|
}
|
|
|
|
if (_nColorDepth <= 8)
|
|
{
|
|
pEle = FindDescendent(StrToID(L"product"));
|
|
if (pEle)
|
|
{
|
|
pEle->SetBackgroundColor(ORGB (96,128,255));
|
|
}
|
|
}
|
|
}
|
|
|
|
_peViewer->AddListener(this);
|
|
_peAccountList->AddListener(this);
|
|
|
|
// Setup frame labels
|
|
SetPowerButtonLabel(LoadResString(IDS_POWER));
|
|
SetUndockButtonLabel(LoadResString(IDS_UNDOCK));
|
|
|
|
ShowLogoArea();
|
|
HideWelcomeArea();
|
|
|
|
return S_OK;
|
|
|
|
|
|
Failure:
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Set the title element (welcome, please wait..) by string resource id
|
|
void LogonFrame::SetTitle(UINT uRCID)
|
|
{
|
|
WCHAR sz[1024];
|
|
ZeroMemory(&sz, sizeof(sz));
|
|
|
|
if (_nStatusID != uRCID)
|
|
{
|
|
|
|
#ifdef DBG
|
|
int cRead = 0;
|
|
cRead = LoadStringW(_pParser->GetHInstance(), uRCID, sz, DUIARRAYSIZE(sz));
|
|
DUIAssert(cRead, "Could not locate string resource ID");
|
|
#else
|
|
LoadStringW(_pParser->GetHInstance(), uRCID, sz, ARRAYSIZE(sz));
|
|
#endif
|
|
|
|
SetTitle(sz);
|
|
_nStatusID = uRCID;
|
|
}
|
|
}
|
|
|
|
// Set the title element (welcome, please wait..)
|
|
// slightly more involved because there is the shadow element that
|
|
// needs to be changed as well
|
|
void LogonFrame::SetTitle(LPCWSTR pszTitle)
|
|
{
|
|
Element *peTitle = NULL, *peShadow = NULL;
|
|
|
|
peTitle= (Button*)FindDescendent(StrToID(L"welcome"));
|
|
DUIAssert(peTitle, "Cannot find title text, check the UI file");
|
|
|
|
if (peTitle)
|
|
{
|
|
peShadow= (Button*)FindDescendent(StrToID(L"welcomeshadow"));
|
|
DUIAssert(peShadow, "Cannot find title shadow text, check the UI file");
|
|
}
|
|
|
|
if (peTitle && peShadow)
|
|
{
|
|
peTitle->SetContentString(pszTitle);
|
|
peShadow->SetContentString(pszTitle);
|
|
}
|
|
}
|
|
|
|
// Generic events
|
|
void LogonFrame::OnEvent(Event* pEvent)
|
|
{
|
|
if (pEvent->nStage == GMF_BUBBLED) // Bubbled events
|
|
{
|
|
g_pErrorBalloon.HideToolTip();
|
|
if (pEvent->uidType == Button::Click)
|
|
{
|
|
if (pEvent->peTarget == _pbPower)
|
|
{
|
|
// Power button pressed
|
|
OnPower();
|
|
|
|
pEvent->fHandled = true;
|
|
return;
|
|
}
|
|
else if (pEvent->peTarget == _pbUndock)
|
|
{
|
|
// Undock button pressed
|
|
OnUndock();
|
|
|
|
pEvent->fHandled = true;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
HWNDElement::OnEvent(pEvent);
|
|
}
|
|
|
|
// PropertyChanged listened events from various descendents
|
|
// Swap out property sheets for account list based on state of the list
|
|
void LogonFrame::OnListenedPropertyChanged(Element* peFrom, PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew)
|
|
{
|
|
UNREFERENCED_PARAMETER(pvOld);
|
|
UNREFERENCED_PARAMETER(pvNew);
|
|
|
|
{
|
|
if (((peFrom == _peAccountList) && IsProp(Selector::Selection)) ||
|
|
((peFrom == _peViewer) && (IsProp(MouseWithin) || IsProp(KeyWithin))))
|
|
{
|
|
|
|
bool bHot = false;
|
|
// Move to "hot" account list sheet if mouse or key is within viewer or an item is selected
|
|
if (GetState() == LAS_PreStatus || GetState() == LAS_Logon)
|
|
{
|
|
bHot = _peViewer->GetMouseWithin() || _peAccountList->GetSelection();
|
|
}
|
|
|
|
if (!g_fNoAnimations)
|
|
{
|
|
KillFlagAnimation();
|
|
_peAccountList->SetValue(SheetProp, PI_Local, bHot ? _pvHotList : _pvList);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// System events
|
|
|
|
// Watch for input events. If the frame receives them, unselect the list and set keyfocus to it
|
|
void LogonFrame::OnInput(InputEvent* pEvent)
|
|
{
|
|
if (pEvent->nStage == GMF_DIRECT || pEvent->nStage == GMF_BUBBLED)
|
|
{
|
|
if (pEvent->nDevice == GINPUT_KEYBOARD)
|
|
{
|
|
KeyboardEvent* pke = (KeyboardEvent*)pEvent;
|
|
if (pke->nCode == GKEY_DOWN)
|
|
{
|
|
switch (pke->ch)
|
|
{
|
|
case VK_ESCAPE:
|
|
g_pErrorBalloon.HideToolTip();
|
|
SetKeyFocus();
|
|
_peAccountList->SetSelection(NULL);
|
|
pEvent->fHandled = true;
|
|
return;
|
|
|
|
case VK_UP:
|
|
case VK_DOWN:
|
|
if (UserListAvailable())
|
|
{
|
|
if (_peAccountList->GetSelection() == NULL)
|
|
{
|
|
Value* pvChildren;
|
|
ElementList* peList = _peAccountList->GetChildren(&pvChildren);
|
|
if (peList)
|
|
{
|
|
LogonAccount* peAccount = (LogonAccount*)peList->GetItem(0);
|
|
if (peAccount)
|
|
{
|
|
peAccount->SetKeyFocus();
|
|
_peAccountList->SetSelection(peAccount);
|
|
}
|
|
}
|
|
pvChildren->Release();
|
|
pEvent->fHandled = true;
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
HWNDElement::OnInput(pEvent);
|
|
}
|
|
|
|
void LogonFrame::OnPropertyChanged(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew)
|
|
{
|
|
if (IsProp(KeyFocused))
|
|
{
|
|
if (pvNew->GetBool())
|
|
{
|
|
// Unselect items from account list if pressed on background
|
|
_peAccountList->SetSelection(NULL);
|
|
}
|
|
}
|
|
|
|
HWNDElement::OnPropertyChanged(ppi, iIndex, pvOld, pvNew);
|
|
}
|
|
|
|
Element* LogonFrame::GetAdjacent(Element* peFrom, int iNavDir, NavReference const* pnr, bool bKeyable)
|
|
{
|
|
Element* peFound = HWNDElement::GetAdjacent(peFrom, iNavDir, pnr, bKeyable);
|
|
|
|
if ((peFound == this))
|
|
{
|
|
// Don't let the frame show up in the tab order. Just repeat the search when we encounter the frame
|
|
return HWNDElement::GetAdjacent(this, iNavDir, pnr, bKeyable);
|
|
}
|
|
|
|
return peFound;
|
|
}
|
|
|
|
// Add an account to the frame list
|
|
HRESULT LogonFrame::AddAccount(LPCWSTR pszPicture, BOOL fPicRes, LPCWSTR pszName, LPCWSTR pszUsername, LPCWSTR pszHint,
|
|
BOOL fPwdNeeded, BOOL fLoggedOn, OUT LogonAccount **ppla)
|
|
{
|
|
HRESULT hr;
|
|
LogonAccount* pla = NULL;
|
|
|
|
if (!_pParser)
|
|
{
|
|
hr = E_FAIL;
|
|
goto Failure;
|
|
}
|
|
|
|
// Build up an account and insert into selection list
|
|
hr = _pParser->CreateElement(L"accountitem", NULL, (Element**)&pla);
|
|
if (FAILED(hr))
|
|
goto Failure;
|
|
|
|
hr = pla->OnTreeReady(pszPicture, fPicRes, pszName, pszUsername, pszHint, fPwdNeeded, fLoggedOn, GetHInstance());
|
|
if (FAILED(hr))
|
|
goto Failure;
|
|
|
|
hr = _peAccountList->Add(pla);
|
|
if (FAILED(hr))
|
|
goto Failure;
|
|
|
|
if (pla)
|
|
{
|
|
SetElementAccessability(pla, true, ROLE_SYSTEM_LISTITEM, pszUsername);
|
|
}
|
|
|
|
if (_nColorDepth <= 8)
|
|
{
|
|
pla->SetBackgroundColor(ORGB (96,128,255));
|
|
|
|
Element *pEle;
|
|
pEle = pla->FindDescendent(StrToID(L"userpane"));
|
|
if (pEle)
|
|
{
|
|
pEle->SetBorderColor(ORGB (96,128,255));
|
|
}
|
|
}
|
|
|
|
if (ppla)
|
|
*ppla = pla;
|
|
|
|
return S_OK;
|
|
|
|
|
|
Failure:
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Passed authentication, log user on
|
|
HRESULT LogonFrame::OnLogUserOn(LogonAccount* pla)
|
|
{
|
|
StartDefer();
|
|
|
|
#ifdef GADGET_ENABLE_GDIPLUS
|
|
|
|
// Disable status so that it can't be clicked on anymore
|
|
pla->DisableStatus(0);
|
|
pla->DisableStatus(1);
|
|
|
|
// Clear list of logon accounts except the one logging on
|
|
Value* pvChildren;
|
|
ElementList* peList = _peAccountList->GetChildren(&pvChildren);
|
|
if (peList)
|
|
{
|
|
LogonAccount* peAccount;
|
|
for (UINT i = 0; i < peList->GetSize(); i++)
|
|
{
|
|
peAccount = (LogonAccount*)peList->GetItem(i);
|
|
|
|
if (peAccount != pla)
|
|
{
|
|
peAccount->SetLogonState(LS_Denied);
|
|
}
|
|
else
|
|
{
|
|
peAccount->SetLogonState(LS_Granted);
|
|
peAccount->InsertStatus(0);
|
|
peAccount->RemoveStatus(1);
|
|
}
|
|
|
|
// Account account items are disabled
|
|
peAccount->SetEnabled(false);
|
|
}
|
|
}
|
|
pvChildren->Release();
|
|
|
|
FxLogUserOn(pla);
|
|
|
|
// Set frame status
|
|
SetStatus(LoadResString(IDS_LOGGINGON));
|
|
|
|
#else
|
|
|
|
// Set keyfocus back to frame so it isn't pushed anywhere when controls are removed.
|
|
// This will also cause a remove of the password panel from the current account
|
|
SetKeyFocus();
|
|
|
|
// Disable status so that it can't be clicked on anymore
|
|
pla->DisableStatus(0);
|
|
pla->DisableStatus(1);
|
|
|
|
// Clear list of logon accounts except the one logging on
|
|
Value* pvChildren;
|
|
ElementList* peList = _peAccountList->GetChildren(&pvChildren);
|
|
if (peList)
|
|
{
|
|
LogonAccount* peAccount;
|
|
for (UINT i = 0; i < peList->GetSize(); i++)
|
|
{
|
|
peAccount = (LogonAccount*)peList->GetItem(i);
|
|
|
|
if (peAccount != pla)
|
|
{
|
|
peAccount->SetLayoutPos(LP_None);
|
|
peAccount->SetLogonState(LS_Denied);
|
|
}
|
|
else
|
|
{
|
|
peAccount->SetLogonState(LS_Granted);
|
|
peAccount->InsertStatus(0);
|
|
peAccount->RemoveStatus(1);
|
|
}
|
|
|
|
// Account account items are disabled
|
|
peAccount->SetEnabled(false);
|
|
}
|
|
}
|
|
pvChildren->Release();
|
|
|
|
// Hide option buttons
|
|
HidePowerButton();
|
|
HideUndockButton();
|
|
|
|
// Set frame status
|
|
SetStatus(LoadResString(IDS_LOGGINGON));
|
|
|
|
_peViewer->RemoveListener(this);
|
|
_peAccountList->RemoveListener(this);
|
|
|
|
#endif
|
|
|
|
EndDefer();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT LogonFrame::OnPower()
|
|
{
|
|
DUITrace("LogonUI: LogonFrame::OnPower()\n");
|
|
|
|
TurnOffComputer();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT LogonFrame::OnUndock()
|
|
{
|
|
DUITrace("LogonUI: LogonFrame::OnUndock()\n");
|
|
|
|
UndockComputer();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// LogonFrame::SetButtonLabels
|
|
//
|
|
// If there is a friendly name of the computer stored in the computer name description,
|
|
// grab it and change the "Turn off" and "Undock" options to include the compute rname
|
|
//
|
|
// RETURNS
|
|
// nothing
|
|
//
|
|
/////////////////////////////////////////
|
|
void LogonFrame::SetButtonLabels()
|
|
{
|
|
WCHAR szComputerName[MAX_COMPUTERDESC_LENGTH + 1] = {0};
|
|
DWORD cchComputerName = MAX_COMPUTERDESC_LENGTH + 1;
|
|
|
|
if ( _pbPower && SUCCEEDED(SHGetComputerDisplayName(NULL, SGCDNF_DESCRIPTIONONLY, szComputerName, cchComputerName)))
|
|
{
|
|
WCHAR szCommand[MAX_COMPUTERDESC_LENGTH + 50], szRes[50];
|
|
|
|
LoadStringW(g_plf->GetHInstance(), IDS_POWERNAME, szRes, DUIARRAYSIZE(szRes));
|
|
wsprintf(szCommand, szRes, szComputerName);
|
|
SetPowerButtonLabel(szCommand);
|
|
|
|
LoadStringW(g_plf->GetHInstance(), IDS_UNDOCKNAME, szRes, DUIARRAYSIZE(szRes));
|
|
wsprintf(szCommand, szRes, szComputerName);
|
|
SetUndockButtonLabel(szCommand);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
// Logon Application State Transitions
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// LogonFrame::EnterPreStatusMode
|
|
//
|
|
// SHGina has sent a message telling logonui to enter the pre-status
|
|
// mode or we are starting up in status mode. Hide items that should
|
|
// not be displayed when in this state (power off, account list, user
|
|
// instructions, etc).
|
|
//
|
|
// RETURNS
|
|
// nothing
|
|
//
|
|
/////////////////////////////////////////
|
|
void LogonFrame::EnterPreStatusMode(BOOL fLock)
|
|
{
|
|
// If currently locked, ignore call
|
|
if (IsPreStatusLock())
|
|
{
|
|
DUIAssert(!fLock, "Receiving a lock while already within pre-Status lock");
|
|
return;
|
|
}
|
|
|
|
if (fLock)
|
|
{
|
|
LogonAccount *pAccount;
|
|
// Entering pre-Status mode with "lock", cannot exit to logon state without an unlock
|
|
_fPreStatusLock = TRUE;
|
|
pAccount = static_cast<LogonAccount*>(_peAccountList->GetSelection());
|
|
if (pAccount != NULL)
|
|
{
|
|
lstrcpynW(szLastSelectedName, pAccount->GetUsername(), ARRAYSIZE(szLastSelectedName));
|
|
}
|
|
}
|
|
|
|
if (GetState() == LAS_Hide)
|
|
{
|
|
_pnhh->ShowWindow();
|
|
SetWindowPos(_pnhh->GetHWND(), NULL, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SWP_NOMOVE | SWP_NOZORDER );
|
|
|
|
}
|
|
|
|
StartDefer();
|
|
|
|
SetKeyFocus(); // Removes selection
|
|
|
|
HidePowerButton();
|
|
HideUndockButton();
|
|
ShowLogoArea();
|
|
HideWelcomeArea();
|
|
HideAccountPanel();
|
|
|
|
Element *pe;
|
|
pe = FindDescendent(StrToID(L"instruct"));
|
|
DUIAssertNoMsg(pe);
|
|
pe->SetVisible(FALSE);
|
|
|
|
SetStatus(LoadResString(IDS_WINDOWSNAME));
|
|
|
|
EndDefer();
|
|
|
|
// Set state
|
|
SetState(LAS_PreStatus);
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// LogonFrame::EnterLogonMode
|
|
//
|
|
// SHGina has sent a message telling logonui to enter the logon mode.
|
|
// this means to build and display the user list. If we are re-entering
|
|
// logon mode from another mode, the user list will already exist and we
|
|
// should just set everything back to the pending state.
|
|
//
|
|
// EnterLogonMode also sets up the undock and power off buttons based on
|
|
// whether those options are allowed.
|
|
//
|
|
//
|
|
// RETURNS
|
|
// nothing
|
|
//
|
|
/////////////////////////////////////////
|
|
void LogonFrame::EnterLogonMode(BOOL fUnLock)
|
|
{
|
|
// If currently locked, ignore call if not to unlock
|
|
if (IsPreStatusLock())
|
|
{
|
|
if (fUnLock)
|
|
{
|
|
// Exiting pre-Status mode lock
|
|
_fPreStatusLock = FALSE;
|
|
}
|
|
else
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
DUIAssert(!fUnLock, "Receiving an unlock while not within pre-Status lock");
|
|
}
|
|
|
|
DUIAssert(GetState() != LAS_Hide, "Cannot enter logon state from hidden state");
|
|
|
|
ResetTheme();
|
|
|
|
Element* pe;
|
|
LogonAccount* plaAutoSelect = NULL;
|
|
|
|
StartDefer();
|
|
|
|
PokeComCtl32();
|
|
|
|
// Retrieve data from backend if not populated
|
|
if (UserListAvailable())
|
|
{
|
|
ResetUserList();
|
|
}
|
|
else
|
|
{
|
|
// Cache password field atoms for quicker identification (static)
|
|
LogonAccount::idPwdGo = AddAtomW(L"go");
|
|
|
|
LogonAccount::idPwdInfo = AddAtomW(L"info");
|
|
|
|
// Create password panel
|
|
Element* pePwdPanel;
|
|
_pParser->CreateElement(L"passwordpanel", NULL, &pePwdPanel);
|
|
DUIAssert(pePwdPanel, "Can't create password panel");
|
|
|
|
// Cache password panel edit control
|
|
Edit* pePwdEdit = (Edit*)pePwdPanel->FindDescendent(StrToID(L"password"));
|
|
DUIAssert(pePwdPanel, "Can't create password edit control");
|
|
|
|
// Cache password panel info button
|
|
Button* pbPwdInfo = (Button*)pePwdPanel->FindDescendent(StrToID(L"info"));
|
|
DUIAssert(pePwdPanel, "Can't create password info button");
|
|
|
|
// Cache password panel keyboard element
|
|
Element* peKbdIcon = (Button*)pePwdPanel->FindDescendent(StrToID(L"keyboard"));
|
|
DUIAssert(pePwdPanel, "Can't create password keyboard icon");
|
|
|
|
LogonAccount::InitPasswordPanel(pePwdPanel, pePwdEdit, pbPwdInfo, peKbdIcon );
|
|
}
|
|
|
|
BuildAccountList(this, &plaAutoSelect);
|
|
|
|
if (szLastSelectedName[0] != L'\0')
|
|
{
|
|
LogonAccount *pAccount;
|
|
pAccount = InternalFindNamedUser(szLastSelectedName);
|
|
if (pAccount != NULL)
|
|
{
|
|
plaAutoSelect = pAccount;
|
|
}
|
|
szLastSelectedName[0] = L'\0';
|
|
}
|
|
|
|
if (IsShutdownAllowed())
|
|
{
|
|
ShowPowerButton();
|
|
}
|
|
else
|
|
{
|
|
HidePowerButton();
|
|
}
|
|
|
|
if (IsUndockAllowed())
|
|
{
|
|
ShowUndockButton();
|
|
}
|
|
else
|
|
{
|
|
HideUndockButton();
|
|
}
|
|
|
|
pe = FindDescendent(StrToID(L"instruct"));
|
|
DUIAssertNoMsg(pe);
|
|
pe->SetVisible(TRUE);
|
|
|
|
|
|
pe = FindDescendent(StrToID(L"product"));
|
|
DUIAssertNoMsg(pe);
|
|
pe->StopAnimation(ANI_AlphaType);
|
|
pe->RemoveLocalValue(BackgroundProp);
|
|
|
|
// Account list viewer
|
|
|
|
ShowAccountPanel();
|
|
|
|
SetTitle(IDS_WELCOME);
|
|
SetStatus(LoadResString(IDS_BEGIN));
|
|
|
|
if (!plaAutoSelect)
|
|
{
|
|
SetKeyFocus();
|
|
}
|
|
|
|
EndDefer();
|
|
|
|
// Set state
|
|
SetState(LAS_Logon);
|
|
|
|
// Set auto-select item, if exists
|
|
if (plaAutoSelect)
|
|
{
|
|
plaAutoSelect->SetKeyFocus();
|
|
_peAccountList->SetSelection(plaAutoSelect);
|
|
}
|
|
|
|
SetButtonLabels();
|
|
SetForegroundWindow(_pnhh->GetHWND());
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// LogonFrame::EnterPostStatusMode
|
|
//
|
|
// SHGina has sent a message telling logonui that the authentication has succeeded
|
|
// and we should now go into the post status mode. LogonFrame::OnLogUserOn has already
|
|
// started the animations for this.
|
|
//
|
|
// RETURNS
|
|
// nothing
|
|
//
|
|
/////////////////////////////////////////
|
|
void LogonFrame::EnterPostStatusMode()
|
|
{
|
|
// Set state
|
|
SetState(LAS_PostStatus);
|
|
|
|
Element *pe;
|
|
pe = FindDescendent(StrToID(L"instruct"));
|
|
DUIAssertNoMsg(pe);
|
|
pe->SetVisible(FALSE);
|
|
|
|
//animation was started in OnLogUserOn
|
|
ShowWelcomeArea();
|
|
HideLogoArea();
|
|
}
|
|
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// LogonFrame::EnterHideMode
|
|
//
|
|
// SHGina has sent a message telling logonui to hide.
|
|
//
|
|
// RETURNS
|
|
// nothing
|
|
//
|
|
/////////////////////////////////////////
|
|
void LogonFrame::EnterHideMode()
|
|
{
|
|
// Set state
|
|
SetState(LAS_Hide);
|
|
|
|
if (_pnhh)
|
|
{
|
|
_pnhh->HideWindow();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// LogonFrame::EnterDoneMode
|
|
//
|
|
// SHGina has sent a message telling logonui to exit.
|
|
//
|
|
// RETURNS
|
|
// nothing
|
|
//
|
|
/////////////////////////////////////////
|
|
void LogonFrame::EnterDoneMode()
|
|
{
|
|
// Set state
|
|
SetState(LAS_Done);
|
|
|
|
if (_pnhh)
|
|
{
|
|
_pnhh->DestroyWindow();
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// LogonFrame::ResetUserList
|
|
//
|
|
// Delete all of the users in the user list so that it can be rebuilt
|
|
//
|
|
// RETURNS
|
|
// nothing
|
|
//
|
|
/////////////////////////////////////////
|
|
void LogonFrame::ResetUserList()
|
|
{
|
|
if (UserListAvailable())
|
|
{
|
|
// reset the candidate to NULL
|
|
LogonAccount::ClearCandidate();
|
|
|
|
// remove of the password panel from the current account (if any)
|
|
SetKeyFocus();
|
|
|
|
//fix up the existing list to get us back into logon mode
|
|
Value* pvChildren;
|
|
ElementList* peList = _peAccountList->GetChildren(&pvChildren);
|
|
|
|
if (peList)
|
|
{
|
|
LogonAccount* peAccount;
|
|
for (int i = peList->GetSize() - 1; i >= 0; i--)
|
|
{
|
|
peAccount = (LogonAccount*)peList->GetItem(i);
|
|
peAccount->Destroy();
|
|
}
|
|
}
|
|
pvChildren->Release();
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// LogonFrame::InteractiveLogonRequest
|
|
//
|
|
// SHGina has sent an InteractiveLogonRequest. We should look for the user
|
|
// that was passed in and if found, try to log them in.
|
|
//
|
|
// RETURNS
|
|
// LRESULT indicating success or failure of finding htem and logging them in.
|
|
//
|
|
/////////////////////////////////////////
|
|
LRESULT LogonFrame::InteractiveLogonRequest(LPCWSTR pszUsername, LPCWSTR pszPassword)
|
|
{
|
|
LRESULT lResult = 0;
|
|
LogonAccount *pla;
|
|
pla = FindNamedUser(pszUsername);
|
|
|
|
if (pla)
|
|
{
|
|
if (pla->OnAuthenticateUser(pszPassword))
|
|
{
|
|
lResult = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
lResult = ERROR_ACCESS_DENIED;
|
|
}
|
|
}
|
|
return(lResult);
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// LogonFrame::InternalFindNamedUser
|
|
//
|
|
// Find a user in the LogonAccount list with the
|
|
// provided username (logon name).
|
|
//
|
|
// RETURNS
|
|
// The LogonAccount* for the indicated user or NULL if
|
|
// not found
|
|
//
|
|
/////////////////////////////////////////
|
|
LogonAccount* LogonFrame::InternalFindNamedUser(LPCWSTR pszUsername)
|
|
|
|
{
|
|
LogonAccount *plaResult = NULL;
|
|
Value* pvChildren;
|
|
|
|
ElementList* peList = _peAccountList->GetChildren(&pvChildren);
|
|
if (peList)
|
|
{
|
|
for (UINT i = 0; i < peList->GetSize(); i++)
|
|
{
|
|
DUIAssert(peList->GetItem(i)->GetClassInfo() == LogonAccount::Class, "Account list must contain LogonAccount objects");
|
|
|
|
LogonAccount* pla = (LogonAccount*)peList->GetItem(i);
|
|
|
|
if (pla)
|
|
{
|
|
if (lstrcmpi(pla->GetUsername(), pszUsername) == 0)
|
|
{
|
|
plaResult = pla;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pvChildren->Release();
|
|
return plaResult;
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// LogonFrame::FindNamedUser
|
|
//
|
|
// Find a user in the LogonAccount list with the
|
|
// provided username (logon name).
|
|
//
|
|
// RETURNS
|
|
// The LogonAccount* for the indicated user or NULL if
|
|
// not found
|
|
//
|
|
/////////////////////////////////////////
|
|
LogonAccount *LogonFrame::FindNamedUser(LPCWSTR pszUsername)
|
|
{
|
|
|
|
// Early out if: no user list available
|
|
// not in logon mode (showing user list)
|
|
|
|
if (!UserListAvailable() || (GetState() != LAS_Logon))
|
|
{
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
return(InternalFindNamedUser(pszUsername));
|
|
}
|
|
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// LogonFrame::UpdateUserStatus
|
|
//
|
|
// Iterate the list of user accounts and call LogonAccount::UpdateNotifications
|
|
// for each one. This will result in them updating the unread mail count and
|
|
// logon status for each of the logon accounts.
|
|
// Pass fRefreshAll through to UpdateApplications
|
|
//
|
|
/////////////////////////////////////////
|
|
|
|
void LogonFrame::UpdateUserStatus(BOOL fRefreshAll)
|
|
{
|
|
Value* pvChildren;
|
|
static fUpdating = false;
|
|
// Early out if: no user list available
|
|
// not in logon mode (showing user list)
|
|
|
|
if (!UserListAvailable() || (GetState() != LAS_Logon) || fUpdating)
|
|
return;
|
|
|
|
fUpdating = true;
|
|
StartDefer();
|
|
|
|
ElementList* peList = _peAccountList->GetChildren(&pvChildren);
|
|
if (peList)
|
|
{
|
|
for (UINT i = 0; i < peList->GetSize(); i++)
|
|
{
|
|
DUIAssert(peList->GetItem(i)->GetClassInfo() == LogonAccount::Class, "Account list must contain LogonAccount objects");
|
|
|
|
LogonAccount* pla = (LogonAccount*)peList->GetItem(i);
|
|
|
|
if (pla)
|
|
{
|
|
pla->UpdateNotifications(fRefreshAll);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (IsUndockAllowed())
|
|
{
|
|
ShowUndockButton();
|
|
}
|
|
else
|
|
{
|
|
HideUndockButton();
|
|
}
|
|
|
|
pvChildren->Release();
|
|
EndDefer();
|
|
fUpdating = false;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// LogonFrame::SelectUser
|
|
//
|
|
//
|
|
//
|
|
/////////////////////////////////////////
|
|
|
|
void LogonFrame::SelectUser(LPCWSTR pszUsername)
|
|
{
|
|
LogonAccount *pla;
|
|
|
|
pla = FindNamedUser(pszUsername);
|
|
if (pla != NULL)
|
|
{
|
|
pla->OnAuthenticatedUser();
|
|
}
|
|
else
|
|
{
|
|
LogonAccount::ClearCandidate();
|
|
EnterPostStatusMode();
|
|
HidePowerButton();
|
|
HideUndockButton();
|
|
HideAccountPanel();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// LogonFrame::Resize
|
|
//
|
|
//
|
|
//
|
|
/////////////////////////////////////////
|
|
|
|
void LogonFrame::Resize(BOOL fWorkArea)
|
|
{
|
|
RECT rc;
|
|
SIZE size;
|
|
static BOOL fWorkAreaChanged = FALSE;
|
|
|
|
if (fWorkArea)
|
|
{
|
|
fWorkAreaChanged = TRUE;
|
|
}
|
|
|
|
if (fWorkAreaChanged)
|
|
{
|
|
SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
|
|
size.cx = rc.right - rc.left;
|
|
size.cy = rc.bottom - rc.top;
|
|
}
|
|
else
|
|
{
|
|
rc.left = 0;
|
|
rc.top = 0;
|
|
size.cx = GetSystemMetrics(SM_CXSCREEN);
|
|
size.cy = GetSystemMetrics(SM_CYSCREEN);
|
|
}
|
|
|
|
SetWindowPos(_pnhh->GetHWND(),
|
|
NULL,
|
|
rc.left,
|
|
rc.top,
|
|
size.cx,
|
|
size.cy,
|
|
SWP_NOACTIVATE | SWP_NOZORDER | SWP_ASYNCWINDOWPOS);
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// LogonFrame::SetAnimations
|
|
//
|
|
//
|
|
//
|
|
/////////////////////////////////////////
|
|
|
|
void LogonFrame::SetAnimations(BOOL fAnimations)
|
|
{
|
|
g_fNoAnimations = !fAnimations;
|
|
if (fAnimations)
|
|
{
|
|
EnableAnimations();
|
|
}
|
|
else
|
|
{
|
|
DisableAnimations();
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
// Property definitions
|
|
|
|
////////////////////////////////////////////////////////
|
|
// ClassInfo (must appear after property definitions)
|
|
|
|
// Define class info with type and base type, set static class pointer
|
|
IClassInfo* LogonFrame::Class = NULL;
|
|
HRESULT LogonFrame::Register()
|
|
{
|
|
return ClassInfo<LogonFrame,HWNDElement>::Register(L"LogonFrame", NULL, 0);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////
|
|
//
|
|
HRESULT LogonAccountList::Create(OUT Element** ppElement)
|
|
{
|
|
*ppElement = NULL;
|
|
|
|
LogonAccountList* plal = HNew<LogonAccountList>();
|
|
if (!plal)
|
|
return E_OUTOFMEMORY;
|
|
|
|
HRESULT hr = plal->Initialize();
|
|
if (FAILED(hr))
|
|
{
|
|
plal->Destroy();
|
|
return hr;
|
|
}
|
|
|
|
*ppElement = plal;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void LogonAccountList::OnPropertyChanged(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew)
|
|
{
|
|
#ifdef GADGET_ENABLE_GDIPLUS
|
|
if (IsProp(MouseWithin))
|
|
{
|
|
if (pvNew->GetBool())
|
|
FxMouseWithin(fdIn);
|
|
else
|
|
FxMouseWithin(fdOut);
|
|
}
|
|
#endif // GADGET_ENABLE_GDIPLUS
|
|
|
|
Selector::OnPropertyChanged(ppi, iIndex, pvOld, pvNew);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
// Property definitions
|
|
|
|
////////////////////////////////////////////////////////
|
|
// ClassInfo (must appear after property definitions)
|
|
|
|
// Define class info with type and base type, set static class pointer
|
|
IClassInfo* LogonAccountList::Class = NULL;
|
|
HRESULT LogonAccountList::Register()
|
|
{
|
|
return ClassInfo<LogonAccountList,Selector>::Register(L"LogonAccountList", NULL, 0);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////
|
|
//
|
|
// LogonAccount
|
|
//
|
|
////////////////////////////////////////////////////////
|
|
|
|
ATOM LogonAccount::idPwdGo = NULL;
|
|
ATOM LogonAccount::idPwdInfo = NULL;
|
|
Element* LogonAccount::_pePwdPanel = NULL;
|
|
Edit* LogonAccount::_pePwdEdit = NULL;
|
|
Button* LogonAccount::_pbPwdInfo = NULL;
|
|
Element* LogonAccount::_peKbdIcon = NULL;
|
|
LogonAccount* LogonAccount::_peCandidate = NULL;
|
|
|
|
HRESULT LogonAccount::Create(OUT Element** ppElement)
|
|
{
|
|
*ppElement = NULL;
|
|
|
|
LogonAccount* pla = HNew<LogonAccount>();
|
|
if (!pla)
|
|
return E_OUTOFMEMORY;
|
|
|
|
HRESULT hr = pla->Initialize();
|
|
if (FAILED(hr))
|
|
{
|
|
pla->Destroy();
|
|
return hr;
|
|
}
|
|
|
|
*ppElement = pla;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT LogonAccount::Initialize()
|
|
{
|
|
// Zero-init members
|
|
_pbStatus[0] = NULL;
|
|
_pbStatus[1] = NULL;
|
|
_pvUsername = NULL;
|
|
_pvHint = NULL;
|
|
_fPwdNeeded = (BOOL)-1; // uninitialized
|
|
_fLoggedOn = FALSE;
|
|
_fHasPwdPanel = FALSE;
|
|
|
|
// Do base class initialization
|
|
HRESULT hr = Button::Initialize(AE_MouseAndKeyboard);
|
|
if (FAILED(hr))
|
|
goto Failure;
|
|
|
|
// Initialize
|
|
|
|
// TODO: Additional LogonAccount initialization code here
|
|
|
|
return S_OK;
|
|
|
|
|
|
Failure:
|
|
|
|
return hr;
|
|
}
|
|
|
|
LogonAccount::~LogonAccount()
|
|
{
|
|
// Free resources
|
|
if (_pvUsername)
|
|
{
|
|
_pvUsername->Release();
|
|
_pvUsername = NULL;
|
|
}
|
|
|
|
if (_pvHint)
|
|
{
|
|
_pvHint->Release();
|
|
_pvHint = NULL;
|
|
}
|
|
|
|
// TODO: Account destruction cleanup
|
|
}
|
|
|
|
void LogonAccount::SetStatus(UINT nLine, LPCWSTR psz)
|
|
{
|
|
if (psz)
|
|
{
|
|
_pbStatus[nLine]->SetContentString(psz);
|
|
SetElementAccessability(_pbStatus[nLine], true, ROLE_SYSTEM_LINK, psz);
|
|
}
|
|
}
|
|
|
|
// Tree is ready
|
|
HRESULT LogonAccount::OnTreeReady(LPCWSTR pszPicture, BOOL fPicRes, LPCWSTR pszName, LPCWSTR pszUsername, LPCWSTR pszHint,
|
|
BOOL fPwdNeeded, BOOL fLoggedOn, HINSTANCE hInst)
|
|
{
|
|
HRESULT hr;
|
|
Element* pePicture = NULL;
|
|
Element* peName = NULL;
|
|
Value* pv = NULL;
|
|
|
|
UNREFERENCED_PARAMETER(fPwdNeeded);
|
|
|
|
StartDefer();
|
|
|
|
// Cache important descendents
|
|
_pbStatus[0] = (Button*)FindDescendent(StrToID(L"status0"));
|
|
DUIAssert(_pbStatus[0], "Cannot find account list, check the UI file");
|
|
if (_pbStatus[0] == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
_pbStatus[1] = (Button*)FindDescendent(StrToID(L"status1"));
|
|
DUIAssert(_pbStatus[1], "Cannot find account list, check the UI file");
|
|
if (_pbStatus[1] == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
// Locate descendents and populate
|
|
pePicture = FindDescendent(StrToID(L"picture"));
|
|
DUIAssert(pePicture, "Cannot find account list, check the UI file");
|
|
if (pePicture == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
// CreateGraphic handles NULL bitmaps
|
|
pv = Value::CreateGraphic(pszPicture, GRAPHIC_NoBlend, 0, 0, 0, (fPicRes) ? hInst : 0);
|
|
if (pv)
|
|
{
|
|
// Our preferred size is 1/2 inch (36pt) square.
|
|
USHORT cx = (USHORT)LogonFrame::PointToPixel(36);
|
|
USHORT cy = cx;
|
|
|
|
Graphic* pg = pv->GetGraphic();
|
|
|
|
// If it's not square, scale the smaller dimension
|
|
// to maintain the aspect ratio.
|
|
if (pg->cx > pg->cy)
|
|
{
|
|
cy = (USHORT)MulDiv(cx, pg->cy, pg->cx);
|
|
}
|
|
else if (pg->cy > pg->cx)
|
|
{
|
|
cx = (USHORT)MulDiv(cy, pg->cx, pg->cy);
|
|
}
|
|
|
|
// Did anything change?
|
|
if (cx != pg->cx || cy != pg->cy)
|
|
{
|
|
// Reload the graphic
|
|
pv->Release();
|
|
pv = Value::CreateGraphic(pszPicture, GRAPHIC_NoBlend, 0, cx, cy, (fPicRes) ? hInst : 0);
|
|
}
|
|
}
|
|
if (!pv)
|
|
{
|
|
// if we can't get the picture, use a default one
|
|
pv = Value::CreateGraphic(MAKEINTRESOURCEW(IDB_USER0), GRAPHIC_NoBlend, 0, (USHORT)LogonFrame::PointToPixel(36), (USHORT)LogonFrame::PointToPixel(36), hInst);
|
|
if (!pv)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
}
|
|
|
|
hr = pePicture->SetValue(Element::ContentProp, PI_Local, pv);
|
|
if (FAILED(hr))
|
|
goto Failure;
|
|
|
|
pv->Release();
|
|
pv = NULL;
|
|
|
|
// Name
|
|
peName = FindDescendent(StrToID(L"username"));
|
|
DUIAssert(peName, "Cannot find account list, check the UI file");
|
|
if (peName == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
hr = peName->SetContentString(pszName);
|
|
if (FAILED(hr))
|
|
goto Failure;
|
|
|
|
// Store members, will be released in destructor
|
|
if (pszUsername)
|
|
{
|
|
_pvUsername = Value::CreateString(pszUsername);
|
|
if (!_pvUsername)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
}
|
|
|
|
if (pszHint)
|
|
{
|
|
_pvHint = Value::CreateString(pszHint);
|
|
if (!_pvHint)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
}
|
|
|
|
_fLoggedOn = fLoggedOn;
|
|
|
|
EndDefer();
|
|
|
|
return S_OK;
|
|
|
|
|
|
Failure:
|
|
|
|
EndDefer();
|
|
|
|
if (pv)
|
|
pv->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Generic events
|
|
void LogonAccount::OnEvent(Event* pEvent)
|
|
{
|
|
if (pEvent->nStage == GMF_DIRECT) // Direct events
|
|
{
|
|
// Watch for click events initiated by LogonAccounts only
|
|
// if we are not logging someone on
|
|
if (pEvent->uidType == Button::Click)
|
|
{
|
|
if (pEvent->peTarget == this)
|
|
{
|
|
if (IsPasswordBlank())
|
|
{
|
|
// No password needed, attempt logon
|
|
OnAuthenticateUser();
|
|
}
|
|
|
|
pEvent->fHandled = true;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else if (pEvent->nStage == GMF_BUBBLED) // Bubbled events
|
|
{
|
|
if (pEvent->uidType == Button::Click)
|
|
{
|
|
if (idPwdGo && (pEvent->peTarget->GetID() == idPwdGo))
|
|
{
|
|
// Attempt logon
|
|
OnAuthenticateUser();
|
|
pEvent->fHandled = true;
|
|
return;
|
|
}
|
|
else if (idPwdInfo && (pEvent->peTarget->GetID() == idPwdInfo))
|
|
{
|
|
// Retrieve hint
|
|
OnHintSelect();
|
|
pEvent->fHandled = true;
|
|
return;
|
|
}
|
|
else if (pEvent->peTarget == _pbStatus[0])
|
|
{
|
|
// Retrieve status info
|
|
OnStatusSelect(0);
|
|
pEvent->fHandled = true;
|
|
return;
|
|
}
|
|
else if (pEvent->peTarget == _pbStatus[1])
|
|
{
|
|
// Retrieve status info
|
|
OnStatusSelect(1);
|
|
pEvent->fHandled = true;
|
|
return;
|
|
}
|
|
}
|
|
else if (pEvent->uidType == Edit::Enter)
|
|
{
|
|
if (_pePwdEdit && pEvent->peTarget == _pePwdEdit)
|
|
{
|
|
// Attempt logon
|
|
OnAuthenticateUser();
|
|
pEvent->fHandled = true;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
Button::OnEvent(pEvent);
|
|
}
|
|
|
|
// System events
|
|
void LogonAccount::OnInput(InputEvent* pEvent)
|
|
{
|
|
KeyboardEvent* pke = (KeyboardEvent*)pEvent;
|
|
|
|
if (pke->nDevice == GINPUT_KEYBOARD && pke->nCode == GKEY_DOWN)
|
|
{
|
|
g_pErrorBalloon.HideToolTip();
|
|
}
|
|
LayoutCheckHandler(LAYOUT_DEF_USER);
|
|
Button::OnInput(pEvent);
|
|
}
|
|
|
|
void LogonAccount::OnPropertyChanged(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew)
|
|
{
|
|
#ifdef GADGET_ENABLE_GDIPLUS
|
|
// MouseWithin must be before Selected
|
|
if (IsProp(MouseWithin))
|
|
{
|
|
if (pvNew->GetBool())
|
|
FxMouseWithin(fdIn);
|
|
else
|
|
FxMouseWithin(fdOut);
|
|
}
|
|
#endif
|
|
|
|
if (IsProp(Selected))
|
|
{
|
|
if (pvNew->GetBool())
|
|
InsertPasswordPanel();
|
|
else
|
|
RemovePasswordPanel();
|
|
}
|
|
|
|
Button::OnPropertyChanged(ppi, iIndex, pvOld, pvNew);
|
|
}
|
|
|
|
BOOL LogonAccount::IsPasswordBlank()
|
|
{
|
|
if (_fPwdNeeded == (BOOL)-1)
|
|
{
|
|
// assume a password is needed
|
|
_fPwdNeeded = TRUE;
|
|
|
|
if (_pvUsername)
|
|
{
|
|
LPTSTR pszUsername;
|
|
|
|
pszUsername = _pvUsername->GetString();
|
|
if (pszUsername)
|
|
{
|
|
ILogonUser* pUser;
|
|
|
|
if (SUCCEEDED(GetLogonUserByLogonName(pszUsername, &pUser)))
|
|
{
|
|
VARIANT_BOOL vbPwdNeeded;
|
|
|
|
if (RunningInWinlogon() &&
|
|
SUCCEEDED(pUser->get_passwordRequired(&vbPwdNeeded)) &&
|
|
(vbPwdNeeded == VARIANT_FALSE))
|
|
{
|
|
_fPwdNeeded = FALSE;
|
|
}
|
|
|
|
pUser->Release();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (_fPwdNeeded == FALSE);
|
|
}
|
|
|
|
HRESULT LogonAccount::InsertPasswordPanel()
|
|
{
|
|
HRESULT hr;
|
|
|
|
// If already have it, or no password is available, or logon state is not pending
|
|
if (_fHasPwdPanel || IsPasswordBlank() || (GetLogonState() != LS_Pending))
|
|
goto Done;
|
|
|
|
StartDefer();
|
|
|
|
// Add password panel
|
|
hr = Add(_pePwdPanel);
|
|
if (FAILED(hr))
|
|
{
|
|
EndDefer();
|
|
goto Failure;
|
|
}
|
|
|
|
SetElementAccessability(_pePwdEdit, true, ROLE_SYSTEM_STATICTEXT, _pvUsername->GetString());
|
|
|
|
_fHasPwdPanel = TRUE;
|
|
|
|
#ifdef GADGET_ENABLE_GDIPLUS
|
|
// Ensure that the Edit control is visible
|
|
ShowEdit();
|
|
#endif
|
|
|
|
// Hide hint button if no hint provided
|
|
if (_pvHint && *(_pvHint->GetString()) != NULL)
|
|
_pbPwdInfo->SetVisible(true);
|
|
else
|
|
_pbPwdInfo->SetVisible(false);
|
|
|
|
// Hide status text (do not remove or insert)
|
|
HideStatus(0);
|
|
HideStatus(1);
|
|
|
|
LayoutCheckHandler(LAYOUT_DEF_USER);
|
|
// Push focus to edit control
|
|
_pePwdEdit->SetKeyFocus();
|
|
|
|
EndDefer();
|
|
|
|
Done:
|
|
|
|
return S_OK;
|
|
|
|
Failure:
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT LogonAccount::RemovePasswordPanel()
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (!_fHasPwdPanel)
|
|
goto Done;
|
|
|
|
StartDefer();
|
|
|
|
// Remove password panel
|
|
hr = Remove(_pePwdPanel);
|
|
if (FAILED(hr))
|
|
{
|
|
EndDefer();
|
|
goto Failure;
|
|
}
|
|
|
|
// Clear out edit control
|
|
_pePwdEdit->SetContentString(L"");
|
|
UnSubClassTheEditBox(_pePwdEdit->GetHWND()); // Provide for trap of the TTN_LINKCLICK event
|
|
|
|
|
|
// Unhide status text
|
|
ShowStatus(0);
|
|
ShowStatus(1);
|
|
|
|
_fHasPwdPanel = FALSE;
|
|
|
|
EndDefer();
|
|
|
|
Done:
|
|
|
|
return S_OK;
|
|
|
|
Failure:
|
|
|
|
return hr;
|
|
}
|
|
|
|
// User has authenticated
|
|
void LogonAccount::OnAuthenticatedUser()
|
|
{
|
|
// On success, log user on
|
|
_peCandidate = this;
|
|
g_plf->OnLogUserOn(this);
|
|
g_plf->EnterPostStatusMode();
|
|
}
|
|
|
|
// User is attempting to log on
|
|
BOOL LogonAccount::OnAuthenticateUser(LPCWSTR pszInPassword)
|
|
{
|
|
HRESULT hr;
|
|
// Logon requested on this account
|
|
LPCWSTR pszPassword = L"";
|
|
Value* pv = NULL;
|
|
|
|
ILogonUser *pobjUser;
|
|
VARIANT_BOOL vbLogonSucceeded = VARIANT_FALSE;
|
|
|
|
WCHAR *pszUsername = _pvUsername->GetString();
|
|
|
|
if (pszUsername)
|
|
{
|
|
if (SUCCEEDED(hr = GetLogonUserByLogonName(pszUsername, &pobjUser)))
|
|
{
|
|
if (!IsPasswordBlank())
|
|
{
|
|
if (pszInPassword)
|
|
{
|
|
pszPassword = pszInPassword;
|
|
}
|
|
else
|
|
{
|
|
if (_pePwdEdit)
|
|
{
|
|
pszPassword = _pePwdEdit->GetContentString(&pv);
|
|
|
|
if (!pszPassword)
|
|
pszPassword = L"";
|
|
|
|
if (pv)
|
|
{
|
|
pv->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
BSTR bstr = SysAllocString(pszPassword);
|
|
pobjUser->logon(bstr, &vbLogonSucceeded);
|
|
SysFreeString(bstr);
|
|
}
|
|
else
|
|
{
|
|
pobjUser->logon(L"", &vbLogonSucceeded);
|
|
}
|
|
pobjUser->Release();
|
|
}
|
|
}
|
|
|
|
if (vbLogonSucceeded == VARIANT_TRUE)
|
|
{
|
|
OnAuthenticatedUser();
|
|
}
|
|
else
|
|
{
|
|
if (pszInPassword == NULL)
|
|
{
|
|
ShowPasswordIncorrectMessage();
|
|
}
|
|
}
|
|
|
|
return (vbLogonSucceeded == VARIANT_TRUE);
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// LogonAccount::ShowPasswordIncorrectMessage
|
|
//
|
|
// Put up the balloon message that says that the password is incorrect.
|
|
//
|
|
/////////////////////////////////////////
|
|
void LogonAccount::ShowPasswordIncorrectMessage()
|
|
{
|
|
TCHAR szError[512], szTitle[128], szAccessible[640];
|
|
BOOL fBackupAvailable = false;
|
|
BOOL fHint = false;
|
|
DWORD dwResult;
|
|
g_szUsername[0] = 0;
|
|
SubClassTheEditBox(_pePwdEdit->GetHWND()); // Provide for trap of the TTN_LINKCLICK event
|
|
if (0 < lstrlen(_pvUsername->GetString()))
|
|
{
|
|
wcscpy(g_szUsername,_pvUsername->GetString());
|
|
if (0 == PRQueryStatus(NULL,_pvUsername->GetString(),&dwResult))
|
|
{
|
|
if (0 == dwResult)
|
|
{
|
|
fBackupAvailable = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NULL != _pvHint && 0 < lstrlen(_pvHint->GetString()))
|
|
{
|
|
fHint = true;
|
|
}
|
|
|
|
LoadStringW(g_plf->GetHInstance(), IDS_BADPWDTITLE, szTitle, DUIARRAYSIZE(szTitle));
|
|
|
|
if (!fBackupAvailable & fHint)
|
|
LoadStringW(g_plf->GetHInstance(), IDS_BADPWDHINT, szError, DUIARRAYSIZE(szError));
|
|
else if (fBackupAvailable & !fHint)
|
|
LoadStringW(g_plf->GetHInstance(), IDS_BADPWDREST, szError, DUIARRAYSIZE(szError));
|
|
else if (fBackupAvailable & fHint)
|
|
LoadStringW(g_plf->GetHInstance(), IDS_BADPWDHINTREST, szError, DUIARRAYSIZE(szError));
|
|
else
|
|
LoadStringW(g_plf->GetHInstance(), IDS_BADPWD, szError, DUIARRAYSIZE(szError));
|
|
g_pErrorBalloon.ShowToolTip(GetModuleHandleW(NULL), _pePwdEdit->GetHWND(), szError, szTitle, TTI_ERROR, EB_WARNINGCENTERED | EB_MARKUP, 10000);
|
|
|
|
lstrcpy(szAccessible, szTitle);
|
|
lstrcat(szAccessible, szError);
|
|
SetElementAccessability(_pePwdEdit, true, ROLE_SYSTEM_STATICTEXT, szAccessible);
|
|
|
|
_pePwdEdit->RemoveLocalValue(ContentProp);
|
|
_pePwdEdit->SetKeyFocus();
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// LogonAccount::OnHintSelect
|
|
//
|
|
// Put up the balloon message that contains the user's password hint.
|
|
//
|
|
/////////////////////////////////////////
|
|
void LogonAccount::OnHintSelect()
|
|
{
|
|
TCHAR szTitle[128];
|
|
|
|
DUIAssertNoMsg(_pbPwdInfo);
|
|
|
|
// get the position of the link so we can target the balloon tip correctly
|
|
POINT pt = {0,0};
|
|
CalcBalloonTargetLocation(g_plf->GetNativeHost()->GetHWND(), _pbPwdInfo, &pt);
|
|
|
|
LoadStringW(g_plf->GetHInstance(), IDS_PASSWORDHINTTITLE, szTitle, DUIARRAYSIZE(szTitle));
|
|
g_pErrorBalloon.ShowToolTip(GetModuleHandleW(NULL), g_plf->GetHWND(), &pt, _pvHint->GetString(), szTitle, TTI_INFO, EB_WARNINGCENTERED, 10000);
|
|
|
|
SetElementAccessability(_pePwdEdit, true, ROLE_SYSTEM_STATICTEXT, _pvHint->GetString());
|
|
|
|
_pePwdEdit->SetKeyFocus();
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// LogonAccount::OnStatusSelect
|
|
//
|
|
// The user clicked one of the notification links (unread mail, running programs, etc).
|
|
// Dispatch that click to the right balloon tip display procs
|
|
//
|
|
/////////////////////////////////////////
|
|
void LogonAccount::OnStatusSelect(UINT nLine)
|
|
{
|
|
if (nLine == LASS_Email)
|
|
{
|
|
UnreadMailTip();
|
|
}
|
|
else if (nLine == LASS_LoggedOn)
|
|
{
|
|
AppRunningTip();
|
|
}
|
|
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// LogonAccount::AppRunningTip
|
|
//
|
|
// The user activated the link that shows how many programs are running. Show the tip that
|
|
// basically says that running lots of programs can show the machine down
|
|
//
|
|
/////////////////////////////////////////
|
|
void LogonAccount::AppRunningTip()
|
|
{
|
|
TCHAR szTitle[256], szTemp[512];
|
|
|
|
Element* pe = FindDescendent(StrToID(L"username"));
|
|
DUIAssertNoMsg(pe);
|
|
|
|
Value* pv;
|
|
LPCWSTR pszDisplayName = pe->GetContentString(&pv);
|
|
if (!pszDisplayName)
|
|
pszDisplayName = L"";
|
|
|
|
if (_dwRunningApps == 0)
|
|
{
|
|
LoadStringW(g_plf->GetHInstance(), IDS_USERISLOGGEDON, szTemp, DUIARRAYSIZE(szTemp));
|
|
wsprintf(szTitle, szTemp, pszDisplayName, _dwRunningApps);
|
|
}
|
|
else
|
|
{
|
|
LoadStringW(g_plf->GetHInstance(), (_dwRunningApps == 1 ? IDS_USERRUNNINGPROGRAM : IDS_USERRUNNINGPROGRAMS), szTemp, DUIARRAYSIZE(szTemp));
|
|
wsprintf(szTitle, szTemp, pszDisplayName, _dwRunningApps);
|
|
}
|
|
|
|
pv->Release();
|
|
|
|
// get the position of the link so we can target the balloon tip correctly
|
|
POINT pt = {0,0};
|
|
CalcBalloonTargetLocation(g_plf->GetNativeHost()->GetHWND(), _pbStatus[LASS_LoggedOn], &pt);
|
|
|
|
LoadStringW(g_plf->GetHInstance(), (_dwRunningApps > 0 ? IDS_TOOMANYPROGRAMS : IDS_TOOMANYUSERS), szTemp, DUIARRAYSIZE(szTemp));
|
|
g_pErrorBalloon.ShowToolTip(GetModuleHandleW(NULL), g_plf->GetHWND(), &pt, szTemp, szTitle, TTI_INFO, EB_WARNINGCENTERED, 10000);
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// LogonAccount::UnreadMailTip
|
|
//
|
|
// The user activated the link that shows how many unread email messages they have.
|
|
// Show the tip that says how many messages each of their email accounts has.
|
|
//
|
|
// TODO -- speed this up. its really slow now because each call to SHGina's
|
|
// ILogonUser::getMailAccountInfo load's the users' hive to get the next account from
|
|
// the registry.
|
|
//
|
|
/////////////////////////////////////////
|
|
void LogonAccount::UnreadMailTip()
|
|
{
|
|
TCHAR szTitle[128], szMsg[1024], szTemp[512], szRes[128];
|
|
HRESULT hr = E_FAIL;
|
|
ILogonUser *pobjUser = NULL;
|
|
|
|
szMsg[0] = TEXT('\0');
|
|
|
|
Element* pe = FindDescendent(StrToID(L"username"));
|
|
DUIAssertNoMsg(pe);
|
|
|
|
Value* pv;
|
|
LPCWSTR pszDisplayName = pe->GetContentString(&pv);
|
|
if (!pszDisplayName)
|
|
pszDisplayName = L"";
|
|
|
|
WCHAR *pszUsername = _pvUsername->GetString();
|
|
DWORD dwAccountsAdded = 0;
|
|
if (pszUsername)
|
|
{
|
|
if (SUCCEEDED(hr = GetLogonUserByLogonName(pszUsername, &pobjUser)) && pobjUser)
|
|
{
|
|
DWORD i, cMailAccounts;
|
|
|
|
cMailAccounts = 5;
|
|
for (i = 0; i < cMailAccounts; i++)
|
|
{
|
|
UINT cUnread;
|
|
VARIANT varAcctName = {0};
|
|
|
|
hr = pobjUser->getMailAccountInfo(i, &varAcctName, &cUnread);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (varAcctName.bstrVal && cUnread > 0)
|
|
{
|
|
if (dwAccountsAdded > 0)
|
|
{
|
|
lstrcat(szMsg, TEXT("\r\n"));
|
|
}
|
|
dwAccountsAdded++;
|
|
LoadStringW(g_plf->GetHInstance(), IDS_UNREADMAILACCOUNT, szRes, DUIARRAYSIZE(szRes));
|
|
wsprintf(szTemp, szRes, varAcctName.bstrVal, cUnread);
|
|
lstrcat(szMsg, szTemp);
|
|
}
|
|
VariantClear(&varAcctName);
|
|
}
|
|
pobjUser->Release();
|
|
}
|
|
}
|
|
LoadStringW(g_plf->GetHInstance(), (_dwUnreadMail == 1 ? IDS_USERUNREADEMAIL : IDS_USERUNREADEMAILS), szTemp, DUIARRAYSIZE(szTemp));
|
|
wsprintf(szTitle, szTemp, pszDisplayName, _dwUnreadMail);
|
|
pv->Release();
|
|
|
|
// get the position of the link so we can target the balloon tip correctly
|
|
POINT pt = {0,0};
|
|
CalcBalloonTargetLocation(g_plf->GetNativeHost()->GetHWND(), _pbStatus[LASS_Email], &pt);
|
|
|
|
if (szMsg[0] == 0)
|
|
{
|
|
LoadStringW(g_plf->GetHInstance(), IDS_UNREADMAILTEMP, szMsg, DUIARRAYSIZE(szMsg));
|
|
}
|
|
g_pErrorBalloon.ShowToolTip(GetModuleHandleW(NULL), g_plf->GetHWND(), &pt, szMsg, szTitle, TTI_INFO, EB_WARNINGCENTERED, 10000);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// LogonAccount::UpdateNotifications
|
|
//
|
|
// Update the notification links for this user. Check to see if they are logged on and
|
|
// if so, find out how many applications they had open when they last switched away.
|
|
//
|
|
// Check the unread mail count for users who are logged on or for everyone if fCheckEverything is
|
|
// true. Checking unread mail counts is slow because it has to load the user's registry hive.
|
|
// Since no applications will update this value when the user is not logged on, there is no
|
|
// need to check this when they are not logged on. The exception to this is when we are first
|
|
// building the list since we need to always load it then, hence the fCheckEverything flag.
|
|
//
|
|
/////////////////////////////////////////
|
|
void LogonAccount::UpdateNotifications(BOOL fCheckEverything)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
ILogonUser *pobjUser = NULL;
|
|
WCHAR szTemp[1024], sz[1024];
|
|
|
|
if (_fHasPwdPanel)
|
|
return;
|
|
|
|
WCHAR *pszUsername = _pvUsername->GetString();
|
|
|
|
if (pszUsername)
|
|
{
|
|
if (SUCCEEDED(hr = GetLogonUserByLogonName(pszUsername, &pobjUser)) && pobjUser)
|
|
{
|
|
VARIANT_BOOL vbLoggedOn;
|
|
VARIANT varUnreadMail;
|
|
BOOL fLoggedOn;
|
|
int iUnreadMailCount = 0;
|
|
DWORD dwProgramsRunning = 0;
|
|
|
|
if (FAILED(pobjUser->get_isLoggedOn(&vbLoggedOn)))
|
|
{
|
|
vbLoggedOn = VARIANT_FALSE;
|
|
}
|
|
|
|
fLoggedOn = (vbLoggedOn == VARIANT_TRUE);
|
|
|
|
if (fLoggedOn)
|
|
{
|
|
HKEY hKey;
|
|
CUserProfile userProfile(pszUsername, NULL);
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(userProfile, TEXT("SessionInformation"), 0, KEY_QUERY_VALUE, &hKey))
|
|
{
|
|
DWORD dwProgramsRunningSize = sizeof(dwProgramsRunning);
|
|
RegQueryValueEx(hKey, TEXT("ProgramCount"), NULL, NULL, reinterpret_cast<LPBYTE>(&dwProgramsRunning), &dwProgramsRunningSize);
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
SetRunningApps(dwProgramsRunning);
|
|
|
|
if (fLoggedOn)
|
|
{
|
|
InsertStatus(LASS_LoggedOn);
|
|
|
|
if (dwProgramsRunning != 0)
|
|
{
|
|
LoadStringW(g_plf->GetHInstance(), (dwProgramsRunning == 1 ? IDS_RUNNINGPROGRAM : IDS_RUNNINGPROGRAMS), szTemp, ARRAYSIZE(szTemp));
|
|
wsprintf(sz, szTemp, dwProgramsRunning);
|
|
SetStatus(LASS_LoggedOn, sz);
|
|
ShowStatus(LASS_LoggedOn);
|
|
}
|
|
else
|
|
{
|
|
LoadStringW(g_plf->GetHInstance(), IDS_USERLOGGEDON, szTemp, ARRAYSIZE(szTemp));
|
|
SetStatus(LASS_LoggedOn, szTemp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if they are not logged on, clean up the logged on text and remove any padding
|
|
RemoveStatus(LASS_LoggedOn);
|
|
}
|
|
|
|
if (fLoggedOn || fCheckEverything)
|
|
{
|
|
varUnreadMail.uintVal = 0;
|
|
if (FAILED(pobjUser->get_setting(L"UnreadMail", &varUnreadMail)))
|
|
{
|
|
varUnreadMail.uintVal = 0;
|
|
}
|
|
iUnreadMailCount = varUnreadMail.uintVal;
|
|
|
|
SetUnreadMail((DWORD)iUnreadMailCount);
|
|
if (iUnreadMailCount != 0)
|
|
{
|
|
InsertStatus(LASS_Email);
|
|
|
|
LoadStringW(g_plf->GetHInstance(), (iUnreadMailCount == 1 ? IDS_UNREADMAIL : IDS_UNREADMAILS), szTemp, ARRAYSIZE(szTemp));
|
|
wsprintf(sz, szTemp, iUnreadMailCount);
|
|
SetStatus(LASS_Email, sz);
|
|
ShowStatus(LASS_Email);
|
|
}
|
|
else
|
|
{
|
|
RemoveStatus(LASS_Email);
|
|
}
|
|
}
|
|
|
|
pobjUser->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef GADGET_ENABLE_GDIPLUS
|
|
|
|
void
|
|
LogonAccount::ShowEdit()
|
|
{
|
|
HWND hwndEdit = _pePwdEdit->GetHWND();
|
|
HWND hwndHost = ::GetParent(hwndEdit);
|
|
|
|
SetWindowPos(hwndHost, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
|
|
EnableWindow(hwndEdit, TRUE);
|
|
SetFocus(hwndEdit);
|
|
}
|
|
|
|
|
|
void
|
|
LogonAccount::HideEdit()
|
|
{
|
|
HWND hwndEdit = _pePwdEdit->GetHWND();
|
|
HWND hwndHost = ::GetParent(hwndEdit);
|
|
|
|
EnableWindow(hwndEdit, FALSE);
|
|
SetWindowPos(hwndHost, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_HIDEWINDOW);
|
|
}
|
|
|
|
#endif // GADGET_ENABLE_GDIPLUS
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
// Property definitions
|
|
|
|
////////////////////////////////////////////////////////
|
|
// ClassInfo (must appear after property definitions)
|
|
|
|
// LogonState property
|
|
static int vvLogonState[] = { DUIV_INT, -1 };
|
|
static PropertyInfo impLogonStateProp = { L"LogonState", PF_Normal, 0, vvLogonState, NULL, Value::pvIntZero /*LS_Pending*/ };
|
|
PropertyInfo* LogonAccount::LogonStateProp = &impLogonStateProp;
|
|
|
|
////////////////////////////////////////////////////////
|
|
// ClassInfo (must appear after property definitions)
|
|
|
|
// Class properties
|
|
static PropertyInfo* _aPI[] = {
|
|
LogonAccount::LogonStateProp,
|
|
};
|
|
|
|
// Define class info with type and base type, set static class pointer
|
|
IClassInfo* LogonAccount::Class = NULL;
|
|
HRESULT LogonAccount::Register()
|
|
{
|
|
return ClassInfo<LogonAccount,Button>::Register(L"LogonAccount", _aPI, DUIARRAYSIZE(_aPI));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////
|
|
// Logon Parser
|
|
|
|
void CALLBACK LogonParseError(LPCWSTR pszError, LPCWSTR pszToken, int dLine)
|
|
{
|
|
WCHAR buf[201];
|
|
|
|
if (dLine != -1)
|
|
swprintf(buf, L"%s '%s' at line %d", pszError, pszToken, dLine);
|
|
else
|
|
swprintf(buf, L"%s '%s'", pszError, pszToken);
|
|
|
|
MessageBoxW(NULL, buf, L"Parser Message", MB_OK);
|
|
}
|
|
|
|
|
|
void DoFadeWindow(HWND hwnd)
|
|
{
|
|
HDC hdc;
|
|
int i;
|
|
RECT rcFrame;
|
|
COLORREF rgbFinal = RGB(90,126,220);
|
|
|
|
hdc = GetDC(hwnd);
|
|
GetClientRect(hwnd, &rcFrame);
|
|
|
|
COLORREF crCurr;
|
|
HBRUSH hbrFill;
|
|
|
|
crCurr = RGB(0,0,0);
|
|
// draw the left bar
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
RECT rcCurrFrame;
|
|
|
|
rcCurrFrame = rcFrame;
|
|
|
|
crCurr = RGB((GetRValue(rgbFinal) / 16)*i,
|
|
(GetGValue(rgbFinal) / 16)*i,
|
|
(GetBValue(rgbFinal) / 16)*i);
|
|
hbrFill = CreateSolidBrush(crCurr);
|
|
if (hbrFill)
|
|
{
|
|
FillRect(hdc, &rcCurrFrame, hbrFill);
|
|
DeleteObject(hbrFill);
|
|
}
|
|
GdiFlush();
|
|
}
|
|
ReleaseDC(hwnd, hdc);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////
|
|
// Logon entry point
|
|
|
|
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow)
|
|
{
|
|
UNREFERENCED_PARAMETER(hPrevInstance);
|
|
UNREFERENCED_PARAMETER(pCmdLine);
|
|
UNREFERENCED_PARAMETER(nCmdShow);
|
|
|
|
WNDCLASSEX wcx = {0};
|
|
BOOL fStatusLaunch = false;
|
|
BOOL fShutdownLaunch = false;
|
|
BOOL fWait = false;
|
|
CBackgroundWindow backgroundWindow(hInst);
|
|
|
|
ZeroMemory(g_rgH, sizeof(g_rgH));
|
|
|
|
|
|
SetErrorHandler();
|
|
InitCommonControls();
|
|
// Register logon notification window
|
|
wcx.cbSize = sizeof(WNDCLASSEX);
|
|
wcx.lpfnWndProc = LogonWindowProc;
|
|
wcx.hInstance = GetModuleHandleW(NULL);
|
|
wcx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
|
|
wcx.lpszClassName = TEXT("LogonWnd");
|
|
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
RegisterClassEx(&wcx);
|
|
|
|
fStatusLaunch = (StrStrIA(pCmdLine, "/status") != NULL);
|
|
fShutdownLaunch = (StrStrIA(pCmdLine, "/shutdown") != NULL);
|
|
fWait = (StrStrIA(pCmdLine, "/wait") != NULL);
|
|
g_fNoAnimations = (StrStrIA(pCmdLine, "/noanim") != NULL);
|
|
|
|
// Create frame
|
|
Parser* pParser = NULL;
|
|
NativeHWNDHost* pnhh = NULL;
|
|
|
|
// DirectUI init process
|
|
if (FAILED(InitProcess()))
|
|
goto Failure;
|
|
|
|
// Register classes
|
|
if (FAILED(LogonFrame::Register()))
|
|
goto Failure;
|
|
|
|
if (FAILED(LogonAccountList::Register()))
|
|
goto Failure;
|
|
|
|
if (FAILED(LogonAccount::Register()))
|
|
goto Failure;
|
|
|
|
// DirectUI init thread
|
|
if (FAILED(InitThread()))
|
|
goto Failure;
|
|
|
|
if (FAILED(CoInitialize(NULL)))
|
|
goto Failure;
|
|
|
|
#ifdef GADGET_ENABLE_GDIPLUS
|
|
if (FAILED(FxInitGuts()))
|
|
goto Failure;
|
|
#endif
|
|
|
|
#ifndef DEBUG
|
|
if (!RunningUnderWinlogon())
|
|
goto Failure;
|
|
#endif
|
|
|
|
DisableAnimations();
|
|
|
|
// Create host
|
|
HMONITOR hMonitor;
|
|
POINT pt;
|
|
MONITORINFO monitorInfo;
|
|
|
|
// Determine initial size of the host. This is desired to be the entire
|
|
// primary monitor resolution because the host always runs on the secure
|
|
// desktop. If magnifier is brought up it will call SHAppBarMessage which
|
|
// will change the work area and we will respond to it appropriately from
|
|
// the listener in shgina that sends us HM_DISPLAYRESIZE messages.
|
|
|
|
pt.x = pt.y = 0;
|
|
hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
|
|
DUIAssert(hMonitor != NULL, "NULL HMONITOR returned from MonitorFromPoint");
|
|
monitorInfo.cbSize = sizeof(monitorInfo);
|
|
if (GetMonitorInfo(hMonitor, &monitorInfo) == FALSE)
|
|
{
|
|
SystemParametersInfo(SPI_GETWORKAREA, 0, &monitorInfo.rcMonitor, 0);
|
|
}
|
|
NativeHWNDHost::Create(L"Windows Logon", backgroundWindow.Create(), NULL, monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top,
|
|
monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top, 0, WS_POPUP, NHHO_IgnoreClose, &pnhh);
|
|
// NativeHWNDHost::Create(L"Windows Logon", NULL, NULL, monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top,
|
|
// 800, 600, 0, WS_POPUP, NHHO_IgnoreClose, &pnhh);
|
|
if (!pnhh)
|
|
goto Failure;
|
|
|
|
// Populate handle list for theme style parsing
|
|
g_rgH[0] = hInst; // Default HINSTANCE
|
|
g_rgH[SCROLLBARHTHEME] = OpenThemeData(pnhh->GetHWND(), L"Scrollbar");
|
|
|
|
// Frame creation
|
|
Parser::Create(IDR_LOGONUI, g_rgH, LogonParseError, &pParser);
|
|
if (!pParser)
|
|
goto Failure;
|
|
|
|
if (!pParser->WasParseError())
|
|
{
|
|
Element::StartDefer();
|
|
|
|
// Always double buffer
|
|
LogonFrame::Create(pnhh->GetHWND(), true, 0, (Element**)&g_plf);
|
|
if (!g_plf)
|
|
{
|
|
Element::EndDefer();
|
|
goto Failure;
|
|
}
|
|
|
|
g_plf->SetNativeHost(pnhh);
|
|
|
|
Element* pe;
|
|
pParser->CreateElement(L"main", g_plf, &pe);
|
|
|
|
if (pe) // Fill contents using substitution
|
|
{
|
|
// Frame tree is built
|
|
if (FAILED(g_plf->OnTreeReady(pParser)))
|
|
{
|
|
Element::EndDefer();
|
|
goto Failure;
|
|
}
|
|
|
|
if (fShutdownLaunch || fWait)
|
|
{
|
|
g_plf->SetTitle(IDS_PLEASEWAIT);
|
|
}
|
|
|
|
if (!fStatusLaunch)
|
|
{
|
|
// Build contents of account list
|
|
g_plf->EnterLogonMode(false);
|
|
}
|
|
else
|
|
{
|
|
g_plf->EnterPreStatusMode(false);
|
|
}
|
|
|
|
// Host
|
|
pnhh->Host(g_plf);
|
|
|
|
g_plf->SetButtonLabels();
|
|
|
|
Element *peLogoArea = g_plf->FindDescendent(StrToID(L"product"));
|
|
|
|
if (!g_fNoAnimations)
|
|
{
|
|
pnhh->ShowWindow();
|
|
DoFadeWindow(pnhh->GetHWND());
|
|
if (peLogoArea)
|
|
{
|
|
peLogoArea->SetAlpha(0);
|
|
}
|
|
}
|
|
|
|
// Set visible and focus
|
|
g_plf->SetVisible(true);
|
|
g_plf->SetKeyFocus();
|
|
|
|
|
|
Element::EndDefer();
|
|
|
|
// Do initial show
|
|
pnhh->ShowWindow();
|
|
|
|
if (!g_fNoAnimations)
|
|
{
|
|
EnableAnimations();
|
|
}
|
|
|
|
if (peLogoArea)
|
|
{
|
|
peLogoArea->SetAlpha(255);
|
|
}
|
|
|
|
StartMessagePump();
|
|
|
|
// psf will be deleted by native HWND host when destroyed
|
|
}
|
|
else
|
|
Element::EndDefer();
|
|
}
|
|
|
|
Failure:
|
|
|
|
if (pnhh)
|
|
pnhh->Destroy();
|
|
if (pParser)
|
|
pParser->Destroy();
|
|
|
|
ReleaseStatusHost();
|
|
|
|
FreeLayoutInfo(LAYOUT_DEF_USER);
|
|
|
|
if (g_rgH[SCROLLBARHTHEME]) // Scrollbar
|
|
{
|
|
CloseThemeData(g_rgH[SCROLLBARHTHEME]);
|
|
}
|
|
|
|
CoUninitialize();
|
|
|
|
UnInitThread();
|
|
|
|
UnInitProcess();
|
|
|
|
// Free cached atom list
|
|
if (LogonAccount::idPwdGo)
|
|
DeleteAtom(LogonAccount::idPwdGo);
|
|
|
|
if (LogonAccount::idPwdInfo)
|
|
DeleteAtom(LogonAccount::idPwdInfo);
|
|
|
|
|
|
EndHostProcess(0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void LogonAccount::SetKeyboardIcon(HICON hIcon)
|
|
{
|
|
HICON hIconCopy = NULL;
|
|
|
|
if (hIcon)
|
|
{
|
|
hIconCopy = CopyIcon(hIcon);
|
|
}
|
|
|
|
if (_peKbdIcon && hIconCopy)
|
|
{
|
|
Value* pvIcon = Value::CreateGraphic(hIconCopy);
|
|
_peKbdIcon->SetValue(Element::ContentProp, PI_Local, pvIcon); // Element takes owners
|
|
_peKbdIcon->SetPadding(0, 5, 0, 7);
|
|
pvIcon->Release();
|
|
}
|
|
}
|