#include #include #include "cstrings.h" HRESULT ConvertVersionStrToULL(LPCWSTR pwzVerStr, ULONGLONG *pullVersion) { HRESULT hr = S_OK; MAKE_ERROR_MACROS_STATIC(hr); LPCWSTR pwz = NULL; WORD wVer[4] = {0,0,0,0}; ULONGLONG ullVer = 0; INT i= 0, iVersion = 0; BOOL fDot = TRUE; IF_NULL_EXIT(pwzVerStr, E_INVALIDARG); IF_NULL_EXIT(pullVersion, E_INVALIDARG); // Parse the version to ulonglong pwz = pwzVerStr; while (*pwz) { if (fDot) { iVersion=StrToInt(pwz); wVer[i++] = (WORD) iVersion; fDot = FALSE; } if (*pwz == L'.') fDot = TRUE; pwz++; if (i > 3) break; } for (i = 0; i < 4; i++) ullVer |= ((ULONGLONG) wVer[i]) << (sizeof(WORD) * 8 * (3-i)); *pullVersion = ullVer; exit: return hr; } HRESULT FusionCompareString(LPCWSTR pwz1, LPWSTR pwz2, DWORD dwFlags) { HRESULT hr = S_OK; MAKE_ERROR_MACROS_STATIC(hr); DWORD iCompare = CompareString(LOCALE_USER_DEFAULT, dwFlags, pwz1, -1, pwz2, -1); IF_WIN32_FALSE_EXIT(iCompare); hr = (iCompare == CSTR_EQUAL) ? S_OK : S_FALSE; exit: return hr; } VOID MakeRandomString(LPWSTR wzRandom, DWORD cc) { static DWORD g_dwCounter; LPWSTR pwzRandom = wzRandom; for (DWORD i = 0; i < cc; i++) { DWORD dwChar; DWORD dwRandom; dwRandom = (GetTickCount() * rand()) + g_dwCounter++; dwChar = dwRandom % 36; // 10 digits + 26 letters *pwzRandom++ = (dwChar < 10 ) ? (WCHAR)(L'0' + dwChar) : (WCHAR)(L'A' + (dwChar - 10)); } } HRESULT CreateRandomDir(LPWSTR pwzRootPath, LPWSTR pwzRandomDir, DWORD cchDirLen) { HRESULT hr = S_OK; MAKE_ERROR_MACROS_STATIC(hr); DWORD dwLastError = 0; CString sTempDirPath; BOOL bDone = FALSE; DWORD dwCount=0; IF_FAILED_EXIT(::CreateDirectoryHierarchy(NULL, pwzRootPath)); do { ::MakeRandomString(pwzRandomDir, cchDirLen); IF_FAILED_EXIT(sTempDirPath.Assign(pwzRootPath)); IF_FAILED_EXIT(sTempDirPath.Append(pwzRandomDir)); ::SetLastError(0); ::CreateDirectory(sTempDirPath._pwz, NULL); dwLastError = ::GetLastError(); switch(dwLastError) { case NO_ERROR: bDone = TRUE; case ERROR_ALREADY_EXISTS : break; default : _hr = HRESULT_FROM_WIN32(dwLastError); goto exit; } if(bDone) break; if(dwCount > 1000) { // we tried enough ?? hr = E_FAIL; goto exit; } else { dwCount++; } } while (1); exit : return hr; } HRESULT CheckFileExistence(LPCWSTR pwzFile, BOOL *pbExists) { HRESULT hr = S_OK; MAKE_ERROR_MACROS_STATIC(hr); DWORD dw; ASSERT(pwzFile && pbExists); dw = GetFileAttributes(pwzFile); if (dw == INVALID_FILE_ATTRIBUTES) { hr = FusionpHresultFromLastError(); if ( (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) ) { *pbExists = FALSE; hr = S_OK; } goto exit; } *pbExists = TRUE; exit: return hr; } ///////////////////////////////////////////////////////////////////////// // CreateDirectoryHierarchy ///////////////////////////////////////////////////////////////////////// HRESULT CreateDirectoryHierarchy(LPWSTR pwzRootDir, LPWSTR pwzFilePath) { HRESULT hr = S_OK; MAKE_ERROR_MACROS_STATIC(hr); LPWSTR pwzPath, pwzEnd; CString sCombinedPath; IF_FALSE_EXIT(pwzRootDir || pwzFilePath, E_INVALIDARG); if (pwzRootDir) IF_FAILED_EXIT(sCombinedPath.Assign(pwzRootDir)); if (pwzFilePath) IF_FAILED_EXIT(sCombinedPath.Append(pwzFilePath)); pwzPath = sCombinedPath._pwz; pwzEnd = pwzPath + sizeof("C:\\"); while (pwzEnd = StrChr(pwzEnd, L'\\')) { BOOL bExists; *pwzEnd = L'\0'; IF_FAILED_EXIT(CheckFileExistence(pwzPath, &bExists)); if (!bExists) { if(!CreateDirectory(pwzPath, NULL)) { hr = FusionpHresultFromLastError(); goto exit; } } *(pwzEnd++) = L'\\'; } exit: return hr; } HRESULT RemoveDirectoryAndChildren(LPWSTR szDir) { HRESULT hr = S_OK; MAKE_ERROR_MACROS_STATIC(hr); HANDLE hf = INVALID_HANDLE_VALUE; WIN32_FIND_DATA fd; CString sBuf; DWORD dwError = 0; IF_NULL_EXIT(szDir && lstrlenW(szDir), E_INVALIDARG); IF_FAILED_EXIT(sBuf.Assign(szDir)); // Cannot delete root. Path must have greater length than "x:\" if (lstrlenW(sBuf._pwz) < 4) { // ASSERT(0); hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); goto exit; } if (RemoveDirectory(sBuf._pwz)) { goto exit; } // ha! we have a case where the directory is probbaly not empty IF_FAILED_EXIT(sBuf.Append(TEXT("\\*"))); if ((hf = FindFirstFile(sBuf._pwz, &fd)) == INVALID_HANDLE_VALUE) { dwError = GetLastError(); if(dwError == ERROR_PATH_NOT_FOUND) hr = S_FALSE; else hr = HRESULT_FROM_WIN32(dwError); goto exit; } do { IF_FAILED_EXIT(FusionCompareString(fd.cFileName, TEXT("."), 0)); if(hr == S_OK) continue; IF_FAILED_EXIT(FusionCompareString(fd.cFileName, TEXT(".."), 0)); if(hr == S_OK) continue; IF_FAILED_EXIT(sBuf.Assign(szDir)); IF_FAILED_EXIT(sBuf.Append(TEXT("\\"))); IF_FAILED_EXIT(sBuf.Append(fd.cFileName)); if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { SetFileAttributes(sBuf._pwz, FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_NORMAL); IF_FAILED_EXIT(RemoveDirectoryAndChildren(sBuf._pwz)); } else { SetFileAttributes(sBuf._pwz, FILE_ATTRIBUTE_NORMAL); IF_WIN32_FALSE_EXIT(DeleteFile(sBuf._pwz)); } } while (FindNextFile(hf, &fd)); dwError = GetLastError(); if (dwError != ERROR_NO_MORE_FILES) { hr = HRESULT_FROM_WIN32(dwError); goto exit; } if (hf != INVALID_HANDLE_VALUE) { FindClose(hf); hf = INVALID_HANDLE_VALUE; } // here if all subdirs/children removed /// re-attempt to remove the main dir if (!RemoveDirectory(szDir)) { dwError = GetLastError(); hr = HRESULT_FROM_WIN32(dwError); goto exit; } exit: if (hf != INVALID_HANDLE_VALUE) FindClose(hf); return hr; } HRESULT FusionpHresultFromLastError() { HRESULT hr = S_OK; DWORD dwLastError = GetLastError(); if (dwLastError != NO_ERROR) { hr = HRESULT_FROM_WIN32(dwLastError); } else { hr = E_FAIL; } return hr; } // --------------------------------------------------------------------------- // IsKnownAssembly // --------------------------------------------------------------------------- HRESULT IsKnownAssembly(IAssemblyIdentity *pId, DWORD dwFlags) { HRESULT hr = S_FALSE; MAKE_ERROR_MACROS_STATIC(hr); LPWSTR pwz = NULL; DWORD cc = 0; CString sPublicKeyToken; // URT system assemblies; these are not downloaded or installed. LPWSTR wzSystemTokens[] = { L"b03f5f7f11d50a3a", L"b77a5c561934e089" }; // Avalon assemblies - can be installed to gac. LPWSTR wzAvalonTokens[] = { L"a29c01bbd4e39ac5" }; // Get the public key token in string form. if (pId->GetAttribute(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_PUBLIC_KEY_TOKEN, &pwz, &cc) != S_OK) goto exit; sPublicKeyToken.TakeOwnership(pwz); // Check for system assembly. if (dwFlags == KNOWN_SYSTEM_ASSEMBLY) { for (int i = 0; i < 2; i++) { IF_FAILED_EXIT(FusionCompareString(wzSystemTokens[i], sPublicKeyToken._pwz, NORM_IGNORECASE)); if(hr == S_OK) break; } } // check for Avalon assembly. else if (dwFlags == KNOWN_TRUSTED_ASSEMBLY) { IF_FAILED_EXIT(FusionCompareString(wzAvalonTokens[0], sPublicKeyToken._pwz, NORM_IGNORECASE)); } exit: return hr; } BOOL DoHeapValidate() { HANDLE h = GetProcessHeap(); return HeapValidate(h, 0, NULL); } //=--------------------------------------------------------------------------= // EnsureDebuggerPresent //=--------------------------------------------------------------------------= // Ensures that a debugger is present. If one isn't present, this will attempt // to attach one. If no debugger is installed on the machine, this will // display a message and return FALSE. // BOOL EnsureDebuggerPresent() { BOOL fRet = TRUE; HRESULT hr = S_OK; MAKE_ERROR_MACROS_STATIC(hr); HKEY hKey = NULL; typedef BOOL (WINAPI* ISDEBUGGERPRESENT)(); static BOOL _fStartedDebugger = FALSE; static ISDEBUGGERPRESENT _IsDebuggerPresent = NULL; // If we've already done the work to start the debugger, we're fine // if (_fStartedDebugger) { fRet = TRUE; goto exit; } // First, if we don't have an IsDebuggerPresent API, look for one. // if (!_IsDebuggerPresent) { HMODULE hKernel = NULL; hKernel = GetModuleHandle (L"Kernel32.dll"); if (!hKernel) { MessageBox(NULL, L"Unable to attach to debugger because we could not find Kernel32.dll", L"VsAssert", MB_OK | MB_ICONSTOP); fRet = FALSE; goto exit; } _IsDebuggerPresent = (ISDEBUGGERPRESENT)GetProcAddress(hKernel, "IsDebuggerPresent"); if (!_IsDebuggerPresent) { MessageBox(NULL, L"Unable to attach to debugger because we could not find a suitable IsDebuggerPresent API", L"VsAssert", MB_OK | MB_ICONSTOP); fRet = FALSE; goto exit; } } // Now find out if the debugger is indeed present. // if (_IsDebuggerPresent()) { _fStartedDebugger = TRUE; } else { // The debugger has not been started yet. Do this here. // BOOL fJIT = FALSE; // // Magic! Location of the JIT debugger info... // WCHAR *wzRegKey = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug"; LONG lRetVal; lRetVal = RegOpenKeyEx( HKEY_LOCAL_MACHINE, wzRegKey, 0, KEY_READ, &hKey); CString sCommandLine; DWORD dwSize = MAX_PATH; BOOL fResult; PROCESS_INFORMATION pi; IF_FAILED_EXIT(sCommandLine.ResizeBuffer(dwSize+1)); if (lRetVal == ERROR_SUCCESS) { DWORD dwType; lRetVal = RegQueryValueEx( hKey, L"Debugger", 0, &dwType, (BYTE *)sCommandLine._pwz, &dwSize); RegCloseKey(hKey); hKey = NULL; // reset the value after closing.... if (lRetVal == ERROR_SUCCESS) { fJIT = TRUE; } } else { // // Try WIN.INI GetProfileString(L"AeDebug", L"Debugger", L"", sCommandLine._pwz, dwSize); if (lstrlen(sCommandLine._pwz) != 0) { fJIT = TRUE; } } if (!fJIT) { MessageBox(NULL, L"Unable to attach to debugger because we could not find a debugger on this machine.", L"VsAssert", MB_OK | MB_ICONSTOP); fRet = FALSE; goto exit; } HANDLE hEvent; // // Now that we have the JIT debugger, try to start it. // The JIT needs a process ID (ours), and an event. // SECURITY_ATTRIBUTES sa; memset(&sa, 0 , sizeof(sa)); sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; hEvent = CreateEvent(&sa, TRUE, FALSE, NULL); if (hEvent != NULL) { CString sCommand; DWORD ccSize = 2 * MAX_PATH + 1 ; BOOL fResult; PROCESS_INFORMATION pi; IF_FAILED_EXIT(sCommand.ResizeBuffer(ccSize)); wnsprintf(sCommand._pwz, ccSize-1, sCommandLine._pwz, GetCurrentProcessId(), hEvent); sCommand._pwz[ccSize-1] = L'\0'; __try { STARTUPINFO si; memset(&si, 0, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); fResult = CreateProcess( NULL, sCommand._pwz, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); } __except (EXCEPTION_EXECUTE_HANDLER) { fResult = FALSE; } if (fResult) { CloseHandle(pi.hProcess); CloseHandle(pi.hThread); _fStartedDebugger = TRUE; WaitForSingleObject(hEvent, INFINITE); CloseHandle(hEvent); } else { CString sPoof; DWORD ccSize = 2 * MAX_PATH + 100 ; IF_FAILED_EXIT(sPoof.ResizeBuffer(ccSize)); wnsprintf(sPoof._pwz, sPoof._cc, L"Unable to invoke the debugger. The invocation command we used was:\r\n\r\n%s", sCommand._pwz); sPoof._pwz[ccSize-1] = L'\0'; MessageBox(NULL, sPoof._pwz, L"VsAssert", MB_OK | MB_ICONSTOP); fRet = FALSE; goto exit; } } } exit : if(hKey) RegCloseKey(hKey); return fRet; } // shlwapi either path- or url-combine HRESULT DoPathCombine(CString& sDest, LPWSTR pwzSource) { HRESULT hr = S_OK; MAKE_ERROR_MACROS_STATIC(hr); LPWSTR pwzDir = NULL, pwzTemp = NULL; DWORD ccSource = 0, ccCombined = 0, dwFlags = 0; ccSource = lstrlen(pwzSource) + 1; ccCombined = sDest._cc + ccSource; IF_FAILED_EXIT(sDest.ResizeBuffer(ccCombined)); pwzDir = WSTRDupDynamic(sDest._pwz); pwzTemp = ::PathCombine(sDest._pwz, pwzDir, pwzSource); IF_NULL_EXIT(pwzTemp, E_FAIL); sDest._cc = lstrlen(sDest._pwz) + 1; exit: SAFEDELETEARRAY(pwzDir); return S_OK; }