VOID WINAPI HashCalcInitSave( PHASHCALCCONTEXT phcctx ) { HWND hWnd = phcctx->hWnd; // We can use the extended portion of the scratch buffer for the file name PTSTR pszFile = (PTSTR)phcctx->scratch.ext; // Default result value phcctx->hFileOut = INVALID_HANDLE_VALUE; // Load settings phcctx->opt.dwFlags = HCOF_FILTERINDEX | HCOF_SAVEENCODING; OptionsLoad(&phcctx->opt); // Initialize the struct for the first time, if needed if (phcctx->ofn.lStructSize == 0) { phcctx->ofn.lStructSize = sizeof(phcctx->ofn); phcctx->ofn.hwndOwner = hWnd; phcctx->ofn.lpstrFilter = SAVE_FILTERS; phcctx->ofn.nFilterIndex = phcctx->opt.dwFilterIndex; phcctx->ofn.lpstrFile = pszFile; phcctx->ofn.nMaxFile = MAX_PATH_BUFFER + 10; phcctx->ofn.Flags = OFN_DONTADDTORECENT | OFN_NOCHANGEDIR | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST; phcctx->ofn.lpstrDefExt = TEXT(""); // Set the initial file name { PTSTR pszOrigPath; SLReset(phcctx->hListRaw); pszOrigPath = SLGetDataAndStep(phcctx->hListRaw); if (SLCheck(phcctx->hListRaw)) { // Multiple items were selected in Explorer SSChainNCpy2( pszFile, pszOrigPath, phcctx->cchPrefix, SAVE_DEFAULT_NAME, countof(SAVE_DEFAULT_NAME) ); } else { // Only one item was selected in Explorer (may be a single // file or a directory containing multiple files) SSChainCpyCat(pszFile, pszOrigPath, SAVE_EXTS[phcctx->ofn.nFilterIndex]); } } } // We should also do a sanity check to make sure that the filter index // is set to a valid value since we depend on that to determine the format if ( GetSaveFileName(&phcctx->ofn) && phcctx->ofn.nFilterIndex && phcctx->ofn.nFilterIndex <= 4 ) { BOOL bSuccess = FALSE; // Save the filter in the user's preferences if (phcctx->opt.dwFilterIndex != phcctx->ofn.nFilterIndex) { phcctx->opt.dwFilterIndex = phcctx->ofn.nFilterIndex; phcctx->opt.dwFlags = HCOF_FILTERINDEX; OptionsSave(&phcctx->opt); } // Extension fixup: Correct the extension to match the selected // type, but only if the extension was one of the 4 in the list if (phcctx->ofn.nFileExtension) { PTSTR pszExt = pszFile + phcctx->ofn.nFileExtension - 1; if ( StrCmpI(pszExt, TEXT(".sfv")) == 0 || StrCmpI(pszExt, TEXT(".md4")) == 0 || StrCmpI(pszExt, TEXT(".md5")) == 0 || StrCmpI(pszExt, TEXT(".sha1")) == 0 ) { if (StrCmpI(pszExt, SAVE_EXTS[phcctx->ofn.nFilterIndex])) SSCpy(pszExt, SAVE_EXTS[phcctx->ofn.nFilterIndex]); } } // Adjust the file paths for the output path, if necessary HashCalcSetSavePrefix(phcctx, pszFile); // Open the file for output phcctx->hFileOut = CreateFile( pszFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL ); if (phcctx->hFileOut != INVALID_HANDLE_VALUE) { // The actual format will be set when HashCalcWriteResult is called phcctx->szFormat[0] = 0; if (phcctx->opt.dwSaveEncoding == 1) { // Write the BOM for UTF-16LE WCHAR BOM = 0xFEFF; DWORD cbWritten; WriteFile(phcctx->hFileOut, &BOM, sizeof(WCHAR), &cbWritten, NULL); } } else { TCHAR szMessage[MAX_STRINGMSG]; LoadString(g_hModThisDll, IDS_HC_SAVE_ERROR, szMessage, countof(szMessage)); MessageBox(hWnd, szMessage, NULL, MB_OK | MB_ICONERROR); } } }
VOID __fastcall HashVerifyWorkerMain( PHASHVERIFYCONTEXT phvctx ) { // Note that ALL message communication to and from the main window MUST // be asynchronous, or else there may be a deadlock PHASHVERIFYITEM pItem; // We need to keep track of the thread's execution time so that we can do a // sound notification of completion when appropriate DWORD dwTickStart = GetTickCount(); // Initialize the path prefix length; used for building the full path PTSTR pszPathTail = StrRChr(phvctx->pszPath, NULL, TEXT('\\')); SIZE_T cchPathPrefix = (pszPathTail) ? pszPathTail + 1 - phvctx->pszPath : 0; while (pItem = SLGetDataAndStep(phvctx->hList)) { BOOL bSuccess; // Part 1: Build the path { SIZE_T cchPrefix = cchPathPrefix; // Do not use the prefix if pszDisplayName is an absolute path if ( pItem->pszDisplayName[0] == TEXT('\\') || pItem->pszDisplayName[1] == TEXT(':') ) { cchPrefix = 0; } SSChainNCpy2( phvctx->ex.pszPath, phvctx->pszPath, cchPrefix, pItem->pszDisplayName, pItem->cchDisplayName ); } // Part 2: Calculate the checksum WorkerThreadHashFile( (PCOMMONCONTEXT)phvctx, phvctx->ex.pszPath, &bSuccess, &phvctx->whctx, NULL, &pItem->filesize ); if (phvctx->status == CANCEL_REQUESTED) return; // Part 3: Do something with the results if (bSuccess) { if (phvctx->whctx.flags == WHEX_ALL128) { // If the MD4/MD5 STILL has not been settled by this point, then // settle it by a simple heuristic: if the checksum matches MD4, // go with that, otherwise default to MD5. if (StrCmpI(pItem->pszExpected, phvctx->whctx.results.szHexMD4) == 0) phvctx->whctx.flags = WHEX_CHECKMD4; else phvctx->whctx.flags = WHEX_CHECKMD5; } switch (phvctx->whctx.flags) { case WHEX_CHECKCRC32: SSStaticCpy(pItem->szActual, phvctx->whctx.results.szHexCRC32); break; case WHEX_CHECKMD4: SSStaticCpy(pItem->szActual, phvctx->whctx.results.szHexMD4); break; case WHEX_CHECKMD5: SSStaticCpy(pItem->szActual, phvctx->whctx.results.szHexMD5); break; case WHEX_CHECKSHA1: SSStaticCpy(pItem->szActual, phvctx->whctx.results.szHexSHA1); break; } if (StrCmpI(pItem->pszExpected, pItem->szActual) == 0) pItem->uStatusID = HV_STATUS_MATCH; else pItem->uStatusID = HV_STATUS_MISMATCH; } else { pItem->uStatusID = HV_STATUS_UNREADABLE; } // Part 4: Update the UI ++phvctx->cSentMsgs; PostMessage(phvctx->hWnd, HM_WORKERTHREAD_UPDATE, (WPARAM)phvctx, (LPARAM)pItem); } // Play a sound to signal the normal, successful termination of operations, // but exempt operations that were nearly instantaneous if (phvctx->cTotal && GetTickCount() - dwTickStart >= 2000) MessageBeep(MB_ICONASTERISK); }