/*++ Microsoft Confidential Copyright (c) 1992-1997 Microsoft Corporation All rights reserved Module Name: util.c Abstract: Utility functions for System Control Panel Applet Author: Eric Flo (ericflo) 19-Jun-1995 Revision History: 15-Oct-1997 scotthal Complete overhaul --*/ #include "sysdm.h" // // Constants // #define CCH_MAX_DEC 12 // Number of chars needed to hold 2^32 #define MAX_SWAPSIZE_X86 (4 * 1024) // 4 Gb (number stored in megabytes) #define MAX_SWAPSIZE_X86_PAE (16 * 1024 * 1024) // 16 Tb #define MAX_SWAPSIZE_IA64 (32 * 1024 * 1024) // 32 Tb #define MAX_SWAPSIZE_AMD64 (16 * 1024 * 1024) // 16 Tb void ErrMemDlg( IN HWND hParent ) /*++ Routine Description: Displays "out of memory" message. Arguments: hParent - Supplies parent window handle. Return Value: None. --*/ { MessageBox( hParent, g_szErrMem, g_szSystemApplet, MB_OK | MB_ICONHAND | MB_SYSTEMMODAL ); return; } LPTSTR SkipWhiteSpace( IN LPTSTR sz ) /*++ Routine Description: SkipWhiteSpace For the purposes of this fuction, whitespace is space, tab, cr, or lf. Arguments: sz - Supplies a string (which presumably has leading whitespace) Return Value: Pointer to string without leading whitespace if successful. --*/ { while( IsWhiteSpace(*sz) ) sz++; return sz; } int StringToInt( IN LPTSTR sz ) /*++ Routine Description: TCHAR version of atoi Arguments: sz - Supplies the string to convert Return Value: Integer representation of the string --*/ { int i = 0; sz = SkipWhiteSpace(sz); while( IsDigit( *sz ) ) { i = i * 10 + DigitVal( *sz ); sz++; } return i; } void IntToString( IN INT i, OUT LPTSTR sz ) /*++ Routine Description: TCHAR version of itoa Arguments: i - Supplies the integer to convert sz - Returns the string form of the supplied int Return Value: None. --*/ { TCHAR szTemp[CCH_MAX_DEC]; int iChr; iChr = 0; do { szTemp[iChr++] = TEXT('0') + (i % 10); i = i / 10; } while (i != 0); do { iChr--; *sz++ = szTemp[iChr]; } while (iChr != 0); *sz++ = TEXT('\0'); } LPTSTR CheckSlash( IN LPTSTR lpDir ) /*++ Routine Description: Checks for an ending backslash and adds one if it is missing. Arguments: lpDir - Supplies the name of a directory. Return Value: A string that ends with a backslash. --*/ { DWORD dwStrLen; LPTSTR lpEnd; lpEnd = lpDir + lstrlen(lpDir); if (*(lpEnd - 1) != TEXT('\\')) { *lpEnd = TEXT('\\'); lpEnd++; *lpEnd = TEXT('\0'); } return lpEnd; } BOOL Delnode_Recurse( IN LPTSTR lpDir ) /*++ Routine Description: Recursive delete function for Delnode Arguments: lpDir - Supplies directory to delete Return Value: TRUE if successful. FALSE if an error occurs. --*/ { WIN32_FIND_DATA fd; HANDLE hFile; // // Setup the current working dir // if (!SetCurrentDirectory (lpDir)) { return FALSE; } // // Find the first file // hFile = FindFirstFile(TEXT("*.*"), &fd); if (hFile == INVALID_HANDLE_VALUE) { if (GetLastError() == ERROR_FILE_NOT_FOUND) { return TRUE; } else { return FALSE; } } do { // // Check for "." and ".." // if (!lstrcmpi(fd.cFileName, TEXT("."))) { continue; } if (!lstrcmpi(fd.cFileName, TEXT(".."))) { continue; } if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { // // Found a directory. // if (!Delnode_Recurse(fd.cFileName)) { FindClose(hFile); return FALSE; } if (fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { fd.dwFileAttributes &= ~FILE_ATTRIBUTE_READONLY; SetFileAttributes (fd.cFileName, fd.dwFileAttributes); } RemoveDirectory (fd.cFileName); } else { // // We found a file. Set the file attributes, // and try to delete it. // if ((fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) || (fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)) { SetFileAttributes (fd.cFileName, FILE_ATTRIBUTE_NORMAL); } DeleteFile (fd.cFileName); } // // Find the next entry // } while (FindNextFile(hFile, &fd)); // // Close the search handle // FindClose(hFile); // // Reset the working directory // if (!SetCurrentDirectory (TEXT(".."))) { return FALSE; } // // Success. // return TRUE; } BOOL Delnode( IN LPTSTR lpDir ) /*++ Routine Description: Recursive function that deletes files and directories. Arguments: lpDir - Supplies directory to delete. Return Value: TRUE if successful FALSE if an error occurs --*/ { TCHAR szCurWorkingDir[MAX_PATH]; if (GetCurrentDirectory(MAX_PATH, szCurWorkingDir)) { Delnode_Recurse (lpDir); SetCurrentDirectory (szCurWorkingDir); if (!RemoveDirectory (lpDir)) { return FALSE; } } else { return FALSE; } return TRUE; } LONG MyRegSaveKey( IN HKEY hKey, IN LPCTSTR lpSubKey ) /*++ Routine Description: Saves a registry key. Arguments: hKey - Supplies handle to a registry key. lpSubKey - Supplies the name of the subkey to save. Return Value: ERROR_SUCCESS if successful. Error code from RegSaveKey() if an error occurs. --*/ { HANDLE hToken; LUID luid; DWORD dwSize = 1024; PTOKEN_PRIVILEGES lpPrevPrivilages; TOKEN_PRIVILEGES tp; LONG error; // // Allocate space for the old privileges // lpPrevPrivilages = GlobalAlloc(GPTR, dwSize); if (!lpPrevPrivilages) { return GetLastError(); } if (!OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { return GetLastError(); } LookupPrivilegeValue( NULL, SE_BACKUP_NAME, &luid ); tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (!AdjustTokenPrivileges( hToken, FALSE, &tp, dwSize, lpPrevPrivilages, &dwSize )) { if (GetLastError() == ERROR_MORE_DATA) { PTOKEN_PRIVILEGES lpTemp; lpTemp = GlobalReAlloc(lpPrevPrivilages, dwSize, GMEM_MOVEABLE); if (!lpTemp) { GlobalFree (lpPrevPrivilages); return GetLastError(); } lpPrevPrivilages = lpTemp; if (!AdjustTokenPrivileges( hToken, FALSE, &tp, dwSize, lpPrevPrivilages, &dwSize )) { return GetLastError(); } } else { return GetLastError(); } } // // Save the hive // error = RegSaveKey(hKey, lpSubKey, NULL); AdjustTokenPrivileges( hToken, FALSE, lpPrevPrivilages, 0, NULL, NULL ); CloseHandle (hToken); return error; } UINT CreateNestedDirectory( IN LPCTSTR lpDirectory, IN LPSECURITY_ATTRIBUTES lpSecurityAttributes ) /*++ Routine Description: Creates a subdirectory and all its parents if necessary. Arguments: lpDirectory - Name of directory to create. lpSecurityAttributes - Desired security attributes. Return Value: Nonzero on success. Zero on failure. --*/ { TCHAR szDirectory[MAX_PATH]; LPTSTR lpEnd; // // Check for NULL pointer // if (!lpDirectory || !(*lpDirectory)) { return 0; } // // First, see if we can create the directory without having // to build parent directories. // if (CreateDirectory (lpDirectory, lpSecurityAttributes)) { return 1; } // // If this directory exists already, this is OK too. // if (GetLastError() == ERROR_ALREADY_EXISTS) { return ERROR_ALREADY_EXISTS; } // // No luck, copy the string to a buffer we can munge // lstrcpy (szDirectory, lpDirectory); // // Find the first subdirectory name // lpEnd = szDirectory; if (szDirectory[1] == TEXT(':')) { lpEnd += 3; } else if (szDirectory[1] == TEXT('\\')) { // // Skip the first two slashes // lpEnd += 2; // // Find the slash between the server name and // the share name. // while (*lpEnd && *lpEnd != TEXT('\\')) { lpEnd++; } if (!(*lpEnd)) { return 0; } // // Skip the slash, and find the slash between // the share name and the directory name. // lpEnd++; while (*lpEnd && *lpEnd != TEXT('\\')) { lpEnd++; } if (!(*lpEnd)) { return 0; } // // Leave pointer at the beginning of the directory. // lpEnd++; } else if (szDirectory[0] == TEXT('\\')) { lpEnd++; } while (*lpEnd) { while (*lpEnd && *lpEnd != TEXT('\\')) { lpEnd++; } if (*lpEnd == TEXT('\\')) { *lpEnd = TEXT('\0'); if (!CreateDirectory (szDirectory, NULL)) { if (GetLastError() != ERROR_ALREADY_EXISTS) { return 0; } } *lpEnd = TEXT('\\'); lpEnd++; } } // // Create the final directory // if (CreateDirectory (szDirectory, lpSecurityAttributes)) { return 1; } if (GetLastError() == ERROR_ALREADY_EXISTS) { return ERROR_ALREADY_EXISTS; } // // Failed // return 0; } LONG MyRegLoadKey( IN HKEY hKey, IN LPTSTR lpSubKey, IN LPTSTR lpFile ) /*++ Routine Description: Loads a hive into the registry Arguments: hKey - Supplies a handle to a registry key which will be the parent of the created key. lpSubKey - Supplies the name of the subkey to create. lpFile - Supplies the name of the file containing the hive. Return Value: ERROR_SUCCESS if successful. Error code from RegLoadKey if unsuccessful. --*/ { NTSTATUS Status; BOOLEAN WasEnabled; int error; // // Enable the restore privilege // Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &WasEnabled); if (NT_SUCCESS(Status)) { error = RegLoadKey(hKey, lpSubKey, lpFile); // // Restore the privilege to its previous state // RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, WasEnabled, FALSE, &WasEnabled); } else { error = GetLastError(); } return error; } LONG MyRegUnLoadKey( IN HKEY hKey, IN LPTSTR lpSubKey ) /*++ Routine Description: Unloads a registry key. Arguments: hKey - Supplies handle to parent key lpSubKey - Supplies name of subkey to delete Return Value: ERROR_SUCCESS if successful Error code if unsuccessful --*/ { LONG error; NTSTATUS Status; BOOLEAN WasEnabled; // // Enable the restore privilege // Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &WasEnabled); if (NT_SUCCESS(Status)) { error = RegUnLoadKey(hKey, lpSubKey); // // Restore the privilege to its previous state // RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, WasEnabled, FALSE, &WasEnabled); } else { error = GetLastError(); } return error; } int GetSelectedItem( IN HWND hCtrl ) /*++ Routine Description: Determines which item in a list view control is selected Arguments: hCtrl - Supplies handle to the desired list view control. Return Value: The index of the selected item, if an item is selected. -1 if no item is selected. --*/ { int i, n; n = (int)SendMessage (hCtrl, LVM_GETITEMCOUNT, 0, 0L); if (n != LB_ERR) { for (i = 0; i < n; i++) { if (SendMessage (hCtrl, LVM_GETITEMSTATE, i, (LPARAM) LVIS_SELECTED) == LVIS_SELECTED) { return i; } } } return -1; } BOOL IsUserAdmin( VOID ) /*++ Routine Description: This routine returns TRUE if the caller's process is a member of the Administrators local group. Caller is NOT expected to be impersonating anyone and IS expected to be able to open their own process and process token. Arguments: None. Return Value: TRUE - Caller has Administrators local group. FALSE - Caller does not have Administrators local group. --*/ { BOOL b = FALSE; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; PSID AdministratorsGroup; if(AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdministratorsGroup )) { CheckTokenMembership(NULL, AdministratorsGroup, &b); FreeSid(AdministratorsGroup); } return(b); } // IsUserAdmin BOOL _DriveIsNTFS( INT iDrive // drive to check on ) { TCHAR szDrive[4] = TEXT("A:\\"); TCHAR szDriveNameBuffer[MAX_PATH]; DWORD dwMaxFnameLen; DWORD dwFSFlags; TCHAR szDriveFormatName[MAX_PATH]; BOOL fRetVal = FALSE; szDrive[0] += (TCHAR)iDrive; if (GetVolumeInformation(szDrive, szDriveNameBuffer, ARRAYSIZE(szDriveNameBuffer), NULL, &dwMaxFnameLen, &dwFSFlags, szDriveFormatName, ARRAYSIZE(szDriveFormatName))) { if (StrStr(szDriveFormatName, TEXT("NTFS"))) { fRetVal = TRUE; } } return fRetVal; } DWORD GetMaxPagefileSizeInMB( INT iDrive // drive to check on ) { #if defined(_AMD64_) return MAX_SWAPSIZE_AMD64; #elif defined(_X86_) if (USER_SHARED_DATA && (USER_SHARED_DATA->ProcessorFeatures[PF_PAE_ENABLED]) && _DriveIsNTFS(iDrive)) { return MAX_SWAPSIZE_X86_PAE; } else { return MAX_SWAPSIZE_X86; } #elif defined(_IA64_) return MAX_SWAPSIZE_IA64; #else return 0; #endif } int MsgBoxParam( IN HWND hWnd, IN DWORD wText, IN DWORD wCaption, IN DWORD wType, ... ) /*++ Routine Description: Combination of MessageBox and printf Arguments: hWnd - Supplies parent window handle wText - Supplies ID of a printf-like format string to display as the message box text wCaption - Supplies ID of a string to display as the message box caption wType - Supplies flags to MessageBox() Return Value: Whatever MessageBox() returns. --*/ { TCHAR szText[ 4 * MAX_PATH ], szCaption[ 2 * MAX_PATH ]; int ival; va_list parg; va_start( parg, wType ); if( wText == IDS_INSUFFICIENT_MEMORY ) goto NoMem; if( !LoadString( hInstance, wText, szCaption, ARRAYSIZE( szCaption ) ) ) goto NoMem; wvsprintf( szText, szCaption, parg ); if( !LoadString( hInstance, wCaption, szCaption, ARRAYSIZE( szCaption ) ) ) goto NoMem; if( (ival = MessageBox( hWnd, szText, szCaption, wType ) ) == 0 ) goto NoMem; va_end( parg ); return( ival ); NoMem: va_end( parg ); ErrMemDlg( hWnd ); return 0; } LPTSTR CloneString( IN LPTSTR pszSrc ) /*++ Routine Description: Allocates a buffer and copies a string into it Arguments: pszSrc - Supplies string to copy Return Value: Valid LPTSTR if successful NULL if out of memory --*/ { LPTSTR pszDst = NULL; if (pszSrc != NULL) { pszDst = MemAlloc(LMEM_FIXED, (lstrlen(pszSrc)+1) * SIZEOF(TCHAR)); if (pszDst) { lstrcpy( pszDst, pszSrc ); } } return pszDst; } DWORD SetLBWidthEx( IN HWND hwndLB, IN LPTSTR szBuffer, IN DWORD cxCurWidth, IN DWORD cxExtra ) /*++ Routine Description: Set the width of a listbox, in pixels, acording to the size of the string passed in Arguments: hwndLB - Supples listbox to resize szBuffer - Supplies string to resize listbox to cxCurWidth - Supplies current width of the listbox cxExtra - Supplies some kind of slop factor Return Value: The new width of the listbox --*/ { HDC hDC; SIZE Size; LONG cx; HFONT hfont, hfontOld; // Get the new Win4.0 thin dialog font hfont = (HFONT)SendMessage(hwndLB, WM_GETFONT, 0, 0); hDC = GetDC(hwndLB); // if we got a font back, select it in this clean hDC if (hfont != NULL) hfontOld = SelectObject(hDC, hfont); // If cxExtra is 0, then give our selves a little breathing space. if (cxExtra == 0) { GetTextExtentPoint(hDC, TEXT("1234"), 4 /* lstrlen("1234") */, &Size); cxExtra = Size.cx; } // Set scroll width of listbox GetTextExtentPoint(hDC, szBuffer, lstrlen(szBuffer), &Size); Size.cx += cxExtra; // Get the name length and adjust the longest name if ((DWORD) Size.cx > cxCurWidth) { cxCurWidth = Size.cx; SendMessage (hwndLB, LB_SETHORIZONTALEXTENT, (DWORD)Size.cx, 0L); } // retstore the original font if we changed it if (hfont != NULL) SelectObject(hDC, hfontOld); ReleaseDC(NULL, hDC); return cxCurWidth; } VOID SetDefButton( IN HWND hwndDlg, IN int idButton ) /*++ Routine Description: Sets the default button for a dialog box or proppage The old default button, if any, has its default status removed Arguments: hwndDlg - Supplies window handle idButton - Supplies ID of button to make default Return Value: None --*/ { LRESULT lr; if (HIWORD(lr = SendMessage(hwndDlg, DM_GETDEFID, 0, 0)) == DC_HASDEFID) { HWND hwndOldDefButton = GetDlgItem(hwndDlg, LOWORD(lr)); SendMessage (hwndOldDefButton, BM_SETSTYLE, MAKEWPARAM(BS_PUSHBUTTON, 0), MAKELPARAM(TRUE, 0)); } SendMessage( hwndDlg, DM_SETDEFID, idButton, 0L ); SendMessage( GetDlgItem(hwndDlg, idButton), BM_SETSTYLE, MAKEWPARAM( BS_DEFPUSHBUTTON, 0 ), MAKELPARAM( TRUE, 0 )); } void HourGlass( IN BOOL bOn ) /*++ Routine Description: Turns hourglass mouse cursor on or off Arguments: bOn - Supplies desired status of hourglass mouse cursor Return Value: None --*/ { if( !GetSystemMetrics( SM_MOUSEPRESENT ) ) ShowCursor( bOn ); SetCursor( LoadCursor( NULL, bOn ? IDC_WAIT : IDC_ARROW ) ); } VCREG_RET OpenRegKey( IN LPTSTR pszKeyName, OUT PHKEY phk ) /*++ Routine Description: Opens a subkey of HKEY_LOCAL_MACHINE Arguments: pszKeyName - Supplies the name of the subkey to open phk - Returns a handle to the key if successfully opened Returns NULL if an error occurs Return Value: VCREG_OK if successful VCREG_READONLY if the key was opened with read-only access VCREG_OK if an error occurred */ { LONG Error; Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pszKeyName, 0, KEY_READ | KEY_WRITE, phk); if (Error != ERROR_SUCCESS) { Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pszKeyName, 0, KEY_READ, phk); if (Error != ERROR_SUCCESS) { *phk = NULL; return VCREG_ERROR; } /* * We only have Read access. */ return VCREG_READONLY; } return VCREG_OK; } LONG CloseRegKey( IN HKEY hkey ) /*++ Routine Description: Closes a registry key opened by OpenRegKey() Arguments: hkey - Supplies handle to key to close Return Value: Whatever RegCloseKey() returns --*/ { return RegCloseKey(hkey); } BOOL IsWorkstationProduct( ) /*++ Routine Description: Determines whether the currently running system is a Workstation product or a Server product. Arguments: None. Return Value: TRUE if the currently running system is a Workstation product. FALSE if the currently running system is some other kind of product. --*/ { NT_PRODUCT_TYPE ProdType; RtlGetNtProductType(&ProdType); return(NtProductWinNt == ProdType); }