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.

1056 lines
20 KiB

  1. /*++
  2. Microsoft Confidential
  3. Copyright (c) 1992-1997 Microsoft Corporation
  4. All rights reserved
  5. Module Name:
  6. util.c
  7. Abstract:
  8. Utility functions for System Control Panel Applet
  9. Author:
  10. Eric Flo (ericflo) 19-Jun-1995
  11. Revision History:
  12. 15-Oct-1997 scotthal
  13. Complete overhaul
  14. --*/
  15. #include "sysdm.h"
  16. #include <strsafe.h>
  17. #include <ntdddisk.h>
  18. //
  19. // Constants
  20. //
  21. #define CCH_MAX_DEC 12 // Number of chars needed to hold 2^32
  22. #define MAX_SWAPSIZE_X86 (4 * 1024) // 4 Gb (number stored in megabytes)
  23. #define MAX_SWAPSIZE_X86_PAE (16 * 1024 * 1024) // 16 Tb
  24. #define MAX_SWAPSIZE_IA64 (32 * 1024 * 1024) // 32 Tb
  25. #define MAX_SWAPSIZE_AMD64 (16 * 1024 * 1024) // 16 Tb
  26. void
  27. ErrMemDlg(
  28. IN HWND hParent
  29. )
  30. /*++
  31. Routine Description:
  32. Displays "out of memory" message.
  33. Arguments:
  34. hParent -
  35. Supplies parent window handle.
  36. Return Value:
  37. None.
  38. --*/
  39. {
  40. MessageBox(
  41. hParent,
  42. g_szErrMem,
  43. g_szSystemApplet,
  44. MB_OK | MB_ICONHAND | MB_SYSTEMMODAL
  45. );
  46. return;
  47. }
  48. LPTSTR
  49. SkipWhiteSpace(
  50. IN LPTSTR sz
  51. )
  52. /*++
  53. Routine Description:
  54. SkipWhiteSpace
  55. For the purposes of this fuction, whitespace is space, tab,
  56. cr, or lf.
  57. Arguments:
  58. sz -
  59. Supplies a string (which presumably has leading whitespace)
  60. Return Value:
  61. Pointer to string without leading whitespace if successful.
  62. --*/
  63. {
  64. while( IsWhiteSpace(*sz) )
  65. sz++;
  66. return sz;
  67. }
  68. int
  69. StringToInt(
  70. IN LPTSTR sz
  71. )
  72. /*++
  73. Routine Description:
  74. TCHAR version of atoi
  75. Arguments:
  76. sz -
  77. Supplies the string to convert
  78. Return Value:
  79. Integer representation of the string
  80. --*/
  81. {
  82. int i = 0;
  83. sz = SkipWhiteSpace(sz);
  84. while( IsDigit( *sz ) ) {
  85. i = i * 10 + DigitVal( *sz );
  86. sz++;
  87. }
  88. return i;
  89. }
  90. BOOL
  91. Delnode_Recurse(
  92. IN LPTSTR lpDir
  93. )
  94. /*++
  95. Routine Description:
  96. Recursive delete function for Delnode
  97. Arguments:
  98. lpDir -
  99. Supplies directory to delete
  100. Return Value:
  101. TRUE if successful.
  102. FALSE if an error occurs.
  103. --*/
  104. {
  105. WIN32_FIND_DATA fd;
  106. HANDLE hFile;
  107. //
  108. // Setup the current working dir
  109. //
  110. if (!SetCurrentDirectory (lpDir)) {
  111. return FALSE;
  112. }
  113. //
  114. // Find the first file
  115. //
  116. hFile = FindFirstFile(TEXT("*.*"), &fd);
  117. if (hFile == INVALID_HANDLE_VALUE) {
  118. if (GetLastError() == ERROR_FILE_NOT_FOUND) {
  119. return TRUE;
  120. } else {
  121. return FALSE;
  122. }
  123. }
  124. do {
  125. //
  126. // Check for "." and ".."
  127. //
  128. if (!lstrcmpi(fd.cFileName, TEXT("."))) {
  129. continue;
  130. }
  131. if (!lstrcmpi(fd.cFileName, TEXT(".."))) {
  132. continue;
  133. }
  134. if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  135. //
  136. // Found a directory.
  137. //
  138. if (!Delnode_Recurse(fd.cFileName)) {
  139. FindClose(hFile);
  140. return FALSE;
  141. }
  142. if (fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
  143. fd.dwFileAttributes &= ~FILE_ATTRIBUTE_READONLY;
  144. SetFileAttributes (fd.cFileName, fd.dwFileAttributes);
  145. }
  146. RemoveDirectory (fd.cFileName);
  147. } else {
  148. //
  149. // We found a file. Set the file attributes,
  150. // and try to delete it.
  151. //
  152. if ((fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ||
  153. (fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)) {
  154. SetFileAttributes (fd.cFileName, FILE_ATTRIBUTE_NORMAL);
  155. }
  156. DeleteFile (fd.cFileName);
  157. }
  158. //
  159. // Find the next entry
  160. //
  161. } while (FindNextFile(hFile, &fd));
  162. //
  163. // Close the search handle
  164. //
  165. FindClose(hFile);
  166. //
  167. // Reset the working directory
  168. //
  169. if (!SetCurrentDirectory (TEXT(".."))) {
  170. return FALSE;
  171. }
  172. //
  173. // Success.
  174. //
  175. return TRUE;
  176. }
  177. BOOL
  178. Delnode(
  179. IN LPTSTR lpDir
  180. )
  181. /*++
  182. Routine Description:
  183. Recursive function that deletes files and
  184. directories.
  185. Arguments:
  186. lpDir -
  187. Supplies directory to delete.
  188. Return Value:
  189. TRUE if successful
  190. FALSE if an error occurs
  191. --*/
  192. {
  193. TCHAR szCurWorkingDir[MAX_PATH];
  194. if (GetCurrentDirectory(ARRAYSIZE(szCurWorkingDir), szCurWorkingDir)) {
  195. Delnode_Recurse (lpDir);
  196. SetCurrentDirectory (szCurWorkingDir);
  197. if (!RemoveDirectory (lpDir)) {
  198. return FALSE;
  199. }
  200. } else {
  201. return FALSE;
  202. }
  203. return TRUE;
  204. }
  205. LONG
  206. MyRegSaveKey(
  207. IN HKEY hKey,
  208. IN LPCTSTR lpSubKey
  209. )
  210. /*++
  211. Routine Description:
  212. Saves a registry key.
  213. Arguments:
  214. hKey -
  215. Supplies handle to a registry key.
  216. lpSubKey -
  217. Supplies the name of the subkey to save.
  218. Return Value:
  219. ERROR_SUCCESS if successful.
  220. Error code from RegSaveKey() if an error occurs.
  221. --*/
  222. {
  223. HANDLE hToken = NULL;
  224. LUID luid;
  225. DWORD dwSize = 1024;
  226. PTOKEN_PRIVILEGES lpPrevPrivilages = NULL;
  227. TOKEN_PRIVILEGES tp;
  228. LONG error;
  229. //
  230. // Allocate space for the old privileges
  231. //
  232. lpPrevPrivilages = GlobalAlloc(GPTR, dwSize);
  233. if (!lpPrevPrivilages) {
  234. error = GetLastError();
  235. goto Exit;
  236. }
  237. if (!OpenProcessToken( GetCurrentProcess(),
  238. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  239. &hToken)) {
  240. error = GetLastError();
  241. goto Exit;
  242. }
  243. if (!LookupPrivilegeValue( NULL, SE_BACKUP_NAME, &luid )) {
  244. error = GetLastError();
  245. goto Exit;
  246. }
  247. tp.PrivilegeCount = 1;
  248. tp.Privileges[0].Luid = luid;
  249. tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  250. if (!AdjustTokenPrivileges( hToken, FALSE, &tp, dwSize,
  251. lpPrevPrivilages, &dwSize )) {
  252. if (GetLastError() == ERROR_MORE_DATA) {
  253. PTOKEN_PRIVILEGES lpTemp;
  254. lpTemp = GlobalReAlloc(lpPrevPrivilages, dwSize, GMEM_MOVEABLE);
  255. if (!lpTemp) {
  256. error = GetLastError();
  257. goto Exit;
  258. }
  259. lpPrevPrivilages = lpTemp;
  260. if (!AdjustTokenPrivileges( hToken, FALSE, &tp, dwSize,
  261. lpPrevPrivilages, &dwSize )) {
  262. error = GetLastError();
  263. goto Exit;
  264. }
  265. } else {
  266. error = GetLastError();
  267. goto Exit;
  268. }
  269. }
  270. //
  271. // Save the hive
  272. //
  273. error = RegSaveKey(hKey, lpSubKey, NULL);
  274. if (!AdjustTokenPrivileges( hToken, FALSE, lpPrevPrivilages,
  275. 0, NULL, NULL )) {
  276. ASSERT(FALSE);
  277. }
  278. Exit:
  279. if (hToken) {
  280. CloseHandle (hToken);
  281. }
  282. if (lpPrevPrivilages) {
  283. GlobalFree(lpPrevPrivilages);
  284. }
  285. return error;
  286. }
  287. LONG
  288. MyRegLoadKey(
  289. IN HKEY hKey,
  290. IN LPTSTR lpSubKey,
  291. IN LPTSTR lpFile
  292. )
  293. /*++
  294. Routine Description:
  295. Loads a hive into the registry
  296. Arguments:
  297. hKey -
  298. Supplies a handle to a registry key which will be the parent
  299. of the created key.
  300. lpSubKey -
  301. Supplies the name of the subkey to create.
  302. lpFile -
  303. Supplies the name of the file containing the hive.
  304. Return Value:
  305. ERROR_SUCCESS if successful.
  306. Error code from RegLoadKey if unsuccessful.
  307. --*/
  308. {
  309. NTSTATUS Status;
  310. BOOLEAN WasEnabled;
  311. int error;
  312. //
  313. // Enable the restore privilege
  314. //
  315. Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &WasEnabled);
  316. if (NT_SUCCESS(Status)) {
  317. error = RegLoadKey(hKey, lpSubKey, lpFile);
  318. //
  319. // Restore the privilege to its previous state
  320. //
  321. RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, WasEnabled, FALSE, &WasEnabled);
  322. } else {
  323. error = GetLastError();
  324. }
  325. return error;
  326. }
  327. LONG
  328. MyRegUnLoadKey(
  329. IN HKEY hKey,
  330. IN LPTSTR lpSubKey
  331. )
  332. /*++
  333. Routine Description:
  334. Unloads a registry key.
  335. Arguments:
  336. hKey -
  337. Supplies handle to parent key
  338. lpSubKey -
  339. Supplies name of subkey to delete
  340. Return Value:
  341. ERROR_SUCCESS if successful
  342. Error code if unsuccessful
  343. --*/
  344. {
  345. LONG error;
  346. NTSTATUS Status;
  347. BOOLEAN WasEnabled;
  348. //
  349. // Enable the restore privilege
  350. //
  351. Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &WasEnabled);
  352. if (NT_SUCCESS(Status)) {
  353. error = RegUnLoadKey(hKey, lpSubKey);
  354. //
  355. // Restore the privilege to its previous state
  356. //
  357. RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, WasEnabled, FALSE, &WasEnabled);
  358. } else {
  359. error = GetLastError();
  360. }
  361. return error;
  362. }
  363. int
  364. GetSelectedItem(
  365. IN HWND hCtrl
  366. )
  367. /*++
  368. Routine Description:
  369. Determines which item in a list view control is selected
  370. Arguments:
  371. hCtrl -
  372. Supplies handle to the desired list view control.
  373. Return Value:
  374. The index of the selected item, if an item is selected.
  375. -1 if no item is selected.
  376. --*/
  377. {
  378. int i, n;
  379. n = (int)SendMessage (hCtrl, LVM_GETITEMCOUNT, 0, 0L);
  380. if (n != LB_ERR)
  381. {
  382. for (i = 0; i < n; i++)
  383. {
  384. if (SendMessage (hCtrl, LVM_GETITEMSTATE,
  385. i, (LPARAM) LVIS_SELECTED) == LVIS_SELECTED) {
  386. return i;
  387. }
  388. }
  389. }
  390. return -1;
  391. }
  392. BOOL
  393. _DriveIsNTFS(
  394. INT iDrive // drive to check on
  395. )
  396. {
  397. TCHAR szDrive[4];
  398. TCHAR szDriveNameBuffer[MAX_PATH];
  399. DWORD dwMaxFnameLen;
  400. DWORD dwFSFlags;
  401. TCHAR szDriveFormatName[MAX_PATH];
  402. BOOL fRetVal = FALSE;
  403. PathBuildRoot(szDrive, iDrive);
  404. if (GetVolumeInformation(szDrive, szDriveNameBuffer, ARRAYSIZE(szDriveNameBuffer), NULL,
  405. &dwMaxFnameLen, &dwFSFlags, szDriveFormatName, ARRAYSIZE(szDriveFormatName)))
  406. {
  407. if (StrStrI(szDriveFormatName, TEXT("NTFS")))
  408. {
  409. fRetVal = TRUE;
  410. }
  411. }
  412. return fRetVal;
  413. }
  414. DWORD
  415. GetMaxPagefileSizeInMB(
  416. INT iDrive // drive to check on
  417. )
  418. {
  419. #if defined(_AMD64_)
  420. return MAX_SWAPSIZE_AMD64;
  421. #elif defined(_X86_)
  422. if ((USER_SHARED_DATA->ProcessorFeatures[PF_PAE_ENABLED]) && _DriveIsNTFS(iDrive))
  423. {
  424. return MAX_SWAPSIZE_X86_PAE;
  425. }
  426. else
  427. {
  428. return MAX_SWAPSIZE_X86;
  429. }
  430. #elif defined(_IA64_)
  431. return MAX_SWAPSIZE_IA64;
  432. #else
  433. return 0;
  434. #endif
  435. }
  436. int
  437. MsgBoxParam(
  438. IN HWND hWnd,
  439. IN DWORD wText,
  440. IN DWORD wCaption,
  441. IN DWORD wType,
  442. ...
  443. )
  444. /*++
  445. Routine Description:
  446. Combination of MessageBox and printf
  447. Arguments:
  448. hWnd -
  449. Supplies parent window handle
  450. wText -
  451. Supplies ID of a printf-like format string to display as the
  452. message box text
  453. wCaption -
  454. Supplies ID of a string to display as the message box caption
  455. wType -
  456. Supplies flags to MessageBox()
  457. Return Value:
  458. Whatever MessageBox() returns.
  459. --*/
  460. {
  461. TCHAR szText[ 4 * MAX_PATH ], szCaption[ 2 * MAX_PATH ];
  462. int ival;
  463. va_list parg;
  464. va_start( parg, wType );
  465. if( wText == IDS_INSUFFICIENT_MEMORY )
  466. goto NoMem;
  467. if( !LoadString( hInstance, wText, szCaption, ARRAYSIZE( szCaption ) ) )
  468. goto NoMem;
  469. if (FAILED(StringCchVPrintf(szText, ARRAYSIZE(szText), szCaption, parg)))
  470. goto NoMem;
  471. if( !LoadString( hInstance, wCaption, szCaption, ARRAYSIZE( szCaption ) ) )
  472. goto NoMem;
  473. if( (ival = MessageBox( hWnd, szText, szCaption, wType ) ) == 0 )
  474. goto NoMem;
  475. va_end( parg );
  476. return( ival );
  477. NoMem:
  478. va_end( parg );
  479. ErrMemDlg( hWnd );
  480. return 0;
  481. }
  482. DWORD
  483. SetLBWidthEx(
  484. IN HWND hwndLB,
  485. IN LPTSTR szBuffer,
  486. IN DWORD cxCurWidth,
  487. IN DWORD cxExtra
  488. )
  489. /*++
  490. Routine Description:
  491. Set the width of a listbox, in pixels, acording to the size of the
  492. string passed in
  493. Arguments:
  494. hwndLB -
  495. Supples listbox to resize
  496. szBuffer -
  497. Supplies string to resize listbox to
  498. cxCurWidth -
  499. Supplies current width of the listbox
  500. cxExtra -
  501. Supplies some kind of slop factor
  502. Return Value:
  503. The new width of the listbox
  504. --*/
  505. {
  506. HDC hDC;
  507. SIZE Size;
  508. LONG cx;
  509. HFONT hfont, hfontOld;
  510. // Get the new Win4.0 thin dialog font
  511. hfont = (HFONT)SendMessage(hwndLB, WM_GETFONT, 0, 0);
  512. hDC = GetDC(hwndLB);
  513. // if we got a font back, select it in this clean hDC
  514. if (hfont != NULL)
  515. hfontOld = SelectObject(hDC, hfont);
  516. // If cxExtra is 0, then give our selves a little breathing space.
  517. if (cxExtra == 0) {
  518. GetTextExtentPoint32(hDC, TEXT("1234"), 4 /* lstrlen("1234") */, &Size);
  519. cxExtra = Size.cx;
  520. }
  521. // Set scroll width of listbox
  522. GetTextExtentPoint32(hDC, szBuffer, lstrlen(szBuffer), &Size);
  523. Size.cx += cxExtra;
  524. // Get the name length and adjust the longest name
  525. if ((DWORD) Size.cx > cxCurWidth)
  526. {
  527. cxCurWidth = Size.cx;
  528. SendMessage (hwndLB, LB_SETHORIZONTALEXTENT, (DWORD)Size.cx, 0L);
  529. }
  530. // retstore the original font if we changed it
  531. if (hfont != NULL)
  532. SelectObject(hDC, hfontOld);
  533. ReleaseDC(NULL, hDC);
  534. return cxCurWidth;
  535. }
  536. VOID
  537. SetDefButton(
  538. IN HWND hwndDlg,
  539. IN int idButton
  540. )
  541. /*++
  542. Routine Description:
  543. Sets the default button for a dialog box or proppage
  544. The old default button, if any, has its default status removed
  545. Arguments:
  546. hwndDlg -
  547. Supplies window handle
  548. idButton -
  549. Supplies ID of button to make default
  550. Return Value:
  551. None
  552. --*/
  553. {
  554. LRESULT lr;
  555. if (HIWORD(lr = SendMessage(hwndDlg, DM_GETDEFID, 0, 0)) == DC_HASDEFID)
  556. {
  557. HWND hwndOldDefButton = GetDlgItem(hwndDlg, LOWORD(lr));
  558. SendMessage (hwndOldDefButton,
  559. BM_SETSTYLE,
  560. MAKEWPARAM(BS_PUSHBUTTON, 0),
  561. MAKELPARAM(TRUE, 0));
  562. }
  563. SendMessage( hwndDlg, DM_SETDEFID, idButton, 0L );
  564. SendMessage( GetDlgItem(hwndDlg, idButton),
  565. BM_SETSTYLE,
  566. MAKEWPARAM( BS_DEFPUSHBUTTON, 0 ),
  567. MAKELPARAM( TRUE, 0 ));
  568. }
  569. void
  570. HourGlass(
  571. IN BOOL bOn
  572. )
  573. /*++
  574. Routine Description:
  575. Turns hourglass mouse cursor on or off
  576. Arguments:
  577. bOn -
  578. Supplies desired status of hourglass mouse cursor
  579. Return Value:
  580. None
  581. --*/
  582. {
  583. if( !GetSystemMetrics( SM_MOUSEPRESENT ) )
  584. ShowCursor( bOn );
  585. SetCursor( LoadCursor( NULL, bOn ? IDC_WAIT : IDC_ARROW ) );
  586. }
  587. VCREG_RET
  588. OpenRegKey(
  589. IN LPTSTR pszKeyName,
  590. OUT PHKEY phk
  591. )
  592. /*++
  593. Routine Description:
  594. Opens a subkey of HKEY_LOCAL_MACHINE
  595. Arguments:
  596. pszKeyName -
  597. Supplies the name of the subkey to open
  598. phk -
  599. Returns a handle to the key if successfully opened
  600. Returns NULL if an error occurs
  601. Return Value:
  602. VCREG_OK if successful
  603. VCREG_READONLY if the key was opened with read-only access
  604. VCREG_OK if an error occurred
  605. */
  606. {
  607. LONG Error;
  608. Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pszKeyName, 0,
  609. KEY_READ | KEY_WRITE, phk);
  610. if (Error != ERROR_SUCCESS)
  611. {
  612. Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pszKeyName, 0, KEY_READ, phk);
  613. if (Error != ERROR_SUCCESS)
  614. {
  615. *phk = NULL;
  616. return VCREG_ERROR;
  617. }
  618. /*
  619. * We only have Read access.
  620. */
  621. return VCREG_READONLY;
  622. }
  623. return VCREG_OK;
  624. }
  625. LONG
  626. CloseRegKey(
  627. IN HKEY hkey
  628. )
  629. /*++
  630. Routine Description:
  631. Closes a registry key opened by OpenRegKey()
  632. Arguments:
  633. hkey -
  634. Supplies handle to key to close
  635. Return Value:
  636. Whatever RegCloseKey() returns
  637. --*/
  638. {
  639. return RegCloseKey(hkey);
  640. }
  641. /*
  642. * UINT VMGetDriveType( LPCTSTR lpszDrive )
  643. *
  644. * Gets the drive type. This function differs from Win32's GetDriveType
  645. * in that it returns DRIVE_FIXED for lockable removable drives (like
  646. * bernolli boxes, etc).
  647. *
  648. * On IA64 we don't do this, however, requiring all pagefiles be on actual
  649. * fixed drives.
  650. */
  651. const TCHAR c_szDevice[] = TEXT("\\Device");
  652. UINT VMGetDriveType( LPCTSTR lpszDrive ) {
  653. UINT i;
  654. TCHAR szDevName[MAX_PATH];
  655. ASSERT(tolower(*lpszDrive) >= 'a' && tolower(*lpszDrive) <= 'z');
  656. // Check for subst drive
  657. if (QueryDosDevice( lpszDrive, szDevName, ARRAYSIZE( szDevName ) ) != 0) {
  658. // If drive does not start with '\Device', then it is not FIXED
  659. szDevName[ARRAYSIZE(c_szDevice) - 1] = '\0';
  660. if ( lstrcmpi(szDevName, c_szDevice) != 0 ) {
  661. return DRIVE_REMOTE;
  662. }
  663. }
  664. i = GetDriveType( lpszDrive );
  665. #ifndef _WIN64
  666. if ( i == DRIVE_REMOVABLE ) {
  667. TCHAR szNtDrive[20];
  668. DWORD cb;
  669. DISK_GEOMETRY dgMediaInfo;
  670. HANDLE hDisk;
  671. /*
  672. * 'Removable' drive. Check to see if it is a Floppy or lockable
  673. * drive.
  674. */
  675. if (SUCCEEDED(PathBuildFancyRoot(szNtDrive, ARRAYSIZE(szNtDrive), tolower(lpszDrive[0]) - 'a')))
  676. {
  677. hDisk = CreateFile(
  678. szNtDrive,
  679. /* GENERIC_READ */ 0,
  680. FILE_SHARE_READ | FILE_SHARE_WRITE,
  681. NULL,
  682. OPEN_EXISTING,
  683. 0,
  684. NULL
  685. ); // fine
  686. if (hDisk != INVALID_HANDLE_VALUE ) {
  687. if (DeviceIoControl( hDisk, IOCTL_DISK_GET_MEDIA_TYPES, NULL,
  688. 0, &dgMediaInfo, sizeof(dgMediaInfo), &cb, NULL) == FALSE &&
  689. GetLastError() != ERROR_MORE_DATA) {
  690. /*
  691. * Drive is not a floppy
  692. */
  693. i = DRIVE_FIXED;
  694. }
  695. CloseHandle(hDisk);
  696. } else if (GetLastError() == ERROR_ACCESS_DENIED) {
  697. /*
  698. * Could not open the drive, either it is bad, or else we
  699. * don't have permission. Since everyone has permission
  700. * to open floppies, then this must be a bernoulli type device.
  701. */
  702. i = DRIVE_FIXED;
  703. }
  704. }
  705. }
  706. #endif
  707. return i;
  708. }
  709. STDAPI
  710. PathBuildFancyRoot(
  711. LPTSTR szRoot,
  712. UINT cchRoot,
  713. int iDrive
  714. )
  715. {
  716. return StringCchPrintf(szRoot, cchRoot, TEXT("\\\\.\\%c:"), iDrive + 'a');
  717. }
  718. __inline BOOL
  719. _SafeGetHwndTextAux(
  720. HWND hwnd,
  721. UINT ulIndex,
  722. UINT msgGetLen,
  723. UINT msgGetString,
  724. LRESULT err,
  725. LPTSTR pszBuffer,
  726. UINT cchBuffer)
  727. {
  728. BOOL fRet = FALSE;
  729. UINT cch = (UINT)SendMessage(hwnd, msgGetLen, (WPARAM)ulIndex, 0);
  730. if (cch < cchBuffer &&
  731. cch != err)
  732. {
  733. if (err != SendMessage(hwnd, msgGetString, (WPARAM)ulIndex, (LPARAM)pszBuffer))
  734. {
  735. fRet = TRUE;
  736. }
  737. }
  738. return fRet;
  739. }
  740. BOOL
  741. SafeGetComboBoxListText(
  742. HWND hCombo,
  743. UINT ulIndex,
  744. LPTSTR pszBuffer,
  745. UINT cchBuffer)
  746. {
  747. return _SafeGetHwndTextAux(hCombo, ulIndex,
  748. CB_GETLBTEXTLEN, CB_GETLBTEXT, CB_ERR,
  749. pszBuffer, cchBuffer);
  750. }
  751. BOOL
  752. SafeGetListBoxText(
  753. HWND hCombo,
  754. UINT ulIndex,
  755. LPTSTR pszBuffer,
  756. UINT cchBuffer)
  757. {
  758. return _SafeGetHwndTextAux(hCombo, ulIndex,
  759. LB_GETTEXTLEN, LB_GETTEXT, LB_ERR,
  760. pszBuffer, cchBuffer);
  761. }