DWORD WINAPI HashSaveThread( PHASHSAVECONTEXT phsctx ) { // First, activate our manifest and AddRef our host ULONG_PTR uActCtxCookie = ActivateManifest(TRUE); ULONG_PTR uHostCookie = HostAddRef(); // Calling HashCalcPrepare with a NULL hList will cause it to calculate // and set cchPrefix, but it will not copy the data or walk the directories // (we will leave that for the worker thread to do); the reason we do a // limited scan now is so that we can show the file dialog (which requires // cchPrefix for the automatic name generation) as soon as possible phsctx->status = INACTIVE; phsctx->hList = NULL; HashCalcPrepare(phsctx); // Get a file name from the user ZeroMemory(&phsctx->ofn, sizeof(phsctx->ofn)); HashCalcInitSave(phsctx); if (phsctx->hFileOut != INVALID_HANDLE_VALUE) { BOOL bDeletionFailed = TRUE; if (phsctx->hList = SLCreateEx(TRUE)) { bDeletionFailed = ! DialogBoxParam( g_hModThisDll, MAKEINTRESOURCE(IDD_HASHSAVE), NULL, HashSaveDlgProc, (LPARAM)phsctx ); SLRelease(phsctx->hList); } CloseHandle(phsctx->hFileOut); // Should only happen on Windows XP if (bDeletionFailed) DeleteFile(phsctx->ofn.lpstrFile); } // This must be the last thing that we free, since this is what supports // our context! SLRelease(phsctx->hListRaw); // Clean up the manifest activation and release our host DeactivateManifest(uActCtxCookie); HostRelease(uHostCookie); InterlockedDecrement(&g_cRefThisDll); return(0); }
STDMETHODIMP CHashCheck::AddPages( LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam ) { PROPSHEETPAGE psp; psp.dwSize = sizeof(psp); psp.dwFlags = PSP_USECALLBACK | PSP_USEREFPARENT | PSP_USETITLE; psp.hInstance = g_hModThisDll; psp.pszTemplate = MAKEINTRESOURCE(IDD_HASHPROP); psp.pszTitle = MAKEINTRESOURCE(IDS_HP_TITLE); psp.pfnDlgProc = HashPropDlgProc; psp.lParam = (LPARAM)m_hList; psp.pfnCallback = HashPropCallback; psp.pcRefParent = (PUINT)&g_cRefThisDll; if (ActivateManifest(FALSE)) { psp.dwFlags |= PSP_USEFUSIONCONTEXT; psp.hActCtx = g_hActCtx; } HPROPSHEETPAGE hPage = CreatePropertySheetPage(&psp); if (hPage && !pfnAddPage(hPage, lParam)) DestroyPropertySheetPage(hPage); // HashProp has AddRef'ed and now owns our list SLRelease(m_hList); m_hList = NULL; return(S_OK); }
VOID WINAPI HashSaveStart( HWND hWndOwner, HSIMPLELIST hListRaw ) { // Explorer will be blocking as long as this function is running, so we // want to return as quickly as possible and leave the work up to the // thread that we are going to spawn PHASHSAVECONTEXT phsctx = SLSetContextSize(hListRaw, sizeof(HASHSAVECONTEXT)); if (phsctx) { HANDLE hThread; phsctx->hWnd = hWndOwner; phsctx->hListRaw = hListRaw; InterlockedIncrement(&g_cRefThisDll); SLAddRef(hListRaw); if (hThread = CreateThreadCRT(HashSaveThread, phsctx)) { CloseHandle(hThread); return; } // If the thread creation was successful, the thread will be // responsible for decrementing the ref count SLRelease(hListRaw); InterlockedDecrement(&g_cRefThisDll); } }
DWORD WINAPI HashVerifyThread( PTSTR pszPath ) { // We will need to free the memory allocated for the data when done PBYTE pbRawData; // First, activate our manifest and AddRef our host ULONG_PTR uActCtxCookie = ActivateManifest(TRUE); ULONG_PTR uHostCookie = HostAddRef(); // Allocate the context data that will persist across this session HASHVERIFYCONTEXT hvctx; // It's important that we zero the memory since an initial value of zero is // assumed for many of the elements ZeroMemory(&hvctx, sizeof(hvctx)); // Prep the path HashNormalizeString(pszPath); StrTrim(pszPath, TEXT(" ")); hvctx.pszPath = pszPath; // Load the raw data pbRawData = HashVerifyLoadData(&hvctx); if (hvctx.pszFileData && (hvctx.hList = SLCreateEx(TRUE))) { HashVerifyParseData(&hvctx); DialogBoxParam( g_hModThisDll, MAKEINTRESOURCE(IDD_HASHVERF), NULL, HashVerifyDlgProc, (LPARAM)&hvctx ); SLRelease(hvctx.hList); } else if (*pszPath) { // Technically, we could reach this point by either having a file read // error or a memory allocation error, but I really don't feel like // doing separate messages for what are supposed to be rare edge cases. TCHAR szFormat[MAX_STRINGRES], szMessage[0x100]; LoadString(g_hModThisDll, IDS_HV_LOADERROR_FMT, szFormat, countof(szFormat)); wnsprintf(szMessage, countof(szMessage), szFormat, pszPath); MessageBox(NULL, szMessage, NULL, MB_OK | MB_ICONERROR); } free(pbRawData); free(pszPath); // Clean up the manifest activation and release our host DeactivateManifest(uActCtxCookie); HostRelease(uHostCookie); InterlockedDecrement(&g_cRefThisDll); return(0); }
STDMETHODIMP CHashCheck::InvokeCommand( LPCMINVOKECOMMANDINFO pici ) { // Ignore string verbs (high word must be zero) // The only valid command index is 0 (low word must be zero) if (pici->lpVerb) return(E_INVALIDARG); // Hand things over to HashSave, where all the work is done... HashSaveStart(pici->hwnd, m_hList); // HaveSave has AddRef'ed and now owns our list SLRelease(m_hList); m_hList = NULL; return(S_OK); }
STDMETHODIMP CHashCheck::Initialize( LPCITEMIDLIST pidlFolder, LPDATAOBJECT pdtobj, HKEY hkeyProgID ) { // We'll be needing a buffer, and let's double it just to be safe TCHAR szPath[MAX_PATH << 1]; // Make sure that we are working with a fresh list SLRelease(m_hList); m_hList = SLCreate(); // This indent exists to facilitate diffing against the CmdOpen source { FORMATETC format = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; STGMEDIUM medium; if (!pdtobj || pdtobj->GetData(&format, &medium) != S_OK) return(E_INVALIDARG); if (HDROP hDrop = (HDROP)GlobalLock(medium.hGlobal)) { UINT uDrops = DragQueryFile(hDrop, -1, NULL, 0); for (UINT uDrop = 0; uDrop < uDrops; ++uDrop) { if (DragQueryFile(hDrop, uDrop, szPath, countof(szPath))) { SLAddStringI(m_hList, szPath); } } GlobalUnlock(medium.hGlobal); } ReleaseStgMedium(&medium); } // If there was any failure, the list would be empty... return((SLCheck(m_hList)) ? S_OK : E_INVALIDARG); }