1253 lines
21 KiB
C
1253 lines
21 KiB
C
/*++
|
|
|
|
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);
|
|
}
|