/****************************************************************************\ NEWFILES.C / OPK Wizard (OPKWIZ.EXE) Microsoft Confidential Copyright (c) Microsoft Corporation 1998 All rights reserved 3/99 - Jason Cohen (JCOHEN) Added this new source file for the OPK Wizard as part of the OOBE update. 09/2000 - Stephen Lodwick (STELO) Ported OPK Wizard to Whistler \****************************************************************************/ // // Include file(s): // #include "pch.h" #include "newfiles.h" #include "resource.h" // // Internal Defined Value(s): // #define DIR_CONFIG_OOBE _T("$OEM$") #define INF_SECT_SOURCEDISK _T("SourcedisksFiles") #define INF_SECT_DESTDIRS _T("DestinationDirs") #define INF_SECT_OOBE _T("RegisterOOBE") #define INF_LINE_COPYFILES _T("CopyFiles") #define INF_PREFIX _T("X") #define SOURCENUM_OPTIONS_CAB _T("782") #define DESTLDID_OOBE _T("11") #define STR_SEARCH _T("*") #define STR_PADDING _T("\r\n\r\n") #define MAX_BUFFER 16384 // 32768 #ifndef CSTR_EQUAL #define CSTR_EQUAL 2 #endif // CSTR_EQUAL // // Internal Structure(s): // typedef struct _FILELIST { LPTSTR lpFileName; LPTSTR lpDirectory; struct _FILELIST * lpNext; } FILELIST, *PFILELIST, *LPFILELIST; // // Internal Function Prototype(s): // static void DelFiles(LPTSTR, LPTSTR, DWORD, LPTSTR, LPTSTR); static LPFILELIST AllocFileList(HWND, LPTSTR, LPTSTR); static BOOL CompareFiles(LPTSTR, LPTSTR); // // External Function(s): // ////////////////////////////////////////////////////////////////////////////// // AddFiles - lpSourceDir = location of files to copy to OOBE directory. // Destination = location of the system directory where installed to // LDID. // lpConfigDir = location of oemaudit.inf, and config files. // lpSourceDir -> OOBE -> lpDestDir // void AddFiles(HWND hwndParent, LPTSTR lpSourceDir, LPTSTR lpDestLdid, LPTSTR lpDestDir, LPTSTR lpDestName, LPTSTR lpConfigDir) { LPTSTR lpFilePart, lpFile, lpFileName, lpSectEnd, lpSearch, lpTarget, lpNext; TCHAR szBuffer[MAX_PATH + 32] = NULLSTR, szCurDir[MAX_PATH] = NULLSTR, szSourceDir[MAX_PATH] = NULLSTR, szCopyDir[MAX_PATH], szWinbom[MAX_PATH], szCopyFiles[MAX_PATH + 32]; LPFILELIST lpflHead = NULL, lpflCur, lpflBuf; BOOL bFound; DWORD dwNum; int iFilePartLen; HRESULT hrCat; HRESULT hrPrintf; // // First thing we do is setup the directories and strings // that we need to do all the work. // // We need the path to the config directory. Copydir is where // the files are going to be copied to from the SourceDir // so it needs to be cleaned out before we do the CopyFile. // CopyDir will be created if not exists. // lstrcpyn(szCopyDir, lpConfigDir, AS(szCopyDir)); AddPathN(szCopyDir, DIR_CONFIG_OOBE,AS(szCopyDir)); AddPathN(szCopyDir, _T("\\"),AS(szCopyDir)); lpFilePart = szCopyDir + lstrlen(szCopyDir); iFilePartLen= AS(szCopyDir)-lstrlen(szCopyDir); // Need a full path to the oemaudit inf. // lstrcpyn(szWinbom, lpConfigDir,AS(szWinbom)); AddPathN(szWinbom, FILE_WINBOM_INI,AS(szWinbom)); // We need to construct the prefix to the copy // files section name. // lstrcpyn(szCopyFiles, INF_PREFIX,AS(szCopyFiles)); hrCat=StringCchCat(szCopyFiles, AS(szCopyFiles), lpDestLdid ? lpDestLdid : DESTLDID_OOBE); if ( lpDestDir && *lpDestDir ) hrCat=StringCchCat(szCopyFiles, AS(szCopyFiles), lpDestDir); StrRem(szCopyFiles, CHR_BACKSLASH); lpSectEnd = szCopyFiles + lstrlen(szCopyFiles); // // Now that we have that info, we need to get rid of any files that // may have already been put in the inf and the destination directory. // // Cleaned out of the inf and destination directory only if we are // passed in NULL for the source. // if ( !(lpSourceDir && *lpSourceDir) ) DelFiles(szCopyDir, lpFilePart, iFilePartLen, szWinbom, szCopyFiles); // // Now we make a list of all the files we are going to add to the // inf and destination directory. // // If the source isn't a valid dir, we must have just wanted to clean up. // if ( ( lpSourceDir && *lpSourceDir ) && ( GetFullPathName(lpSourceDir, sizeof(szSourceDir) / sizeof(TCHAR), szSourceDir, &lpFile) && szSourceDir[0] ) && ( (dwNum = GetFileAttributes(szSourceDir)) != 0xFFFFFFFF ) ) { // Check to see if we were passed a file or a directory. // if ( ( dwNum & FILE_ATTRIBUTE_DIRECTORY ) || ( lpFile <= szSourceDir ) ) { // We are search for all the files in the diretory. // lpFile = STR_SEARCH; } else { // We are only doing one file. We need to separate // the file from the directory. // *(lpFile - 1) = NULLCHR; } // Set the staring point for our file search. // GetCurrentDirectory(sizeof(szCurDir) / sizeof(TCHAR), szCurDir); SetCurrentDirectory(szSourceDir); // Get the file list. // lpflHead = AllocFileList(hwndParent, szBuffer, lpFile); // Make sure the destination dir exits. // *lpFilePart = NULLCHR; CreatePath(szCopyDir); // // Now that we have the file list, go through each one processing // it separately and then free the memory allocated for it. // // Loop through all the files in our linked list. // for ( lpflCur = lpflHead; lpflCur; lpflCur = lpflBuf ) { // // First copy the file into the flat directory. // // Setup the relative path from the currect directory // to the file we want to copy. // if ( lpflCur->lpDirectory && *lpflCur->lpDirectory ) lstrcpyn(szBuffer, lpflCur->lpDirectory,AS(szBuffer)); else szBuffer[0] = NULLCHR; AddPathN(szBuffer, lpflCur->lpFileName,AS(szBuffer)); // Support for a different file name for the destination. // lpFileName = lpDestName ? lpDestName : lpflCur->lpFileName; // Setup the destination file name. // lstrcpyn(lpFilePart, lpFileName, iFilePartLen); // Copy the file to the Options\Cabs directory and display // an error if the copy failed. Probably means that this // is a duplicate file. // if ( !CopyFile(szBuffer, szCopyDir, TRUE) ) { // Save the CopyFile error and then check to see if the file // is actaully different then the one tried to copy over. // dwNum = GetLastError(); if ( ( !CompareFiles(szBuffer, szCopyDir) ) && ( lpTarget = (LPTSTR) MALLOC(256 * sizeof(TCHAR)) ) ) { // // I hate doing UI in backend type code. Because of time I don't have // much choice, but in the future, this UI code should be replaced // with a call back mechanism so the caller can do the UI. // // This is the first of only two places where UI is used in here. // // Allocate another buffer to hold the message with the file name. // if ( ( LoadString(NULL, dwNum == ERROR_FILE_EXISTS ? IDS_ERR_DUPFILE : IDS_ERR_COPY, lpTarget, 256 * sizeof(TCHAR)) ) && ( lpNext = (LPTSTR) MALLOC((lstrlen(lpFileName) + lstrlen(lpTarget) + 1) * sizeof(TCHAR)) ) ) { // Add the file name to the message, get the title for the message // box and display the error. // hrPrintf=StringCchPrintf(lpNext, (lstrlen(lpFileName) + lstrlen(lpTarget) + 1), lpTarget, lpFileName); *lpTarget = NULLCHR; LoadString(NULL, IDS_APPNAME, lpTarget, 256 * sizeof(TCHAR)); MessageBox(hwndParent, lpNext, lpTarget, MB_OK | MB_ICONWARNING | MB_APPLMODAL); FREE(lpNext); } FREE(lpTarget); } } // // Now add the file to the [SourceDiskFiles] section. // // We just use WritePrivateProfileString() to write // FILENAME=781 to the [SourceDiskFiles] section. // WritePrivateProfileString(INF_SECT_SOURCEDISK, lpFileName, SOURCENUM_OPTIONS_CAB, szWinbom); // // This code figures out what the copy files section will be // called. This is based on the path where the files will // be copied. // // Create the name of the copy files section the file will be in. // *lpSectEnd = NULLCHR; if ( lpflCur->lpDirectory && *lpflCur->lpDirectory ) lstrcpyn(lpSectEnd, lpflCur->lpDirectory, AS(szCopyFiles)-(int)(lpSectEnd - szCopyFiles) ); StrRem(lpSectEnd, CHR_BACKSLASH); // // Now add the file path to the [DestinationDirs] section. // // Create the LDID and dir combo to write to the dest dir section. // lstrcpyn(szBuffer, lpDestLdid ? lpDestLdid : DESTLDID_OOBE,AS(szBuffer)); if ( ( lpDestDir && *lpDestDir ) || ( lpflCur->lpDirectory && *lpflCur->lpDirectory ) ) { hrCat=StringCchCat(szBuffer,AS(szBuffer), _T(",\"")); if ( lpDestDir && *lpDestDir ) { hrCat=StringCchCat(szBuffer, AS(szBuffer),lpDestDir); if ( lpflCur->lpDirectory && *lpflCur->lpDirectory ) AddPathN(szBuffer, lpflCur->lpDirectory,AS(szBuffer)); } else hrCat=StringCchCat(szBuffer, AS(szBuffer), lpflCur->lpDirectory); hrCat=StringCchCat(szBuffer, AS(szBuffer), _T("\"")); } // We just use WritePrivateProfileString() to write // COPYFILES=11,"OOBE\\DIR" to the [DestinationDirs] section. // WritePrivateProfileString(INF_SECT_DESTDIRS, szCopyFiles, szBuffer, szWinbom); // // Now add the copy files section to the CopyFiles line. // // First get current CopyFiles line. // szBuffer[0] = NULLCHR; GetPrivateProfileString(INF_SECT_OOBE, INF_LINE_COPYFILES, NULLSTR, szBuffer, sizeof(szBuffer) / sizeof(TCHAR), szWinbom); // Search each section listed in the CopyFiles line to see // if we need to add this one. The sections are divided by // commas. // // ISSUE-2002/02/28-stelo- May want to take qutoes into account, but I don't think so. // bFound = FALSE; for ( lpTarget = szBuffer; !bFound && lpTarget && *lpTarget; lpTarget = lpNext ) { // Get rid of proceeding spaces. // while ( *lpTarget == CHR_SPACE ) lpTarget = CharNext(lpTarget); // NULL terminate at the ',' and setup // the lpNext pointer. // if ( lpNext = StrChr(lpTarget, _T(',')) ) *lpNext = NULLCHR; // Make sure there are no trailing spaces. // if ( lpSearch = StrChr(lpTarget, CHR_SPACE) ) *lpSearch = NULLCHR; // Check if this section is the same as the one // we are going to add. // if ( CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lpTarget, -1, szCopyFiles, -1) == CSTR_EQUAL ) bFound = TRUE; // Need to restore the characters we may have stomped on. // if ( lpNext ) *lpNext++ = _T(','); if ( lpSearch ) *lpSearch = CHR_SPACE; } // Now see if we need to add the line. // if ( !bFound ) { // Append our copy files section. // if ( szBuffer[0] ) hrCat=StringCchCat(szBuffer,AS(szBuffer), _T(", ")); hrCat=StringCchCat(szBuffer, AS(szBuffer), szCopyFiles); // We just use WritePrivateProfileString() to write // the CopyFiles line back to the [RegisterOOBE] section // with our added copy files section on it. // WritePrivateProfileString(INF_SECT_OOBE, INF_LINE_COPYFILES, szBuffer, szWinbom); } // // Now write the file name to it's copy files section. // // First get the entire copy files section. // GetPrivateProfileSection(szCopyFiles, szBuffer, sizeof(szBuffer) / sizeof(TCHAR), szWinbom); // Loop throught the strings to see if the file is already there. // bFound = FALSE; for ( lpTarget = szBuffer; !bFound && *lpTarget; lpTarget += (lstrlen(lpTarget) + 1) ) { // Get rid of proceeding spaces. // while ( *lpTarget == CHR_SPACE ) lpTarget = CharNext(lpTarget); // Make sure there are no trailing spaces. // if ( lpSearch = StrChr(lpTarget, CHR_SPACE) ) *lpSearch = NULLCHR; // Check if this section is the same as the one // we are going to add. // if ( CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lpTarget, -1, lpFileName, -1) == CSTR_EQUAL ) bFound = TRUE; // Need to restore the character we may have stomped on. // if ( lpSearch ) *lpSearch = CHR_SPACE; } // Now write back the section if we need to. // if ( !bFound ) { // Need to a pointer to the end of the sub strings. // for ( lpSearch = szBuffer; *lpSearch; lpSearch += (lstrlen(lpSearch) + 1) ); // Copy the string to the end and add an extra NULL. // lstrcpyn(lpSearch, lpFileName, ((MAX_PATH+32)-(int)(lpSearch-szBuffer)) ); lpSearch += (lstrlen(lpSearch) + 1); *lpSearch = NULLCHR; // We need to call WritePrivateProfileSection() with NULL // to remove the section. We shouldn't have to do this, // but the Win32 docs are not correct. // WritePrivateProfileSection(szCopyFiles, NULL, szWinbom); // We just use WritePrivateProfileSection() to write the // copy files section back with our added file in it. // WritePrivateProfileSection(szCopyFiles, szBuffer, szWinbom); } // // Now free the structure and the data within it. // // Save the next pointer before we free the structure. // lpflBuf = lpflCur->lpNext; // Free the file buffers and the structure. // FREE(lpflCur->lpFileName); FREE(lpflCur->lpDirectory); FREE(lpflCur); } // // All done, now just clean up. // // Put the current directory back to where it should be. // if ( szCurDir[0] ) SetCurrentDirectory(szCurDir); } // Make sure the changes to the inf are flushed to disk // WritePrivateProfileString(NULL, NULL, NULL, szWinbom); } // // Internal Function(s): // static void DelFiles(LPTSTR lpszCopyDir, LPTSTR lpszFilePart, DWORD cbFilePart, LPTSTR lpszWinbom, LPTSTR lpszCopyFiles) { LPTSTR lpSearch, lpSection, lpFileName, lpTarget, lpNext; LPTSTR lpszSections = NULL, lpszFileNames = NULL, lpszBuffer = NULL; BOOL bFound; // // Allocate buffers... // lpszSections = MALLOC(MAX_BUFFER * sizeof(TCHAR)); lpszFileNames = MALLOC(MAX_BUFFER * sizeof(TCHAR)); lpszBuffer = MALLOC(MAX_BUFFER * sizeof(TCHAR)); if ( !lpszSections || !lpszFileNames || !lpszBuffer ) { // Free the buffers... Note: FREE macro checks for NULL // FREE( lpszSections ); FREE( lpszFileNames ); FREE( lpszBuffer ); return; } // We need all the section names. // GetPrivateProfileSectionNames(lpszSections, MAX_BUFFER, lpszWinbom); // Loop throught the section to see if there is any that match our search criteria. // for ( lpSection = lpszSections; lpSection && *lpSection; lpSection += (lstrlen(lpSection) + 1) ) { // Get rid of proceeding spaces. // while ( *lpSection == CHR_SPACE ) lpSection = CharNext(lpSection); // Make sure there are no trailing spaces. // if ( lpSearch = StrChr(lpSection, CHR_SPACE) ) *lpSearch = NULLCHR; // Check if this section is the same as the one // we are going to add. // if ( CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lpSection, lstrlen(lpszCopyFiles), lpszCopyFiles, lstrlen(lpszCopyFiles)) == CSTR_EQUAL ) { // We need all the files in the section. // GetPrivateProfileSection(lpSection, lpszFileNames, MAX_BUFFER, lpszWinbom); // Loop throught the section to see if there is any that match our search criteria. // for ( lpFileName = lpszFileNames; *lpFileName; lpFileName += (lstrlen(lpFileName) + 1) ) { // Get rid of proceeding spaces. // while ( *lpFileName == CHR_SPACE ) lpFileName = CharNext(lpFileName); // Make sure there are no trailing spaces. // if ( lpSearch = StrChr(lpFileName, CHR_SPACE) ) *lpSearch = NULLCHR; // Delete the file from the destination directory. // lstrcpyn(lpszFilePart, lpFileName, cbFilePart); DeleteFile(lpszCopyDir); // Remove the line from the source disk section. // WritePrivateProfileString(INF_SECT_SOURCEDISK, lpFileName, NULL, lpszWinbom); } // Search each section listed in the CopyFiles and remove // this one. The sections are divided by commas. // bFound = FALSE; GetPrivateProfileString(INF_SECT_OOBE, INF_LINE_COPYFILES, NULLSTR, lpszBuffer, MAX_BUFFER, lpszWinbom); for ( lpTarget = lpszBuffer; !bFound && lpTarget && *lpTarget; lpTarget = lpNext ) { // Get rid of proceeding spaces. // while ( *lpTarget == CHR_SPACE ) lpTarget = CharNext(lpTarget); // NULL terminate at the ',' and setup // the lpNext pointer. // if ( lpNext = StrChr(lpTarget, _T(',')) ) *lpNext = NULLCHR; // Make sure there are no trailing spaces. // if ( lpSearch = StrChr(lpTarget, CHR_SPACE) ) *lpSearch = NULLCHR; // Check if this section is the same as the one // we are going to remove. // if ( CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lpTarget, -1, lpSection, -1) == CSTR_EQUAL ) bFound = TRUE; // Need to restore the characters we may have stomped on. // if ( lpNext ) *lpNext++ = _T(','); if ( lpSearch ) *lpSearch = CHR_SPACE; if ( bFound ) { // Go back to the ',' or the beginning of the buffer. // while ( ( lpTarget > lpszBuffer) && ( *lpTarget != _T(',') ) ) lpTarget = CharPrev(lpszBuffer, lpTarget); // Now overwrite the string we took out. // if ( lpNext ) lstrcpyn(lpTarget, lpNext - 1, (MAX_BUFFER-(int)(lpTarget-lpszBuffer))); else *lpTarget = NULLCHR; } } if ( bFound ) { // We should eat any preceeding spaces and/or commas just // for good measure. // for ( lpTarget = lpszBuffer; ( *lpTarget == CHR_SPACE ) || ( *lpTarget == _T(',') ); lpTarget = CharNext(lpTarget) ); // Now write the buffer back to the inf file. // WritePrivateProfileString(INF_SECT_OOBE, INF_LINE_COPYFILES, *lpTarget ? lpTarget : NULL, lpszWinbom); } // Remove the line from the destination dirs section. // WritePrivateProfileString(INF_SECT_DESTDIRS, lpSection, NULL, lpszWinbom); // Remove this section entirely. // WritePrivateProfileSection(lpSection, NULL, lpszWinbom); } } // Free the buffers... Note: FREE macro checks for NULL // FREE( lpszSections ); FREE( lpszFileNames ); FREE( lpszBuffer ); } static LPFILELIST AllocFileList(HWND hwndParent, LPTSTR lpDirectory, LPTSTR lpSearch) { WIN32_FIND_DATA FileFound; HANDLE hFile; LPTSTR lpEnd, lpFileName; LPFILELIST lpflHead = NULL; LPFILELIST* lplpflNext = &lpflHead; HRESULT hrPrintf; // Process all the files and directories. // if ( (hFile = FindFirstFile(lpSearch, &FileFound)) != INVALID_HANDLE_VALUE ) { do { // Display an error if the short and long file names don't match. // Means that it is a LFN, which INFs don't like. // if ( ( FileFound.cAlternateFileName[0] ) && ( CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, FileFound.cAlternateFileName, -1, FileFound.cFileName, -1) != CSTR_EQUAL ) && ( lpEnd = (LPTSTR) MALLOC(256 * sizeof(TCHAR)) ) ) { // // I hate doing UI in backend type code. Because of time I don't have // much choice, but in the future, this UI code should be replaced // with a call back mechanism so the caller can do the UI. // // This is the second of only two places where UI is used in here. // // Allocate another buffer to hold the message with the file name. // if ( ( LoadString(NULL, IDS_ERR_LFN, lpEnd, 256) ) && ( lpFileName = (LPTSTR) MALLOC((lstrlen(FileFound.cFileName) + lstrlen(lpEnd) + 1) * sizeof(TCHAR)) ) ) { // Add the file name to the message, get the title for the message // box and display the error. // hrPrintf=StringCchPrintf(lpFileName, (lstrlen(FileFound.cFileName) + lstrlen(lpEnd) + 1), lpEnd, FileFound.cFileName); *lpEnd = NULLCHR; LoadString(NULL, IDS_APPNAME, lpEnd, 256 * sizeof(TCHAR)); MessageBox(hwndParent, lpFileName, lpEnd, MB_OK | MB_ICONWARNING | MB_APPLMODAL); FREE(lpFileName); } FREE(lpEnd); } // Get a pointer to the file name, the short one if possible. // if ( FileFound.cAlternateFileName[0] ) lpFileName = FileFound.cAlternateFileName; else lpFileName = FileFound.cFileName; // First check to see if this is a files (not a directory). // if ( !( FileFound.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ) { // Allocate the next item in the structure. // if ( *lplpflNext = (LPFILELIST) MALLOC(sizeof(FILELIST)) ) { // Allocate the buffer for the file name and path and // make sure that none of the allocations fail. // if ( ( (*lplpflNext)->lpFileName = (LPTSTR) MALLOC((lstrlen(lpFileName) + 1) * sizeof(TCHAR)) ) && ( (*lplpflNext)->lpDirectory = (LPTSTR) MALLOC((lstrlen(lpDirectory) + 1) * sizeof(TCHAR)) ) ) { // Copy the file name and path into the buffers. // lstrcpyn((*lplpflNext)->lpFileName, lpFileName, (lstrlen(lpFileName) + 1)); lstrcpyn((*lplpflNext)->lpDirectory, lpDirectory, (lstrlen(lpDirectory) + 1)); // Null the next pointer so we know this is the last item. // (*lplpflNext)->lpNext = NULL; // Set the next pointer to point to the address of // the next member of this new structure. // lplpflNext = &((*lplpflNext)->lpNext); } else { // Don't worry, the FREE() macro checks for NULL // before it frees the memory. // FREE((*lplpflNext)->lpFileName); FREE(*lplpflNext); } } } // Otherwise, make sure the directory is not "." or "..". // else if ( ( lstrcmp(lpFileName, _T(".")) ) && ( lstrcmp(lpFileName, _T("..")) ) ) { // Tack on this directory name to the current path saving // the end pointer so that it is easy to get rid of this // directory name when we return back. // lpEnd = lpDirectory + lstrlen(lpDirectory); AddPath(lpDirectory, lpFileName); // Go into the next directory, get all the files, and // the set the current directory back to the original // directory. // SetCurrentDirectory(lpFileName); *lplpflNext = AllocFileList(hwndParent, lpDirectory, lpSearch); SetCurrentDirectory(_T("..")); // Get rid of the directory name off our path buffer. // *lpEnd = NULLCHR; // Need to setup our next pointer to the end of the list // returned to us. // while ( *lplpflNext ) lplpflNext = &((*lplpflNext)->lpNext); } } while ( FindNextFile(hFile, &FileFound) ); FindClose(hFile); } return lpflHead; } static BOOL CompareFiles(LPTSTR lpFile1, LPTSTR lpFile2) { BOOL bCompare, bRead1, bRead2; HANDLE hFile1, hFile2; BYTE baBuffer1[4096], baBuffer2[4096]; DWORD dwBytes1, dwBytes2, dwCount; // Open the files. // hFile1 = CreateFile(lpFile1, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); hFile2 = CreateFile(lpFile2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); // Make sure the files were opened. // if ( ( hFile1 != INVALID_HANDLE_VALUE ) && ( hFile2 != INVALID_HANDLE_VALUE ) ) { // Read all the data from the files. // do { // Read in the max buffer from each file. // bRead1 = ReadFile(hFile1, baBuffer1, sizeof(baBuffer1), &dwBytes1, NULL); bRead2 = ReadFile(hFile2, baBuffer2, sizeof(baBuffer2), &dwBytes2, NULL); // Make sure the reads didn't fail. // if ( bRead1 && bRead2 ) { // Check to make sure the sizes are the same. // if ( bCompare = ( dwBytes1 == dwBytes2 ) ) { // Make sure the buffers are identical. // for ( dwCount = 0; bCompare && ( dwCount < dwBytes1 ); dwCount++ ) bCompare = ( baBuffer1[dwCount] == baBuffer2[dwCount] ); } } else // If both the reads failed, we will return true. // bCompare = ( !bRead1 && !bRead2 ); } while ( bCompare && bRead1 && bRead2 && dwBytes1 && dwBytes2 ); } else // If both the files does not exist, then we will // return false. // bCompare = ( ( hFile1 != INVALID_HANDLE_VALUE ) && ( hFile2 != INVALID_HANDLE_VALUE ) ); // Close the files. // if ( hFile1 == INVALID_HANDLE_VALUE ) CloseHandle(hFile1); if ( hFile2 == INVALID_HANDLE_VALUE ) CloseHandle(hFile2); return bCompare; }