//======================================================================= // // Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved. // // File: fileutil.cpp // // Description: // // IU file utility library // //======================================================================= #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mistsafe.h" #include "wusafefn.h" const TCHAR REGKEY_WINDOWSUPDATE[] = _T("\\WindowsUpdate\\"); const TCHAR REGKEY_INDUSTRYUPDATE[] = _T("\\WindowsUpdate\\V4\\"); const TCHAR REGKEY_WINCURDIR[] = _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"); const TCHAR REGKEY_PROGFILES[] = _T(":\\Program Files"); const TCHAR REGKEY_PROGFILESDIR[] = _T("ProgramFilesDir"); const TCHAR REGKEY_IUCTL[] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\IUControl"); const TCHAR REGVAL_ISBETA[] = _T("IsBeta"); const TCHAR IDENT_IUSERVERCACHE[] = _T("IUServerCache"); const TCHAR IDENT_DEFAULTQUERYSERVERINDEX[] = _T("DefaultQueryServerIndex"); const TCHAR IDENT_BETAQUERYSERVERINDEX[] = _T("BetaQueryServerIndex"); const TCHAR IDENT_QUERYSERVERINDEX[] = _T("QueryServerIndex"); #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) #define IfNullReturnNull(ptr) if (NULL == ptr) return NULL; #define InitString(lpStr) if (NULL != lpStr) lpStr[0] = TCHAR_EOS typedef BOOL (WINAPI * PFN_GetDiskFreeSpaceEx) ( LPCTSTR lpDirectoryName, // directory name PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk ); //--------------------------------------------------------------------- // CreateNestedDirectory // Creates the full path of the directory (nested directories) //--------------------------------------------------------------------- #pragma warning( disable : 4706 ) // Ignore warning C4706: assignment within conditional expression BOOL CreateNestedDirectory(LPCTSTR pszDir) { BOOL bRc; TCHAR szPath[MAX_PATH]; HRESULT hr=S_OK; if (NULL == pszDir || MAX_PATH < (lstrlen(pszDir) + 1)) { return FALSE; } // // make a local copy and remove final slash // hr=StringCchCopyEx(szPath,ARRAYSIZE(szPath),pszDir,NULL,NULL,MISTSAFE_STRING_FLAGS); if(FAILED(hr)) { SetLastError(HRESULT_CODE(hr)); return FALSE; } int iLast = lstrlen(szPath) - 1; if (0 > iLast) // Prefix iLast = 0; if (szPath[iLast] == '\\') szPath[iLast] = 0; // // check to see if directory already exists // DWORD dwAttr = GetFileAttributes(szPath); if (dwAttr != 0xFFFFFFFF) { if ((dwAttr & FILE_ATTRIBUTE_DIRECTORY) != 0) return TRUE; } // // create it // TCHAR* p = szPath; if (p[1] == ':') p += 2; else { // Check if the path is a UNC, need to skip past the UNC Server\Share specification to get to // real path if (p[0] == '\\' && p[1] == '\\') { p += 2; // skip to the beginning of the share declaration p = _tcschr(p, '\\'); if (NULL == p) { return FALSE; // invalid UNC } p++; // look for a trailing '\', if it exists then we want to further check for any nested levels, // otherwise the path as is should be valid. p = _tcschr(p, '\\'); if (NULL == p) { // UNC is valid base share name, assume its valid return TRUE; } else { // look for any further levels, if they exist then pass through to the rest of the directory // creator p++; if (NULL == p) { // UNC is valid base share name, but had a trailing slash, not a problem, assume its valid return TRUE; } // if we haven't exited then there are remaining levels, don't reset our current pointer in the string // and let the rest of the nested directory creation work. } } } if (*p == '\\') p++; while (p = _tcschr(p, '\\')) // Ignore warning C4706: assignment within conditional expression { *p = 0; bRc = CreateDirectory(szPath, NULL); *p = '\\'; p++; if (!bRc) { if (GetLastError() != ERROR_ALREADY_EXISTS) { return FALSE; } } } bRc = CreateDirectory(szPath, NULL); if ( !bRc ) { if (GetLastError() != ERROR_ALREADY_EXISTS) { return FALSE; } } return TRUE; } #pragma warning( default : 4706 ) //----------------------------------------------------------------------------------- // GetIndustryUpdateDirectory // This function returns the location of the IndustryUpdate directory. All local // files are stored in this directory. The pszPath parameter needs to be at least // MAX_PATH. //----------------------------------------------------------------------------------- void GetIndustryUpdateDirectory(LPTSTR pszPath) { /* HRESULT hr=S_OK; LOG_Block("GetIndustryUpdateDirectory"); if (NULL == pszPath) { LOG_ErrorMsg(E_INVALIDARG); return; } static TCHAR szCachePath[MAX_PATH] = {'\0'}; if (szCachePath[0] == '\0') { HKEY hkey; pszPath[0] = '\0'; if (RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY_WINCURDIR, &hkey) == ERROR_SUCCESS) { DWORD cbPath = MAX_PATH * sizeof(TCHAR); RegQueryValueEx(hkey, REGKEY_PROGFILESDIR, NULL, NULL, (LPBYTE)pszPath, &cbPath); RegCloseKey(hkey); } if (pszPath[0] == '\0') { TCHAR szWinDir[MAX_PATH]; if (! GetWindowsDirectory(szWinDir, ARRAYSIZE(szWinDir))) { //if GetWinDir fails, assume C: CleanUpIfFailedAndSetHrMsg(StringCchCopyEx(szWinDir,ARRAYSIZE(szWinDir),_T("C"),NULL,NULL,MISTSAFE_STRING_FLAGS)); } pszPath[0] = szWinDir[0]; pszPath[1] = '\0'; //It is assumed that the pszPath will be of the size MAX_PATH CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszPath,MAX_PATH,REGKEY_PROGFILES,NULL,NULL,MISTSAFE_STRING_FLAGS)); } CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszPath,MAX_PATH,REGKEY_INDUSTRYUPDATE,NULL,NULL,MISTSAFE_STRING_FLAGS)); CreateNestedDirectory(pszPath); // // save it in the cache (lstrcpy -> lstrcpyn to shut Prefix up, although this // would always be safe given the constants used). // lstrcpyn(szCachePath, pszPath, MAX_PATH); } else { //It is assumed that the pszPath will be of the size MAX_PATH CleanUpIfFailedAndSetHrMsg(StringCchCopyEx(pszPath,MAX_PATH,szCachePath,NULL,NULL,MISTSAFE_STRING_FLAGS)); } CleanUp: return; */ (void) GetWUDirectory(pszPath, MAX_PATH, TRUE); } //----------------------------------------------------------------------------------- // GetWindowsUpdateV3Directory - used for V3 history migration // This function returns the location of the WindowsUpdate(V3) directory. All V3 // local files are stored in this directory. The pszPath parameter needs to be // at least MAX_PATH. The directory is created if not found //----------------------------------------------------------------------------------- void GetWindowsUpdateV3Directory(LPTSTR pszPath) { LOG_Block("GetWindowsUpdateV3Directory"); HRESULT hr=S_OK; if (NULL == pszPath) { LOG_ErrorMsg(E_INVALIDARG); return; } static TCHAR szWUCachePath[MAX_PATH] = {'\0'}; if (szWUCachePath[0] == '\0') { HKEY hkey; pszPath[0] = '\0'; if (RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY_WINCURDIR, &hkey) == ERROR_SUCCESS) { DWORD cbPath = MAX_PATH * sizeof(TCHAR); RegQueryValueEx(hkey, REGKEY_PROGFILESDIR, NULL, NULL, (LPBYTE)pszPath, &cbPath); RegCloseKey(hkey); } if (pszPath[0] == '\0') { TCHAR szWinDir[MAX_PATH]; if (! GetWindowsDirectory(szWinDir, ARRAYSIZE(szWinDir))) { //if GetWinDir fails, assume C: CleanUpIfFailedAndSetHrMsg(StringCchCopyEx(szWinDir,ARRAYSIZE(szWinDir),_T("C"),NULL,NULL,MISTSAFE_STRING_FLAGS)); } pszPath[0] = szWinDir[0]; pszPath[1] = '\0'; CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszPath,MAX_PATH,REGKEY_PROGFILES,NULL,NULL,MISTSAFE_STRING_FLAGS)); } CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszPath,MAX_PATH,REGKEY_WINDOWSUPDATE,NULL,NULL,MISTSAFE_STRING_FLAGS)); CreateNestedDirectory(pszPath); // // save it in the cache (lstrcpy -> lstrcpyn to shut Prefix up, although this // would always be safe given the constants used). // lstrcpyn(szWUCachePath, pszPath, MAX_PATH); } else { CleanUpIfFailedAndSetHrMsg(StringCchCopyEx(pszPath,MAX_PATH,szWUCachePath,NULL,NULL,MISTSAFE_STRING_FLAGS)); } CleanUp: return; } // ---------------------------------------------------------------------- // // Public function MySplitPath() - same as CRT _tsplitpath() // to break a path into pieces // // Input: // see below // // Return: // Returns the address of the last occurrence of the character in // the string if successful, or NULL otherwise. // // Algorithm: // C:\mydir\...\mysubdir\myfile.ext // _________| _________| |____ // | | | // start of dir start of filename start of extension // // ---------------------------------------------------------------------- void MySplitPath( LPCTSTR lpcszPath, // original path LPTSTR lpszDrive, // point to buffer to receive drive letter LPTSTR lpszDir, // point to buffer to receive directory LPTSTR lpszFName, // point to buffer to receive file name LPTSTR lpszExt // point to buffer to receive extension ) { LPCTSTR lpFirstSlash, lpLastSlash, lpPeriod; LPCTSTR lpStart = lpcszPath; int nPathLen = lstrlen(lpcszPath); int nExtLen; // // initialize pass in vars // InitString(lpszDrive); InitString(lpszDir); InitString(lpszFName); InitString(lpszExt); if (0 == nPathLen || TCHAR_DOT == lpcszPath[0]) { // // not a valid path // return; } lpFirstSlash = MyStrChr(lpcszPath, TCHAR_BACKSLASH); lpLastSlash = MyStrRChr(lpcszPath, NULL, TCHAR_BACKSLASH); lpPeriod = MyStrRChr(lpcszPath, NULL, TCHAR_DOT); nExtLen = lstrlen(lpPeriod); if (NULL != lpPeriod && NULL != lpszExt) { // // found a period from right, and // we have buffer to output extension // if(FAILED(StringCchCopyEx(lpszExt,nExtLen+1,lpPeriod,NULL,NULL,MISTSAFE_STRING_FLAGS))) return; } // // process drive // if (nPathLen > 2 && TCHAR_COLON == lpcszPath[1]) { lpStart = lpcszPath + 2; if (NULL != lpszDir) { lstrcpyn(lpszDrive, lpcszPath, 3); } } if (NULL == lpFirstSlash) { // // no backslash, assume this is file name only // if (NULL != lpszFName) { lstrcpyn(lpszFName, lpStart, lstrlen(lpStart) - nExtLen + 1); } } else { // // find directory if not empty // //if (lpLastSlash != lpFirstSlash && NULL != lpszDir) if (NULL != lpszDir) { lstrcpyn(lpszDir, lpFirstSlash, (int)(lpLastSlash - lpFirstSlash + 2)); } // // find file name // if (NULL != lpszFName) { lstrcpyn(lpszFName, lpLastSlash + 1, lstrlen(lpLastSlash) - nExtLen ); } } } // ********************************************************************************** // // File version related declarations // // ********************************************************************************** // ---------------------------------------------------------------------------------- // // public function to retrieve file version // // ---------------------------------------------------------------------------------- BOOL GetFileVersion(LPCTSTR lpsFile, LPFILE_VERSION lpstVersion) { LOG_Block("GetFileVersion()"); DWORD dwVerInfoSize; DWORD dwHandle; DWORD dwVerNumber; LPVOID lpBuffer = NULL; UINT uiSize = 0; VS_FIXEDFILEINFO* lpVSFixedFileInfo; USES_MY_MEMORY; if (NULL != lpstVersion) { // // if this pointer not null, we always try to initialize // this structure to 0, in order to reduce the change of // programming error, no matter the file exists or not. // ZeroMemory(lpstVersion, sizeof(FILE_VERSION)); } if (NULL == lpsFile || NULL == lpstVersion) { LOG_ErrorMsg(E_INVALIDARG); return FALSE; } // // 506212 IU - FRE log reports incorrect version data for iuengine.dll // if (FALSE == FileExists(lpsFile)) { // // GetFileVersionInfoSize() returns 0 but sets last error to 0 (or // doesn't set) if file doesn't exist on Win2K. // LOG_Out(_T("File \"%s\" doesn't exist, returning FALSE"), lpsFile); return FALSE; } dwVerInfoSize = GetFileVersionInfoSize((LPTSTR)lpsFile, &dwHandle); if (0 == dwVerInfoSize) { DWORD dwErr = GetLastError(); if (0 == dwErr) { LOG_Error(_T("File %s does not have version data. Use 0.0.0.0"), lpsFile); lpstVersion->Major = 0x0; lpstVersion->Minor = 0x0; lpstVersion->Build = 0x0; lpstVersion->Ext = 0x0; return TRUE; } else { LOG_ErrorMsg(dwErr); return FALSE; } } if (NULL == (lpBuffer = (LPVOID) MemAlloc(dwVerInfoSize))) { LOG_Error(_T("Failed to allocate memory to get version info")); return FALSE; } if (!GetFileVersionInfo((LPTSTR)lpsFile, dwHandle, dwVerInfoSize, lpBuffer)) { LOG_ErrorMsg(GetLastError()); return FALSE; } // // Get the value for Translation // if (!VerQueryValue(lpBuffer, _T("\\"), (LPVOID*)&lpVSFixedFileInfo, &uiSize) && (uiSize) && NULL != lpVSFixedFileInfo) { LOG_ErrorMsg(GetLastError()); return FALSE; } dwVerNumber = lpVSFixedFileInfo->dwFileVersionMS; lpstVersion->Major = HIWORD(dwVerNumber); lpstVersion->Minor = LOWORD(dwVerNumber); dwVerNumber = lpVSFixedFileInfo->dwFileVersionLS; lpstVersion->Build = HIWORD(dwVerNumber); lpstVersion->Ext = LOWORD(dwVerNumber); LOG_Out(_T("File %s found version %d.%d.%d.%d"), lpsFile, lpstVersion->Major, lpstVersion->Minor, lpstVersion->Build, lpstVersion->Ext); return TRUE; } // ---------------------------------------------------------------------------------- // // public functions to compare file versions // // return: // -1: if file ver of 1st parameter < file ver of 2nd parameter // 0: if file ver of 1st parameter = file ver of 2nd parameter // +1: if file ver of 1st parameter > file ver of 2nd parameter // // ---------------------------------------------------------------------------------- int CompareFileVersion(const FILE_VERSION stVersion1, const FILE_VERSION stVersion2) { if ((short)stVersion1.Major < 0 || (short)stVersion2.Major < 0) { // // two empty version structure to compare, we call it equal // return 0; } if (stVersion1.Major != stVersion2.Major) { // // major diff, then we know the answer // return (stVersion1.Major < stVersion2.Major) ? -1 : 1; } else { if ((short)stVersion1.Minor < 0 || (short)stVersion2.Minor < 0) { // // if any minor missing, they equal // return 0; } if (stVersion1.Minor != stVersion2.Minor) { // // minor diff, then we know the answer // return (stVersion1.Minor < stVersion2.Minor) ? -1 : 1; } else { if ((short)stVersion1.Build < 0 || (short)stVersion2.Build < 0) { // // if any build is missing, they equal // return 0; } if (stVersion1.Build != stVersion2.Build) { // // if build diff then we are done // return (stVersion1.Build < stVersion2.Build) ? -1 : 1; } else { if ((short)stVersion1.Ext < 0 || (short)stVersion2.Ext < 0 || stVersion1.Ext == stVersion2.Ext) { // // if any ext is missing, or they equal, we are done // return 0; } else { return (stVersion1.Ext < stVersion2.Ext) ? -1 : 1; } } } } } HRESULT CompareFileVersion(LPCTSTR lpsFile1, LPCTSTR lpsFile2, int *pCompareResult) { LOG_Block("CompareFileVersion(File, File)"); FILE_VERSION stVer1 = {-1,-1,-1,-1}, stVer2 = {-1,-1,-1,-1}; if (NULL == lpsFile1 || NULL == lpsFile2) { LOG_ErrorMsg(E_INVALIDARG); return E_INVALIDARG; } if (!GetFileVersion(lpsFile1, &stVer1)) { return E_INVALIDARG; } if (!GetFileVersion(lpsFile2, &stVer2)) { return E_INVALIDARG; } *pCompareResult = CompareFileVersion(stVer1, stVer2); return S_OK; } HRESULT CompareFileVersion(LPCTSTR lpsFile, FILE_VERSION stVersion, int *pCompareResult) { LOG_Block("CompareFileVersion(FILE, VER)"); FILE_VERSION stVer = {0}; if (NULL == lpsFile) { LOG_Error(_T("NULL file pointer passed in. Function returns 0")); return E_INVALIDARG; } if (!GetFileVersion(lpsFile, &stVer)) { return E_INVALIDARG; } *pCompareResult = CompareFileVersion(stVer, stVersion); return S_OK; } // ---------------------------------------------------------------------------------- // // publif function to convert a string type functoin to FILE_VERSION type // // ---------------------------------------------------------------------------------- BOOL ConvertStringVerToFileVer(LPCSTR lpsVer, LPFILE_VERSION lpstVer) { LOG_Block("ConvertStringVerToFileVer()"); WORD n = -1; char c; BOOL fHasNumber = FALSE; #if defined(DBG) // full logging for checked builds USES_IU_CONVERSION; #endif if (NULL == lpsVer || NULL == lpstVer) { LOG_ErrorMsg(E_INVALIDARG); return FALSE; } #if defined(DBG) // full logging for checked builds LOG_Out(_T("String version = %s"), A2T(const_cast(lpsVer))); #endif lpstVer->Major = lpstVer->Minor = lpstVer->Build = lpstVer->Ext = -1; c = *lpsVer; // // get first number // n = 0; while (c != '\0' && '0' <= c && c <= '9') { n = n * 10 + (int)(c - '0'); c = *++lpsVer; fHasNumber = TRUE; } if (fHasNumber) { lpstVer->Major = n; } else { return TRUE; } // // skip delimiter // while (c != '\0' && ('0' > c || c > '9')) { c = *++lpsVer; } // // get 2nd number // n = 0; fHasNumber = FALSE; while (c != '\0' && '0' <= c && c <= '9') { n = n * 10 + (int)(c - '0'); c = *++lpsVer; fHasNumber = TRUE; } if (fHasNumber) { lpstVer->Minor = n; } else { return TRUE; } // // skip delimiter // while (c != '\0' && ('0' > c || c > '9')) { c = *++lpsVer; } // // get 3rd number // n = 0; fHasNumber = FALSE; while (c != '\0' && '0' <= c && c <= '9') { n = n * 10 + (int)(c - '0'); c = *++lpsVer; fHasNumber = TRUE; } if (fHasNumber) { lpstVer->Build = n; } else { return TRUE; } // // skip delimiter // while (c != '\0' && ('0' > c || c > '9')) { c = *++lpsVer; } // // get 4th number // n = 0; fHasNumber = FALSE; while (c != '\0' && '0' <= c && c <= '9') { n = n * 10 + (int)(c - '0'); c = *++lpsVer; fHasNumber = TRUE; } if (fHasNumber) { lpstVer->Ext = n; } return TRUE; } // ---------------------------------------------------------------------------------- // // publif function to convert a FILE_VERSION to a string // // ---------------------------------------------------------------------------------- BOOL ConvertFileVerToStringVer( FILE_VERSION stVer, // version to convert char chDel, // delimiter to use LPSTR lpsBuffer, // buffer of string int ccBufSize // size of buffer ) { // // declare max buffer that wsprintf can use // char szBuf[1024]; HRESULT hr=S_OK; hr=StringCchPrintfExA( szBuf,ARRAYSIZE(szBuf), NULL,NULL,MISTSAFE_STRING_FLAGS, "%d%c%d%c%d%c", stVer.Major, chDel, stVer.Minor, chDel, stVer.Build, chDel, stVer.Ext, chDel ); if(FAILED(hr)) { goto ErrorExit; } hr=StringCchCopyExA(lpsBuffer,ccBufSize,szBuf,NULL,NULL,MISTSAFE_STRING_FLAGS); if(FAILED(hr)) { goto ErrorExit; } return TRUE; ErrorExit: lpsBuffer[0] = '\0'; return FALSE; } // ---------------------------------------------------------------------------------- // // public function to check if a file exists // // ---------------------------------------------------------------------------------- BOOL FileExists( LPCTSTR lpsFile // file with path to check ) { LOG_Block("FileExists"); DWORD dwAttr; BOOL rc; if (NULL == lpsFile || _T('\0') == *lpsFile) { LOG_ErrorMsg(E_INVALIDARG); return FALSE; } dwAttr = GetFileAttributes(lpsFile); if (-1 == dwAttr) { LOG_InfoMsg(GetLastError()); rc = FALSE; } else { rc = (0x0 == (FILE_ATTRIBUTE_DIRECTORY & dwAttr)); } return rc; } // ---------------------------------------------------------------------------------- // // publif function to retrieve the creation time of a file in ISO 8601 format // without zone info // // if buffer too small, call GetLastError(); // // ---------------------------------------------------------------------------------- BOOL GetFileTimeStamp(LPCTSTR lpsFile, LPTSTR lpsTimeStamp, int iBufSize) { BOOL fRet = FALSE; HANDLE hFile; SYSTEMTIME tm; WIN32_FILE_ATTRIBUTE_DATA fileData; HRESULT hr=S_OK; if (0 != GetFileAttributesEx(lpsFile, GetFileExInfoStandard, &fileData) && 0 != FileTimeToSystemTime((const FILETIME*)&(fileData.ftCreationTime), &tm)) { // // the output of this systemtime, according to ISA 8601 format, will be // like yyyy-mm-ddThh:mm:ss format, so it is 20 chars incl terminator // if (iBufSize < 20) { SetLastError(ERROR_BUFFER_OVERFLOW); return fRet; } hr=StringCchPrintfEx(lpsTimeStamp,iBufSize,NULL,NULL,MISTSAFE_STRING_FLAGS, _T("%4d-%02d-%02dT%02d:%02d:%02d"), tm.wYear, tm.wMonth, tm.wDay, tm.wHour, tm.wMinute, tm.wSecond); if(FAILED(hr)) { fRet=FALSE; SetLastError(HRESULT_CODE(hr)); } else fRet = TRUE; } return fRet; } // ---------------------------------------------------------------------------------- // // publif function to find the free disk space in KB // // // ---------------------------------------------------------------------------------- HRESULT GetFreeDiskSpace(TCHAR tcDriveLetter, int *piKBytes) { HRESULT hr = E_INVALIDARG; BOOL fResult; TCHAR szDrive[4]; if (!(_T('A') <= tcDriveLetter && tcDriveLetter <= _T('Z') || _T('a') <= tcDriveLetter && tcDriveLetter <= _T('z'))) { return hr; } hr=StringCchPrintfEx(szDrive,ARRAYSIZE(szDrive),NULL,NULL,MISTSAFE_STRING_FLAGS,_T("%c:\\"), tcDriveLetter); if(FAILED(hr)) return hr; PFN_GetDiskFreeSpaceEx pGetDiskFreeSpaceEx = (PFN_GetDiskFreeSpaceEx) GetProcAddress( GetModuleHandle(_T("kernel32.dll")), #ifdef UNICODE "GetDiskFreeSpaceExW"); #else "GetDiskFreeSpaceExA"); #endif if (pGetDiskFreeSpaceEx) { LARGE_INTEGER i64FreeBytesToCaller, i64TotalBytes; fResult = pGetDiskFreeSpaceEx (szDrive, (PULARGE_INTEGER)&i64FreeBytesToCaller, (PULARGE_INTEGER)&i64TotalBytes, (PULARGE_INTEGER)NULL); *piKBytes = (int) (i64FreeBytesToCaller.QuadPart / 1024); } else { DWORD dwSectPerClust = 0x0, dwBytesPerSect = 0x0, dwFreeClusters = 0x0, dwTotalClusters = 0x0; fResult = GetDiskFreeSpace (szDrive, &dwSectPerClust, &dwBytesPerSect, &dwFreeClusters, &dwTotalClusters); *piKBytes = (int) ((float)(((int)dwFreeClusters) * ((int)dwSectPerClust)) / 1024.0 * (int)dwBytesPerSect); } return (fResult) ? S_OK : HRESULT_FROM_WIN32(GetLastError()); } HRESULT GetFreeDiskSpace(LPCTSTR pszUNC, int *piKBytes) { HRESULT hr = E_INVALIDARG; BOOL fResult; PFN_GetDiskFreeSpaceEx pGetDiskFreeSpaceEx = (PFN_GetDiskFreeSpaceEx) GetProcAddress( GetModuleHandle(_T("kernel32.dll")), #ifdef UNICODE "GetDiskFreeSpaceExW"); #else "GetDiskFreeSpaceExA"); #endif if (pGetDiskFreeSpaceEx) { LARGE_INTEGER i64FreeBytesToCaller, i64TotalBytes; fResult = pGetDiskFreeSpaceEx (pszUNC, (PULARGE_INTEGER)&i64FreeBytesToCaller, (PULARGE_INTEGER)&i64TotalBytes, (PULARGE_INTEGER)NULL); *piKBytes = (int) (i64FreeBytesToCaller.QuadPart / 1024); } else { DWORD dwSectPerClust = 0x0, dwBytesPerSect = 0x0, dwFreeClusters = 0x0, dwTotalClusters = 0x0; fResult = GetDiskFreeSpace (pszUNC, &dwSectPerClust, &dwBytesPerSect, &dwFreeClusters, &dwTotalClusters); *piKBytes = (int) ((float)(((int)dwFreeClusters) * ((int)dwSectPerClust)) / 1024.0 * (int)dwBytesPerSect); } return (fResult) ? S_OK : HRESULT_FROM_WIN32(GetLastError()); } // ---------------------------------------------------------------------------------- // // publif function to expand the file path // // Assumption: lpszFilePath points to allocated buffer of MAX_PATH. // if the expanded path is longer than MAX_PATH, error returned. // // ---------------------------------------------------------------------------------- HRESULT ExpandFilePath(LPCTSTR lpszFilePath, LPTSTR lpszDestination, UINT cChars) { HRESULT hr = S_OK; LPTSTR lpEnvExpanded; LPTSTR lp2ndPercentChar = NULL; LPTSTR lpSearchStart; USES_MY_MEMORY; if (NULL == (lpEnvExpanded = (LPTSTR) MemAlloc((cChars + 1) * sizeof(TCHAR)))) { return E_OUTOFMEMORY; } // // first, let's substitute the system defined variables // if (0 == ExpandEnvironmentStrings(lpszFilePath, lpEnvExpanded, cChars)) { hr = HRESULT_FROM_WIN32(GetLastError()); } // // then handle pre-defined variables that we need to recognize // these include all CSIDL definitions inside shlobj.h for SHGetFolderPath() API // const int C_NAME_LEN = 32; struct _CSIDL_NAME { long CSIDL_Id; TCHAR CSIDL_Str[C_NAME_LEN]; }; const _CSIDL_NAME C_CSIDL_NAMES[] = { {CSIDL_ADMINTOOLS , _T("CSIDL_ADMINTOOLS")}, {CSIDL_ALTSTARTUP , _T("CSIDL_ALTSTARTUP")}, {CSIDL_APPDATA , _T("CSIDL_APPDATA")}, {CSIDL_BITBUCKET , _T("CSIDL_BITBUCKET")}, {CSIDL_COMMON_ADMINTOOLS , _T("CSIDL_COMMON_ADMINTOOLS")}, {CSIDL_COMMON_ALTSTARTUP , _T("CSIDL_COMMON_ALTSTARTUP")}, {CSIDL_COMMON_APPDATA , _T("CSIDL_COMMON_APPDATA")}, {CSIDL_COMMON_DESKTOPDIRECTORY , _T("CSIDL_COMMON_DESKTOPDIRECTORY")}, {CSIDL_COMMON_DOCUMENTS , _T("CSIDL_COMMON_DOCUMENTS")}, {CSIDL_COMMON_FAVORITES , _T("CSIDL_COMMON_FAVORITES")}, {CSIDL_COMMON_PROGRAMS , _T("CSIDL_COMMON_PROGRAMS")}, {CSIDL_COMMON_STARTMENU , _T("CSIDL_COMMON_STARTMENU")}, {CSIDL_COMMON_STARTUP , _T("CSIDL_COMMON_STARTUP")}, {CSIDL_COMMON_TEMPLATES , _T("CSIDL_COMMON_TEMPLATES")}, {CSIDL_CONTROLS , _T("CSIDL_CONTROLS")}, {CSIDL_COOKIES , _T("CSIDL_COOKIES")}, {CSIDL_DESKTOP , _T("CSIDL_DESKTOP")}, {CSIDL_DESKTOPDIRECTORY , _T("CSIDL_DESKTOPDIRECTORY")}, {CSIDL_DRIVES , _T("CSIDL_DRIVES")}, {CSIDL_FAVORITES , _T("CSIDL_FAVORITES")}, {CSIDL_FONTS , _T("CSIDL_FONTS")}, {CSIDL_HISTORY , _T("CSIDL_HISTORY")}, {CSIDL_INTERNET , _T("CSIDL_INTERNET")}, {CSIDL_INTERNET_CACHE , _T("CSIDL_INTERNET_CACHE")}, {CSIDL_LOCAL_APPDATA , _T("CSIDL_LOCAL_APPDATA")}, {CSIDL_MYPICTURES , _T("CSIDL_MYPICTURES")}, {CSIDL_NETHOOD , _T("CSIDL_NETHOOD")}, {CSIDL_NETWORK , _T("CSIDL_NETWORK")}, {CSIDL_PERSONAL , _T("CSIDL_PERSONAL")}, {CSIDL_PRINTERS , _T("CSIDL_PRINTERS")}, {CSIDL_PRINTHOOD , _T("CSIDL_PRINTHOOD")}, {CSIDL_PROFILE , _T("CSIDL_PROFILE")}, {CSIDL_PROGRAM_FILES , _T("CSIDL_PROGRAM_FILES")}, {CSIDL_PROGRAM_FILES_COMMON , _T("CSIDL_PROGRAM_FILES_COMMON")}, {CSIDL_PROGRAMS , _T("CSIDL_PROGRAMS")}, {CSIDL_RECENT , _T("CSIDL_RECENT")}, {CSIDL_SENDTO , _T("CSIDL_SENDTO")}, {CSIDL_STARTMENU , _T("CSIDL_STARTMENU")}, {CSIDL_STARTUP , _T("CSIDL_STARTUP")}, {CSIDL_SYSTEM , _T("CSIDL_SYSTEM")}, {CSIDL_TEMPLATES , _T("CSIDL_TEMPLATES")}, {CSIDL_WINDOWS , _T("CSIDL_WINDOWS")} }; // // see if this path has any of these variables // lpSearchStart = lpEnvExpanded + 1; if (SUCCEEDED(hr) && _T('%') == *lpEnvExpanded && NULL != (lp2ndPercentChar = StrChr(lpSearchStart, _T('%')))) { // // copy the variable name to passed in buffer // lstrcpyn(lpszDestination, lpSearchStart, (int)(lp2ndPercentChar - lpSearchStart + 1)); // skip the 1st % char lp2ndPercentChar++; // move to begining of rest of path // // find out what this variable is // for (int i = 0; i < sizeof(C_CSIDL_NAMES)/sizeof(C_CSIDL_NAMES[0]); i++) { if (lstrcmpi(lpszDestination, C_CSIDL_NAMES[i].CSIDL_Str) == 0) { // // found the matching variable! // if (S_OK == (hr = SHGetFolderPath(NULL, C_CSIDL_NAMES[i].CSIDL_Id, NULL, SHGFP_TYPE_CURRENT, lpszDestination))) { // // ensure buffer big enough // if (lstrlen(lp2ndPercentChar) + lstrlen(lpszDestination) + sizeof(TCHAR) >= cChars) { hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW); } // // append the rest of them - shouldn't be any of // these variables in the rest of string, since this // kind variable alaways starts at the beginning of // a path // if(SUCCEEDED(hr)) hr=PathCchAppend(lpszDestination,MAX_PATH,lp2ndPercentChar); if (SUCCEEDED(hr)) { return hr; } } // // we found the matching variable, but couldn't get the // string replaced. // break; } } // // didn't find it. // } // // didn't find it, or failed. // if (FAILED(hr)) { *lpszDestination = _T('\0'); } else { lstrcpyn(lpszDestination, lpEnvExpanded, cChars); } return hr; } //---------------------------------------------------------------------- // // function to validate the folder to make sure // user has required priviledge // // folder will be verified exist. then required priviledge will be checked. // // ASSUMPTION: lpszFolder not exceeding MAX_PATH long!!! // //---------------------------------------------------------------------- DWORD ValidateFolder(LPTSTR lpszFolder, BOOL fCheckForWrite) { LOG_Block("ValidateFolder"); DWORD dwErr = ERROR_SUCCESS; HRESULT hr=S_OK; // // first, check if the folder exist // dwErr = GetFileAttributes(lpszFolder); if (-1 == dwErr) { dwErr = GetLastError(); LOG_ErrorMsg(dwErr); return dwErr; } // // make sure it's a directory // if ((FILE_ATTRIBUTE_DIRECTORY & dwErr) == 0) { dwErr = ERROR_PATH_NOT_FOUND; LOG_ErrorMsg(dwErr); return dwErr; } if (fCheckForWrite) { TCHAR szFile[MAX_PATH], szFileName[40]; SYSTEMTIME tm; HANDLE hFile; // // create a random file name // hr=StringCchCopyEx(szFile,ARRAYSIZE(szFile),lpszFolder,NULL,NULL,MISTSAFE_STRING_FLAGS); if(FAILED(hr)) { dwErr = HRESULT_CODE(hr);; LOG_ErrorMsg(dwErr); return dwErr; } GetLocalTime(&tm); hr=StringCchPrintfEx( szFileName, ARRAYSIZE(szFileName), NULL,NULL,MISTSAFE_STRING_FLAGS, _T("%08x%08x%02hd%02hd%02hd%02hd%02hd%03hd%08x"), GetCurrentProcessId(), GetCurrentThreadId(), tm.wMonth, tm.wDay, tm.wHour, tm.wMinute, tm.wSecond, tm.wMilliseconds, GetTickCount()); if(FAILED(hr)) { dwErr = HRESULT_CODE(hr);; LOG_ErrorMsg(dwErr); return dwErr; } hr=PathCchAppend(szFile,ARRAYSIZE(szFile),szFileName); if(FAILED(hr)) { dwErr = HRESULT_CODE(hr);; LOG_ErrorMsg(dwErr); return dwErr; } // // try to write file // hFile = CreateFile(szFile, GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); if (INVALID_HANDLE_VALUE == hFile) { dwErr = GetLastError(); LOG_ErrorMsg(dwErr); return dwErr; } CloseHandle(hFile); } return ERROR_SUCCESS; } //---------------------------------------------------------------------- // // function to get a QueryServer from the Ident File for a Given ClientName // This also looks in the registry for the IsBeta regkey indicating Beta // functionlality // // Returns: // S_OK : we successfully got QueryServer for this Client // S_FALSE : we did NOT find a QueryServer for this Client (pszQueryServer will be a null string) // E_INVALIDARG : parameters were incorrect //---------------------------------------------------------------------- HRESULT GetClientQueryServer(LPCTSTR pszClientName, LPTSTR pszQueryServer, UINT cChars) { HKEY hkey; BOOL fBeta = FALSE; int iIndex; TCHAR szQueryServerKeyName[128]; TCHAR szIUDir[MAX_PATH]; TCHAR szIdentFile[MAX_PATH]; DWORD dwValue = 0; DWORD dwLength = sizeof(dwValue); HRESULT hr=S_OK; LOG_Block("GetClientQueryServer"); if ((NULL == pszClientName) || (NULL == pszQueryServer) || (0 == cChars)) { LOG_ErrorMsg(E_INVALIDARG); return E_INVALIDARG; } // Check IUControl Reg Key for Beta Mode if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY_IUCTL, &hkey)) { if (ERROR_SUCCESS == RegQueryValueEx(hkey, REGVAL_ISBETA, NULL, NULL, (LPBYTE)&dwValue, &dwLength)) { if (1 == dwValue) { fBeta = TRUE; } } RegCloseKey(hkey); } GetIndustryUpdateDirectory(szIUDir); hr=PathCchCombine (szIdentFile,ARRAYSIZE(szIdentFile),szIUDir,IDENTTXT); if(FAILED(hr)) { LOG_ErrorMsg(hr); return hr; } // Form the KeyName for the QueryServer Index hr=StringCchPrintfEx(szQueryServerKeyName,ARRAYSIZE(szQueryServerKeyName),NULL,NULL,MISTSAFE_STRING_FLAGS,_T("%s%s"), pszClientName, fBeta ? IDENT_BETAQUERYSERVERINDEX : IDENT_QUERYSERVERINDEX); if(FAILED(hr)) { LOG_ErrorMsg(hr); return hr; } iIndex = GetPrivateProfileInt(IDENT_IUSERVERCACHE, szQueryServerKeyName, 0, szIdentFile); if (0 == iIndex) { iIndex = GetPrivateProfileInt(IDENT_IUSERVERCACHE, IDENT_DEFAULTQUERYSERVERINDEX, 0, szIdentFile); if (0 == iIndex) { return S_FALSE; } } // Form the KeyName for the Specified QueryServer based on the Index hr=StringCchPrintfEx(szQueryServerKeyName,ARRAYSIZE(szQueryServerKeyName),NULL,NULL,MISTSAFE_STRING_FLAGS,_T("Server%d"), iIndex); if(FAILED(hr)) { LOG_ErrorMsg(hr); return hr; } GetPrivateProfileString(IDENT_IUSERVERCACHE, szQueryServerKeyName, _T(""), pszQueryServer, cChars, szIdentFile); if ('\0' == *pszQueryServer) { return S_FALSE; } else { return S_OK; } } HRESULT DecompressFolderCabs(LPCTSTR pszDecompressPath) { HRESULT hr = S_FALSE; // default is not an Error, but if there are no cabs we return S_FALSE TCHAR szSearchInfo[MAX_PATH]; TCHAR szCabPath[MAX_PATH]; LPTSTR pszCabList = NULL; LPTSTR pszWritePosition = NULL; LONG lCabCount = 0; WIN32_FIND_DATA fd; HANDLE hFind; BOOL fMore = TRUE; BOOL fRet = TRUE; USES_IU_CONVERSION; hr=PathCchCombine (szSearchInfo,ARRAYSIZE(szSearchInfo),pszDecompressPath, _T("*.cab")); if(FAILED(hr)) { return hr; } hFind = FindFirstFile(szSearchInfo, &fd); if (hFind != INVALID_HANDLE_VALUE) { while (fMore) { if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { lCabCount++; } fMore = FindNextFile(hFind, &fd); } FindClose(hFind); pszCabList = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (MAX_PATH * sizeof(TCHAR) * lCabCount)); if (NULL == pszCabList) { hr = E_OUTOFMEMORY; return hr; } pszWritePosition = pszCabList; hFind = FindFirstFile(szSearchInfo, &fd); fMore = (INVALID_HANDLE_VALUE != hFind); DWORD dwRemLength=lCabCount*MAX_PATH; while (fMore) { if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { hr=PathCchCombine(szCabPath,ARRAYSIZE(szCabPath),pszDecompressPath, fd.cFileName); if(FAILED(hr)) { SafeHeapFree(pszCabList); return hr; } hr=StringCchCatEx(pszWritePosition,dwRemLength,szCabPath,NULL,NULL,MISTSAFE_STRING_FLAGS); if(FAILED(hr)) { SafeHeapFree(pszCabList); return hr; } dwRemLength=dwRemLength- ( lstrlen(pszWritePosition)+ 2 * (sizeof(TCHAR)) ); pszWritePosition += lstrlen(pszWritePosition) + 2 * (sizeof(TCHAR)); } fMore = FindNextFile(hFind, &fd); } FindClose(hFind); pszWritePosition = pszCabList; for (LONG lCnt = 0; lCnt < lCabCount; lCnt++) { fRet = IUExtractFiles(pszWritePosition, pszDecompressPath); if (!fRet) { break; } pszWritePosition += lstrlen(pszWritePosition) + 2 * (sizeof(TCHAR)); } SafeHeapFree(pszCabList); if (!fRet) { hr = E_FAIL; // one of the cabs had an error decompressing } else { hr = S_OK; } } return hr; } //Extracts a cab file to the specified destination. Optionally we can pass in a colon seperated list of files to extract BOOL IUExtractFiles(LPCTSTR pszCabFile, LPCTSTR pszDecompressFolder, LPCTSTR pszFileNames) { HRESULT hr = S_OK; #ifdef UNICODE char szCabFile[MAX_PATH]; char szDecompressFolder[MAX_PATH]; WideCharToMultiByte(CP_ACP, 0, pszCabFile, -1, szCabFile, sizeof(szCabFile), NULL, NULL); WideCharToMultiByte(CP_ACP, 0, pszDecompressFolder, -1, szDecompressFolder, sizeof(szDecompressFolder), NULL, NULL); char *pszFiles = NULL; if(pszFileNames != NULL) { pszFiles = (char*)malloc(lstrlen(pszFileNames)+1); if (pszFiles == NULL) { return FALSE; } WideCharToMultiByte(CP_ACP, 0, pszFileNames, -1, pszFiles, lstrlen(pszFileNames)+1, NULL, NULL); } hr = ExtractFiles(szCabFile, szDecompressFolder, 0, pszFiles, 0, 0); free(pszFiles); #else hr = ExtractFiles(pszCabFile, pszDecompressFolder, 0, pszFileNames, 0, 0); #endif return SUCCEEDED(hr); } ///////////////////////////////////////////////////////////////////////////// // // ReplaceFileExtension // ///////////////////////////////////////////////////////////////////////////// BOOL ReplaceFileExtension( LPCTSTR pszPath, LPCTSTR pszNewExt, LPTSTR pszNewPathBuf, DWORD cchNewPathBuf) { LPCTSTR psz; HRESULT hr; DWORD cchPath, cchExt, cch; if (pszPath == NULL || *pszPath == _T('\0')) return FALSE; cchPath = lstrlen(pszPath); // note that only a '>' comparison is needed since the file extension // should never start at the 1st char in the path. for (psz = pszPath + cchPath; psz > pszPath && *psz != _T('\\') && *psz != _T('.'); psz--); if (*psz == _T('\\')) psz = pszPath + cchPath; else if (psz == pszPath) return FALSE; // ok, so now psz points to the place where the new extension is going to // go. Make sure our buffer is big enough. cchPath = (DWORD)(psz - pszPath); cchExt = lstrlen(pszNewExt); if (cchPath + cchExt >= cchNewPathBuf) return FALSE; // yay. we got a big enuf buffer. hr = StringCchCopyEx(pszNewPathBuf, cchNewPathBuf, pszPath, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) return FALSE; hr = StringCchCopyEx(pszNewPathBuf + cchPath, cchNewPathBuf - cchPath, pszNewExt, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) return FALSE; return TRUE; } ///////////////////////////////////////////////////////////////////////////// // // ReplaceFileInPath // ///////////////////////////////////////////////////////////////////////////// BOOL ReplaceFileInPath(LPCTSTR pszPath, LPCTSTR pszNewFile, LPTSTR pszNewPathBuf, DWORD cchNewPathBuf) { LPCTSTR psz; HRESULT hr; DWORD cchPath, cchFile, cch; if (pszPath == NULL || *pszPath == _T('\0')) return FALSE; cchPath = lstrlen(pszPath); // note that only the '>=' comparison is safe cuz we check if pszPath is // NULL above, so there should always be at least one value < pszPath for (psz = pszPath + cchPath; psz >= pszPath && *psz != _T('\\'); psz--); // either way we break out of the loop, gotta increment the pointer to // be either the first char in the string or the first char after the // last backslash psz++; // ok, so now psz points to the place where the new filename is going to // go. Make sure our buffer is big enough. cchPath = (DWORD)(psz - pszPath); cchFile = lstrlen(pszNewFile); if (cchPath + cchFile >= cchNewPathBuf) return FALSE; // yay. we got a big enuf buffer. if (cchPath > 0) { hr = StringCchCopyEx(pszNewPathBuf, cchNewPathBuf, pszPath, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) return FALSE; } hr = StringCchCopyEx(pszNewPathBuf + cchPath, cchNewPathBuf - cchPath, pszNewFile, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) return FALSE; return TRUE; } // ---------------------------------------------------------------------------------- // // VerifyFileCRC : This function takes a File Path, calculates the hash on this file // and compares it to the passed in Hash (pCRC). // Returns: // S_OK: CRC's Match // ERROR_CRC (HRESULT_FROM_WIN32(ERROR_CRC): if the CRC's do not match // Otherwise an HRESULT Error Code // // ---------------------------------------------------------------------------------- HRESULT VerifyFileCRC(LPCTSTR pszFileToVerify, LPCTSTR pszHash) { HRESULT hr = S_OK; TCHAR szCompareCRC[CRC_HASH_STRING_LENGTH]; // Validate Parameters if ((NULL == pszFileToVerify) || (NULL == pszHash)) return E_INVALIDARG; hr = CalculateFileCRC(pszFileToVerify, szCompareCRC, ARRAYSIZE(szCompareCRC)); if (FAILED(hr)) return hr; // Now we need to Compare the Calculated CRC with the Passed in CRC if (0 == lstrcmpi(szCompareCRC, pszHash)) return S_OK; // CRC's Match else return HRESULT_FROM_WIN32(ERROR_CRC); // CRC's do not match } // ---------------------------------------------------------------------------------- // // CalculateFileCRC : This function takes a File Path, calculates a CRC from the file // converts it to a string and returns it in the supplied TCHAR buffer // // ---------------------------------------------------------------------------------- typedef BOOL (WINAPI * PFN_CryptCATAdminCalcHashFromFileHandle)(HANDLE hFile, DWORD *pcbHash, BYTE *pbHash, DWORD dwFlags); HRESULT CalculateFileCRC(LPCTSTR pszFileToHash, LPTSTR pszHash, int cchBuf) { HANDLE hFile; HRESULT hr = S_OK; DWORD cbHash = CRC_HASH_SIZE; BYTE bHashBytes[CRC_HASH_SIZE]; BYTE b; // Validate Parameters if ((NULL == pszFileToHash) || (NULL == pszHash) || (cchBuf < CRC_HASH_STRING_LENGTH)) return E_INVALIDARG; hFile = CreateFile(pszFileToHash, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE != hFile) { HMODULE hWinTrust = LoadLibraryFromSystemDir(_T("wintrust.dll")); if (NULL == hWinTrust) { hr = HRESULT_FROM_WIN32(GetLastError()); } else { PFN_CryptCATAdminCalcHashFromFileHandle fpnCryptCATAdminCalcHashFromFileHandle = NULL; fpnCryptCATAdminCalcHashFromFileHandle = (PFN_CryptCATAdminCalcHashFromFileHandle) GetProcAddress(hWinTrust, "CryptCATAdminCalcHashFromFileHandle"); if (NULL == fpnCryptCATAdminCalcHashFromFileHandle) { hr = HRESULT_FROM_WIN32(GetLastError()); } else { if (!fpnCryptCATAdminCalcHashFromFileHandle(hFile, &cbHash, bHashBytes, 0)) { hr = HRESULT_FROM_WIN32(GetLastError()); } fpnCryptCATAdminCalcHashFromFileHandle = NULL; } FreeLibrary(hWinTrust); } CloseHandle(hFile); } else { hr = HRESULT_FROM_WIN32(GetLastError()); } if (FAILED(hr)) return hr; LPTSTR p = pszHash; // Now we have the Calculated CRC of the File, we need to convert it to a String and Return it. The following // loop will go through each byte in the array and convert it to a Hex Character in the supplied TCHAR buffer for (int i = 0; i < CRC_HASH_SIZE; i++) { b = bHashBytes[i] >> 4; if (b <= 9) *p = '0' + (TCHAR)b; else *p = 'A' + (TCHAR)(b - 10); p++; b = bHashBytes[i] & 0x0F; if (b <= 9) *p = '0' + (TCHAR)b; else *p = 'A' + (TCHAR)(b - 10); p++; } *p = _T('\0'); return hr; }