//------------------------------------------------------------------------------------ // TaskManager call this function on a different thread //------------------------------------------------------------------------------------ core::Task* System::Do() { if (m_bAsyncUpdate == false) return NULL; AsyncUpdate(); return this; } // Do
static NTSTATUS DownloadUpdateThreadStart( __in PVOID Parameter ) { PPH_STRING downloadUrlPath = NULL; HANDLE tempFileHandle = NULL; HINTERNET hInitialize = NULL, hConnection = NULL, hRequest = NULL; NTSTATUS status = STATUS_UNSUCCESSFUL; HWND hwndDlg = (HWND)Parameter; Button_Enable(GetDlgItem(hwndDlg, IDC_DOWNLOAD), FALSE); SetDlgItemText(hwndDlg, IDC_STATUS, L"Initializing"); // Reset the progress state on Vista and above. if (WindowsVersion > WINDOWS_XP) SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETSTATE, PBST_NORMAL, 0L); if (!ConnectionAvailable()) return status; __try { // Get temp dir. WCHAR tempPathString[MAX_PATH]; DWORD tempPathLength = GetTempPath(MAX_PATH, tempPathString); if (tempPathLength == 0 || tempPathLength > MAX_PATH) { LogEvent(hwndDlg, PhFormatString(L"CreateFile failed (%d)", GetLastError())); __leave; } // create the download path string. downloadUrlPath = PhFormatString( L"/projects/processhacker/files/processhacker2/processhacker-%u.%u-setup.exe/download?use_mirror=autoselect", /* ?use_mirror=waix" */ UpdateData.MajorVersion, UpdateData.MinorVersion ); // Append the tempath to our string: %TEMP%processhacker-%u.%u-setup.exe // Example: C:\\Users\\dmex\\AppData\\Temp\\processhacker-2.10-setup.exe SetupFilePath = PhFormatString( L"%sprocesshacker-%u.%u-setup.exe", tempPathString, UpdateData.MajorVersion, UpdateData.MinorVersion ); // Create output file status = PhCreateFileWin32( &tempFileHandle, SetupFilePath->Buffer, FILE_GENERIC_READ | FILE_GENERIC_WRITE, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_TEMPORARY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ); if (!NT_SUCCESS(status)) { LogEvent(hwndDlg, PhFormatString(L"PhCreateFileWin32 failed (%s)", ((PPH_STRING)PHA_DEREFERENCE(PhGetNtMessage(status)))->Buffer)); __leave; } { // Create a user agent string. PPH_STRING phVersion = PhGetPhVersion(); PPH_STRING userAgent = PhConcatStrings2(L"PH Updater v", phVersion->Buffer); // Initialize the wininet library. if (!(hInitialize = InternetOpen( userAgent->Buffer, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 ))) { LogEvent(hwndDlg, PhFormatString(L"Updater: (InitializeConnection) InternetOpen failed (%d)", GetLastError())); PhDereferenceObject(userAgent); PhDereferenceObject(phVersion); __leave; } PhDereferenceObject(userAgent); PhDereferenceObject(phVersion); } // Connect to the server. if (!(hConnection = InternetConnect( hInitialize, L"sourceforge.net", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0))) { LogEvent(hwndDlg, PhFormatString(L"InternetConnect failed (%d)", GetLastError())); __leave; } // Open the HTTP request. if (!(hRequest = HttpOpenRequest( hConnection, NULL, downloadUrlPath->Buffer, NULL, NULL, NULL, INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_RESYNCHRONIZE, 0 ))) { LogEvent(hwndDlg, PhFormatString(L"HttpOpenRequest failed (%d)", GetLastError())); __leave; } SetDlgItemText(hwndDlg, IDC_STATUS, L"Connecting"); // Send the HTTP request. if (!HttpSendRequest(hRequest, NULL, 0, NULL, 0)) { LogEvent(hwndDlg, PhFormatString(L"HttpSendRequest failed (%d)", GetLastError())); // Enable the 'Retry' button. Button_Enable(GetDlgItem(hwndDlg, IDC_DOWNLOAD), TRUE); SetDlgItemText(hwndDlg, IDC_DOWNLOAD, L"Retry"); // Reset the state and let user retry the download. PhUpdaterState = Download; } else { BYTE hashBuffer[20]; DWORD contentLengthSize = sizeof(DWORD); PH_HASH_CONTEXT hashContext; // Initialize hash algorithm. PhInitializeHash(&hashContext, Sha1HashAlgorithm); if (!HttpQueryInfoW(hRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &contentLength, &contentLengthSize, 0)) { // No content length...impossible to calculate % complete... // we can read the data, BUT in this instance Sourceforge always returns the content length // so instead we'll exit here instead of downloading the file. LogEvent(hwndDlg, PhFormatString(L"HttpQueryInfo failed (%d)", GetLastError())); __leave; } else { BYTE buffer[PAGE_SIZE]; DWORD bytesRead = 0, startTick = 0; IO_STATUS_BLOCK isb; // Zero the buffer. ZeroMemory(buffer, PAGE_SIZE); // Reset the counters. bytesDownloaded = 0, timeTransferred = 0, LastUpdateTime = 0; IsUpdating = FALSE; // Start the clock. startTick = GetTickCount(); timeTransferred = startTick; // Download the data. while (InternetReadFile(hRequest, buffer, PAGE_SIZE, &bytesRead)) { // If we get zero bytes, the file was uploaded or there was an error. if (bytesRead == 0) break; // If window closed and thread handle was closed, just dispose and exit. // (This also skips error checking/prompts and updating the disposed UI) if (!DownloadThreadHandle) __leave; // Update the hash of bytes we downloaded. PhUpdateHash(&hashContext, buffer, bytesRead); // Write the downloaded bytes to disk. status = NtWriteFile( tempFileHandle, NULL, NULL, NULL, &isb, buffer, bytesRead, NULL, NULL ); if (!NT_SUCCESS(status)) { PPH_STRING message = PhGetNtMessage(status); LogEvent(hwndDlg, PhFormatString(L"NtWriteFile failed (%s)", message->Buffer)); PhDereferenceObject(message); break; } // Check dwBytesRead are the same dwBytesWritten length returned by WriteFile. if (bytesRead != isb.Information) { PPH_STRING message = PhGetNtMessage(status); LogEvent(hwndDlg, PhFormatString(L"NtWriteFile failed (%s)", message->Buffer)); PhDereferenceObject(message); break; } // Update our total bytes downloaded PhAcquireQueuedLockExclusive(&Lock); bytesDownloaded += (DWORD)isb.Information; PhReleaseQueuedLockExclusive(&Lock); AsyncUpdate(); } // Check if we downloaded the entire file. assert(bytesDownloaded == contentLength); // Compute our hash result. if (PhFinalHash(&hashContext, &hashBuffer, 20, NULL)) { // Allocate our hash string, hex the final hash result in our hashBuffer. PPH_STRING hexString = PhBufferToHexString(hashBuffer, 20); if (PhEqualString(hexString, UpdateData.Hash, TRUE)) { // If PH is not elevated, set the UAC shield for the install button as the setup requires elevation. if (!PhElevated) SendMessage(GetDlgItem(hwndDlg, IDC_DOWNLOAD), BCM_SETSHIELD, 0, TRUE); // Set the download result, don't include hash status since it succeeded. //SetDlgItemText(hwndDlg, IDC_STATUS, L"Download Complete"); // Set button text for next action Button_SetText(GetDlgItem(hwndDlg, IDC_DOWNLOAD), L"Install"); // Enable the Install button Button_Enable(GetDlgItem(hwndDlg, IDC_DOWNLOAD), TRUE); // Hash succeeded, set state as ready to install. PhUpdaterState = Install; } else { if (WindowsVersion > WINDOWS_XP) SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETSTATE, PBST_ERROR, 0L); SetDlgItemText(hwndDlg, IDC_STATUS, L"Download complete, SHA1 Hash failed."); // Set button text for next action Button_SetText(GetDlgItem(hwndDlg, IDC_DOWNLOAD), L"Retry"); // Enable the Install button Button_Enable(GetDlgItem(hwndDlg, IDC_DOWNLOAD), TRUE); // Hash failed, reset state to downloading so user can redownload the file. PhUpdaterState = Download; } PhDereferenceObject(hexString); } else { //SetDlgItemText(hwndDlg, IDC_STATUS, L"PhFinalHash failed"); // Show fancy Red progressbar if hash failed on Vista and above. if (WindowsVersion > WINDOWS_XP) SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETSTATE, PBST_ERROR, 0L); } } } status = STATUS_SUCCESS; } __finally { if (hInitialize) { InternetCloseHandle(hInitialize); hInitialize = NULL; } if (hConnection) { InternetCloseHandle(hConnection); hConnection = NULL; } if (hRequest) { InternetCloseHandle(hRequest); hRequest = NULL; } if (tempFileHandle) { NtClose(tempFileHandle); tempFileHandle = NULL; } if (downloadUrlPath) { PhDereferenceObject(downloadUrlPath); downloadUrlPath = NULL; } } return status; }