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); } }
STDMETHODIMP CHashCheck::Drop( LPDATAOBJECT pdtobj, DWORD grfKeyState, POINTL pt, PDWORD pdwEffect ) { FORMATETC format = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; STGMEDIUM medium; UINT uThreads = 0; if (pdtobj && pdtobj->GetData(&format, &medium) == S_OK) { if (HDROP hDrop = (HDROP)GlobalLock(medium.hGlobal)) { UINT uDrops = DragQueryFile(hDrop, -1, NULL, 0); UINT cchPath; LPTSTR lpszPath; // Reduce the likelihood of a race condition when trying to create // an activation context by creating it before creating threads ActivateManifest(FALSE); for (UINT uDrop = 0; uDrop < uDrops; ++uDrop) { if ( (cchPath = DragQueryFile(hDrop, uDrop, NULL, 0)) && (lpszPath = (LPTSTR)malloc((cchPath + 1) * sizeof(TCHAR))) ) { InterlockedIncrement(&g_cRefThisDll); HANDLE hThread; if ( (DragQueryFile(hDrop, uDrop, lpszPath, cchPath + 1) == cchPath) && (!(GetFileAttributes(lpszPath) & FILE_ATTRIBUTE_DIRECTORY)) && (hThread = CreateThreadCRT(HashVerifyThread, lpszPath)) ) { // The thread should free lpszPath, not us CloseHandle(hThread); ++uThreads; } else { free(lpszPath); InterlockedDecrement(&g_cRefThisDll); } } } GlobalUnlock(medium.hGlobal); } ReleaseStgMedium(&medium); } if (uThreads) { // DROPEFFECT_LINK would work here as well; it really doesn't matter *pdwEffect = DROPEFFECT_COPY; return(S_OK); } else { // We shouldn't ever be hitting this case *pdwEffect = DROPEFFECT_NONE; return(E_INVALIDARG); } }
INT_PTR CALLBACK HashSaveDlgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { PHASHSAVECONTEXT phsctx; switch (uMsg) { case WM_INITDIALOG: { phsctx = (PHASHSAVECONTEXT)lParam; // Associate the window with the context and vice-versa phsctx->hWnd = hWnd; SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR)phsctx); SetAppIDForWindow(hWnd, TRUE); HashSaveDlgInit(phsctx); phsctx->ex.pfnWorkerMain = HashSaveWorkerMain; phsctx->hThread = CreateThreadCRT(NULL, phsctx); if (!phsctx->hThread || WaitForSingleObject(phsctx->hThread, 1000) != WAIT_TIMEOUT) { WorkerThreadCleanup((PCOMMONCONTEXT)phsctx); EndDialog(hWnd, 0); } return(TRUE); } case WM_DESTROY: { SetAppIDForWindow(hWnd, FALSE); break; } case WM_ENDSESSION: case WM_CLOSE: { phsctx = (PHASHSAVECONTEXT)GetWindowLongPtr(hWnd, DWLP_USER); goto cleanup_and_exit; } case WM_COMMAND: { phsctx = (PHASHSAVECONTEXT)GetWindowLongPtr(hWnd, DWLP_USER); switch (LOWORD(wParam)) { case IDC_PAUSE: { WorkerThreadTogglePause((PCOMMONCONTEXT)phsctx); return(TRUE); } case IDC_CANCEL: { cleanup_and_exit: phsctx->dwFlags |= HCF_EXIT_PENDING; WorkerThreadStop((PCOMMONCONTEXT)phsctx); WorkerThreadCleanup((PCOMMONCONTEXT)phsctx); EndDialog(hWnd, 0); break; } } break; } case WM_TIMER: { // Vista: Workaround to fix their buggy progress bar KillTimer(hWnd, TIMER_ID_PAUSE); phsctx = (PHASHSAVECONTEXT)GetWindowLongPtr(hWnd, DWLP_USER); if (phsctx->status == PAUSED) SetProgressBarPause((PCOMMONCONTEXT)phsctx, PBST_PAUSED); return(TRUE); } case HM_WORKERTHREAD_DONE: { phsctx = (PHASHSAVECONTEXT)wParam; WorkerThreadCleanup((PCOMMONCONTEXT)phsctx); EndDialog(hWnd, 0); return(TRUE); } case HM_WORKERTHREAD_UPDATE: { phsctx = (PHASHSAVECONTEXT)wParam; ++phsctx->cHandledMsgs; SendMessage(phsctx->hWndPBTotal, PBM_SETPOS, phsctx->cHandledMsgs, 0); return(TRUE); } case HM_WORKERTHREAD_TOGGLEPREP: { HashCalcTogglePrep((PHASHSAVECONTEXT)wParam, (BOOL)lParam); return(TRUE); } } return(FALSE); }
INT_PTR CALLBACK HashVerifyDlgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { PHASHVERIFYCONTEXT phvctx; switch (uMsg) { case WM_INITDIALOG: { phvctx = (PHASHVERIFYCONTEXT)lParam; // Associate the window with the context and vice-versa phvctx->hWnd = hWnd; SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR)phvctx); SetAppIDForWindow(hWnd, TRUE); HashVerifyDlgInit(phvctx); phvctx->ex.pfnWorkerMain = HashVerifyWorkerMain; phvctx->hThread = CreateThreadCRT(NULL, phvctx); if (!phvctx->hThread) WorkerThreadCleanup((PCOMMONCONTEXT)phvctx); // Initialize the summary SendMessage(phvctx->hWndPBTotal, PBM_SETRANGE32, 0, phvctx->cTotal); HashVerifyUpdateSummary(phvctx, NULL); return(TRUE); } case WM_DESTROY: { SetAppIDForWindow(hWnd, FALSE); break; } case WM_ENDSESSION: case WM_CLOSE: { phvctx = (PHASHVERIFYCONTEXT)GetWindowLongPtr(hWnd, DWLP_USER); goto cleanup_and_exit; } case WM_COMMAND: { phvctx = (PHASHVERIFYCONTEXT)GetWindowLongPtr(hWnd, DWLP_USER); switch (LOWORD(wParam)) { case IDC_PAUSE: { WorkerThreadTogglePause((PCOMMONCONTEXT)phvctx); return(TRUE); } case IDC_STOP: { WorkerThreadStop((PCOMMONCONTEXT)phvctx); return(TRUE); } case IDC_EXIT: { cleanup_and_exit: phvctx->dwFlags |= HCF_EXIT_PENDING; WorkerThreadStop((PCOMMONCONTEXT)phvctx); WorkerThreadCleanup((PCOMMONCONTEXT)phvctx); EndDialog(hWnd, 0); break; } } break; } case WM_NOTIFY: { LPNMHDR pnm = (LPNMHDR)lParam; if (pnm && pnm->idFrom == IDC_LIST) { phvctx = (PHASHVERIFYCONTEXT)GetWindowLongPtr(hWnd, DWLP_USER); switch (pnm->code) { case LVN_GETDISPINFO: { HashVerifyListInfo(phvctx, (LPNMLVDISPINFO)lParam); return(TRUE); } case NM_CUSTOMDRAW: { SetWindowLongPtr(hWnd, DWLP_MSGRESULT, HashVerifySetColor(phvctx, (LPNMLVCUSTOMDRAW)lParam)); return(TRUE); } case LVN_ODFINDITEM: { SetWindowLongPtr(hWnd, DWLP_MSGRESULT, HashVerifyFindItem(phvctx, (LPNMLVFINDITEM)lParam)); return(TRUE); } case LVN_COLUMNCLICK: { HashVerifySortColumn(phvctx, (LPNMLISTVIEW)lParam); return(TRUE); } case LVN_ITEMCHANGED: { if (((LPNMLISTVIEW)lParam)->uChanged & LVIF_STATE) phvctx->bFreshStates = FALSE; break; } case LVN_ODSTATECHANGED: { phvctx->bFreshStates = FALSE; break; } } } break; } case WM_TIMER: { // Vista: Workaround to fix their buggy progress bar KillTimer(hWnd, TIMER_ID_PAUSE); phvctx = (PHASHVERIFYCONTEXT)GetWindowLongPtr(hWnd, DWLP_USER); if (phvctx->status == PAUSED) SetProgressBarPause((PCOMMONCONTEXT)phvctx, PBST_PAUSED); return(TRUE); } case HM_WORKERTHREAD_DONE: { phvctx = (PHASHVERIFYCONTEXT)wParam; WorkerThreadCleanup((PCOMMONCONTEXT)phvctx); return(TRUE); } case HM_WORKERTHREAD_UPDATE: { phvctx = (PHASHVERIFYCONTEXT)wParam; ++phvctx->cHandledMsgs; HashVerifyUpdateSummary(phvctx, (PHASHVERIFYITEM)lParam); return(TRUE); } case HM_WORKERTHREAD_SETSIZE: { phvctx = (PHASHVERIFYCONTEXT)wParam; // At the time we receive this message, cSentMsgs will be the ID of // the item the worker thread is currently working on, and // cHandledMsgs will be the ID of the item for which the SETSIZE // message was intended for; we need to update the UI only if // the worker thread is still working on this item when we process // this message; otherwise, we can just wait for the UPDATE message. if (phvctx->cSentMsgs == phvctx->cHandledMsgs) ListView_RedrawItems(phvctx->hWndList, phvctx->cHandledMsgs, phvctx->cHandledMsgs); return(TRUE); } } return(FALSE); }