/******************************************************************** Copyright (c) 1999-2000 Microsoft Corporation Module Name: util.cpp Abstract: utility functions implementation Revision History: DerekM created 05/01/99 ********************************************************************/ #include "stdafx.h" #include "util.h" #ifdef MANIFEST_HEAP #include #endif // MANIFEST_HEAP ///////////////////////////////////////////////////////////////////////////// // tracing #ifdef THIS_FILE #undef THIS_FILE #endif static char __szTraceSourceFile[] = __FILE__; #define THIS_FILE __szTraceSourceFile HANDLE g_hPFPrivateHeap = NULL; struct SLangCodepage { WORD wLanguage; WORD wCodePage; }; ////////////////////////////////////////////////////////////////////////////// // string stuff // *************************************************************************** WCHAR *MyStrStrIW(const WCHAR *wcs1, const WCHAR *wcs2) { WCHAR *cp = (WCHAR *)wcs1; WCHAR *s1, *s2; while (*cp != '\0') { s1 = cp; s2 = (WCHAR *) wcs2; while (*s1 != '\0' && *s2 !='\0' && (towlower(*s1) - towlower(*s2)) == 0) s1++, s2++; if (*s2 == '\0') return(cp); cp++; } return(NULL); } // *************************************************************************** CHAR *MyStrStrIA(const CHAR *cs1, const CHAR *cs2) { CHAR *cp = (CHAR *)cs1; CHAR *s1, *s2; while (*cp != '\0') { s1 = cp; s2 = (CHAR *) cs2; while (*s1 != '\0' && *s2 !='\0' && (tolower(*s1) - tolower(*s2)) == 0) s1++, s2++; if (*s2 == '\0') return(cp); cp++; } return(NULL); } //////////////////////////////////////////////////////////////////////////// // temp file stuff // *************************************************************************** BOOL DeleteTempDirAndFile(LPCWSTR wszPath, BOOL fFilePresent) { LPWSTR wszPathToDel = NULL, pwsz; DWORD cchPath; BOOL fRet = FALSE; if (wszPath == NULL) { SetLastError(ERROR_INVALID_PARAMETER); goto done; } cchPath = wcslen(wszPath); __try { wszPathToDel = (LPWSTR)_alloca(cchPath * sizeof(WCHAR)); } __except(EXCEPTION_EXECUTE_HANDLER) { wszPathToDel = NULL; } if (wszPathToDel == NULL) { SetLastError(ERROR_OUTOFMEMORY); goto done; } wcscpy(wszPathToDel, wszPath); // delete the actual file if (fFilePresent) { DeleteFileW(wszPathToDel); // next, delete the directory that we put it in for(pwsz = wszPathToDel + cchPath - 1; *pwsz != L'\\' && pwsz > wszPathToDel; pwsz--); if (*pwsz != L'\\' || pwsz <= wszPathToDel) goto done; } else { pwsz = wszPathToDel + cchPath; } *pwsz = L'\0'; RemoveDirectoryW(wszPathToDel); for(pwsz = pwsz - 1; *pwsz != L'.' && pwsz > wszPathToDel; pwsz--); if (*pwsz == L'.' && pwsz > wszPathToDel) { *pwsz = L'\0'; DeleteFileW(wszPathToDel); } fRet = TRUE; done: return fRet; } // *************************************************************************** DWORD CreateTempDirAndFile(LPCWSTR wszTempDir, LPCWSTR wszName, LPWSTR *pwszPath) { LPWSTR wszFilePath = NULL; WCHAR *wszTemp = NULL; DWORD cch = 0, cchDir = 0, iSuffix = 0, cSuffix = 0; WCHAR wsz[1024]; BOOL fRet = FALSE; if (pwszPath == NULL) { SetLastError(ERROR_INVALID_PARAMETER); goto done; } *pwszPath = NULL; if (wszTempDir != NULL) cch = wcslen(wszTempDir); if (cch == 0) { cch = GetTempPathW(0, NULL); if (cch == 0) goto done; } // compute the size of the buffer for the string we're going // to generate. The 20 includes the following: // max size of the temp filename // extra space for the NULL terminator. cch += (16 + sizeofSTRW(c_wszDirSuffix)); if (wszName != NULL) cch += wcslen(wszName); // ok, so GetTempFileName likes to write MAX_PATH characters to the buffer, // so make sure it's at least MAX_PATH in size... cch = MyMax(cch, MAX_PATH + 1); wszFilePath = (LPWSTR)MyAlloc(cch * sizeof(WCHAR)); if (wszFilePath == NULL) { SetLastError(ERROR_OUTOFMEMORY); goto done; } if (wszTempDir != NULL && wszTempDir[0] != L'\0') { cch = wcslen(wszTempDir); wszTemp = (LPWSTR)wszTempDir; } else { cch = GetTempPathW(cch, wszFilePath); if (cch == 0) goto done; cch++; __try { wszTemp = (WCHAR *)_alloca(cch * sizeof(WCHAR)); } __except(EXCEPTION_EXECUTE_HANDLER) { wszTemp = NULL; } if (wszTemp == NULL) { SetLastError(ERROR_OUTOFMEMORY); goto done; } wcscpy(wszTemp, wszFilePath); } cch = GetTempFileNameW(wszTemp, L"WER", 0, wszFilePath); if (cch == 0) goto done; cch = wcslen(wszFilePath); wcscpy(&wszFilePath[cch], c_wszDirSuffix); // iSuffix points to the first digit of the '00' at the end of // c_wszDirSuffix iSuffix = cch + sizeofSTRW(c_wszDirSuffix) - 3; cSuffix = 1; do { fRet = CreateDirectoryW(wszFilePath, NULL); if (fRet) break; wszFilePath[iSuffix] = L'0' + (WCHAR)(cSuffix / 10); wszFilePath[iSuffix + 1] = L'0' + (WCHAR)(cSuffix % 10); cSuffix++; } while (cSuffix <= 100); // hmm, couldn't create the directory... if (cSuffix > 100) { cchDir = cch; cch = 0; goto done; } cch += (sizeofSTRW(c_wszDirSuffix) - 1); if (wszName != NULL) { wszFilePath[cch++] = L'\\'; wcscpy(&wszFilePath[cch], wszName); cch += wcslen(wszName); } *pwszPath = wszFilePath; wszFilePath = NULL; fRet = TRUE; done: if (wszFilePath != NULL) { if (cchDir > 0) { wszFilePath[cchDir] = L'\0'; DeleteFileW(wszFilePath); } MyFree(wszFilePath); } return cch; } #ifdef MANIFEST_HEAP BOOL DeleteFullAndTriageMiniDumps( LPCWSTR wszPath ) // // We create a FullMinidump file along with triage minidump in the same dir // This routine cleans up both those files // { LPWSTR wszFullMinidump = NULL; DWORD cch; BOOL fRet; fRet = DeleteFileW(wszPath); cch = wcslen(wszPath) + sizeofSTRW(c_wszHeapDumpSuffix); __try { wszFullMinidump = (WCHAR *)_alloca(cch * sizeof(WCHAR)); } __except(EXCEPTION_STACK_OVERFLOW) { wszFullMinidump = NULL; } if (wszFullMinidump) { LPWSTR wszFileExt = NULL; // Build Dump-with-heap path wcsncpy(wszFullMinidump, wszPath, cch); wszFileExt = wszFullMinidump + wcslen(wszFullMinidump) - sizeofSTRW(c_wszDumpSuffix) + 1; if (!wcscmp(wszFileExt, c_wszDumpSuffix)) { *wszFileExt = L'\0'; } wcsncat(wszFullMinidump, c_wszHeapDumpSuffix, cch); fRet = DeleteFileW(wszFullMinidump); } else { fRet = FALSE; } return fRet; } #endif // MANIFEST_HEAP //////////////////////////////////////////////////////////////////////////// // File mapping // ************************************************************************** HRESULT OpenFileMapped(LPWSTR wszFile, LPVOID *ppvFile, DWORD *pcbFile) { USE_TRACING("OpenFileMapped"); HRESULT hr = NOERROR; HANDLE hMMF = NULL; HANDLE hFile = INVALID_HANDLE_VALUE; LPVOID pvFile = NULL; DWORD cbFile = 0; VALIDATEPARM(hr, (wszFile == NULL || ppvFile == NULL)); if (FAILED(hr)) goto done; *ppvFile = NULL; if (pcbFile != NULL) *pcbFile = 0; hFile = CreateFileW(wszFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); TESTBOOL(hr, (hFile != INVALID_HANDLE_VALUE)); if (FAILED(hr)) goto done; cbFile = GetFileSize(hFile, NULL); TESTBOOL(hr, (cbFile != (DWORD)-1)); if (FAILED(hr)) goto done; hMMF = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, cbFile, NULL); TESTBOOL(hr, (hMMF != NULL)); if (FAILED(hr)) goto done; pvFile = MapViewOfFile(hMMF, FILE_MAP_READ, 0, 0, 0); TESTBOOL(hr, (pvFile != NULL)); if (FAILED(hr)) goto done; *ppvFile = pvFile; if (pcbFile != NULL) *pcbFile = cbFile; done: if (hMMF != NULL) CloseHandle(hMMF); if (hFile != NULL) CloseHandle(hFile); return hr; } // ************************************************************************** HRESULT DeleteTempFile(LPWSTR wszFile) { USE_TRACING("DeleteTempFile"); HRESULT hr = NOERROR; WCHAR *pwsz; if (wszFile == NULL) return NOERROR; // strip off the extension at the end (if it's not a .tmp) for(pwsz = wszFile + wcslen(wszFile); *pwsz != L'.' && pwsz > wszFile; pwsz--); if (pwsz > wszFile && _wcsicmp(pwsz, L".tmp") != 0) *pwsz = L'\0'; if (DeleteFileW(wszFile) == FALSE) hr = Err2HR(GetLastError()); // can do this even if the extension was a tmp since the value pointed to // by pwsz is '.' if it's greater than wszFile... if (pwsz > wszFile) *pwsz = L'.'; return hr; } // ************************************************************************** HRESULT MyCallNamedPipe(LPCWSTR wszPipe, LPVOID pvIn, DWORD cbIn, LPVOID pvOut, DWORD cbOut, DWORD *pcbRead, DWORD dwWaitPipe, DWORD dwWaitRead) { HRESULT hr = NOERROR; HANDLE hPipe = INVALID_HANDLE_VALUE; HANDLE hev = NULL; DWORD dwStart = GetTickCount(), dwNow, dw; BOOL fRet; USE_TRACING("MyCallNamedPipe"); VALIDATEPARM(hr, (wszPipe == NULL || pvIn == NULL || pvOut == NULL || pcbRead == NULL)); if (FAILED(hr)) { SetLastError(ERROR_INVALID_PARAMETER); hr = E_INVALIDARG; goto done; } *pcbRead = 0; for(;;) { hPipe = CreateFileW(wszPipe, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | SECURITY_IDENTIFICATION | SECURITY_SQOS_PRESENT | SECURITY_CONTEXT_TRACKING, NULL); if (hPipe != INVALID_HANDLE_VALUE) break; // if we get ACCESS_DENIED to the above, then WaitNamedPipe will // return SUCCESS, so we get stuck until the timeout expires. Better // to just bail now. if (GetLastError() == ERROR_ACCESS_DENIED) goto done; TESTBOOL(hr, WaitNamedPipeW(wszPipe, dwWaitPipe)); if (FAILED(hr)) goto done; dwNow = GetTickCount(); if (dwNow < dwStart) dw = ((DWORD)-1 - dwStart) + dwNow; else dw = dwNow - dwStart; if (dw >= dwWaitPipe) dwWaitPipe = 0; else dwWaitPipe -= dw; if (dwWaitPipe == 0) { SetLastError(ERROR_TIMEOUT); goto done; } } __try { OVERLAPPED ol; DWORD dwMode = PIPE_READMODE_MESSAGE | PIPE_WAIT; DWORD cbRead = 0; // Default open is readmode byte stream- change to message mode. TESTBOOL(hr, SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL)) if (FAILED(hr)) __leave; // we need an event for the overlapped structure hev = CreateEventW(NULL, TRUE, FALSE, NULL); TESTBOOL(hr, (hev != NULL)); if (FAILED(hr)) __leave; // populate the overlapped stuff ZeroMemory(&ol, sizeof(ol)); ol.hEvent = hev; fRet = TransactNamedPipe(hPipe, pvIn, cbIn, pvOut, cbOut, &cbRead, &ol); if (GetLastError() != ERROR_IO_PENDING) { if (fRet) { SetEvent(hev); } else { hr = Err2HR(GetLastError()); __leave; } } dw = WaitForSingleObject(hev, dwWaitRead); if (dw != WAIT_OBJECT_0) { hr = (dw == WAIT_TIMEOUT) ? Err2HR(WAIT_TIMEOUT) : Err2HR(GetLastError()); __leave; } TESTBOOL(hr, GetOverlappedResult(hPipe, &ol, &cbRead, FALSE)); if (FAILED(hr)) __leave; *pcbRead = cbRead; hr = NOERROR; } __finally { } done: dw = GetLastError(); if (hPipe != INVALID_HANDLE_VALUE) CloseHandle(hPipe); if (hev != NULL) CloseHandle(hev); SetLastError(dw); return hr; } ////////////////////////////////////////////////////////////////////////////// // Security stuff // *************************************************************************** #define MEMBER_ACCESS 1 BOOL IsUserAnAdmin(HANDLE hToken) { SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY; SECURITY_DESCRIPTOR *psdAdm = NULL; GENERIC_MAPPING gm; PRIVILEGE_SET *pPS; HANDLE hTokenImp = NULL; DWORD cbSD, cbPS, dwGranted = 0; BYTE rgBuf[sizeof(PRIVILEGE_SET) + 3 * sizeof(LUID_AND_ATTRIBUTES)]; BOOL fRet = FALSE, fStatus; PSID psidAdm = NULL; PACL pACL = NULL; HRESULT hr; USE_TRACING("IsUserAnAdmin"); gm.GenericRead = GENERIC_READ; gm.GenericWrite = GENERIC_WRITE; gm.GenericExecute = GENERIC_EXECUTE; gm.GenericAll = GENERIC_ALL; pPS = (PRIVILEGE_SET *)rgBuf; cbPS = sizeof(rgBuf); // AccessCheck() reqires an impersonation token... TESTBOOL(hr, DuplicateToken(hToken, SecurityImpersonation, &hTokenImp)); if (FAILED(hr)) goto done; fRet = FALSE; // construct a SID that contains the administrator's group. TESTBOOL(hr, AllocateAndInitializeSid(&sia, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdm)); if (FAILED(hr)) goto done; cbSD = sizeof(SECURITY_DESCRIPTOR) + sizeof(ACCESS_ALLOWED_ACE) + sizeof(ACL) + 3 * GetLengthSid(psidAdm); __try { psdAdm = (SECURITY_DESCRIPTOR *)_alloca(cbSD); } __except(EXCEPTION_STACK_OVERFLOW) { psdAdm = NULL; } if (psdAdm == NULL) goto done; ZeroMemory(psdAdm, cbSD); pACL = (PACL)(psdAdm + 1); TESTBOOL(hr, InitializeSecurityDescriptor(psdAdm, SECURITY_DESCRIPTOR_REVISION)); if (FAILED(hr)) goto done; TESTBOOL(hr, SetSecurityDescriptorOwner(psdAdm, psidAdm, FALSE)); if (FAILED(hr)) goto done; TESTBOOL(hr, SetSecurityDescriptorGroup(psdAdm, psidAdm, FALSE)); if (FAILED(hr)) goto done; TESTBOOL(hr, InitializeAcl(pACL, cbSD - sizeof(SECURITY_DESCRIPTOR), ACL_REVISION)); if (FAILED(hr)) goto done; TESTBOOL(hr, AddAccessAllowedAce(pACL, ACL_REVISION, MEMBER_ACCESS, psidAdm)); if (FAILED(hr)) goto done; TESTBOOL(hr, SetSecurityDescriptorDacl(psdAdm, TRUE, pACL, FALSE)); if (FAILED(hr)) goto done; TESTBOOL(hr, AccessCheck(psdAdm, hTokenImp, MEMBER_ACCESS, &gm, pPS, &cbPS, &dwGranted, &fStatus)); if (FAILED(hr)) goto done; fRet = (fStatus && dwGranted == MEMBER_ACCESS); done: if (psidAdm != NULL) FreeSid(psidAdm); if (hTokenImp != NULL) CloseHandle(hTokenImp); return fRet; } // *************************************************************************** BOOL AllocSD(SECURITY_DESCRIPTOR *psd, DWORD dwOLs, DWORD dwAd, DWORD dwWA) { SID_IDENTIFIER_AUTHORITY siaCreate = SECURITY_CREATOR_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY siaWorld = SECURITY_WORLD_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY siaNT = SECURITY_NT_AUTHORITY; DWORD cb, dw; PACL pacl = NULL; PSID psidOwner = NULL; PSID psidLS = NULL; PSID psidWorld = NULL; PSID psidAnon = NULL; PSID psidAdm = NULL; BOOL fRet = FALSE; if (psd == NULL) { SetLastError(ERROR_INVALID_PARAMETER); goto done; } fRet = InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION); if (fRet == FALSE) goto done; // get the SID for local system acct fRet = AllocateAndInitializeSid(&siaNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &psidLS); if (fRet == FALSE) goto done; // get the SID for the creator fRet = AllocateAndInitializeSid(&siaCreate, 1, SECURITY_CREATOR_OWNER_RID, 0, 0, 0, 0, 0, 0, 0, &psidOwner); if (fRet == FALSE) goto done; cb = sizeof(ACL) + GetLengthSid(psidLS) + GetLengthSid(psidOwner) + 2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)); // if we have an access mask to apply for the administrators group, then // we need it's SID. if (dwAd != 0) { // get the SID for the local administrators group fRet = AllocateAndInitializeSid(&siaNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdm); if (fRet == FALSE) goto done; cb += (GetLengthSid(psidAdm) + sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)); } // if we have an access mask to apply for world / anonymous, then we need // their SIDs if (dwWA != 0) { // get the SID for the world (everyone) fRet = AllocateAndInitializeSid(&siaNT, 1, SECURITY_ANONYMOUS_LOGON_RID, 0, 0, 0, 0, 0, 0, 0, &psidWorld); // get the SID for the anonymous users acct fRet = AllocateAndInitializeSid(&siaWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &psidAnon); if (fRet == FALSE) goto done; cb += GetLengthSid(psidWorld) + GetLengthSid(psidAnon) + 2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)); } // make the DACL pacl = (PACL)MyAlloc(cb); if (pacl == NULL) { SetLastError(ERROR_OUTOFMEMORY); fRet = FALSE; goto done; } fRet = InitializeAcl(pacl, cb, ACL_REVISION); if (fRet == FALSE) goto done; fRet = AddAccessAllowedAce(pacl, ACL_REVISION, dwOLs, psidOwner); if (fRet == FALSE) goto done; fRet = AddAccessAllowedAce(pacl, ACL_REVISION, dwOLs, psidLS); if (fRet == FALSE) goto done; // if we have an administrator access mask, then apply it if (dwAd != 0) { fRet = AddAccessAllowedAce(pacl, ACL_REVISION, dwAd, psidAdm); if (fRet == FALSE) goto done; } // if we have a world / anonymous access mask, then apply it if (dwWA != 0) { fRet = AddAccessAllowedAce(pacl, ACL_REVISION, dwWA, psidWorld); if (fRet == FALSE) goto done; fRet = AddAccessAllowedAce(pacl, ACL_REVISION, dwWA, psidAnon); if (fRet == FALSE) goto done; } // set the SD dacl fRet = SetSecurityDescriptorDacl(psd, TRUE, pacl, FALSE); if (fRet == FALSE) goto done; pacl = NULL; done: dw = GetLastError(); if (psidLS != NULL) FreeSid(psidLS); if (psidWorld != NULL) FreeSid(psidWorld); if (psidAnon != NULL) FreeSid(psidAnon); if (psidAdm != NULL) FreeSid(psidAdm); if (psidOwner != NULL) FreeSid(psidOwner); if (pacl != NULL) MyFree(pacl); SetLastError(dw); return fRet; } // *************************************************************************** void FreeSD(SECURITY_DESCRIPTOR *psd) { PSID psid = NULL; PACL pacl = NULL; BOOL f, f2; if (psd == NULL) return; if (GetSecurityDescriptorDacl(psd, &f, &pacl, &f2) && pacl != NULL) MyFree(pacl); } ////////////////////////////////////////////////////////////////////////////// // Registry stuff // ************************************************************************** HRESULT OpenRegKey(HKEY hkeyMain, LPCWSTR wszSubKey, DWORD dwOpt, HKEY *phkey) { USE_TRACING("OpenRegKey"); HRESULT hr = NOERROR; REGSAM samDesired; DWORD dwErr; VALIDATEPARM(hr, (hkeyMain == NULL || wszSubKey == NULL || phkey == NULL)); if (FAILED(hr)) goto done; *phkey = NULL; samDesired = ((dwOpt & orkWantWrite) != 0) ? KEY_ALL_ACCESS : KEY_READ; samDesired |= ((dwOpt & orkUseWOW64) != 0) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY; // first try calling RegCreateKeyEx to make sure we create the key if // it doesn't exist TESTERR(hr, RegCreateKeyExW(hkeyMain, wszSubKey, 0, NULL, 0, samDesired, NULL, phkey, NULL)); if (FAILED(hr)) { // ok, that didn't work, so try opening the key instead TESTERR(hr, RegOpenKeyExW(hkeyMain, wszSubKey, 0, samDesired, phkey)); } done: return hr; } // ************************************************************************** HRESULT ReadRegEntry(HKEY hkey, LPCWSTR wszValName, DWORD *pdwType, PBYTE pbBuffer, DWORD *pcbBuffer, PBYTE pbDefault, DWORD cbDefault) { USE_TRACING("ReadRegEntry"); HRESULT hr = NOERROR; DWORD dwErr; VALIDATEPARM(hr, (hkey == NULL || wszValName == NULL)); if (FAILED(hr)) goto done; dwErr = RegQueryValueExW(hkey, wszValName, 0, pdwType, pbBuffer, pcbBuffer); VALIDATEEXPR(hr, (dwErr != ERROR_PATH_NOT_FOUND && dwErr != ERROR_FILE_NOT_FOUND && dwErr != ERROR_SUCCESS), Err2HR(dwErr)); if (FAILED(hr)) goto done; if (dwErr != ERROR_SUCCESS && pbDefault != NULL) { VALIDATEPARM(hr, (pcbBuffer == NULL && pbBuffer != NULL)); if (FAILED(hr)) goto done; // if the receiving buffer is NULL, just return the error that // RegQueryValueEx gave us cuz the user doesn't really want the // value anyway VALIDATEEXPR(hr, (pcbBuffer == NULL), Err2HR(dwErr)); if (FAILED(hr)) goto done; if (pbBuffer == NULL) { *pcbBuffer = cbDefault; hr = NOERROR; goto done; } else if (cbDefault > *pcbBuffer) { *pcbBuffer = cbDefault; hr = Err2HR(ERROR_MORE_DATA); goto done; } CopyMemory(pbBuffer, pbDefault, cbDefault); *pcbBuffer = cbDefault; if (pdwType != NULL) *pdwType = REG_BINARY; hr = NOERROR; goto done; } done: return hr; } // ************************************************************************** HRESULT ReadRegEntry(HKEY *rghkey, DWORD cKeys, LPCWSTR wszValName, DWORD *pdwType, PBYTE pbBuffer, DWORD *pcbBuffer, PBYTE pbDefault, DWORD cbDefault, DWORD *piKey) { USE_TRACING("ReadRegEntryPolicy"); HRESULT hr = NOERROR; DWORD dwErr=0, i; VALIDATEPARM(hr, (rghkey == NULL || wszValName == NULL)); if (FAILED(hr)) goto done; for(i = 0; i < cKeys; i++) { dwErr = RegQueryValueExW(rghkey[i], wszValName, 0, pdwType, pbBuffer, pcbBuffer); VALIDATEEXPR(hr, (dwErr != ERROR_PATH_NOT_FOUND && dwErr != ERROR_FILE_NOT_FOUND && dwErr != ERROR_SUCCESS), Err2HR(dwErr)); if (FAILED(hr)) goto done; if (dwErr == ERROR_SUCCESS) { if (piKey != NULL) *piKey = i; break; } } if (dwErr != ERROR_SUCCESS && pbDefault != NULL) { VALIDATEPARM(hr, (pcbBuffer == NULL && pbBuffer != NULL)); if (FAILED(hr)) goto done; // if the receiving buffer is NULL, just return the error that // RegQueryValueEx gave us cuz the user doesn't really want the // value anyway VALIDATEEXPR(hr, (pcbBuffer == NULL), Err2HR(dwErr)); if (FAILED(hr)) goto done; if (pbBuffer == NULL) { *pcbBuffer = cbDefault; hr = NOERROR; goto done; } else if (cbDefault > *pcbBuffer) { *pcbBuffer = cbDefault; hr = Err2HR(ERROR_MORE_DATA); goto done; } CopyMemory(pbBuffer, pbDefault, cbDefault); *pcbBuffer = cbDefault; if (pdwType != NULL) *pdwType = REG_BINARY; if (piKey != NULL) *piKey = cKeys; hr = NOERROR; goto done; } done: return hr; } ////////////////////////////////////////////////////////////////////////////// // version info stuff // ************************************************************************** DWORD IsMicrosoftApp(LPWSTR wszAppPath, PBYTE pbAppInfo, DWORD cbAppInfo) { USE_TRACING("IsMicrosoftApp"); SLangCodepage *plc; HRESULT hr = NOERROR; LPWSTR pwszName, pwszNameK32, wszModK32; WCHAR wszQueryString[128]; DWORD cbFVI, cbFVIK32, dwJunk, dwRet = 0; PBYTE pbFVI = NULL, pbFVIK32 = NULL; UINT cb, cbVerInfo, i, cchNeed, cch; VALIDATEPARM(hr, (wszAppPath == NULL && (pbAppInfo == NULL || cbAppInfo == 0))); if (FAILED(hr)) goto done; if (pbAppInfo == NULL) { // dwJunk is a useful parameter. Gotta pass it in so the function call // set it to 0. Gee this would make a great (tho non-efficient) // way to set DWORDs to 0. Much better than saying dwJunk = 0 by itself. cbFVI = GetFileVersionInfoSizeW(wszAppPath, &dwJunk); TESTBOOL(hr, (cbFVI != 0)); if (FAILED(hr)) { // if it fails, assume the file doesn't have any version info & // return S_FALSE hr = S_FALSE; goto done; } // alloca only throws exceptions so gotta catch 'em here.... __try { pbFVI = (PBYTE)_alloca(cbFVI); } __except(EXCEPTION_STACK_OVERFLOW) { pbFVI = NULL; } VALIDATEEXPR(hr, (pbFVI == NULL), E_OUTOFMEMORY); if (FAILED(hr)) goto done; cb = cbFVI; TESTBOOL(hr, GetFileVersionInfoW(wszAppPath, 0, cbFVI, (LPVOID *)pbFVI)); if (FAILED(hr)) { // if it fails, assume the file doesn't have any version info & // return S_FALSE hr = S_FALSE; goto done; } } else { pbFVI = pbAppInfo; cbFVI = cbAppInfo; } // get the info for kernel32.dll cchNeed = GetSystemDirectoryW(NULL, 0); if (cchNeed == 0) goto done; cchNeed += (sizeofSTRW(L"\\kernel32.dll") + 1); __try { wszModK32 = (LPWSTR)_alloca(cchNeed * sizeof(WCHAR)); } __except(EXCEPTION_STACK_OVERFLOW) { wszModK32 = NULL; } VALIDATEEXPR(hr, (wszModK32 == NULL), E_OUTOFMEMORY); if (FAILED(hr)) goto done; // get the info for kernel32.dll cch = GetSystemDirectoryW(wszModK32, cchNeed); if (cch == 0) goto done; if (*(wszModK32 + cch - 1) == L'\\') *(wszModK32 + cch - 1) = L'\0'; wcscat(wszModK32, L"\\kernel32.dll"); // dwJunk is a useful parameter. Gotta pass it in so the function call // set it to 0. Gee this would make a great (tho non-efficient) // way to set DWORDs to 0. Much better than saying dwJunk = 0 by itself. cbFVIK32 = GetFileVersionInfoSizeW(wszModK32, &dwJunk); TESTBOOL(hr, (cbFVIK32 != 0)); if (FAILED(hr)) { // if it fails, assume the file doesn't have any version info & // return S_FALSE hr = S_FALSE; goto done; } // alloca only throws exceptions so gotta catch 'em here.... __try { pbFVIK32 = (PBYTE)_alloca(cbFVIK32); } __except(EXCEPTION_STACK_OVERFLOW) { pbFVIK32 = NULL; } VALIDATEEXPR(hr, (pbFVIK32 == NULL), E_OUTOFMEMORY); if (FAILED(hr)) goto done; cb = cbFVI; TESTBOOL(hr, GetFileVersionInfoW(wszModK32, 0, cbFVIK32, (LPVOID *)pbFVIK32)); if (FAILED(hr)) { // if it fails, assume the file doesn't have any version info & // return S_FALSE hr = S_FALSE; goto done; } // Ok, since we can have any number of languages in the module, gotta // grep thru all of them & see if the company name field includes // 'Microsoft'. TESTBOOL(hr, VerQueryValueW(pbFVI, L"\\VarFileInfo\\Translation", (LPVOID *)&plc, &cbVerInfo)); if (FAILED(hr)) { // if it fails, assume the file doesn't have any version info & // return S_FALSE hr = S_FALSE; goto done; } // Read the file description for each language and code page. for(i = 0; i < (cbVerInfo / sizeof(SLangCodepage)); i++) { wsprintfW(wszQueryString, L"\\StringFileInfo\\%04x%04x\\CompanyName", plc[i].wLanguage, plc[i].wCodePage); // Retrieve file description for language and code page "i". TESTBOOL(hr, VerQueryValueW(pbFVI, wszQueryString, (LPVOID *)&pwszName, &cb)); if (FAILED(hr)) continue; // see if the string contains the word 'Microsoft' if (MyStrStrIW(pwszName, L"Microsoft") != NULL) { dwRet |= APP_MSAPP; goto doneCompany; } // ok, didn't match the word 'Microsoft', so instead, see if it matches // the string in kernel32.dll TESTBOOL(hr, VerQueryValueW(pbFVIK32, wszQueryString, (LPVOID *)&pwszNameK32, &cb)); if (FAILED(hr)) continue; if (CompareStringW(MAKELCID(plc[i].wLanguage, SORT_DEFAULT), NORM_IGNORECASE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH | SORT_STRINGSORT, pwszName, -1, pwszNameK32, -1) == CSTR_EQUAL) dwRet |= APP_MSAPP; else continue; doneCompany: wsprintfW(wszQueryString, L"\\StringFileInfo\\%04x%04x\\ProductName", plc[i].wLanguage, plc[i].wCodePage); // Retrieve file description for language and code page "i". TESTBOOL(hr, VerQueryValueW(pbFVI, wszQueryString, (LPVOID *)&pwszName, &cb)); if (FAILED(hr)) continue; // see if the string contains the words 'Microsoft® Windows®' if (MyStrStrIW(pwszName, L"Microsoft® Windows®") != NULL) { dwRet |= APP_WINCOMP; break; } // ok, didn't match the words 'Microsoft® Windows®', so instead, see if // it matches the string in kernel32.dll TESTBOOL(hr, VerQueryValueW(pbFVIK32, wszQueryString, (LPVOID *)&pwszNameK32, &cb)); if (FAILED(hr)) continue; if (CompareStringW(MAKELCID(plc[i].wLanguage, SORT_DEFAULT), NORM_IGNORECASE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH | SORT_STRINGSORT, pwszName, -1, pwszNameK32, -1) == CSTR_EQUAL) { dwRet |= APP_WINCOMP; break; } } hr = S_FALSE; done: return dwRet; }