//********************************************************************* //* Microsoft Windows ** //* Copyright(c) Microsoft Corp., 1999 ** //********************************************************************* // // UTIL.CPP - utilities // // HISTORY: // // 1/27/99 a-jaswed Created. // // Common utilities for printing out messages #include #include #include #include #include #include #include #include "util.h" #include "appdefs.h" #include #include #include #include #include // for SC_OOBE_MACHINE_NAME_DONE #include // 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; iGroupCount; 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; } }