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.

1341 lines
36 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: winutil.c
  3. *
  4. * Copyright (c) 1991, Microsoft Corporation
  5. *
  6. * Implements windows specific utility functions
  7. *
  8. * History:
  9. * 12-09-91 Davidc Created.
  10. \***************************************************************************/
  11. #include "msgina.h"
  12. #include <stdio.h>
  13. #include <wchar.h>
  14. //
  15. // Define this if you want a verbose commentary from these routines
  16. //
  17. // #define VERBOSE_UTILS
  18. #ifdef VERBOSE_UTILS
  19. #define VerbosePrint(s) WLPrint(s)
  20. #else
  21. #define VerbosePrint(s)
  22. #endif
  23. #define LRM 0x200E // UNICODE Left-to-right mark control character
  24. #define RLM 0x200F // UNICODE Left-to-right mark control character
  25. /***************************************************************************\
  26. * SetupSystemMenu
  27. *
  28. * Purpose : Does any manipulation required for a dialog system menu.
  29. * Should be called during WM_INITDIALOG processing for a dialog
  30. *
  31. * History:
  32. * 12-09-91 Davidc Created.
  33. \***************************************************************************/
  34. VOID
  35. SetupSystemMenu(
  36. HWND hDlg
  37. )
  38. {
  39. // Remove the Close item from the system menu if we don't
  40. // have a CANCEL button
  41. if (GetDlgItem(hDlg, IDCANCEL) == NULL) {
  42. HMENU hMenu = GetSystemMenu(hDlg, FALSE);
  43. if (hMenu)
  44. {
  45. DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
  46. }
  47. }
  48. }
  49. /***************************************************************************\
  50. * CentreWindow
  51. *
  52. * Purpose : Positions a window so that it is centred in its parent
  53. *
  54. * History:
  55. * 12-09-91 Davidc Created.
  56. \***************************************************************************/
  57. VOID
  58. CentreWindow(
  59. HWND hwnd
  60. )
  61. {
  62. RECT rect;
  63. LONG dx, dy;
  64. LONG dxParent, dyParent;
  65. LONG Style;
  66. // Get window rect
  67. GetWindowRect(hwnd, &rect);
  68. dx = rect.right - rect.left;
  69. dy = rect.bottom - rect.top;
  70. // Get parent rect
  71. Style = GetWindowLong(hwnd, GWL_STYLE);
  72. if ((Style & WS_CHILD) == 0) {
  73. // Return the desktop windows size (size of main screen)
  74. dxParent = GetSystemMetrics(SM_CXSCREEN);
  75. dyParent = GetSystemMetrics(SM_CYSCREEN);
  76. } else {
  77. HWND hwndParent;
  78. RECT rectParent;
  79. hwndParent = GetParent(hwnd);
  80. if (hwndParent == NULL) {
  81. hwndParent = GetDesktopWindow();
  82. }
  83. GetWindowRect(hwndParent, &rectParent);
  84. dxParent = rectParent.right - rectParent.left;
  85. dyParent = rectParent.bottom - rectParent.top;
  86. }
  87. // Centre the child in the parent
  88. rect.left = (dxParent - dx) / 2;
  89. rect.top = (dyParent - dy) / 3;
  90. // Move the child into position
  91. SetWindowPos(hwnd, HWND_TOP, rect.left, rect.top, 0, 0, SWP_NOSIZE);
  92. SetForegroundWindow(hwnd);
  93. }
  94. /***************************************************************************\
  95. * SetPasswordFocus
  96. *
  97. * Sets the focus window in a dialog to the first empty control in
  98. * the list IDD_LOGON_DOMAIN, IDD_NEW_PASSWORD
  99. * This routine would normally be called during WM_INITDIALOG processing.
  100. *
  101. * Returns FALSE if the focus was set, otherwise TRUE - this value can
  102. * be used as the return value to the WM_INITDIALOG message.
  103. *
  104. * History:
  105. * 12-09-91 Davidc Created.
  106. \***************************************************************************/
  107. BOOL
  108. SetPasswordFocus(
  109. HWND hDlg
  110. )
  111. {
  112. int ids[] = { IDD_LOGON_NAME,
  113. IDD_LOGON_DOMAIN,
  114. IDD_LOGON_PASSWORD,
  115. IDD_UNLOCK_PASSWORD,
  116. IDD_CHANGEPWD_OLD,
  117. IDD_CHANGEPWD_NEW,
  118. IDD_CHANGEPWD_CONFIRM,
  119. };
  120. SHORT Index;
  121. HWND hwndFocus = NULL;
  122. // Set focus to first enabled, visible, empty field
  123. for (Index = 0; Index < sizeof(ids)/sizeof(*ids); Index ++) {
  124. int idControl = ids[Index];
  125. HWND hwndControl;
  126. hwndControl = GetDlgItem(hDlg, idControl);
  127. if (hwndControl != NULL) {
  128. if ( (GetWindowTextLength(hwndControl) == 0) &&
  129. ((GetWindowLong(hwndControl, GWL_STYLE) &
  130. (WS_VISIBLE | WS_DISABLED)) == WS_VISIBLE)) {
  131. hwndFocus = hwndControl;
  132. break;
  133. }
  134. }
  135. }
  136. if (hwndFocus != NULL) {
  137. SetFocus(hwndFocus);
  138. }
  139. return(hwndFocus == NULL);
  140. }
  141. //
  142. // Globals used to store cursor handles for SetupCursor
  143. //
  144. static HCURSOR hCursorArrow = NULL;
  145. static HCURSOR hCursorWait = NULL;
  146. /***************************************************************************\
  147. * SetupCursor
  148. *
  149. * Sets the cursor to an hourglass if fWait = TRUE, otherwise sets it
  150. * to an arrow.
  151. *
  152. * History:
  153. * 12-09-91 Davidc Created.
  154. \***************************************************************************/
  155. VOID
  156. SetupCursor(
  157. BOOL fWait
  158. )
  159. {
  160. if (hCursorArrow == NULL) {
  161. hCursorArrow = LoadCursor(NULL, IDC_ARROW);
  162. }
  163. if (hCursorWait == NULL) {
  164. hCursorWait = LoadCursor(NULL, IDC_WAIT);
  165. }
  166. SetCursor(fWait ? hCursorWait : hCursorArrow);
  167. }
  168. /****************************************************************************
  169. FUNCTION: TimeFieldsToSystemTime
  170. PURPOSE: Converts a TIME_FIELDS structure into a SYSTEMTIME structure
  171. RETURNS : nothing
  172. History:
  173. 05-15-93 RobertRe Created.
  174. ****************************************************************************/
  175. VOID
  176. TimeFieldsToSystemTime(
  177. IN PTIME_FIELDS TimeFields,
  178. OUT LPSYSTEMTIME SystemTime
  179. )
  180. {
  181. SystemTime->wYear = TimeFields->Year ;
  182. SystemTime->wMonth = TimeFields->Month ;
  183. SystemTime->wDayOfWeek = TimeFields->Weekday ;
  184. SystemTime->wDay = TimeFields->Day ;
  185. SystemTime->wHour = TimeFields->Hour ;
  186. SystemTime->wMinute = TimeFields->Minute ;
  187. SystemTime->wSecond = TimeFields->Second ;
  188. SystemTime->wMilliseconds = TimeFields->Milliseconds;
  189. return;
  190. }
  191. /****************************************************************************
  192. FUNCTION: FormatTime
  193. PURPOSE: Converts a system time into a readable string(in local time).
  194. if flags contains FT_TIME the time appears in the string
  195. if flags contains FT_DATE the date appears in the string.
  196. if both values appear, the string contains date then time.
  197. RETURNS : TRUE on success, FALSE on failure
  198. ****************************************************************************/
  199. BOOL
  200. FormatTime(
  201. IN PTIME Time,
  202. IN OUT PWCHAR Buffer,
  203. IN ULONG BufferLength,
  204. IN USHORT Flags
  205. )
  206. {
  207. NTSTATUS Status;
  208. TIME_FIELDS TimeFields;
  209. TIME LocalTime;
  210. SYSTEMTIME SystemTime;
  211. DWORD dwDateFlags = DATE_SHORTDATE;
  212. //
  213. // Terminate the string in case they didn't pass any flags
  214. //
  215. if (BufferLength > 0) {
  216. Buffer[0] = 0;
  217. }
  218. //
  219. // Convert the system time to local time
  220. //
  221. Status = RtlSystemTimeToLocalTime(Time, &LocalTime);
  222. if (!NT_SUCCESS(Status)) {
  223. WLPrint(("Failed to convert system time to local time, status = 0x%lx", Status));
  224. return(FALSE);
  225. }
  226. //
  227. // Split the time into its components
  228. //
  229. RtlTimeToTimeFields(&LocalTime, &TimeFields);
  230. TimeFieldsToSystemTime( &TimeFields, &SystemTime );
  231. //
  232. // Format the string
  233. //
  234. if (Flags & FT_LTR)
  235. dwDateFlags |= DATE_LTRREADING;
  236. else if(Flags & FT_RTL)
  237. dwDateFlags |= DATE_RTLREADING;
  238. if (Flags & FT_DATE) {
  239. int Length;
  240. Length = GetDateFormatW(GetUserDefaultLCID(),
  241. dwDateFlags,
  242. &SystemTime,
  243. NULL,
  244. Buffer,
  245. BufferLength
  246. );
  247. if (Length)
  248. {
  249. Length--; // The returned length includes the trailing 0
  250. Buffer += Length;
  251. BufferLength -= Length;
  252. }
  253. }
  254. if (Flags & FT_TIME) {
  255. int Length;
  256. if (Flags & FT_DATE) {
  257. if (BufferLength > 1) {
  258. *Buffer++ = TEXT(' ');
  259. *Buffer = 0; // in case GetTimeFormat doesn't add anything
  260. BufferLength --;
  261. }
  262. // [msadek]; need to insert strong a Unicode control character to simulate
  263. // a strong run in the opposite base direction to enforce
  264. // correct display of concatinated string in all cases.
  265. if((BufferLength > 2) && (Flags & FT_RTL)) {
  266. *Buffer++ = LRM; // simulate an opposite run
  267. *Buffer++ = RLM; // force RTL display of the time part.
  268. *Buffer = 0; // in case GetTimeFormat doesn't add anything
  269. BufferLength -= 2;
  270. }
  271. else if((BufferLength > 2) && (Flags & FT_LTR)) {
  272. *Buffer++ = RLM; // simulate an opposite run
  273. *Buffer++ = LRM; // force LTR display of the time part.
  274. *Buffer = 0; // in case GetTimeFormat doesn't add anything
  275. BufferLength -= 2;
  276. }
  277. }
  278. Length = GetTimeFormatW(GetUserDefaultLCID(),
  279. 0,
  280. &SystemTime,
  281. NULL,
  282. Buffer,
  283. BufferLength
  284. );
  285. }
  286. return(TRUE);
  287. }
  288. /***************************************************************************\
  289. * DuplicateUnicodeString
  290. *
  291. * Purpose : Allocates space for new string then copies new into old.
  292. * The new string is always 0 terminated
  293. * The new string should be free using RtlFreeUnicodeString()
  294. *
  295. * Returns : TRUE on success, FALSE on failure
  296. *
  297. * History:
  298. * 11-04-92 Davidc Created.
  299. * 05-29-98 DSheldon Modified so that no uni->ansi->uni translation occurs
  300. \***************************************************************************/
  301. BOOL
  302. DuplicateUnicodeString(
  303. PUNICODE_STRING OutString,
  304. PUNICODE_STRING InString
  305. )
  306. {
  307. *OutString = *InString ;
  308. OutString->Buffer = RtlAllocateHeap( RtlProcessHeap(), 0, InString->Length + sizeof(WCHAR) );
  309. if ( OutString->Buffer )
  310. {
  311. RtlCopyMemory( OutString->Buffer,
  312. InString->Buffer,
  313. InString->Length );
  314. OutString->Buffer[ OutString->Length / sizeof( WCHAR ) ] = L'\0';
  315. OutString->MaximumLength = OutString->Length + sizeof( WCHAR );
  316. }
  317. return (OutString->Buffer != NULL);
  318. }
  319. /***************************************************************************\
  320. * FUNCTION: OpenIniFileUserMapping
  321. *
  322. * PURPOSE: Forces the ini file mapping apis to reference the current user's
  323. * registry.
  324. *
  325. * RETURNS: TRUE on success, FALSE on failure
  326. *
  327. * HISTORY:
  328. *
  329. * 24-Aug-92 Davidc Created.
  330. *
  331. \***************************************************************************/
  332. BOOL
  333. OpenIniFileUserMapping(
  334. PGLOBALS pGlobals
  335. )
  336. {
  337. BOOL Result;
  338. HANDLE ImpersonationHandle;
  339. //
  340. // Impersonate the user
  341. //
  342. ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL);
  343. if (ImpersonationHandle == NULL) {
  344. DebugLog((DEB_ERROR, "OpenIniFileUserMapping failed to impersonate user"));
  345. return(FALSE);
  346. }
  347. Result = OpenProfileUserMapping();
  348. if (!Result) {
  349. DebugLog((DEB_ERROR, "OpenProfileUserMapping failed, error = %d", GetLastError()));
  350. }
  351. //
  352. // Revert to being 'ourself'
  353. //
  354. if (!StopImpersonating(ImpersonationHandle)) {
  355. DebugLog((DEB_ERROR, "OpenIniFileUserMapping failed to revert to self"));
  356. }
  357. return(Result);
  358. }
  359. /***************************************************************************\
  360. * FUNCTION: CloseIniFileUserMapping
  361. *
  362. * PURPOSE: Closes the ini file mapping to the user's registry such
  363. * that future use of the ini apis will fail if they reference
  364. * the user's registry.
  365. *
  366. * RETURNS: Nothing
  367. *
  368. * HISTORY:
  369. *
  370. * 24-Aug-92 Davidc Created.
  371. *
  372. \***************************************************************************/
  373. VOID
  374. CloseIniFileUserMapping(
  375. PGLOBALS pGlobals
  376. )
  377. {
  378. BOOL Result;
  379. Result = CloseProfileUserMapping();
  380. if (!Result) {
  381. DebugLog((DEB_ERROR, "CloseProfileUserMapping failed, error = %d", GetLastError()));
  382. }
  383. UNREFERENCED_PARAMETER(pGlobals);
  384. }
  385. /***************************************************************************\
  386. * FUNCTION: AllocAndGetDlgItemText
  387. *
  388. * PURPOSE: Allocates memory for and returns pointer to a copy of the text
  389. * in the specified dialog control.
  390. * The returned string should be freed using Free()
  391. *
  392. * RETURNS: Pointer to copy of dlg item text, or NULL on failure.
  393. *
  394. * HISTORY:
  395. *
  396. * 9-Sep-92 Davidc Created.
  397. *
  398. \***************************************************************************/
  399. LPTSTR
  400. AllocAndGetDlgItemText(
  401. HWND hDlg,
  402. int iItem
  403. )
  404. {
  405. HWND hwnd;
  406. LPTSTR String;
  407. LONG Length;
  408. LONG BytesRequired;
  409. LONG LengthCopied;
  410. //
  411. // Go find the window handle of the control
  412. //
  413. hwnd = GetDlgItem(hDlg, iItem);
  414. if (hwnd == NULL) {
  415. DebugLog((DEB_ERROR, "AllocAndGetDlgItemText : Couldn't find control %d in dialog 0x%lx", iItem, hDlg));
  416. ASSERT(hwnd != NULL);
  417. return(NULL);
  418. }
  419. //
  420. // Get the length of the control's text
  421. //
  422. Length = (LONG)SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0);
  423. if (Length < 0) {
  424. DebugLog((DEB_ERROR, "AllocAndGetDlgItemText : Dialog control text length < 0 (%d)", Length));
  425. ASSERT(Length >= 0);
  426. return(NULL);
  427. }
  428. //
  429. // Calculate the bytes required for the string.
  430. // The length doesn't include the terminator
  431. //
  432. Length ++; // Add one for terminator
  433. BytesRequired = Length * sizeof(TCHAR);
  434. String = (LPTSTR)Alloc(BytesRequired);
  435. if (String == NULL) {
  436. DebugLog((DEB_ERROR, "AllocAndGetDlgItemText : Failed to allocate %d bytes for dialog control text", BytesRequired));
  437. return(NULL);
  438. }
  439. //
  440. // Fill in the allocated block with the text
  441. //
  442. LengthCopied = (LONG)SendMessage(hwnd, WM_GETTEXT, Length, (LPARAM)String);
  443. if (LengthCopied != (Length - 1)) {
  444. DebugLog((DEB_ERROR, "AllocAndGetDlgItemText : WM_GETTEXT for %d chars only copied %d chars", Length-1, LengthCopied));
  445. ASSERT(LengthCopied == (Length - 1));
  446. Free(String);
  447. return(NULL);
  448. }
  449. String[Length - 1] = TEXT('\0');
  450. return(String);
  451. }
  452. /***************************************************************************\
  453. * FUNCTION: AllocAndGetPrivateProfileString
  454. *
  455. * PURPOSE: Allocates memory for and returns pointer to a copy of the
  456. * specified profile string
  457. * The returned string should be freed using Free()
  458. *
  459. * RETURNS: Pointer to copy of profile string or NULL on failure.
  460. *
  461. * HISTORY:
  462. *
  463. * 12-Nov-92 Davidc Created.
  464. *
  465. \***************************************************************************/
  466. LPTSTR
  467. AllocAndGetPrivateProfileString(
  468. LPCTSTR lpAppName,
  469. LPCTSTR lpKeyName,
  470. LPCTSTR lpDefault,
  471. LPCTSTR lpFileName
  472. )
  473. {
  474. LPTSTR String;
  475. LPTSTR NewString ;
  476. LONG LengthAllocated;
  477. LONG LengthCopied;
  478. //
  479. // Pick a random buffer length, if it's not big enough reallocate
  480. // it and try again until it is.
  481. //
  482. LengthAllocated = TYPICAL_STRING_LENGTH;
  483. String = Alloc(LengthAllocated * sizeof(TCHAR));
  484. if (String == NULL) {
  485. DebugLog((DEB_ERROR, "AllocAndGetPrivateProfileString : Failed to allocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
  486. return(NULL);
  487. }
  488. while (TRUE) {
  489. LengthCopied = GetPrivateProfileString( lpAppName,
  490. lpKeyName,
  491. lpDefault,
  492. String,
  493. LengthAllocated,
  494. lpFileName
  495. );
  496. //
  497. // If the returned value is our passed size - 1 (weird way for error)
  498. // then our buffer is too small. Make it bigger and start over again.
  499. //
  500. if (LengthCopied == (LengthAllocated - 1)) {
  501. VerbosePrint(("AllocAndGetPrivateProfileString: Failed with buffer length = %d, reallocating and retrying", LengthAllocated));
  502. LengthAllocated *= 2;
  503. NewString = ReAlloc(String, LengthAllocated * sizeof(TCHAR));
  504. if (NewString == NULL) {
  505. Free( String );
  506. String = NULL ;
  507. DebugLog((DEB_ERROR, "AllocAndGetPrivateProfileString : Failed to reallocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
  508. break;
  509. }
  510. String = NewString ;
  511. //
  512. // Go back and try to read it again
  513. //
  514. } else {
  515. //
  516. // Success!
  517. //
  518. break;
  519. }
  520. }
  521. return(String);
  522. }
  523. /***************************************************************************\
  524. * FUNCTION: WritePrivateProfileInt
  525. *
  526. * PURPOSE: Writes out an integer to a profile file
  527. *
  528. * RETURNS: TRUE on success, FALSE on failure
  529. *
  530. * HISTORY:
  531. *
  532. * 12-Nov-92 Davidc Created.
  533. *
  534. \***************************************************************************/
  535. BOOL
  536. WritePrivateProfileInt(
  537. LPCTSTR lpAppName,
  538. LPCTSTR lpKeyName,
  539. UINT Value,
  540. LPCTSTR lpFileName
  541. )
  542. {
  543. NTSTATUS Status;
  544. TCHAR String[30];
  545. UNICODE_STRING UniString;
  546. UniString.MaximumLength = 30;
  547. UniString.Buffer = String;
  548. Status = RtlIntegerToUnicodeString(Value,10,&UniString);
  549. if (!NT_SUCCESS(Status)) {
  550. return(FALSE);
  551. }
  552. return (WritePrivateProfileString(lpAppName, lpKeyName, UniString.Buffer, lpFileName));
  553. }
  554. /***************************************************************************\
  555. * FUNCTION: AllocAndRegQueryValueEx
  556. *
  557. * PURPOSE: Version of RegQueryValueEx that returns value in allocated buffer.
  558. * The returned buffer should be freed using Free()
  559. *
  560. * RETURNS: Pointer to key value or NULL on failure. The reason for the
  561. * error can be obtains using GetLastError()
  562. *
  563. * HISTORY:
  564. *
  565. * 15-Jan-93 Davidc Created.
  566. *
  567. \***************************************************************************/
  568. LPTSTR
  569. AllocAndRegQueryValueEx(
  570. HKEY hKey,
  571. LPTSTR lpValueName,
  572. LPDWORD lpReserved,
  573. LPDWORD lpType
  574. )
  575. {
  576. LPTSTR String;
  577. LPTSTR NewString;
  578. DWORD BytesAllocated;
  579. //
  580. // Pick a random buffer length, if it's not big enough reallocate
  581. // it and try again until it is.
  582. //
  583. BytesAllocated = TYPICAL_STRING_LENGTH * sizeof(TCHAR);
  584. String = Alloc(BytesAllocated);
  585. if (String == NULL) {
  586. DebugLog((DEB_ERROR, "AllocAndRegQueryValueEx : Failed to allocate %d bytes for string", BytesAllocated));
  587. return(NULL);
  588. }
  589. while (TRUE) {
  590. DWORD Error;
  591. DWORD BytesReturned = BytesAllocated;
  592. Error = RegQueryValueEx(hKey,
  593. lpValueName,
  594. lpReserved,
  595. lpType,
  596. (LPBYTE)String,
  597. &BytesReturned);
  598. if (Error == ERROR_SUCCESS) {
  599. break;
  600. }
  601. if (Error != ERROR_MORE_DATA) {
  602. DebugLog((DEB_ERROR, "AllocAndRegQueryValueEx : RegQueryValueEx failed, error = %d", Error));
  603. Free(String);
  604. String = NULL;
  605. SetLastError(Error);
  606. break;
  607. }
  608. //
  609. // The buffer was too small, make it bigger and try again
  610. //
  611. VerbosePrint(("AllocAndRegQueryValueEx: Failed with buffer length = %d bytes, reallocating and retrying", BytesAllocated));
  612. BytesAllocated *= 2;
  613. NewString = ReAlloc(String, BytesAllocated);
  614. if (NewString == NULL) {
  615. Free( String );
  616. String = NULL ;
  617. DebugLog((DEB_ERROR, "AllocAndRegQueryValueEx : Failed to reallocate %d bytes for string", BytesAllocated));
  618. break;
  619. }
  620. String = NewString;
  621. }
  622. return(String);
  623. }
  624. /***************************************************************************\
  625. * FUNCTION: ReadWinlogonBoolValue
  626. *
  627. * PURPOSE: Determines the correct BOOL value for the requested
  628. * value name by first looking up the machine preference
  629. * and then checking for policy
  630. *
  631. * RETURNS: TRUE or FALSE
  632. *
  633. * HISTORY:
  634. *
  635. * EricFlo 10-14-98 Created
  636. *
  637. \***************************************************************************/
  638. BOOL
  639. ReadWinlogonBoolValue (LPTSTR lpValueName, BOOL bDefault)
  640. {
  641. BOOL bResult;
  642. HKEY hKey;
  643. DWORD dwSize, dwType;
  644. //
  645. // Get the machine preference first
  646. //
  647. bResult = GetProfileInt(APPLICATION_NAME, lpValueName, bDefault);
  648. //
  649. // Check for a machine policy
  650. //
  651. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WINLOGON_POLICY_KEY,
  652. 0, KEY_READ, &hKey) == ERROR_SUCCESS)
  653. {
  654. dwSize = sizeof(bResult);
  655. RegQueryValueEx(hKey, lpValueName, 0, &dwType,
  656. (LPBYTE)&bResult, &dwSize);
  657. RegCloseKey (hKey);
  658. }
  659. return bResult;
  660. }
  661. /***************************************************************************\
  662. * HandleComboBoxOK
  663. *
  664. * Deals with UI requirements when OK is selected in a dialog when the
  665. * focus is on or in a combo-box.
  666. *
  667. * This routine should be called from a dialog proc that contains a
  668. * combo-box when a WM_COMMAND, IDOK is received.
  669. *
  670. * Returns TRUE if the message was dealt with and the caller should ignore it,
  671. * FALSE if this routine did nothing with it and the caller should process it
  672. * normally.
  673. *
  674. * History:
  675. * 24-Sep-92 Davidc Created.
  676. \***************************************************************************/
  677. BOOL
  678. HandleComboBoxOK(
  679. HWND hDlg,
  680. int ComboBoxId
  681. )
  682. {
  683. HWND hwndFocus = GetFocus();
  684. HWND hwndCB = GetDlgItem(hDlg, ComboBoxId);
  685. //
  686. // Hitting enter on a combo-box with the list showing should simply
  687. // hide the list.
  688. // We check for focus window being a child of the combo-box to
  689. // handle non-list style combo-boxes which have the focus on
  690. // the child edit control.
  691. //
  692. if ((hwndFocus == hwndCB) || IsChild(hwndCB, hwndFocus)) {
  693. if (SendMessage(hwndCB, CB_GETDROPPEDSTATE, 0, 0)) {
  694. //
  695. // Make the list-box disappear and we're done.
  696. //
  697. SendMessage(hwndCB, CB_SHOWDROPDOWN, (WPARAM)FALSE, 0);
  698. return(TRUE);
  699. }
  700. }
  701. //
  702. // We didn't do anything
  703. //
  704. return(FALSE);
  705. }
  706. /***************************************************************************\
  707. * FUNCTION: EncodeMultiSzW
  708. *
  709. * PURPOSE: Converts a multi-sz string and encodes it to look like
  710. * a single string.
  711. *
  712. * We replace the terminators between strings
  713. * with the TERMINATOR_REPLACEMENT character. We replace
  714. * existing occurrences of the replacement character with
  715. * two of them.
  716. *
  717. * RETURNS: Pointer to encoded string or NULL on failure.
  718. * The returned buffer should be freed using Free()
  719. *
  720. * HISTORY:
  721. *
  722. * 01-12-93 Davidc Created.
  723. *
  724. \***************************************************************************/
  725. #define TERMINATOR_REPLACEMENT TEXT(',')
  726. LPWSTR
  727. EncodeMultiSzW(
  728. IN LPWSTR MultiSz
  729. )
  730. {
  731. DWORD Length;
  732. DWORD NewLength;
  733. LPWSTR NewBuffer;
  734. LPWSTR p, q;
  735. DWORD ExtraCharacters;
  736. //
  737. // First calculate the length of the new string (with replacements)
  738. //
  739. p = MultiSz;
  740. ExtraCharacters = 0;
  741. while (*p) {
  742. while (*p) {
  743. if (*p == TERMINATOR_REPLACEMENT) {
  744. ExtraCharacters ++;
  745. }
  746. p ++;
  747. }
  748. p ++;
  749. }
  750. Length = (DWORD)(p - MultiSz); // p points at 'second' (final) null terminator
  751. NewLength = Length + ExtraCharacters;
  752. //
  753. // Allocate space for the new string
  754. //
  755. NewBuffer = Alloc((NewLength + 1) * sizeof(WCHAR));
  756. if (NewBuffer == NULL) {
  757. DebugLog((DEB_ERROR, "EncodeMultiSz: failed to allocate space for %d bytes", (NewLength + 1) * sizeof(WCHAR)));
  758. return(NULL);
  759. }
  760. //
  761. // Copy the string into the new buffer making replacements as we go
  762. //
  763. p = MultiSz;
  764. q = NewBuffer;
  765. while (*p) {
  766. while (*p) {
  767. *q = *p;
  768. if (*p == TERMINATOR_REPLACEMENT) {
  769. q ++;
  770. *q = TERMINATOR_REPLACEMENT;
  771. }
  772. p ++;
  773. q ++;
  774. }
  775. *q = TERMINATOR_REPLACEMENT;
  776. p ++;
  777. q ++;
  778. }
  779. ASSERT((DWORD)(q - NewBuffer) == NewLength);
  780. //
  781. // Add terminator
  782. //
  783. *q = 0;
  784. return(NewBuffer);
  785. }
  786. /***************************************************************************\
  787. * TimeoutMessageBox
  788. *
  789. * Same as a normal message box, but times out if there is no user input
  790. * for the specified number of seconds
  791. * For convenience, this api takes string resource ids rather than string
  792. * pointers as input. The resources are loaded from the .exe module
  793. *
  794. * 12-05-91 Davidc Created.
  795. \***************************************************************************/
  796. INT_PTR
  797. TimeoutMessageBox(
  798. HWND hwnd,
  799. PGLOBALS pGlobals,
  800. UINT IdText,
  801. UINT IdCaption,
  802. UINT wType,
  803. TIMEOUT Timeout
  804. )
  805. {
  806. PTCHAR Caption = NULL;
  807. PTCHAR Text = NULL;
  808. INT_PTR result;
  809. Text = (TCHAR*) Alloc(MAX_STRING_BYTES * sizeof(TCHAR));
  810. if( NULL == Text )
  811. {
  812. return MSGINA_DLG_FAILURE;
  813. }
  814. Text[0] = '\0';
  815. LoadString(hDllInstance, IdText, Text, MAX_STRING_BYTES);
  816. if (IdCaption != 0) {
  817. Caption = (TCHAR*) Alloc(MAX_STRING_BYTES * sizeof(TCHAR));
  818. if( NULL != Caption )
  819. {
  820. Caption[0] = '\0';
  821. LoadString(hDllInstance, IdCaption, Caption, MAX_STRING_BYTES);
  822. }
  823. }
  824. result = TimeoutMessageBoxlpstr(hwnd, pGlobals, Text, Caption, wType, Timeout);
  825. if( NULL != Text )
  826. {
  827. Free(Text);
  828. }
  829. if( NULL != Caption )
  830. {
  831. Free(Caption);
  832. }
  833. return result;
  834. }
  835. /***************************************************************************\
  836. * TimeoutMessageBoxlpstr
  837. *
  838. * Same as a normal message box, but times out if there is no user input
  839. * for the specified number of seconds
  840. *
  841. * 12-05-91 Davidc Created.
  842. \***************************************************************************/
  843. INT_PTR
  844. TimeoutMessageBoxlpstr(
  845. HWND hwnd,
  846. PGLOBALS pGlobals,
  847. LPTSTR Text,
  848. LPTSTR Caption,
  849. UINT wType,
  850. TIMEOUT Timeout
  851. )
  852. {
  853. INT_PTR DlgResult;
  854. BOOL fStatusHostHidden;
  855. fStatusHostHidden = _Shell_LogonStatus_IsHidden();
  856. _Shell_LogonStatus_Hide();
  857. // Set up input timeout
  858. pWlxFuncs->WlxSetTimeout(pGlobals->hGlobalWlx, Timeout);
  859. DlgResult = pWlxFuncs->WlxMessageBox( pGlobals->hGlobalWlx,
  860. hwnd,
  861. Text,
  862. Caption,
  863. wType);
  864. if (!fStatusHostHidden)
  865. {
  866. _Shell_LogonStatus_Show();
  867. }
  868. return(DlgResult);
  869. }
  870. PWSTR
  871. DupString(PWSTR pszString)
  872. {
  873. DWORD cbString;
  874. PWSTR pszNewString;
  875. cbString = (DWORD) (wcslen(pszString) + 1) * sizeof(WCHAR);
  876. pszNewString = LocalAlloc(LMEM_FIXED, cbString);
  877. if (pszNewString)
  878. {
  879. CopyMemory(pszNewString, pszString, cbString);
  880. }
  881. return(pszNewString);
  882. }
  883. PWSTR
  884. DupUnicodeString(PUNICODE_STRING pString)
  885. {
  886. PWSTR pszNewString;
  887. if (pString->Length)
  888. {
  889. pszNewString = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, pString->Length + sizeof(WCHAR));
  890. if (pszNewString)
  891. {
  892. CopyMemory(pszNewString, pString->Buffer, pString->Length);
  893. }
  894. }
  895. else
  896. pszNewString = NULL;
  897. return(pszNewString);
  898. }
  899. /***************************************************************************\
  900. * FUNCTION: EnableDomainForUPN
  901. *
  902. * PURPOSE: Enables or disables the domain text box based on whether or not
  903. * a UPN-style name is typed into the username box.
  904. *
  905. * RETURNS: none
  906. *
  907. * HISTORY:
  908. *
  909. * 04-17-1998 dsheldon created
  910. *
  911. \***************************************************************************/
  912. void EnableDomainForUPN(HWND hwndUsername, HWND hwndDomain)
  913. {
  914. BOOL fEnable;
  915. // Get the string the user is typing
  916. TCHAR* pszLogonName;
  917. int cchBuffer = (int)SendMessage(hwndUsername, WM_GETTEXTLENGTH, 0, 0) + 1;
  918. pszLogonName = (TCHAR*) Alloc(cchBuffer * sizeof(TCHAR));
  919. if (pszLogonName != NULL)
  920. {
  921. SendMessage(hwndUsername, WM_GETTEXT, (WPARAM) cchBuffer, (LPARAM) pszLogonName);
  922. // Disable the domain combo if the user is using a
  923. // UPN (if there is a "@") - ie [email protected] OR
  924. // domain\username form
  925. fEnable = (NULL == wcspbrk(pszLogonName, TEXT("@\\")));
  926. EnableWindow(hwndDomain, fEnable);
  927. Free(pszLogonName);
  928. }
  929. }
  930. // TRUE if we must always hide the domain box (local logon, UPN, smartcard only)
  931. // FALSE if this policy isn't set or is set to 0x0
  932. BOOL ForceNoDomainUI()
  933. {
  934. DWORD dwPolicyVal = 0;
  935. HKEY hkey;
  936. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0, KEY_QUERY_VALUE, &hkey))
  937. {
  938. DWORD cbData = sizeof (dwPolicyVal);
  939. DWORD dwType;
  940. if (ERROR_SUCCESS != RegQueryValueEx(hkey, NODOMAINCOMBO, 0, &dwType, (LPBYTE) &dwPolicyVal, &cbData))
  941. {
  942. dwPolicyVal = 0;
  943. }
  944. RegCloseKey(hkey);
  945. }
  946. return (0 != dwPolicyVal);
  947. }
  948. DWORD GetReasonSelection(HWND hwndCombo)
  949. {
  950. DWORD dwResult;
  951. PREASON pReason;
  952. int iItem = ComboBox_GetCurSel(hwndCombo);
  953. if (iItem != (int) CB_ERR) {
  954. pReason = (PREASON) ComboBox_GetItemData(hwndCombo, iItem);
  955. dwResult = pReason->dwCode;
  956. } else {
  957. dwResult = SHTDN_REASON_UNKNOWN;
  958. }
  959. return dwResult;
  960. }
  961. VOID SetReasonDescription(HWND hwndCombo, HWND hwndStatic)
  962. {
  963. PREASON pReason;
  964. int iItem = ComboBox_GetCurSel(hwndCombo);
  965. if (iItem != CB_ERR) {
  966. pReason = (PREASON) ComboBox_GetItemData(hwndCombo, iItem);
  967. SetWindowText(hwndStatic, pReason->szDesc);
  968. }
  969. }
  970. #define SMALL_STRING_SIZE 128
  971. /***************************************************************************\
  972. * DisplayForceLogoffWarning
  973. *
  974. * This prompts the warning when one administrator has locked the system and
  975. * the other administrator is trying to unlock it. The warning message includes
  976. * the idle time that the other user is Same as a normal message box,
  977. *
  978. \***************************************************************************/
  979. INT_PTR
  980. DisplayForceLogoffWarning(
  981. HWND hwnd,
  982. PGLOBALS pGlobals,
  983. UINT wType,
  984. TIMEOUT Timeout
  985. )
  986. {
  987. TCHAR *Caption = NULL;
  988. TCHAR *Text = NULL;
  989. TCHAR Buffer[SMALL_STRING_SIZE];
  990. TCHAR *MessageBuf = NULL;
  991. TIME Now;
  992. LONGLONG IdleTime;
  993. INT_PTR DlgResult;
  994. TCHAR *IdleTimeStr;
  995. // Calculate the idle time in days, hours, minutes and seconds.
  996. ULONG Days, Hours, Minutes;
  997. // Allocate space for console info.
  998. IdleTimeStr = (TCHAR *)LocalAlloc(LMEM_FIXED, MAX_STRING_BYTES*sizeof(TCHAR));
  999. if (IdleTimeStr == NULL) {
  1000. return MSGINA_DLG_FAILURE;
  1001. }
  1002. // Allocate space for message buffer.
  1003. MessageBuf = (TCHAR *)LocalAlloc(LMEM_FIXED, (MAX_STRING_BYTES*2)*sizeof(TCHAR));
  1004. if (MessageBuf == NULL) {
  1005. LocalFree(IdleTimeStr);
  1006. return MSGINA_DLG_FAILURE;
  1007. }
  1008. Text = (TCHAR *)LocalAlloc(LMEM_FIXED, (MAX_STRING_BYTES)*sizeof(TCHAR));
  1009. if (Text == NULL) {
  1010. LocalFree(IdleTimeStr);
  1011. LocalFree(MessageBuf);
  1012. return MSGINA_DLG_FAILURE;
  1013. }
  1014. Caption = (TCHAR *)LocalAlloc(LMEM_FIXED, (MAX_STRING_BYTES)*sizeof(TCHAR));
  1015. if (Caption == NULL) {
  1016. LocalFree(IdleTimeStr);
  1017. LocalFree(MessageBuf);
  1018. LocalFree(Text);
  1019. return MSGINA_DLG_FAILURE;
  1020. }
  1021. // Some initializations
  1022. IdleTimeStr[0] = (TCHAR)0;
  1023. MessageBuf[0] = (TCHAR)0;
  1024. Buffer[0] = (TCHAR)0;
  1025. Text[0] = (TCHAR)0;
  1026. GetSystemTimeAsFileTime((FILETIME*) &Now);
  1027. // Get the idle time in seconds.
  1028. IdleTime = Now.QuadPart - pGlobals->LockTime.QuadPart;
  1029. IdleTime /= 600000000L;
  1030. Days = (ULONG) (IdleTime / 1440);
  1031. IdleTime %= 1440;
  1032. Hours = (ULONG) (IdleTime / 60);
  1033. Minutes = (ULONG) (IdleTime % 60);
  1034. if (Days) {
  1035. if (Hours) {
  1036. LoadString(hDllInstance, IDS_IDLETIME_INDAYSANDHOURS, Buffer, SMALL_STRING_SIZE);
  1037. _snwprintf(IdleTimeStr, MAX_STRING_BYTES, Buffer, Days, Hours);
  1038. }
  1039. else {
  1040. LoadString(hDllInstance, IDS_IDLETIME_INDAYS, Buffer, SMALL_STRING_SIZE);
  1041. _snwprintf(IdleTimeStr, MAX_STRING_BYTES, Buffer, Days);
  1042. }
  1043. }
  1044. else {
  1045. if (Hours) {
  1046. if (Minutes) {
  1047. LoadString(hDllInstance, IDS_IDLETIME_INHOURSANDMINUTES, Buffer, SMALL_STRING_SIZE);
  1048. _snwprintf(IdleTimeStr, MAX_STRING_BYTES, Buffer, Hours, Minutes);
  1049. }
  1050. else {
  1051. LoadString(hDllInstance, IDS_IDLETIME_INHOURS, Buffer, SMALL_STRING_SIZE);
  1052. _snwprintf(IdleTimeStr, MAX_STRING_BYTES, Buffer, Hours);
  1053. }
  1054. }
  1055. else {
  1056. LoadString(hDllInstance, IDS_IDLETIME_INMINUTES, Buffer, SMALL_STRING_SIZE);
  1057. _snwprintf(IdleTimeStr, MAX_STRING_BYTES, Buffer, Minutes);
  1058. }
  1059. }
  1060. IdleTimeStr[MAX_STRING_BYTES - 1] = 0; // Let's make sure it's NULL terminated
  1061. if ( pGlobals->Domain[0] == TEXT('\0') ) {
  1062. LoadString(hDllInstance, IDS_FORCE_LOGOFF_UPN_WARNING, Text, MAX_STRING_BYTES);
  1063. _snwprintf(MessageBuf, (MAX_STRING_BYTES*2), Text, pGlobals->UserName, IdleTimeStr);
  1064. } else {
  1065. LoadString(hDllInstance, IDS_FORCE_LOGOFF_WARNING, Text, MAX_STRING_BYTES);
  1066. _snwprintf(MessageBuf, (MAX_STRING_BYTES*2), Text, pGlobals->Domain, pGlobals->UserName, IdleTimeStr);
  1067. }
  1068. MessageBuf[MAX_STRING_BYTES*2 - 1] = 0; // Let's make sure it's NULL terminated
  1069. LoadString(hDllInstance, IDS_LOGON_MESSAGE, Caption, MAX_STRING_BYTES);
  1070. DlgResult = TimeoutMessageBoxlpstr(hwnd, pGlobals, MessageBuf, Caption, wType, Timeout);
  1071. if (MessageBuf)
  1072. LocalFree(MessageBuf);
  1073. if (Text)
  1074. LocalFree(Text);
  1075. if (Caption)
  1076. LocalFree(Caption);
  1077. if (IdleTimeStr)
  1078. LocalFree(IdleTimeStr);
  1079. return DlgResult;
  1080. }