Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

422 lines
13 KiB

  1. // MainPage.cpp : Implementation of CMainPage
  2. #include "stdafx.h"
  3. #include "MainPage.h"
  4. EXTERN_C const CLSID CLSID_MainPage = __uuidof(CMainPage);
  5. /////////////////////////////////////////////////////////////////////////////
  6. // CMainPage
  7. LPWSTR CMainPage::c_aHTML[] =
  8. {
  9. L"res://nusrmgr.exe/mainpage.htm",
  10. L"res://nusrmgr.exe/mainpage_sec.htm"
  11. };
  12. STDMETHODIMP CMainPage::createUserTable(IDispatch *pdispUserTableParent)
  13. {
  14. HRESULT hr;
  15. if (NULL == pdispUserTableParent)
  16. return E_INVALIDARG;
  17. if (NULL == _pBag)
  18. return E_UNEXPECTED;
  19. CComVariant var;
  20. hr = _pBag->Read(UA_PROP_USERLIST, &var, NULL);
  21. if (SUCCEEDED(hr))
  22. {
  23. hr = E_FAIL;
  24. CComQIPtr<ILogonEnumUsers> spUserList(var.punkVal);
  25. CComQIPtr<IHTMLElement> spParent(pdispUserTableParent);
  26. if (spParent)
  27. {
  28. CComBSTR strHTML;
  29. hr = CreateUserTableHTML(spUserList, 2, &strHTML);
  30. if (SUCCEEDED(hr))
  31. hr = spParent->put_innerHTML(strHTML);
  32. }
  33. }
  34. return hr;
  35. }
  36. LPWSTR FormatString(LPCWSTR pszFormat, ...)
  37. {
  38. LPWSTR pszResult = NULL;
  39. DWORD dwResult;
  40. va_list args;
  41. if (NULL == pszFormat)
  42. return NULL;
  43. va_start(args, pszFormat);
  44. dwResult = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  45. pszFormat,
  46. 0,
  47. 0,
  48. (LPWSTR)&pszResult,
  49. 1,
  50. &args);
  51. va_end(args);
  52. if (0 == dwResult && NULL != pszResult)
  53. {
  54. LocalFree(pszResult);
  55. pszResult = NULL;
  56. }
  57. return pszResult;
  58. }
  59. //
  60. // Localized strings (move to resources)
  61. //
  62. const WCHAR L_Admin_Property[] = L"Owner account";
  63. const WCHAR L_Standard_Property[] = L"Standard account";
  64. const WCHAR L_Limited_Property[] = L"Limited account";
  65. const WCHAR L_Password_Property[] = L"<BR>Password-protected";
  66. const WCHAR L_GuestEnabled_Property[] = L"Guest access allowed";
  67. const WCHAR L_GuestDisabled_Property[] = L"Guest access not allowed";
  68. const WCHAR L_Account_ToolTip[] = L"Changes this person&#039s account information, such as the account type, name, or picture, or lets you delete this account.";
  69. const WCHAR L_Guest_ToolTip[] = L"Lets you change the guest account picture or prevent guest access to this computer.";
  70. const WCHAR L_GuestEnable_ToolTip[] = L"Provides computer access for people without a user account on this machine.";
  71. //
  72. // Non-localized strings
  73. //
  74. const WCHAR c_szAdminGroup[] = L"Owners";
  75. const WCHAR c_szStandardGroup[] = L"Adults";
  76. const WCHAR c_szLimitedGroup[] = L"Children";
  77. const WCHAR c_szGuestGroup[] = L"Guests";
  78. const WCHAR c_szDefaultImage[] = L"accountgrey.bmp";
  79. struct { LPCWSTR szGroupName; LPCWSTR szAccountType; }
  80. g_AccountTypes[] =
  81. {
  82. { c_szAdminGroup, L_Admin_Property },
  83. { c_szStandardGroup, L_Standard_Property },
  84. { c_szLimitedGroup, L_Limited_Property },
  85. { c_szGuestGroup, L_GuestEnabled_Property },
  86. };
  87. BOOL IsAccountType(ILogonUser* pUser, UINT iType)
  88. {
  89. if (iType < ARRAYSIZE(g_AccountTypes))
  90. {
  91. CComVariant varType;
  92. if (SUCCEEDED(pUser->get_setting(L"AccountType", &varType)) && VT_BSTR == varType.vt)
  93. {
  94. return (0 == lstrcmpiW(varType.bstrVal, g_AccountTypes[iType].szGroupName));
  95. }
  96. }
  97. return FALSE;
  98. }
  99. UINT GetAccountType(ILogonUser* pUser)
  100. {
  101. UINT i;
  102. for (i = 0; i < ARRAYSIZE(g_AccountTypes); i++)
  103. {
  104. if (IsAccountType(pUser, i))
  105. return i;
  106. }
  107. return 2; //LIMITED;
  108. }
  109. BOOL IsSameAccount(ILogonUser* pUser, LPCWSTR pszLoginName)
  110. {
  111. CComVariant varName;
  112. if (SUCCEEDED(pUser->get_setting(L"LoginName", &varName)) && VT_BSTR == varName.vt)
  113. {
  114. return (0 == lstrcmpiW(varName.bstrVal, pszLoginName));
  115. }
  116. return FALSE;
  117. }
  118. BSTR GetUserDisplayName(ILogonUser* pUser)
  119. {
  120. BSTR strResult = NULL;
  121. CComVariant var;
  122. HRESULT hr = pUser->get_setting(L"DisplayName", &var);
  123. if (FAILED(hr) || VT_BSTR != var.vt || NULL == var.bstrVal || L'\0' == *var.bstrVal)
  124. {
  125. var.Clear();
  126. hr = pUser->get_setting(L"LoginName", &var);
  127. }
  128. if (SUCCEEDED(hr) && VT_BSTR == var.vt && NULL != var.bstrVal)
  129. {
  130. strResult = var.bstrVal;
  131. var.vt = VT_EMPTY;
  132. // Truncate really long names
  133. if (lstrlenW(strResult) > 20)
  134. {
  135. //var iBreak = szDisplayName.lastIndexOf(' ',17);
  136. //if (-1 == iBreak) iBreak = 17;
  137. //szDisplayName = szDisplayName.substring(0,iBreak) + "...";
  138. lstrcpyW(&strResult[17], L"...");
  139. }
  140. }
  141. return strResult;
  142. }
  143. LPWSTR CreateUserDisplayHTML(LPCWSTR pszName, LPCWSTR pszSubtitle, LPCWSTR pszPicture)
  144. {
  145. static const WCHAR c_szUserHTML[] =
  146. L"<TABLE cellspacing=0 cellpadding=0 style='border:0'><TR>" \
  147. L"<TD style='padding:1mm;margin-right:2mm'>" \
  148. L"<IMG src='%3' class='UserPict' onerror='OnPictureLoadError(this);'/>" \
  149. L"</TD>" \
  150. L"<TD style='vertical-align:middle'>" \
  151. L"<DIV class='FontSubHeader1 ColorPrimaryLink1'>%1</DIV>" \
  152. L"<DIV class='FontDescription1 ColorPrimaryLink1'>%2</DIV>" \
  153. L"</TD>" \
  154. L"</TR></TABLE>";
  155. return FormatString(c_szUserHTML, pszName, pszSubtitle, pszPicture);
  156. }
  157. LPWSTR CreateUserDisplayHTML(ILogonUser* pUser)
  158. {
  159. if (NULL == pUser)
  160. return NULL;
  161. CComBSTR strSubtitle(g_AccountTypes[GetAccountType(pUser)].szAccountType);
  162. VARIANT_BOOL bPassword = VARIANT_FALSE;
  163. if (SUCCEEDED(pUser->get_passwordRequired(&bPassword)) && (VARIANT_TRUE == bPassword))
  164. {
  165. strSubtitle.Append(L_Password_Property);
  166. }
  167. CComVariant varPicture;
  168. if (FAILED(pUser->get_setting(L"Picture", &varPicture)))
  169. varPicture = c_szDefaultImage;
  170. CComBSTR strName;
  171. strName.Attach(GetUserDisplayName(pUser));
  172. return CreateUserDisplayHTML(strName, strSubtitle, varPicture.bstrVal);
  173. }
  174. LPWSTR CreateDisabledGuestHTML()
  175. {
  176. return CreateUserDisplayHTML(g_szGuestName, L_GuestDisabled_Property, c_szDefaultImage);
  177. }
  178. HRESULT CreateUserTableHTML(ILogonEnumUsers* pUserList, UINT cColumns, BSTR* pstrHTML)
  179. {
  180. HRESULT hr;
  181. static const WCHAR c_szTableStart[] = L"<TABLE cellspacing=10 cellpadding=1 style='border:0;table-layout:fixed'>";
  182. static const WCHAR c_szTableEnd[] = L"</TABLE>";
  183. static const WCHAR c_szTRStart[] = L"<TR>";
  184. static const WCHAR c_szTREnd[] = L"</TR>";
  185. static const WCHAR c_szTDStart[] = L"<TD class='Selectable' tabindex=0 LoginName='%1' title='%2' onclick='%3' style='width:%4!d!%%'>";
  186. static const WCHAR c_szTDEnd[] = L"</TD>";
  187. static const WCHAR c_szSwitchUser[] = L"window.external.navigate(\"{F4924514-CFBC-4AAB-9EC5-6C6E6D0DB38D}\",false,this.LoginName);";
  188. static const WCHAR c_szEnableGuest[] = L"window.external.navigate(\"enableguest.htm\",false);";
  189. if (NULL == pUserList)
  190. return E_INVALIDARG;
  191. if (NULL == pstrHTML)
  192. return E_POINTER;
  193. *pstrHTML = NULL;
  194. if (0 == cColumns)
  195. cColumns = 1;
  196. LONG nColWidth = 100 / cColumns; // percent (e.g. for 2 columns, width=50%)
  197. UINT cUsers = 0;
  198. hr = pUserList->get_length(&cUsers);
  199. if (SUCCEEDED(hr) && 0 == cUsers)
  200. hr = E_FAIL;
  201. if (FAILED(hr))
  202. return hr;
  203. CComPtr<IStream> spStream;
  204. hr = CreateStreamOnHGlobal(NULL, TRUE, &spStream);
  205. if (FAILED(hr))
  206. return hr;
  207. // Continue if this fails
  208. CComPtr<ILogonUser> spLoggedOnUser;
  209. pUserList->get_currentUser(&spLoggedOnUser);
  210. BOOL fIncludeSelf = (NULL != spLoggedOnUser.p);
  211. BOOL bShowAdmin = (!fIncludeSelf || IsSameAccount(spLoggedOnUser, g_szAdminName));
  212. if (!bShowAdmin)
  213. {
  214. // TODO: Check registry
  215. }
  216. UINT i;
  217. UINT j = 0;
  218. VARIANT varI;
  219. varI.vt = VT_I4;
  220. ULONG cbWritten;
  221. spStream->Write(c_szTableStart, sizeof(c_szTableStart)-sizeof(L'\0'), &cbWritten);
  222. for (i = 0; i < cUsers;)
  223. {
  224. spStream->Write(c_szTRStart, sizeof(c_szTRStart)-sizeof(L'\0'), &cbWritten);
  225. for (j = 0; j < cColumns && i < cUsers; i++)
  226. {
  227. CComPtr<ILogonUser> spUser;
  228. varI.ulVal = i;
  229. hr = pUserList->item(varI, &spUser);
  230. if (FAILED(hr))
  231. continue;
  232. CComVariant varLoginName;
  233. if (FAILED(spUser->get_setting(L"LoginName", &varLoginName)) || VT_BSTR != varLoginName.vt)
  234. continue;
  235. // Add "Guest" later
  236. if (0 == lstrcmpiW(varLoginName.bstrVal, g_szGuestName))
  237. continue;
  238. // Normally don't want to show "Administrator"
  239. if (!bShowAdmin && (0 == lstrcmpiW(varLoginName.bstrVal, g_szAdminName)))
  240. continue;
  241. BOOL bIsLoggedOnUser = spLoggedOnUser ? IsSameAccount(spLoggedOnUser, varLoginName.bstrVal) : FALSE;
  242. //
  243. // fIncludeSelf causes spLoggedOnUser to be
  244. // placed first in the list
  245. //
  246. if (fIncludeSelf || !bIsLoggedOnUser)
  247. {
  248. if (fIncludeSelf)
  249. {
  250. if (!bIsLoggedOnUser)
  251. {
  252. CComVariant varTemp;
  253. if (SUCCEEDED(spLoggedOnUser->get_setting(L"LoginName", &varTemp)) && VT_BSTR == varTemp.vt)
  254. {
  255. varLoginName = varTemp;
  256. spUser = spLoggedOnUser;
  257. i--;
  258. }
  259. }
  260. fIncludeSelf = FALSE;
  261. }
  262. LPWSTR pszTDStart = FormatString(c_szTDStart, varLoginName.bstrVal, L_Account_ToolTip, c_szSwitchUser, nColWidth);
  263. if (NULL != pszTDStart)
  264. {
  265. spStream->Write(pszTDStart, sizeof(WCHAR)*lstrlenW(pszTDStart), &cbWritten);
  266. LocalFree(pszTDStart);
  267. }
  268. else
  269. {
  270. continue;
  271. }
  272. LPWSTR pszUserDisplay = CreateUserDisplayHTML(spUser);
  273. if (NULL != pszUserDisplay)
  274. {
  275. spStream->Write(pszUserDisplay, sizeof(WCHAR)*lstrlenW(pszUserDisplay), &cbWritten);
  276. LocalFree(pszUserDisplay);
  277. }
  278. spStream->Write(c_szTDEnd, sizeof(c_szTDEnd)-sizeof(L'\0'), &cbWritten);
  279. j++;
  280. }
  281. }
  282. // Last time through?
  283. if (i == cUsers)
  284. {
  285. // Add the "Guest" entry now
  286. VARIANT_BOOL bGuestEnabled = VARIANT_FALSE;
  287. CComPtr<ILocalMachine> spLocalMachine;
  288. hr = spLocalMachine.CoCreateInstance(CLSID_ShellLocalMachine);
  289. if (SUCCEEDED(hr))
  290. spLocalMachine->get_isGuestEnabled(&bGuestEnabled);
  291. if (j == cColumns)
  292. {
  293. spStream->Write(c_szTREnd, sizeof(c_szTREnd)-sizeof(L'\0'), &cbWritten);
  294. spStream->Write(c_szTRStart, sizeof(c_szTRStart)-sizeof(L'\0'), &cbWritten);
  295. }
  296. LPCWSTR pszTitle;
  297. LPCWSTR pszOnClick;
  298. LPWSTR pszUserDisplay;
  299. if (VARIANT_TRUE == bGuestEnabled)
  300. {
  301. // Enabled Guest is a real entry (from pUserList)
  302. CComPtr<ILogonUser> spUser;
  303. CComVariant var(g_szGuestName);
  304. hr = pUserList->item(var, &spUser);
  305. pszTitle = L_Guest_ToolTip;
  306. pszOnClick = c_szSwitchUser;
  307. pszUserDisplay = CreateUserDisplayHTML(spUser);
  308. }
  309. else
  310. {
  311. // Disabled Guest is a fake entry
  312. pszTitle = L_GuestEnable_ToolTip;
  313. pszOnClick = c_szEnableGuest;
  314. pszUserDisplay = CreateDisabledGuestHTML();
  315. }
  316. LPWSTR pszTDStart = FormatString(c_szTDStart, g_szGuestName, pszTitle, pszOnClick, nColWidth);
  317. if (NULL != pszTDStart)
  318. {
  319. spStream->Write(pszTDStart, sizeof(WCHAR)*lstrlenW(pszTDStart), &cbWritten);
  320. LocalFree(pszTDStart);
  321. if (NULL != pszUserDisplay)
  322. spStream->Write(pszUserDisplay, sizeof(WCHAR)*lstrlenW(pszUserDisplay), &cbWritten);
  323. spStream->Write(c_szTDEnd, sizeof(c_szTDEnd)-sizeof(L'\0'), &cbWritten);
  324. }
  325. if (NULL != pszUserDisplay)
  326. LocalFree(pszUserDisplay);
  327. }
  328. spStream->Write(c_szTREnd, sizeof(c_szTREnd)-sizeof(L'\0'), &cbWritten);
  329. }
  330. // Include the NULL terminator on the last write
  331. spStream->Write(c_szTableEnd, sizeof(c_szTableEnd), &cbWritten);
  332. HGLOBAL hBuffer;
  333. hr = GetHGlobalFromStream(spStream, &hBuffer);
  334. if (SUCCEEDED(hr))
  335. {
  336. LPCWSTR pszHTML = (LPCWSTR)GlobalLock(hBuffer);
  337. *pstrHTML = SysAllocString(pszHTML);
  338. GlobalUnlock(hBuffer);
  339. if (NULL == *pstrHTML)
  340. hr = E_OUTOFMEMORY;
  341. }
  342. return hr;
  343. }