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.

1379 lines
35 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. WCHAR DateString[256];
  241. Length = GetDateFormatW(GetUserDefaultLCID(),
  242. dwDateFlags,
  243. &SystemTime,
  244. NULL,
  245. DateString,
  246. 256
  247. );
  248. Length = _snwprintf( Buffer,
  249. BufferLength,
  250. TEXT("%s"),
  251. DateString
  252. );
  253. Buffer += Length;
  254. BufferLength -= Length;
  255. }
  256. if (Flags & FT_TIME) {
  257. int Length;
  258. WCHAR TimeString[256];
  259. if (Flags & FT_DATE) {
  260. if (BufferLength > 0) {
  261. *Buffer++ = TEXT(' ');
  262. BufferLength --;
  263. }
  264. // [msadek]; need to insert strong a Unicode control character to simulate
  265. // a strong run in the opposite base direction to enforce
  266. // correct display of concatinated string in all cases.
  267. if((BufferLength > 0) && (Flags & FT_RTL)) {
  268. *Buffer++ = LRM; // simulate an opposite run
  269. *Buffer++ = RLM; // force RTL display of the time part.
  270. *Buffer = 0; // in case GetTimeFormat doesn't add anything
  271. BufferLength -= 2;
  272. }
  273. else if((BufferLength > 0) && (Flags & FT_LTR)) {
  274. *Buffer++ = RLM; // simulate an opposite run
  275. *Buffer++ = LRM; // force LTR display of the time part.
  276. *Buffer = 0; // in case GetTimeFormat doesn't add anything
  277. BufferLength -= 2;
  278. }
  279. }
  280. Length = GetTimeFormatW(GetUserDefaultLCID(),
  281. 0,
  282. &SystemTime,
  283. NULL,
  284. TimeString,
  285. 256
  286. );
  287. _snwprintf(Buffer, BufferLength,
  288. TEXT("%s"),
  289. TimeString
  290. );
  291. }
  292. return(TRUE);
  293. }
  294. /***************************************************************************\
  295. * DuplicateUnicodeString
  296. *
  297. * Purpose : Allocates space for new string then copies new into old.
  298. * The new string is always 0 terminated
  299. * The new string should be free using RtlFreeUnicodeString()
  300. *
  301. * Returns : TRUE on success, FALSE on failure
  302. *
  303. * History:
  304. * 11-04-92 Davidc Created.
  305. * 05-29-98 DSheldon Modified so that no uni->ansi->uni translation occurs
  306. \***************************************************************************/
  307. BOOL
  308. DuplicateUnicodeString(
  309. PUNICODE_STRING OutString,
  310. PUNICODE_STRING InString
  311. )
  312. {
  313. *OutString = *InString ;
  314. OutString->Buffer = RtlAllocateHeap( RtlProcessHeap(), 0, InString->Length + sizeof(WCHAR) );
  315. if ( OutString->Buffer )
  316. {
  317. RtlCopyMemory( OutString->Buffer,
  318. InString->Buffer,
  319. InString->Length );
  320. OutString->Buffer[ OutString->Length / sizeof( WCHAR ) ] = L'\0';
  321. OutString->MaximumLength = OutString->Length + sizeof( WCHAR );
  322. }
  323. return (OutString->Buffer != NULL);
  324. }
  325. /***************************************************************************\
  326. * UnicodeStringToString
  327. *
  328. * Purpose : Converts a unicode string to it's local format and allocates
  329. * space for it. The returned NULL terminated string can be freed
  330. * using Free()
  331. *
  332. * Returns : Pointer to NULL terminated string or NULL on failure.
  333. *
  334. * History:
  335. * 11-04-92 Davidc Created.
  336. \***************************************************************************/
  337. LPTSTR
  338. UnicodeStringToString(
  339. PUNICODE_STRING UnicodeString
  340. )
  341. {
  342. LPTSTR String;
  343. ULONG BytesRequired = sizeof(TCHAR)*(UnicodeString->Length + 1);
  344. String = Alloc(BytesRequired);
  345. if (String != NULL) {
  346. if (UnicodeString->Length && UnicodeString->Buffer ) {
  347. lstrcpy(String, UnicodeString->Buffer);
  348. } else {
  349. Free(String);
  350. String = 0;
  351. }
  352. }
  353. return(String);
  354. }
  355. /***************************************************************************\
  356. * FUNCTION: OpenIniFileUserMapping
  357. *
  358. * PURPOSE: Forces the ini file mapping apis to reference the current user's
  359. * registry.
  360. *
  361. * RETURNS: TRUE on success, FALSE on failure
  362. *
  363. * HISTORY:
  364. *
  365. * 24-Aug-92 Davidc Created.
  366. *
  367. \***************************************************************************/
  368. BOOL
  369. OpenIniFileUserMapping(
  370. PGLOBALS pGlobals
  371. )
  372. {
  373. BOOL Result;
  374. HANDLE ImpersonationHandle;
  375. //
  376. // Impersonate the user
  377. //
  378. ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL);
  379. if (ImpersonationHandle == NULL) {
  380. DebugLog((DEB_ERROR, "OpenIniFileUserMapping failed to impersonate user"));
  381. return(FALSE);
  382. }
  383. Result = OpenProfileUserMapping();
  384. if (!Result) {
  385. DebugLog((DEB_ERROR, "OpenProfileUserMapping failed, error = %d", GetLastError()));
  386. }
  387. //
  388. // Revert to being 'ourself'
  389. //
  390. if (!StopImpersonating(ImpersonationHandle)) {
  391. DebugLog((DEB_ERROR, "OpenIniFileUserMapping failed to revert to self"));
  392. }
  393. return(Result);
  394. }
  395. /***************************************************************************\
  396. * FUNCTION: CloseIniFileUserMapping
  397. *
  398. * PURPOSE: Closes the ini file mapping to the user's registry such
  399. * that future use of the ini apis will fail if they reference
  400. * the user's registry.
  401. *
  402. * RETURNS: Nothing
  403. *
  404. * HISTORY:
  405. *
  406. * 24-Aug-92 Davidc Created.
  407. *
  408. \***************************************************************************/
  409. VOID
  410. CloseIniFileUserMapping(
  411. PGLOBALS pGlobals
  412. )
  413. {
  414. BOOL Result;
  415. Result = CloseProfileUserMapping();
  416. if (!Result) {
  417. DebugLog((DEB_ERROR, "CloseProfileUserMapping failed, error = %d", GetLastError()));
  418. }
  419. UNREFERENCED_PARAMETER(pGlobals);
  420. }
  421. /***************************************************************************\
  422. * FUNCTION: AllocAndGetDlgItemText
  423. *
  424. * PURPOSE: Allocates memory for and returns pointer to a copy of the text
  425. * in the specified dialog control.
  426. * The returned string should be freed using Free()
  427. *
  428. * RETURNS: Pointer to copy of dlg item text, or NULL on failure.
  429. *
  430. * HISTORY:
  431. *
  432. * 9-Sep-92 Davidc Created.
  433. *
  434. \***************************************************************************/
  435. LPTSTR
  436. AllocAndGetDlgItemText(
  437. HWND hDlg,
  438. int iItem
  439. )
  440. {
  441. HWND hwnd;
  442. LPTSTR String;
  443. LONG Length;
  444. LONG BytesRequired;
  445. LONG LengthCopied;
  446. //
  447. // Go find the window handle of the control
  448. //
  449. hwnd = GetDlgItem(hDlg, iItem);
  450. if (hwnd == NULL) {
  451. DebugLog((DEB_ERROR, "AllocAndGetDlgItemText : Couldn't find control %d in dialog 0x%lx", iItem, hDlg));
  452. ASSERT(hwnd != NULL);
  453. return(NULL);
  454. }
  455. //
  456. // Get the length of the control's text
  457. //
  458. Length = (LONG)SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0);
  459. if (Length < 0) {
  460. DebugLog((DEB_ERROR, "AllocAndGetDlgItemText : Dialog control text length < 0 (%d)", Length));
  461. ASSERT(Length >= 0);
  462. return(NULL);
  463. }
  464. //
  465. // Calculate the bytes required for the string.
  466. // The length doesn't include the terminator
  467. //
  468. Length ++; // Add one for terminator
  469. BytesRequired = Length * sizeof(TCHAR);
  470. String = (LPTSTR)Alloc(BytesRequired);
  471. if (String == NULL) {
  472. DebugLog((DEB_ERROR, "AllocAndGetDlgItemText : Failed to allocate %d bytes for dialog control text", BytesRequired));
  473. return(NULL);
  474. }
  475. //
  476. // Fill in the allocated block with the text
  477. //
  478. LengthCopied = (LONG)SendMessage(hwnd, WM_GETTEXT, Length, (LPARAM)String);
  479. if (LengthCopied != (Length - 1)) {
  480. DebugLog((DEB_ERROR, "AllocAndGetDlgItemText : WM_GETTEXT for %d chars only copied %d chars", Length-1, LengthCopied));
  481. ASSERT(LengthCopied == (Length - 1));
  482. Free(String);
  483. return(NULL);
  484. }
  485. String[Length - 1] = TEXT('\0');
  486. return(String);
  487. }
  488. /***************************************************************************\
  489. * FUNCTION: AllocAndGetPrivateProfileString
  490. *
  491. * PURPOSE: Allocates memory for and returns pointer to a copy of the
  492. * specified profile string
  493. * The returned string should be freed using Free()
  494. *
  495. * RETURNS: Pointer to copy of profile string or NULL on failure.
  496. *
  497. * HISTORY:
  498. *
  499. * 12-Nov-92 Davidc Created.
  500. *
  501. \***************************************************************************/
  502. LPTSTR
  503. AllocAndGetPrivateProfileString(
  504. LPCTSTR lpAppName,
  505. LPCTSTR lpKeyName,
  506. LPCTSTR lpDefault,
  507. LPCTSTR lpFileName
  508. )
  509. {
  510. LPTSTR String;
  511. LPTSTR NewString ;
  512. LONG LengthAllocated;
  513. LONG LengthCopied;
  514. //
  515. // Pick a random buffer length, if it's not big enough reallocate
  516. // it and try again until it is.
  517. //
  518. LengthAllocated = TYPICAL_STRING_LENGTH;
  519. String = Alloc(LengthAllocated * sizeof(TCHAR));
  520. if (String == NULL) {
  521. DebugLog((DEB_ERROR, "AllocAndGetPrivateProfileString : Failed to allocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
  522. return(NULL);
  523. }
  524. while (TRUE) {
  525. LengthCopied = GetPrivateProfileString( lpAppName,
  526. lpKeyName,
  527. lpDefault,
  528. String,
  529. LengthAllocated,
  530. lpFileName
  531. );
  532. //
  533. // If the returned value is our passed size - 1 (weird way for error)
  534. // then our buffer is too small. Make it bigger and start over again.
  535. //
  536. if (LengthCopied == (LengthAllocated - 1)) {
  537. VerbosePrint(("AllocAndGetPrivateProfileString: Failed with buffer length = %d, reallocating and retrying", LengthAllocated));
  538. LengthAllocated *= 2;
  539. NewString = ReAlloc(String, LengthAllocated * sizeof(TCHAR));
  540. if (NewString == NULL) {
  541. Free( String );
  542. String = NULL ;
  543. DebugLog((DEB_ERROR, "AllocAndGetPrivateProfileString : Failed to reallocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
  544. break;
  545. }
  546. String = NewString ;
  547. //
  548. // Go back and try to read it again
  549. //
  550. } else {
  551. //
  552. // Success!
  553. //
  554. break;
  555. }
  556. }
  557. return(String);
  558. }
  559. /***************************************************************************\
  560. * FUNCTION: WritePrivateProfileInt
  561. *
  562. * PURPOSE: Writes out an integer to a profile file
  563. *
  564. * RETURNS: TRUE on success, FALSE on failure
  565. *
  566. * HISTORY:
  567. *
  568. * 12-Nov-92 Davidc Created.
  569. *
  570. \***************************************************************************/
  571. BOOL
  572. WritePrivateProfileInt(
  573. LPCTSTR lpAppName,
  574. LPCTSTR lpKeyName,
  575. UINT Value,
  576. LPCTSTR lpFileName
  577. )
  578. {
  579. NTSTATUS Status;
  580. TCHAR String[30];
  581. UNICODE_STRING UniString;
  582. UniString.MaximumLength = 30;
  583. UniString.Buffer = String;
  584. Status = RtlIntegerToUnicodeString(Value,10,&UniString);
  585. if (!NT_SUCCESS(Status)) {
  586. return(FALSE);
  587. }
  588. return (WritePrivateProfileString(lpAppName, lpKeyName, UniString.Buffer, lpFileName));
  589. }
  590. /***************************************************************************\
  591. * FUNCTION: AllocAndExpandEnvironmentStrings
  592. *
  593. * PURPOSE: Allocates memory for and returns pointer to buffer containing
  594. * the passed string expanded to include environment strings
  595. * The returned buffer should be freed using Free()
  596. *
  597. * RETURNS: Pointer to expanded string or NULL on failure.
  598. *
  599. * HISTORY:
  600. *
  601. * 21-Dec-92 Davidc Created.
  602. *
  603. \***************************************************************************/
  604. LPTSTR
  605. AllocAndExpandEnvironmentStrings(
  606. LPCTSTR lpszSrc
  607. )
  608. {
  609. LPTSTR String;
  610. LONG LengthAllocated;
  611. LONG LengthCopied;
  612. //
  613. // Pick a random buffer length, if it's not big enough reallocate
  614. // it and try again until it is.
  615. //
  616. LengthAllocated = lstrlen(lpszSrc) + TYPICAL_STRING_LENGTH;
  617. String = Alloc(LengthAllocated * sizeof(TCHAR));
  618. if (String == NULL) {
  619. DebugLog((DEB_ERROR, "AllocAndExpandEnvironmentStrings : Failed to allocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
  620. return(NULL);
  621. }
  622. while (TRUE) {
  623. LengthCopied = ExpandEnvironmentStrings( lpszSrc,
  624. String,
  625. LengthAllocated
  626. );
  627. if (LengthCopied == 0) {
  628. DebugLog((DEB_ERROR, "AllocAndExpandEnvironmentStrings : ExpandEnvironmentStrings failed, error = %d", GetLastError()));
  629. Free(String);
  630. String = NULL;
  631. break;
  632. }
  633. //
  634. // If the buffer was too small, make it bigger and try again
  635. //
  636. if (LengthCopied > LengthAllocated) {
  637. VerbosePrint(("AllocAndExpandEnvironmentStrings: Failed with buffer length = %d, reallocating to %d and retrying (retry should succeed)", LengthAllocated, LengthCopied));
  638. String = ReAlloc(String, LengthCopied * sizeof(TCHAR));
  639. if (String == NULL) {
  640. DebugLog((DEB_ERROR, "AllocAndExpandEnvironmentStrings : Failed to reallocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
  641. break;
  642. }
  643. //
  644. // Go back and try to expand the string again
  645. //
  646. } else {
  647. //
  648. // Success!
  649. //
  650. break;
  651. }
  652. }
  653. return(String);
  654. }
  655. /***************************************************************************\
  656. * FUNCTION: AllocAndRegEnumKey
  657. *
  658. * PURPOSE: Allocates memory for and returns pointer to buffer containing
  659. * the next registry sub-key name under the specified key
  660. * The returned buffer should be freed using Free()
  661. *
  662. * RETURNS: Pointer to sub-key name or NULL on failure. The reason for the
  663. * error can be obtains using GetLastError()
  664. *
  665. * HISTORY:
  666. *
  667. * 21-Dec-92 Davidc Created.
  668. *
  669. \***************************************************************************/
  670. LPTSTR
  671. AllocAndRegEnumKey(
  672. HKEY hKey,
  673. DWORD iSubKey
  674. )
  675. {
  676. LPTSTR String;
  677. LONG LengthAllocated;
  678. //
  679. // Pick a random buffer length, if it's not big enough reallocate
  680. // it and try again until it is.
  681. //
  682. LengthAllocated = TYPICAL_STRING_LENGTH;
  683. String = Alloc(LengthAllocated * sizeof(TCHAR));
  684. if (String == NULL) {
  685. DebugLog((DEB_ERROR, "AllocAndRegEnumKey : Failed to allocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
  686. return(NULL);
  687. }
  688. while (TRUE) {
  689. DWORD Error = RegEnumKey(hKey, iSubKey, String, LengthAllocated);
  690. if (Error == ERROR_SUCCESS) {
  691. break;
  692. }
  693. if (Error != ERROR_MORE_DATA) {
  694. if (Error != ERROR_NO_MORE_ITEMS) {
  695. DebugLog((DEB_ERROR, "AllocAndRegEnumKey : RegEnumKey failed, error = %d", Error));
  696. }
  697. Free(String);
  698. String = NULL;
  699. SetLastError(Error);
  700. break;
  701. }
  702. //
  703. // The buffer was too small, make it bigger and try again
  704. //
  705. VerbosePrint(("AllocAndRegEnumKey: Failed with buffer length = %d, reallocating and retrying", LengthAllocated));
  706. LengthAllocated *= 2;
  707. String = ReAlloc(String, LengthAllocated * sizeof(TCHAR));
  708. if (String == NULL) {
  709. DebugLog((DEB_ERROR, "AllocAndRegEnumKey : Failed to reallocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
  710. break;
  711. }
  712. }
  713. return(String);
  714. }
  715. /***************************************************************************\
  716. * FUNCTION: AllocAndRegQueryValueEx
  717. *
  718. * PURPOSE: Version of RegQueryValueEx that returns value in allocated buffer.
  719. * The returned buffer should be freed using Free()
  720. *
  721. * RETURNS: Pointer to key value or NULL on failure. The reason for the
  722. * error can be obtains using GetLastError()
  723. *
  724. * HISTORY:
  725. *
  726. * 15-Jan-93 Davidc Created.
  727. *
  728. \***************************************************************************/
  729. LPTSTR
  730. AllocAndRegQueryValueEx(
  731. HKEY hKey,
  732. LPTSTR lpValueName,
  733. LPDWORD lpReserved,
  734. LPDWORD lpType
  735. )
  736. {
  737. LPTSTR String;
  738. DWORD BytesAllocated;
  739. //
  740. // Pick a random buffer length, if it's not big enough reallocate
  741. // it and try again until it is.
  742. //
  743. BytesAllocated = TYPICAL_STRING_LENGTH * sizeof(TCHAR);
  744. String = Alloc(BytesAllocated);
  745. if (String == NULL) {
  746. DebugLog((DEB_ERROR, "AllocAndRegQueryValueEx : Failed to allocate %d bytes for string", BytesAllocated));
  747. return(NULL);
  748. }
  749. while (TRUE) {
  750. DWORD Error;
  751. DWORD BytesReturned = BytesAllocated;
  752. Error = RegQueryValueEx(hKey,
  753. lpValueName,
  754. lpReserved,
  755. lpType,
  756. (LPBYTE)String,
  757. &BytesReturned);
  758. if (Error == ERROR_SUCCESS) {
  759. break;
  760. }
  761. if (Error != ERROR_MORE_DATA) {
  762. DebugLog((DEB_ERROR, "AllocAndRegQueryValueEx : RegQueryValueEx failed, error = %d", Error));
  763. Free(String);
  764. String = NULL;
  765. SetLastError(Error);
  766. break;
  767. }
  768. //
  769. // The buffer was too small, make it bigger and try again
  770. //
  771. VerbosePrint(("AllocAndRegQueryValueEx: Failed with buffer length = %d bytes, reallocating and retrying", BytesAllocated));
  772. BytesAllocated *= 2;
  773. String = ReAlloc(String, BytesAllocated);
  774. if (String == NULL) {
  775. DebugLog((DEB_ERROR, "AllocAndRegQueryValueEx : Failed to reallocate %d bytes for string", BytesAllocated));
  776. break;
  777. }
  778. }
  779. return(String);
  780. }
  781. /***************************************************************************\
  782. * FUNCTION: ReadWinlogonBoolValue
  783. *
  784. * PURPOSE: Determines the correct BOOL value for the requested
  785. * value name by first looking up the machine preference
  786. * and then checking for policy
  787. *
  788. * RETURNS: TRUE or FALSE
  789. *
  790. * HISTORY:
  791. *
  792. * EricFlo 10-14-98 Created
  793. *
  794. \***************************************************************************/
  795. BOOL
  796. ReadWinlogonBoolValue (LPTSTR lpValueName, BOOL bDefault)
  797. {
  798. BOOL bResult;
  799. HKEY hKey;
  800. DWORD dwSize, dwType;
  801. //
  802. // Get the machine preference first
  803. //
  804. bResult = GetProfileInt(APPLICATION_NAME, lpValueName, bDefault);
  805. //
  806. // Check for a machine policy
  807. //
  808. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WINLOGON_POLICY_KEY,
  809. 0, KEY_READ, &hKey) == ERROR_SUCCESS)
  810. {
  811. dwSize = sizeof(bResult);
  812. RegQueryValueEx(hKey, lpValueName, 0, &dwType,
  813. (LPBYTE)&bResult, &dwSize);
  814. RegCloseKey (hKey);
  815. }
  816. return bResult;
  817. }
  818. /***************************************************************************\
  819. * HandleComboBoxOK
  820. *
  821. * Deals with UI requirements when OK is selected in a dialog when the
  822. * focus is on or in a combo-box.
  823. *
  824. * This routine should be called from a dialog proc that contains a
  825. * combo-box when a WM_COMMAND, IDOK is received.
  826. *
  827. * Returns TRUE if the message was dealt with and the caller should ignore it,
  828. * FALSE if this routine did nothing with it and the caller should process it
  829. * normally.
  830. *
  831. * History:
  832. * 24-Sep-92 Davidc Created.
  833. \***************************************************************************/
  834. BOOL
  835. HandleComboBoxOK(
  836. HWND hDlg,
  837. int ComboBoxId
  838. )
  839. {
  840. HWND hwndFocus = GetFocus();
  841. HWND hwndCB = GetDlgItem(hDlg, ComboBoxId);
  842. //
  843. // Hitting enter on a combo-box with the list showing should simply
  844. // hide the list.
  845. // We check for focus window being a child of the combo-box to
  846. // handle non-list style combo-boxes which have the focus on
  847. // the child edit control.
  848. //
  849. if ((hwndFocus == hwndCB) || IsChild(hwndCB, hwndFocus)) {
  850. if (SendMessage(hwndCB, CB_GETDROPPEDSTATE, 0, 0)) {
  851. //
  852. // Make the list-box disappear and we're done.
  853. //
  854. SendMessage(hwndCB, CB_SHOWDROPDOWN, (WPARAM)FALSE, 0);
  855. return(TRUE);
  856. }
  857. }
  858. //
  859. // We didn't do anything
  860. //
  861. return(FALSE);
  862. }
  863. /***************************************************************************\
  864. * FUNCTION: EncodeMultiSzW
  865. *
  866. * PURPOSE: Converts a multi-sz string and encodes it to look like
  867. * a single string.
  868. *
  869. * We replace the terminators between strings
  870. * with the TERMINATOR_REPLACEMENT character. We replace
  871. * existing occurrences of the replacement character with
  872. * two of them.
  873. *
  874. * RETURNS: Pointer to encoded string or NULL on failure.
  875. * The returned buffer should be freed using Free()
  876. *
  877. * HISTORY:
  878. *
  879. * 01-12-93 Davidc Created.
  880. *
  881. \***************************************************************************/
  882. #define TERMINATOR_REPLACEMENT TEXT(',')
  883. LPWSTR
  884. EncodeMultiSzW(
  885. IN LPWSTR MultiSz
  886. )
  887. {
  888. DWORD Length;
  889. DWORD NewLength;
  890. LPWSTR NewBuffer;
  891. LPWSTR p, q;
  892. DWORD ExtraCharacters;
  893. //
  894. // First calculate the length of the new string (with replacements)
  895. //
  896. p = MultiSz;
  897. ExtraCharacters = 0;
  898. while (*p) {
  899. while (*p) {
  900. if (*p == TERMINATOR_REPLACEMENT) {
  901. ExtraCharacters ++;
  902. }
  903. p ++;
  904. }
  905. p ++;
  906. }
  907. Length = (DWORD)(p - MultiSz); // p points at 'second' (final) null terminator
  908. NewLength = Length + ExtraCharacters;
  909. //
  910. // Allocate space for the new string
  911. //
  912. NewBuffer = Alloc((NewLength + 1) * sizeof(WCHAR));
  913. if (NewBuffer == NULL) {
  914. DebugLog((DEB_ERROR, "EncodeMultiSz: failed to allocate space for %d bytes", (NewLength + 1) * sizeof(WCHAR)));
  915. return(NULL);
  916. }
  917. //
  918. // Copy the string into the new buffer making replacements as we go
  919. //
  920. p = MultiSz;
  921. q = NewBuffer;
  922. while (*p) {
  923. while (*p) {
  924. *q = *p;
  925. if (*p == TERMINATOR_REPLACEMENT) {
  926. q ++;
  927. *q = TERMINATOR_REPLACEMENT;
  928. }
  929. p ++;
  930. q ++;
  931. }
  932. *q = TERMINATOR_REPLACEMENT;
  933. p ++;
  934. q ++;
  935. }
  936. ASSERT((DWORD)(q - NewBuffer) == NewLength);
  937. //
  938. // Add terminator
  939. //
  940. *q = 0;
  941. return(NewBuffer);
  942. }
  943. /***************************************************************************\
  944. * TimeoutMessageBox
  945. *
  946. * Same as a normal message box, but times out if there is no user input
  947. * for the specified number of seconds
  948. * For convenience, this api takes string resource ids rather than string
  949. * pointers as input. The resources are loaded from the .exe module
  950. *
  951. * 12-05-91 Davidc Created.
  952. \***************************************************************************/
  953. INT_PTR
  954. TimeoutMessageBox(
  955. HWND hwnd,
  956. PGLOBALS pGlobals,
  957. UINT IdText,
  958. UINT IdCaption,
  959. UINT wType,
  960. TIMEOUT Timeout
  961. )
  962. {
  963. TCHAR CaptionBuffer[MAX_STRING_BYTES];
  964. PTCHAR Caption = CaptionBuffer;
  965. TCHAR Text[MAX_STRING_BYTES];
  966. LoadString(hDllInstance, IdText, Text, MAX_STRING_LENGTH);
  967. if (IdCaption != 0) {
  968. LoadString(hDllInstance, IdCaption, Caption, MAX_STRING_LENGTH);
  969. } else {
  970. Caption = NULL;
  971. }
  972. return TimeoutMessageBoxlpstr(hwnd, pGlobals, Text, Caption, wType, Timeout);
  973. }
  974. /***************************************************************************\
  975. * TimeoutMessageBoxlpstr
  976. *
  977. * Same as a normal message box, but times out if there is no user input
  978. * for the specified number of seconds
  979. *
  980. * 12-05-91 Davidc Created.
  981. \***************************************************************************/
  982. INT_PTR
  983. TimeoutMessageBoxlpstr(
  984. HWND hwnd,
  985. PGLOBALS pGlobals,
  986. LPTSTR Text,
  987. LPTSTR Caption,
  988. UINT wType,
  989. TIMEOUT Timeout
  990. )
  991. {
  992. INT_PTR DlgResult;
  993. BOOL fStatusHostHidden;
  994. fStatusHostHidden = _Shell_LogonStatus_IsHidden();
  995. _Shell_LogonStatus_Hide();
  996. // Set up input timeout
  997. pWlxFuncs->WlxSetTimeout(pGlobals->hGlobalWlx, Timeout);
  998. DlgResult = pWlxFuncs->WlxMessageBox( pGlobals->hGlobalWlx,
  999. hwnd,
  1000. Text,
  1001. Caption,
  1002. wType);
  1003. if (!fStatusHostHidden)
  1004. {
  1005. _Shell_LogonStatus_Show();
  1006. }
  1007. return(DlgResult);
  1008. }
  1009. PWSTR
  1010. DupString(PWSTR pszString)
  1011. {
  1012. DWORD cbString;
  1013. PWSTR pszNewString;
  1014. cbString = (DWORD) (wcslen(pszString) + 1) * sizeof(WCHAR);
  1015. pszNewString = LocalAlloc(LMEM_FIXED, cbString);
  1016. if (pszNewString)
  1017. {
  1018. CopyMemory(pszNewString, pszString, cbString);
  1019. }
  1020. return(pszNewString);
  1021. }
  1022. PWSTR
  1023. DupUnicodeString(PUNICODE_STRING pString)
  1024. {
  1025. PWSTR pszNewString;
  1026. if (pString->Length)
  1027. {
  1028. pszNewString = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, pString->Length + sizeof(WCHAR));
  1029. if (pszNewString)
  1030. {
  1031. CopyMemory(pszNewString, pString->Buffer, pString->Length);
  1032. }
  1033. }
  1034. else
  1035. pszNewString = NULL;
  1036. return(pszNewString);
  1037. }
  1038. /***************************************************************************\
  1039. * FUNCTION: EnableDomainForUPN
  1040. *
  1041. * PURPOSE: Enables or disables the domain text box based on whether or not
  1042. * a UPN-style name is typed into the username box.
  1043. *
  1044. * RETURNS: none
  1045. *
  1046. * HISTORY:
  1047. *
  1048. * 04-17-1998 dsheldon created
  1049. *
  1050. \***************************************************************************/
  1051. void EnableDomainForUPN(HWND hwndUsername, HWND hwndDomain)
  1052. {
  1053. BOOL fEnable;
  1054. // Get the string the user is typing
  1055. TCHAR* pszLogonName;
  1056. int cchBuffer = (int)SendMessage(hwndUsername, WM_GETTEXTLENGTH, 0, 0) + 1;
  1057. pszLogonName = (TCHAR*) Alloc(cchBuffer * sizeof(TCHAR));
  1058. if (pszLogonName != NULL)
  1059. {
  1060. SendMessage(hwndUsername, WM_GETTEXT, (WPARAM) cchBuffer, (LPARAM) pszLogonName);
  1061. // Disable the domain combo if the user is using a
  1062. // UPN (if there is a "@") - ie [email protected]
  1063. fEnable = (NULL == wcschr(pszLogonName, TEXT('@')));
  1064. EnableWindow(hwndDomain, fEnable);
  1065. Free(pszLogonName);
  1066. }
  1067. }
  1068. // TRUE if we must always hide the domain box (local logon, UPN, smartcard only)
  1069. // FALSE if this policy isn't set or is set to 0x0
  1070. BOOL ForceNoDomainUI()
  1071. {
  1072. DWORD dwPolicyVal = 0;
  1073. HKEY hkey;
  1074. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0, KEY_QUERY_VALUE, &hkey))
  1075. {
  1076. DWORD cbData = sizeof (dwPolicyVal);
  1077. DWORD dwType;
  1078. if (ERROR_SUCCESS != RegQueryValueEx(hkey, NODOMAINCOMBO, 0, &dwType, (LPBYTE) &dwPolicyVal, &cbData))
  1079. {
  1080. dwPolicyVal = 0;
  1081. }
  1082. RegCloseKey(hkey);
  1083. }
  1084. return (0 != dwPolicyVal);
  1085. }
  1086. DWORD GetReasonSelection(HWND hwndCombo)
  1087. {
  1088. DWORD dwResult;
  1089. PREASON pReason;
  1090. int iItem = ComboBox_GetCurSel(hwndCombo);
  1091. if (iItem != (int) CB_ERR) {
  1092. pReason = (PREASON) ComboBox_GetItemData(hwndCombo, iItem);
  1093. dwResult = pReason->dwCode;
  1094. } else {
  1095. dwResult = SHTDN_REASON_UNKNOWN;
  1096. }
  1097. return dwResult;
  1098. }
  1099. VOID SetReasonDescription(HWND hwndCombo, HWND hwndStatic)
  1100. {
  1101. PREASON pReason;
  1102. int iItem = ComboBox_GetCurSel(hwndCombo);
  1103. if (iItem != CB_ERR) {
  1104. pReason = (PREASON) ComboBox_GetItemData(hwndCombo, iItem);
  1105. SetWindowText(hwndStatic, pReason->szDesc);
  1106. }
  1107. }