|
|
//*********************************************************************
//* Microsoft Windows **
//* Copyright(c) Microsoft Corp., 1999 **
//*********************************************************************
//
// UTIL.CPP - utilities
//
// HISTORY:
//
// 1/27/99 a-jaswed Created.
//
// Common utilities for printing out messages
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <objbase.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "util.h"
#include "appdefs.h"
#include <shlwapi.h>
#include <shlobj.h>
#include <shfolder.h>
#include <wchar.h>
#include <winsvcp.h> // for SC_OOBE_MACHINE_NAME_DONE
#include <safeboot.h> // for SAFEBOOT_DSREPAIR_STR_W
///////////////////////////////////////////////////////////
// Print out the COM/OLE error string for an HRESULT.
//
void ErrorMessage(LPCWSTR message, HRESULT hr) { const WCHAR* sz ; if (message == NULL) { sz = L"The following error occured." ; } else { sz = message ; }
void* pMsgBuf;
::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPWSTR) &pMsgBuf, 0, NULL );
WCHAR buf[256] ; wsprintf(buf, L"%s\r\nError: (%x) - %s", sz, hr, (LPWSTR)pMsgBuf) ;
MessageBox(NULL, buf, L"Utility Error Message Box.", MB_OK) ;
// Free the buffer.
LocalFree( pMsgBuf ); }
////////////////////////////////////////////////////////////
// Check to see if both interfaces are on the same component.
//
BOOL InterfacesAreOnSameComponent(IUnknown* p1, IUnknown* p2) { HRESULT hr = S_OK ;
// Get the real IUnknown for the first interface.
IUnknown* pReal1 = NULL ; hr = p1->QueryInterface(IID_IUnknown, (void**)&pReal1) ; assert(SUCCEEDED(hr)) ;
// Get the real IUnknown for the second interface.
IUnknown* pReal2 = NULL ; hr = p2->QueryInterface(IID_IUnknown, (void**)&pReal2) ; assert(SUCCEEDED(hr)) ;
// Compare the IUnknown pointers.
BOOL bReturn = (pReal1 == pReal2) ;
// Cleanup
pReal1->Release() ; pReal2->Release() ;
// Return the value.
return bReturn; }
///////////////////////////////////////////////////////////
// IsValidAddress
//
BOOL IsValidAddress(const void* lp, UINT nBytes, BOOL bReadWrite) { return (lp != NULL && !::IsBadReadPtr(lp, nBytes) && (!bReadWrite || !::IsBadWritePtr((LPVOID)lp, nBytes))); }
///////////////////////////////////////////////////////////
// MyDebug
//
#if ASSERTS_ON
VOID AssertFail( IN PSTR FileName, IN UINT LineNumber, IN PSTR Condition ) { int i; CHAR Name[MAX_PATH]; PCHAR p; CHAR Msg[4096];
//
// Use dll name as caption
//
GetModuleFileNameA(NULL,Name,MAX_PATH); if(p = strrchr(Name,'\\')) { p++; } else { p = Name; }
wsprintfA( Msg, "Assertion failure at line %u in file %s: %s%s", LineNumber, FileName, Condition, "\n\nCall DebugBreak()?" );
i = MessageBoxA( NULL, Msg, p, MB_YESNO | MB_TASKMODAL | MB_ICONSTOP | MB_SETFOREGROUND );
if(i == IDYES) { DebugBreak(); } } #endif
///////////////////////////////////////////////////////////
// Trace
//
void __cdecl MyTrace(LPCWSTR lpszFormat, ...) { USES_CONVERSION; va_list args; va_start(args, lpszFormat);
int nBuf; WCHAR szBuffer[512];
nBuf = _vsnwprintf(szBuffer, MAX_CHARS_IN_BUFFER(szBuffer), lpszFormat, args);
// was there an error? was the expanded string too long?
assert(nBuf > 0);
#if DBG
DbgPrintEx( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, W2A(szBuffer) ); #endif
va_end(args); }
//BUGBUG need bettter default
bool GetString(HINSTANCE hInstance, UINT uiID, LPWSTR szString, UINT uiStringLen) { // BUGBUG: Should this assume current module if hInstance is NULL??
MYASSERT(NULL != hInstance); if (NULL != hInstance) return (0 < LoadString(hInstance, uiID, szString, uiStringLen)); else return (false); }
// the goal of this function is to be able to able to get to
// c:\windows dir\system dir\oobe\oobeinfo.ini
// c:\windows dir\system dir\oeminfo.ini
// c:\windows dir\oemaudit.oem
// the canonicalize allows the specification for oemaudit.oem to be ..\oemaudit.oem
bool GetCanonicalizedPath(LPWSTR szCompletePath, LPCWSTR szFileName) { if (0 < GetSystemDirectory(szCompletePath, MAX_PATH)) { lstrcat(szCompletePath, szFileName);
WCHAR szLocal[MAX_PATH]; lstrcpy(szLocal, szCompletePath); return PathCanonicalize(szCompletePath, (LPCWSTR) szLocal) ? true : false; }
return false; }
bool GetOOBEPath(LPWSTR szOOBEPath) { if (0 < GetSystemDirectory(szOOBEPath, MAX_PATH)) { lstrcat(szOOBEPath, L"\\OOBE");
return true; }
return false; }
// This returns the path for the localized OOBE files on a system with MUI.
//
bool GetOOBEMUIPath(LPWSTR szOOBEPath) { LANGID UILang; WCHAR szMUIPath[MAX_PATH];
if (GetOOBEPath(szOOBEPath)) { UILang = GetUserDefaultUILanguage(); if ( UILang != GetSystemDefaultUILanguage() ) { wsprintf( szMUIPath, L"\\MUI\\%04x", UILang ); lstrcat(szOOBEPath, szMUIPath ); }
return true; }
return false; }
HRESULT GetINIKey(HINSTANCE hInstance, LPCWSTR szINIFileName, UINT uiSectionName, UINT uiKeyName, LPVARIANT pvResult) { WCHAR szSectionName[MAX_PATH], szKeyName[MAX_PATH]; WCHAR szItem[1024]; //bugbug bad constant
if (GetString(hInstance, uiSectionName, szSectionName) && GetString(hInstance, uiKeyName, szKeyName)) { WCHAR szINIPath[MAX_PATH]; if (GetCanonicalizedPath(szINIPath, szINIFileName)) { if (VT_I4 == V_VT(pvResult)) { V_I4(pvResult) = GetPrivateProfileInt(szSectionName, szKeyName, 0, szINIPath); return S_OK; } else { if (GetPrivateProfileString( szSectionName, szKeyName, L"", szItem, MAX_CHARS_IN_BUFFER(szItem), szINIPath)) { V_BSTR(pvResult) = SysAllocString(szItem); return S_OK; } } } }
if (VT_BSTR == V_VT(pvResult)) V_BSTR(pvResult) = SysAllocString(L"\0"); else V_I4(pvResult) = 0;
return S_OK; }
HRESULT GetINIKeyBSTR(HINSTANCE hInstance, LPCWSTR szINIFileName, UINT uiSectionName, UINT uiKeyName, LPVARIANT pvResult) { VariantInit(pvResult); V_VT(pvResult) = VT_BSTR;
return (GetINIKey(hInstance, szINIFileName, uiSectionName, uiKeyName, pvResult)); }
HRESULT GetINIKeyUINT(HINSTANCE hInstance, LPCWSTR szINIFileName, UINT uiSectionName, UINT uiKeyName, LPVARIANT pvResult) { VariantInit(pvResult); V_VT(pvResult) = VT_I4;
return (GetINIKey(hInstance, szINIFileName, uiSectionName, uiKeyName, pvResult)); }
HRESULT SetINIKey(HINSTANCE hInstance, LPCWSTR szINIFileName, UINT uiSectionName, UINT uiKeyName, LPVARIANT pvResult) { WCHAR szSectionName[MAX_PATH], szKeyName[MAX_PATH];
VariantInit(pvResult); V_VT(pvResult) = VT_BSTR;
if (GetString(hInstance, uiSectionName, szSectionName) && GetString(hInstance, uiKeyName, szKeyName)) { if (WritePrivateProfileString(V_BSTR(pvResult), szKeyName, V_BSTR(pvResult), szINIFileName)) { return S_OK; } }
return E_FAIL; }
void WINAPI URLEncode(WCHAR* pszUrl, size_t bsize) { if (!pszUrl) return; WCHAR* pszEncode = NULL; WCHAR* pszEStart = NULL; WCHAR* pszEEnd = (WCHAR*)wmemchr( pszUrl, L'\0', bsize ); int iUrlLen = (int)(pszEEnd-pszUrl); pszEEnd = pszUrl;
WCHAR c; size_t cch = (iUrlLen+1) * sizeof(WCHAR) * 3;
assert( cch <= bsize ); if (cch <= bsize) {
pszEncode = (WCHAR*)malloc(BYTES_REQUIRED_BY_CCH(cch)); if(pszEncode) { pszEStart = pszEncode; ZeroMemory(pszEncode, BYTES_REQUIRED_BY_CCH(cch));
for(; c = *(pszUrl); pszUrl++) { switch(c) { case L' ': //SPACE
memcpy(pszEncode, L"+", 1*sizeof(WCHAR)); pszEncode+=1; break; case L'#': memcpy(pszEncode, L"%23", 3*sizeof(WCHAR)); pszEncode+=3; break; case L'&': memcpy(pszEncode, L"%26", 3*sizeof(WCHAR)); pszEncode+=3; break; case L'%': memcpy(pszEncode, L"%25", 3*sizeof(WCHAR)); pszEncode+=3; break; case L'=': memcpy(pszEncode, L"%3D", 3*sizeof(WCHAR)); pszEncode+=3; break; case L'<': memcpy(pszEncode, L"%3C", 3*sizeof(WCHAR)); pszEncode+=3; break; case L'+': memcpy(pszEncode, L"%2B", 3*sizeof(WCHAR)); pszEncode += 3; break;
default: *pszEncode++ = c; break; } } *pszEncode++ = L'\0'; memcpy(pszEEnd ,pszEStart, (size_t)(pszEncode - pszEStart)); free(pszEStart); } } }
//BUGBUG: Need to turn spaces into "+"
void WINAPI URLAppendQueryPair ( LPWSTR lpszQuery, LPWSTR lpszName, LPWSTR lpszValue OPTIONAL ) { // Append the Name
lstrcat(lpszQuery, lpszName); lstrcat(lpszQuery, cszEquals);
// Append the Value
if ( lpszValue ) { lstrcat(lpszQuery, lpszValue); }
// Append an Ampersand if this is NOT the last pair
lstrcat(lpszQuery, cszAmpersand); }
void GetCmdLineToken(LPWSTR *ppszCmd, LPWSTR pszOut) { LPWSTR c; int i = 0; BOOL fInQuote = FALSE;
c = *ppszCmd;
pszOut[0] = *c; if (!*c) return; if (*c == L' ') { pszOut[1] = L'\0'; *ppszCmd = c+1; return; } else if( L'"' == *c ) { fInQuote = TRUE; }
NextChar: i++; c++; if( !*c || (!fInQuote && (*c == L' ')) ) { pszOut[i] = L'\0'; *ppszCmd = c; return; } else if( fInQuote && (*c == L'"') ) { fInQuote = FALSE; pszOut[i] = *c;
i++; c++; pszOut[i] = L'\0'; *ppszCmd = c; return; } else { pszOut[i] = *c; goto NextChar; } }
BOOL IsOEMDebugMode() { HKEY hKey = NULL; DWORD dwIsDebug = 0; DWORD dwSize = sizeof(dwIsDebug);
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, OOBE_MAIN_REG_KEY, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) { RegQueryValueEx(hKey, OOBE_OEMDEBUG_REG_VAL, 0, NULL, (LPBYTE)&dwIsDebug, &dwSize); RegCloseKey(hKey); } #ifdef DEBUG
return (BOOL)1; #else
return (BOOL)dwIsDebug; #endif
}
VOID PumpMessageQueue( VOID ) { MSG msg;
while(PeekMessage(&msg, NULL, 0,0,PM_REMOVE)) { DispatchMessage(&msg); }
}
BOOL IsThreadActive( HANDLE hThread ) { DWORD dwExitCode = 0;
return (NULL != hThread && GetExitCodeThread(hThread, &dwExitCode) && STILL_ACTIVE == dwExitCode ); }
void GetDesktopDirectory(WCHAR* pszPath) { WCHAR pszFolder[MAX_PATH]; *pszFolder = L'\0'; HRESULT hRet = SHGetFolderPath(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, 0, pszFolder ); if (S_OK != hRet) { hRet = SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, pszFolder ); }
if (S_OK == hRet) { lstrcpy(pszPath , pszFolder); }
}
void RemoveDesktopShortCut ( LPWSTR lpszShortcutName ) { WCHAR szShortcutPath[MAX_PATH] = L"\0";
GetDesktopDirectory(szShortcutPath);
if(szShortcutPath[0] != L'\0') { lstrcat(szShortcutPath, L"\\"); lstrcat(szShortcutPath, lpszShortcutName); lstrcat(szShortcutPath, L".LNK"); DeleteFile(szShortcutPath); } }
BOOL InvokeExternalApplication( IN PCWSTR ApplicationName, OPTIONAL IN PCWSTR CommandLine, IN OUT PDWORD ExitCode OPTIONAL )
/*++
Routine Description:
Invokes an external program, which is optionally detached.
Arguments:
ApplicationName - supplies app name. May be a partial or full path, or just a filename, in which case the standard win32 path search is performed. If not specified then the first element in CommandLine must specify the binary to execute.
CommandLine - supplies the command line to be passed to the application.
ExitCode - If specified, the execution is synchronous and this value receives the exit code of the application. If not specified, the execution is asynchronous.
Return Value:
Boolean value indicating whether the process was started successfully.
--*/
{ PWSTR FullCommandLine; BOOL b; PROCESS_INFORMATION ProcessInfo; STARTUPINFO StartupInfo; DWORD d;
b = FALSE; //
// Form the command line to be passed to CreateProcess.
//
if(ApplicationName) { FullCommandLine = (PWSTR) malloc(BYTES_REQUIRED_BY_SZ(ApplicationName)+BYTES_REQUIRED_BY_SZ(CommandLine)+BYTES_REQUIRED_BY_CCH(2)); if(!FullCommandLine) { goto err0; }
lstrcpy(FullCommandLine, ApplicationName); lstrcat(FullCommandLine, L" "); lstrcat(FullCommandLine, CommandLine); } else { FullCommandLine = (PWSTR) malloc(BYTES_REQUIRED_BY_SZ(CommandLine)); if(!FullCommandLine) { goto err0; } lstrcpy(FullCommandLine, CommandLine); }
//
// Initialize startup info.
//
ZeroMemory(&StartupInfo, sizeof(STARTUPINFO)); StartupInfo.cb = sizeof(STARTUPINFO);
//
// Create the process.
//
b = CreateProcess( NULL, FullCommandLine, NULL, NULL, FALSE, ExitCode ? 0 : DETACHED_PROCESS, NULL, NULL, &StartupInfo, &ProcessInfo );
if(!b) { goto err1; }
//
// If execution is asynchronus, we're done.
//
if(!ExitCode) { goto err2; }
err2: CloseHandle(ProcessInfo.hThread); CloseHandle(ProcessInfo.hProcess); err1: free(FullCommandLine); err0: return(b); }
//////////////////////////////////////////////////////////////////////////////
//
// InSafeMode
//
// Determine whether the system is running in safe mode or clean mode.
//
// parameters:
// None.
//
// returns:
// TRUE if the system was booted in safe mode
// FALSE if the system was booted in clean mode
//
//////////////////////////////////////////////////////////////////////////////
BOOL InSafeMode() { if (BOOT_CLEAN != GetSystemMetrics(SM_CLEANBOOT)) { TRACE(L"Running in SAFEMODE..."); return TRUE; } return FALSE;
} // InSafeMode
//////////////////////////////////////////////////////////////////////////////
//
// InDsRestoreMode
//
// Determine whether the system is running in Directory Services Restore Mode
//
// parameters:
// None.
//
// returns:
// TRUE if the system was booted in restore mode
// FALSE if the system was not booted in restore mode
//
//////////////////////////////////////////////////////////////////////////////
BOOL InDsRestoreMode() { WCHAR SafeBootEnvVar[ARRAYSIZE(SAFEBOOT_DSREPAIR_STR_W)] = L"\0";
if ( GetEnvironmentVariableW( L"SAFEBOOT_OPTION", SafeBootEnvVar, ARRAYSIZE(SafeBootEnvVar) ) ) { if ( wcscmp( SafeBootEnvVar, SAFEBOOT_DSREPAIR_STR_W ) == 0 ) { TRACE(L"Running in DS Restore Mode..."); return TRUE; } }
return FALSE;
} // InDsRestoreMode
// Signal winlogon that the computer name has been changed. WinLogon waits to
// start services that depend on the computer name until this event is
// signalled.
//
BOOL SignalComputerNameChangeComplete() { BOOL fReturn = TRUE;
// Open event with EVENT_ALL_ACCESS so that synchronization and state
// change can be done.
//
HANDLE hevent = OpenEvent(EVENT_ALL_ACCESS, FALSE, SC_OOBE_MACHINE_NAME_DONE );
// It is not fatal for OpenEvent to fail: this synchronization is only
// required when OOBE will be run in OEM mode.
//
if (NULL != hevent) { if (! SetEvent(hevent)) { // It is fatal to open but not set the event: services.exe will not
// continue until this event is signalled.
//
TRACE2(L"Failed to signal SC_OOBE_MACHINE_NAME_DONE(%s): 0x%08X\n", SC_OOBE_MACHINE_NAME_DONE, GetLastError()); fReturn = FALSE; } MYASSERT(fReturn); // Why did we fail to set an open event??
}
return fReturn; }
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.
--*/
{ HANDLE Token; DWORD BytesRequired; PTOKEN_GROUPS Groups; BOOL b; DWORD i; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; PSID AdministratorsGroup;
//
// Open the process token.
//
if(!OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&Token)) { return(FALSE); }
b = FALSE; Groups = NULL;
//
// Get group information.
//
if(!GetTokenInformation(Token,TokenGroups,NULL,0,&BytesRequired) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER) && (Groups = (PTOKEN_GROUPS)LocalAlloc(LPTR,BytesRequired)) && GetTokenInformation(Token,TokenGroups,Groups,BytesRequired,&BytesRequired)) {
b = AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdministratorsGroup );
if(b) {
//
// See if the user has the administrator group.
//
b = FALSE; for(i=0; i<Groups->GroupCount; i++) { if(EqualSid(Groups->Groups[i].Sid,AdministratorsGroup)) { b = TRUE; break; } }
FreeSid(AdministratorsGroup); } }
//
// Clean up and return.
//
if(Groups) { LocalFree((HLOCAL)Groups); }
CloseHandle(Token);
return(b); }
#define MyMalloc(s) GlobalAlloc(GPTR, s)
#define MyFree(p) GlobalFree(p)
static LPTSTR pDuplicateString( LPCTSTR szText ) { int cchText; LPTSTR szOutText;
if (szText == NULL) { return NULL; }
cchText = lstrlen(szText); szOutText = (LPTSTR) MyMalloc(sizeof(TCHAR) * (cchText + 1)); if (szOutText) { lstrcpyn(szOutText, szText, cchText + 1); }
return szOutText; }
PSTRINGLIST CreateStringCell ( IN PCTSTR String ) { PSTRINGLIST p = (PSTRINGLIST) MyMalloc (sizeof (STRINGLIST)); if (p) { ZeroMemory (p, sizeof (STRINGLIST)); if (String) { p->String = pDuplicateString (String); if (!p->String) { MyFree (p); p = NULL; } } else { p->String = NULL; } } return p; }
VOID DeleteStringCell ( IN PSTRINGLIST Cell ) { if (Cell) { MyFree (Cell->String); MyFree (Cell); } }
BOOL InsertList ( IN OUT PSTRINGLIST* List, IN PSTRINGLIST NewList ) { PSTRINGLIST p;
if (!NewList) { return FALSE; } if (*List) { for (p = *List; p->Next; p = p->Next) ; p->Next = NewList; } else { *List = NewList; } return TRUE; }
VOID DestroyList ( IN PSTRINGLIST List ) { PSTRINGLIST p, q;
for (p = List; p; p = q) { q = p->Next; DeleteStringCell (p); } }
BOOL RemoveListI( IN OUT PSTRINGLIST* List, IN PCTSTR String ) { PSTRINGLIST p = *List; BOOL b = FALSE;
if (p) { if (!lstrcmpi(p->String, String)) { *List = p->Next; DeleteStringCell(p); b = TRUE; } else { PSTRINGLIST q; for (q = p->Next; q; p = q, q = q->Next) { if (!lstrcmpi(q->String, String)) { p->Next = q->Next; DeleteStringCell(q); b = TRUE; break; } } } }
return b; }
BOOL ExistInListI( IN PSTRINGLIST List, IN PCTSTR String ) { PSTRINGLIST p;
for (p = List; p; p = p->Next) { if (!lstrcmpi(p->String, String)) { break; } }
return (p != NULL); }
BOOL IsDriveNTFS(IN TCHAR Drive) { TCHAR DriveName[4]; TCHAR Filesystem[256]; TCHAR VolumeName[MAX_PATH]; DWORD SerialNumber; DWORD MaxComponent; DWORD Flags; BOOL bIsNTFS = FALSE;
DriveName[0] = Drive; DriveName[1] = TEXT(':'); DriveName[2] = TEXT('\\'); DriveName[3] = 0;
if (GetVolumeInformation( DriveName, VolumeName,MAX_PATH, &SerialNumber, &MaxComponent, &Flags, Filesystem, sizeof(Filesystem)/sizeof(TCHAR) )) { bIsNTFS = (lstrcmpi(Filesystem,TEXT("NTFS")) == 0); }
return bIsNTFS; }
BOOL HasTablet() { TCHAR szPath[MAX_PATH+1];
ZeroMemory(szPath, sizeof(szPath));
if (FAILED(SHGetFolderPath( NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, SHGFP_TYPE_DEFAULT, szPath))) { return FALSE; }
StrCatBuff(szPath, TEXT("\\Microsoft Shared\\Ink\\tabtip.exe"), MAX_PATH+1);
return PathFileExists(szPath); }
DWORD MyGetModuleFileName ( IN HMODULE Module, OUT PTSTR Buffer, IN DWORD BufferLength ) { DWORD d = GetModuleFileName (Module, Buffer, BufferLength);
if (BufferLength > 0) { Buffer[BufferLength - 1] = 0; }
if (d < BufferLength) { return d; } else { SetLastError(ERROR_INSUFFICIENT_BUFFER); return 0; } }
|