util.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 20k
Category:

Windows Kernel

Development Platform:

Visual C++

  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. //
  17. // Constants
  18. //
  19. #define CCH_MAX_DEC 12             // Number of chars needed to hold 2^32
  20. void
  21. ErrMemDlg(
  22.     IN HWND hParent
  23. )
  24. /*++
  25. Routine Description:
  26.     Displays "out of memory" message.
  27. Arguments:
  28.     hParent -
  29.         Supplies parent window handle.
  30. Return Value:
  31.     None.
  32. --*/
  33. {
  34.     MessageBox(
  35.         hParent,
  36.         g_szErrMem,
  37.         g_szSystemApplet,
  38.         MB_OK | MB_ICONHAND | MB_SYSTEMMODAL
  39.     );
  40.     return;
  41. }
  42. LPTSTR
  43. SkipWhiteSpace(
  44.     IN LPTSTR sz
  45. )
  46. /*++
  47. Routine Description:
  48.     SkipWhiteSpace
  49.     For the purposes of this fuction, whitespace is space, tab,
  50.     cr, or lf.
  51. Arguments:
  52.     sz -
  53.         Supplies a string (which presumably has leading whitespace)
  54. Return Value:
  55.     Pointer to string without leading whitespace if successful.
  56. --*/
  57. {
  58.     while( IsWhiteSpace(*sz) )
  59.         sz++;
  60.     return sz;
  61. }
  62. int 
  63. StringToInt( 
  64.     IN LPTSTR sz 
  65. /*++
  66. Routine Description:
  67.     TCHAR version of atoi
  68. Arguments:
  69.     sz -
  70.         Supplies the string to convert
  71. Return Value:
  72.     Integer representation of the string
  73. --*/
  74. {
  75.     int i = 0;
  76.     sz = SkipWhiteSpace(sz);
  77.     while( IsDigit( *sz ) ) {
  78.         i = i * 10 + DigitVal( *sz );
  79.         sz++;
  80.     }
  81.     return i;
  82. }
  83. void 
  84. IntToString( 
  85.     IN INT i, 
  86.     OUT LPTSTR sz
  87. /*++
  88. Routine Description:
  89.     TCHAR version of itoa
  90. Arguments:
  91.     i -
  92.         Supplies the integer to convert
  93.     sz -
  94.         Returns the string form of the supplied int
  95. Return Value:
  96.     None.
  97. --*/
  98. {
  99.     TCHAR szTemp[CCH_MAX_DEC];
  100.     int iChr;
  101.     iChr = 0;
  102.     do {
  103.         szTemp[iChr++] = TEXT('0') + (i % 10);
  104.         i = i / 10;
  105.     } while (i != 0);
  106.     do {
  107.         iChr--;
  108.         *sz++ = szTemp[iChr];
  109.     } while (iChr != 0);
  110.     *sz++ = TEXT('');
  111. }
  112. LPTSTR 
  113. CheckSlash(
  114.     IN LPTSTR lpDir
  115. )
  116. /*++
  117. Routine Description:
  118.     Checks for an ending backslash and adds one if
  119.     it is missing.
  120. Arguments:
  121.     lpDir -
  122.         Supplies the name of a directory.
  123. Return Value:
  124.     A string that ends with a backslash.
  125. --*/
  126. {
  127.     DWORD dwStrLen;
  128.     LPTSTR lpEnd;
  129.     lpEnd = lpDir + lstrlen(lpDir);
  130.     if (*(lpEnd - 1) != TEXT('\')) {
  131.         *lpEnd =  TEXT('\');
  132.         lpEnd++;
  133.         *lpEnd =  TEXT('');
  134.     }
  135.     return lpEnd;
  136. }
  137. BOOL 
  138. Delnode_Recurse(
  139.     IN LPTSTR lpDir
  140. )
  141. /*++
  142. Routine Description:
  143.     Recursive delete function for Delnode
  144. Arguments:
  145.     lpDir -
  146.         Supplies directory to delete
  147. Return Value:
  148.     TRUE if successful.
  149.     FALSE if an error occurs.
  150. --*/
  151. {
  152.     WIN32_FIND_DATA fd;
  153.     HANDLE hFile;
  154.     //
  155.     // Setup the current working dir
  156.     //
  157.     if (!SetCurrentDirectory (lpDir)) {
  158.         return FALSE;
  159.     }
  160.     //
  161.     // Find the first file
  162.     //
  163.     hFile = FindFirstFile(TEXT("*.*"), &fd);
  164.     if (hFile == INVALID_HANDLE_VALUE) {
  165.         if (GetLastError() == ERROR_FILE_NOT_FOUND) {
  166.             return TRUE;
  167.         } else {
  168.             return FALSE;
  169.         }
  170.     }
  171.     do {
  172.         //
  173.         // Check for "." and ".."
  174.         //
  175.         if (!lstrcmpi(fd.cFileName, TEXT("."))) {
  176.             continue;
  177.         }
  178.         if (!lstrcmpi(fd.cFileName, TEXT(".."))) {
  179.             continue;
  180.         }
  181.         if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  182.             //
  183.             // Found a directory.
  184.             //
  185.             if (!Delnode_Recurse(fd.cFileName)) {
  186.                 FindClose(hFile);
  187.                 return FALSE;
  188.             }
  189.             if (fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
  190.                 fd.dwFileAttributes &= ~FILE_ATTRIBUTE_READONLY;
  191.                 SetFileAttributes (fd.cFileName, fd.dwFileAttributes);
  192.             }
  193.             RemoveDirectory (fd.cFileName);
  194.         } else {
  195.             //
  196.             // We found a file.  Set the file attributes,
  197.             // and try to delete it.
  198.             //
  199.             if ((fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ||
  200.                 (fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)) {
  201.                 SetFileAttributes (fd.cFileName, FILE_ATTRIBUTE_NORMAL);
  202.             }
  203.             DeleteFile (fd.cFileName);
  204.         }
  205.         //
  206.         // Find the next entry
  207.         //
  208.     } while (FindNextFile(hFile, &fd));
  209.     //
  210.     // Close the search handle
  211.     //
  212.     FindClose(hFile);
  213.     //
  214.     // Reset the working directory
  215.     //
  216.     if (!SetCurrentDirectory (TEXT(".."))) {
  217.         return FALSE;
  218.     }
  219.     //
  220.     // Success.
  221.     //
  222.     return TRUE;
  223. }
  224. BOOL 
  225. Delnode(
  226.     IN LPTSTR lpDir
  227. )
  228. /*++
  229. Routine Description:
  230.     Recursive function that deletes files and
  231.     directories.
  232. Arguments:
  233.     lpDir -
  234.         Supplies directory to delete.
  235. Return Value:
  236.     TRUE if successful
  237.     FALSE if an error occurs
  238. --*/
  239. {
  240.     TCHAR szCurWorkingDir[MAX_PATH];
  241.     if (GetCurrentDirectory(MAX_PATH, szCurWorkingDir)) {
  242.         Delnode_Recurse (lpDir);
  243.         SetCurrentDirectory (szCurWorkingDir);
  244.         if (!RemoveDirectory (lpDir)) {
  245.             return FALSE;
  246.         }
  247.     } else {
  248.         return FALSE;
  249.     }
  250.     return TRUE;
  251. }
  252. LONG 
  253. MyRegSaveKey(
  254.     IN HKEY hKey, 
  255.     IN LPCTSTR lpSubKey
  256. )
  257. /*++
  258. Routine Description:
  259.     Saves a registry key.
  260. Arguments:
  261.     hKey -
  262.         Supplies handle to a registry key.
  263.     lpSubKey -
  264.         Supplies the name of the subkey to save.
  265. Return Value:
  266.     ERROR_SUCCESS if successful.
  267.     Error code from RegSaveKey() if an error occurs.
  268. --*/
  269. {
  270.     HANDLE hToken;
  271.     LUID luid;
  272.     DWORD dwSize = 1024;
  273.     PTOKEN_PRIVILEGES lpPrevPrivilages;
  274.     TOKEN_PRIVILEGES tp;
  275.     LONG error;
  276.     //
  277.     // Allocate space for the old privileges
  278.     //
  279.     lpPrevPrivilages = GlobalAlloc(GPTR, dwSize);
  280.     if (!lpPrevPrivilages) {
  281.         return GetLastError();
  282.     }
  283.     if (!OpenProcessToken( GetCurrentProcess(),
  284.                       TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
  285.          return GetLastError();
  286.     }
  287.     LookupPrivilegeValue( NULL, SE_BACKUP_NAME, &luid );
  288.     tp.PrivilegeCount           = 1;
  289.     tp.Privileges[0].Luid       = luid;
  290.     tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  291.     if (!AdjustTokenPrivileges( hToken, FALSE, &tp,
  292.          dwSize, lpPrevPrivilages, &dwSize )) {
  293.         if (GetLastError() == ERROR_MORE_DATA) {
  294.             PTOKEN_PRIVILEGES lpTemp;
  295.             lpTemp = GlobalReAlloc(lpPrevPrivilages, dwSize, GMEM_MOVEABLE);
  296.             if (!lpTemp) {
  297.                 GlobalFree (lpPrevPrivilages);
  298.                 return GetLastError();
  299.             }
  300.             lpPrevPrivilages = lpTemp;
  301.             if (!AdjustTokenPrivileges( hToken, FALSE, &tp,
  302.                  dwSize, lpPrevPrivilages, &dwSize )) {
  303.                 return GetLastError();
  304.             }
  305.         } else {
  306.             return GetLastError();
  307.         }
  308.     }
  309.     //
  310.     // Save the hive
  311.     //
  312.     error = RegSaveKey(hKey, lpSubKey, NULL);
  313.     AdjustTokenPrivileges( hToken, FALSE, lpPrevPrivilages,
  314.                            0, NULL, NULL );
  315.     CloseHandle (hToken);
  316.     return error;
  317. }
  318. UINT 
  319. CreateNestedDirectory(
  320.     IN LPCTSTR lpDirectory, 
  321.     IN LPSECURITY_ATTRIBUTES lpSecurityAttributes
  322. )
  323. /*++
  324. Routine Description:
  325.     Creates a subdirectory and all its parents
  326.     if necessary.
  327. Arguments:
  328.     lpDirectory -
  329.         Name of directory to create.
  330.     lpSecurityAttributes -
  331.         Desired security attributes.
  332. Return Value:
  333.     Nonzero on success.
  334.     Zero on failure.
  335. --*/
  336. {
  337.     TCHAR szDirectory[MAX_PATH];
  338.     LPTSTR lpEnd;
  339.     //
  340.     // Check for NULL pointer
  341.     //
  342.     if (!lpDirectory || !(*lpDirectory)) {
  343.         return 0;
  344.     }
  345.     //
  346.     // First, see if we can create the directory without having
  347.     // to build parent directories.
  348.     //
  349.     if (CreateDirectory (lpDirectory, lpSecurityAttributes)) {
  350.         return 1;
  351.     }
  352.     //
  353.     // If this directory exists already, this is OK too.
  354.     //
  355.     if (GetLastError() == ERROR_ALREADY_EXISTS) {
  356.         return ERROR_ALREADY_EXISTS;
  357.     }
  358.     //
  359.     // No luck, copy the string to a buffer we can munge
  360.     //
  361.     lstrcpy (szDirectory, lpDirectory);
  362.     //
  363.     // Find the first subdirectory name
  364.     //
  365.     lpEnd = szDirectory;
  366.     if (szDirectory[1] == TEXT(':')) {
  367.         lpEnd += 3;
  368.     } else if (szDirectory[1] == TEXT('\')) {
  369.         //
  370.         // Skip the first two slashes
  371.         //
  372.         lpEnd += 2;
  373.         //
  374.         // Find the slash between the server name and
  375.         // the share name.
  376.         //
  377.         while (*lpEnd && *lpEnd != TEXT('\')) {
  378.             lpEnd++;
  379.         }
  380.         if (!(*lpEnd)) {
  381.             return 0;
  382.         }
  383.         //
  384.         // Skip the slash, and find the slash between
  385.         // the share name and the directory name.
  386.         //
  387.         lpEnd++;
  388.         while (*lpEnd && *lpEnd != TEXT('\')) {
  389.             lpEnd++;
  390.         }
  391.         if (!(*lpEnd)) {
  392.             return 0;
  393.         }
  394.         //
  395.         // Leave pointer at the beginning of the directory.
  396.         //
  397.         lpEnd++;
  398.     } else if (szDirectory[0] == TEXT('\')) {
  399.         lpEnd++;
  400.     }
  401.     while (*lpEnd) {
  402.         while (*lpEnd && *lpEnd != TEXT('\')) {
  403.             lpEnd++;
  404.         }
  405.         if (*lpEnd == TEXT('\')) {
  406.             *lpEnd = TEXT('');
  407.             if (!CreateDirectory (szDirectory, NULL)) {
  408.                 if (GetLastError() != ERROR_ALREADY_EXISTS) {
  409.                     return 0;
  410.                 }
  411.             }
  412.             *lpEnd = TEXT('\');
  413.             lpEnd++;
  414.         }
  415.     }
  416.     //
  417.     // Create the final directory
  418.     //
  419.     if (CreateDirectory (szDirectory, lpSecurityAttributes)) {
  420.         return 1;
  421.     }
  422.     if (GetLastError() == ERROR_ALREADY_EXISTS) {
  423.         return ERROR_ALREADY_EXISTS;
  424.     }
  425.     //
  426.     // Failed
  427.     //
  428.     return 0;
  429. }
  430. LONG 
  431. MyRegLoadKey(
  432.     IN HKEY hKey, 
  433.     IN LPTSTR lpSubKey, 
  434.     IN LPTSTR lpFile
  435. )
  436. /*++
  437. Routine Description:
  438.     Loads a hive into the registry
  439. Arguments:
  440.     hKey -
  441.         Supplies a handle to a registry key which will be the parent
  442.         of the created key.
  443.     lpSubKey -
  444.         Supplies the name of the subkey to create.
  445.     lpFile -
  446.         Supplies the name of the file containing the hive.
  447. Return Value:
  448.     ERROR_SUCCESS if successful.
  449.     Error code from RegLoadKey if unsuccessful.
  450. --*/
  451. {
  452.     NTSTATUS Status;
  453.     BOOLEAN WasEnabled;
  454.     int error;
  455.     //
  456.     // Enable the restore privilege
  457.     //
  458.     Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &WasEnabled);
  459.     if (NT_SUCCESS(Status)) {
  460.         error = RegLoadKey(hKey, lpSubKey, lpFile);
  461.         //
  462.         // Restore the privilege to its previous state
  463.         //
  464.         RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, WasEnabled, FALSE, &WasEnabled);
  465.     } else {
  466.         error = GetLastError();
  467.     }
  468.     return error;
  469. }
  470. LONG 
  471. MyRegUnLoadKey(
  472.     IN HKEY hKey, 
  473.     IN LPTSTR lpSubKey
  474. )
  475. /*++
  476. Routine Description:
  477.     Unloads a registry key.
  478. Arguments:
  479.     hKey -
  480.         Supplies handle to parent key
  481.     lpSubKey -
  482.         Supplies name of subkey to delete
  483. Return Value:
  484.     ERROR_SUCCESS if successful
  485.     Error code if unsuccessful
  486. --*/
  487. {
  488.     LONG error;
  489.     NTSTATUS Status;
  490.     BOOLEAN WasEnabled;
  491.     //
  492.     // Enable the restore privilege
  493.     //
  494.     Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &WasEnabled);
  495.     if (NT_SUCCESS(Status)) {
  496.         error = RegUnLoadKey(hKey, lpSubKey);
  497.         //
  498.         // Restore the privilege to its previous state
  499.         //
  500.         RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, WasEnabled, FALSE, &WasEnabled);
  501.     } else {
  502.         error = GetLastError();
  503.     }
  504.     return error;
  505. }
  506. int 
  507. GetSelectedItem(
  508.     IN HWND hCtrl
  509. )
  510. /*++
  511. Routine Description:
  512.     
  513.     Determines which item in a list view control is selected
  514. Arguments:
  515.     hCtrl -
  516.         Supplies handle to the desired list view control.
  517. Return Value:
  518.     The index of the selected item, if an item is selected.
  519.     -1 if no item is selected.
  520. --*/
  521. {
  522.     int i, n;
  523.     n = (int)SendMessage (hCtrl, LVM_GETITEMCOUNT, 0, 0L);
  524.     if (n != LB_ERR)
  525.     {
  526.         for (i = 0; i < n; i++)
  527.         {
  528.             if (SendMessage (hCtrl, LVM_GETITEMSTATE,
  529.                              i, (LPARAM) LVIS_SELECTED) == LVIS_SELECTED) {
  530.                 return i;
  531.             }
  532.         }
  533.     }
  534.     return -1;
  535. }
  536. BOOL
  537. IsUserAdmin(
  538.     VOID
  539. )
  540. /*++
  541. Routine Description:
  542.     This routine returns TRUE if the caller's process is a
  543.     member of the Administrators local group.
  544.     Caller is NOT expected to be impersonating anyone and IS
  545.     expected to be able to open their own process and process
  546.     token.
  547. Arguments:
  548.     None.
  549. Return Value:
  550.     TRUE - Caller has Administrators local group.
  551.     FALSE - Caller does not have Administrators local group.
  552. --*/
  553. {
  554.     BOOL b = FALSE;
  555.     SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  556.     PSID AdministratorsGroup;
  557.     if(AllocateAndInitializeSid(
  558.         &NtAuthority,
  559.         2,
  560.         SECURITY_BUILTIN_DOMAIN_RID,
  561.         DOMAIN_ALIAS_RID_ADMINS,
  562.         0, 0, 0, 0, 0, 0,
  563.         &AdministratorsGroup
  564.         ))
  565.     {
  566.         CheckTokenMembership(NULL, AdministratorsGroup, &b);
  567.         FreeSid(AdministratorsGroup);
  568.     }
  569.     return(b);
  570. } // IsUserAdmin
  571. int 
  572. MsgBoxParam( 
  573.     IN HWND hWnd, 
  574.     IN DWORD wText, 
  575.     IN DWORD wCaption, 
  576.     IN DWORD wType, 
  577.     ... 
  578. )
  579. /*++
  580. Routine Description:
  581.     Combination of MessageBox and printf
  582. Arguments:
  583.     hWnd -
  584.         Supplies parent window handle
  585.     wText -
  586.         Supplies ID of a printf-like format string to display as the
  587.         message box text
  588.     wCaption -
  589.         Supplies ID of a string to display as the message box caption
  590.     wType -
  591.         Supplies flags to MessageBox()
  592. Return Value:
  593.     Whatever MessageBox() returns.
  594. --*/
  595. {
  596.     TCHAR   szText[ 4 * MAX_PATH ], szCaption[ 2 * MAX_PATH ];
  597.     int     ival;
  598.     va_list parg;
  599.     va_start( parg, wType );
  600.     if( wText == INITS )
  601.         goto NoMem;
  602.     if( !LoadString( hInstance, wText, szCaption, ARRAYSIZE( szCaption ) ) )
  603.         goto NoMem;
  604.     wvsprintf( szText, szCaption, parg );
  605.     if( !LoadString( hInstance, wCaption, szCaption, ARRAYSIZE( szCaption ) ) )
  606.         goto NoMem;
  607.     if( (ival = MessageBox( hWnd, szText, szCaption, wType ) ) == 0 )
  608.         goto NoMem;
  609.     va_end( parg );
  610.     return( ival );
  611. NoMem:
  612.     va_end( parg );
  613.     ErrMemDlg( hWnd );
  614.     return 0;
  615. }
  616. LPTSTR 
  617. CloneString( 
  618.     IN LPTSTR pszSrc 
  619. /*++
  620. Routine Description:
  621.     Allocates a buffer and copies a string into it
  622. Arguments:
  623.     pszSrc -
  624.         Supplies string to copy
  625. Return Value:
  626.     Valid LPTSTR if successful
  627.     NULL if out of memory
  628. --*/
  629. {
  630.     LPTSTR pszDst = NULL;
  631.     if (pszSrc != NULL) {
  632.         pszDst = MemAlloc(LMEM_FIXED, (lstrlen(pszSrc)+1) * SIZEOF(TCHAR));
  633.         if (pszDst) {
  634.             lstrcpy( pszDst, pszSrc );
  635.         }
  636.     }
  637.     return pszDst;
  638. }
  639. DWORD 
  640. SetLBWidthEx(
  641.     IN HWND hwndLB, 
  642.     IN LPTSTR szBuffer, 
  643.     IN DWORD cxCurWidth, 
  644.     IN DWORD cxExtra
  645. )
  646. /*++
  647. Routine Description:
  648.     Set the width of a listbox, in pixels, acording to the size of the
  649.     string passed in
  650. Arguments:
  651.     hwndLB -
  652.         Supples listbox to resize
  653.     szBuffer -
  654.         Supplies string to resize listbox to
  655.     cxCurWidth -
  656.         Supplies current width of the listbox
  657.     cxExtra -
  658.         Supplies some kind of slop factor
  659. Return Value:
  660.     The new width of the listbox
  661. --*/
  662. {
  663.     HDC     hDC;
  664.     SIZE    Size;
  665.     LONG    cx;
  666.     HFONT   hfont, hfontOld;
  667.     // Get the new Win4.0 thin dialog font
  668.     hfont = (HFONT)SendMessage(hwndLB, WM_GETFONT, 0, 0);
  669.     hDC = GetDC(hwndLB);
  670.     // if we got a font back, select it in this clean hDC
  671.     if (hfont != NULL)
  672.         hfontOld = SelectObject(hDC, hfont);
  673.     // If cxExtra is 0, then give our selves a little breathing space.
  674.     if (cxExtra == 0) {
  675.         GetTextExtentPoint(hDC, TEXT("1234"), 4 /* lstrlen("1234") */, &Size);
  676.         cxExtra = Size.cx;
  677.     }
  678.     // Set scroll width of listbox
  679.     GetTextExtentPoint(hDC, szBuffer, lstrlen(szBuffer), &Size);
  680.     Size.cx += cxExtra;
  681.     // Get the name length and adjust the longest name
  682.     if ((DWORD) Size.cx > cxCurWidth)
  683.     {
  684.         cxCurWidth = Size.cx;
  685.         SendMessage (hwndLB, LB_SETHORIZONTALEXTENT, (DWORD)Size.cx, 0L);
  686.     }
  687.     // retstore the original font if we changed it
  688.     if (hfont != NULL)
  689.         SelectObject(hDC, hfontOld);
  690.     ReleaseDC(NULL, hDC);
  691.     return cxCurWidth;
  692. }
  693. VOID 
  694. SetDefButton(
  695.     IN HWND hwndDlg,
  696.     IN int idButton
  697. )
  698. /*++
  699. Routine Description:
  700.     Sets the default button for a dialog box or proppage
  701.     The old default button, if any,  has its default status removed
  702. Arguments:
  703.     hwndDlg -
  704.         Supplies window handle
  705.     idButton -
  706.         Supplies ID of button to make default
  707. Return Value:
  708.     None
  709. --*/
  710. {
  711.     LRESULT lr;
  712.     if (HIWORD(lr = SendMessage(hwndDlg, DM_GETDEFID, 0, 0)) == DC_HASDEFID)
  713.     {
  714.         HWND hwndOldDefButton = GetDlgItem(hwndDlg, LOWORD(lr));
  715.         SendMessage (hwndOldDefButton,
  716.                      BM_SETSTYLE,
  717.                      MAKEWPARAM(BS_PUSHBUTTON, 0),
  718.                      MAKELPARAM(TRUE, 0));
  719.     }
  720.     SendMessage( hwndDlg, DM_SETDEFID, idButton, 0L );
  721.     SendMessage( GetDlgItem(hwndDlg, idButton),
  722.                  BM_SETSTYLE,
  723.                  MAKEWPARAM( BS_DEFPUSHBUTTON, 0 ),
  724.                  MAKELPARAM( TRUE, 0 ));
  725. }
  726. void 
  727. HourGlass( 
  728.     IN BOOL bOn 
  729. )
  730. /*++
  731. Routine Description:
  732.     Turns hourglass mouse cursor on or off
  733. Arguments:
  734.     bOn -
  735.         Supplies desired status of hourglass mouse cursor
  736. Return Value:
  737.     None
  738. --*/
  739. {
  740.     if( !GetSystemMetrics( SM_MOUSEPRESENT ) )
  741.         ShowCursor( bOn );
  742.     SetCursor( LoadCursor( NULL, bOn ? IDC_WAIT : IDC_ARROW ) );
  743. }
  744. VCREG_RET 
  745. OpenRegKey( 
  746.     IN LPTSTR pszKeyName, 
  747.     OUT PHKEY phk 
  748. /*++
  749. Routine Description:
  750.     Opens a subkey of HKEY_LOCAL_MACHINE
  751. Arguments:
  752.     pszKeyName -
  753.         Supplies the name of the subkey to open
  754.     phk -
  755.         Returns a handle to the key if successfully opened
  756.         Returns NULL if an error occurs
  757. Return Value:
  758.     VCREG_OK if successful
  759.     VCREG_READONLY if the key was opened with read-only access
  760.     VCREG_OK if an error occurred
  761. */
  762. {
  763.     LONG Error;
  764.     Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pszKeyName, 0,
  765.             KEY_READ | KEY_WRITE, phk);
  766.     if (Error != ERROR_SUCCESS)
  767.     {
  768.         Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pszKeyName, 0, KEY_READ, phk);
  769.         if (Error != ERROR_SUCCESS)
  770.         {
  771.             *phk = NULL;
  772.             return VCREG_ERROR;
  773.         }
  774.         /*
  775.          * We only have Read access.
  776.          */
  777.         return VCREG_READONLY;
  778.     }
  779.     return VCREG_OK;
  780. }
  781. LONG    
  782. CloseRegKey( 
  783.     IN HKEY hkey 
  784. /*++
  785. Routine Description:
  786.     Closes a registry key opened by OpenRegKey()
  787. Arguments:
  788.     hkey -
  789.         Supplies handle to key to close
  790. Return Value:
  791.     Whatever RegCloseKey() returns
  792. --*/
  793. {
  794.     return RegCloseKey(hkey);
  795. }
  796. BOOL
  797. IsWorkstationProduct(
  798. )
  799. /*++
  800. Routine Description:
  801.     Determines whether the currently running system is a Workstation
  802.     product or a Server product.
  803. Arguments:
  804.     None.
  805. Return Value:
  806.     TRUE if the currently running system is a Workstation product.
  807.     FALSE if the currently running system is some other kind of product.
  808. --*/
  809. {
  810.     NT_PRODUCT_TYPE ProdType;
  811.     RtlGetNtProductType(&ProdType);
  812.     return(NtProductWinNt == ProdType);
  813. }