From 65aa7a732a1a76294a9ca8a1e0536ea94e16a463 Mon Sep 17 00:00:00 2001 From: Valentin Radu Date: Wed, 24 Nov 2021 01:28:10 +0200 Subject: [PATCH] Option to receive pre-release versions via the updater --- CHANGELOG.md | 7 +- ExplorerPatcher/settings.reg | 2 + ExplorerPatcher/updates.c | 571 ++++++++++++++++++++++------------- ExplorerPatcher/updates.h | 4 + ExplorerPatcher/utility.h | 1 - version.h | 6 +- 6 files changed, 374 insertions(+), 217 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81a6f7f..6f7368e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,11 +13,11 @@ Tested on build 22000.318. * Implemented support for Windows 7 battery flyout (#274) * Implemented `/extract` switch which unpacks the files from `ep_setup.exe` to disk (#396) (.1): * `ep_setup /extract` - extracts `ExplorerPatcher.IA-32.dll` and `ExplorerPatcher.amd64.dll` to current directory - * `ep-setup /extract test` - extracts to `test` folder in current directory - * `ep-setup /extract "C:\test with space"` - extracts to `C:\test with space` directory + * `ep_setup /extract test` - extracts to `test` folder in current directory + * `ep_setup /extract "C:\test with space"` - extracts to `C:\test with space` directory * Taskbar toolbar layouts are preserved when switching between Windows 10 and Windows 11 taskbars and in general (these will be reset when installing this update but should be subsequently remembered) (#395) (.2) * Implemented option to toggle taskbar auto-hide when double clicking the main taskbar (#389) (.3) -* Running `ep-setup.exe` again while EP is already installed will now update the program to the latest version. To uninstall, as the previous behavior did, run `ep_setup.exe /uninstall` (.4) +* Running `ep_setup.exe` again while EP is already installed will now update the program to the latest version. To uninstall, as the previous behavior did, run `ep_setup.exe /uninstall` (.4) * Implemented absolute height and width parameters for the Windows 10 switcher. These are especially useful for ultra wide monitors, in a scenario similar to the one described in [this post](https://github.com/valinet/ExplorerPatcher/discussions/110#discussioncomment-1673007) - to configure, set `MaxWidthAbs` and/or `MaxHeightAbs` DWORD values in `HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\ExplorerPatcher\sws` (#110) (.5) * Provides a simple mechanism for chainloading a custom library when the shell interface is created, from which you can execute your custom code (subject to change, see [this](https://github.com/valinet/ExplorerPatcher/discussions/408#discussioncomment-1674348) for more details) (#408) (.6) @@ -26,6 +26,7 @@ Tested on build 22000.318. * Improved reliability when invoking Control Center (`Win`+`A`) when the taskbar icon is disabled (the icon should now not reappear anymore sometimes) (#242) * Small reorganization of some options in "Properties" +* Option to receive pre-release versions, if available, when checking for updates (.9) #### Fixes diff --git a/ExplorerPatcher/settings.reg b/ExplorerPatcher/settings.reg index fcda4d9..61f403c 100644 --- a/ExplorerPatcher/settings.reg +++ b/ExplorerPatcher/settings.reg @@ -337,6 +337,8 @@ ;x 0 Prompt to install available updates ;x 2 Do not check for updates "UpdatePolicy"=dword:00000001 +;b Receive pre-release versions, if available (not recommended) +"UpdatePreferStaging"=dword:00000000 ;t ________________________ ;y Check for updates ;;;EP_CHECK_FOR_UPDATES diff --git a/ExplorerPatcher/updates.c b/ExplorerPatcher/updates.c index f8e61ab..df57b68 100644 --- a/ExplorerPatcher/updates.c +++ b/ExplorerPatcher/updates.c @@ -55,13 +55,16 @@ void IsUpdateAvailableHelperCallback( } BOOL IsUpdateAvailableHelper( - char* url, - char* szCheckAgainst, - DWORD dwUpdateTimeout, + char* url, + char* szCheckAgainst, + DWORD dwUpdateTimeout, BOOL* lpFail, __x_ABI_CWindows_CUI_CNotifications_CIToastNotifier* notifier, __x_ABI_CWindows_CUI_CNotifications_CIToastNotificationFactory* notifFactory, - __x_ABI_CWindows_CUI_CNotifications_CIToastNotification** toast + __x_ABI_CWindows_CUI_CNotifications_CIToastNotification** toast, + BOOL bUpdatePreferStaging, + WCHAR* wszInfoURL, + DWORD dwInfoURLLen ) { BOOL bIsUpdateAvailable = FALSE; @@ -73,17 +76,18 @@ BOOL IsUpdateAvailableHelper( return bIsUpdateAvailable; } + char* staging_buffer = NULL; HINTERNET hInternet = NULL; - if (hInternet = InternetOpenA( - UPDATES_USER_AGENT, - INTERNET_OPEN_TYPE_PRECONFIG, - NULL, - NULL, - 0 //INTERNET_FLAG_ASYNC - )) + + if (bUpdatePreferStaging) { - //InternetSetOptionA(hInternet, INTERNET_OPTION_CONNECT_TIMEOUT, &dwUpdateTimeout, sizeof(DWORD)); - //if (InternetSetStatusCallbackA(hInternet, IsUpdateAvailableHelperCallback) != INTERNET_INVALID_STATUS_CALLBACK) + if (hInternet = InternetOpenA( + UPDATES_USER_AGENT, + INTERNET_OPEN_TYPE_PRECONFIG, + NULL, + NULL, + 0 + )) { HINTERNET hConnect = InternetOpenUrlA( hInternet, @@ -99,201 +103,50 @@ BOOL IsUpdateAvailableHelper( INTERNET_FLAG_DONT_CACHE, ¶ms ); - /*if (!hConnect && GetLastError() == ERROR_IO_PENDING) - { - if (WaitForSingleObject(params.hEvent, dwUpdateTimeout) == WAIT_OBJECT_0) - { - hConnect = params.hInternet; - } - }*/ if (hConnect) { - if (szCheckAgainst) + DWORD dwSize = 5000; + DWORD dwRead = dwSize; + staging_buffer = calloc(dwSize, sizeof(char)); + if (staging_buffer) { BOOL bRet = FALSE; - DWORD dwRead = 0; - char hash[DOSMODE_OFFSET + UPDATES_HASH_SIZE + 1]; - ZeroMemory(hash, DOSMODE_OFFSET + UPDATES_HASH_SIZE + 1); if (bRet = InternetReadFile( hConnect, - hash, - DOSMODE_OFFSET + UPDATES_HASH_SIZE, + staging_buffer, + dwSize - 1, &dwRead - ) && dwRead == DOSMODE_OFFSET + UPDATES_HASH_SIZE) + )) { -#ifdef UPDATES_VERBOSE_OUTPUT - printf("[Updates] Hash of remote file is \"%s\" (%s).\n", DOSMODE_OFFSET + hash, (hash[0] == 0x4D && hash[1] == 0x5A) ? "valid" : "invalid"); -#endif - if (hash[0] == 0x4D && hash[1] == 0x5A && _stricmp(DOSMODE_OFFSET + hash, szCheckAgainst)) + char* a1 = strstr(staging_buffer, "\"browser_download_url\""); + if (a1) { - bIsUpdateAvailable = TRUE; - } - } - else - { -#ifdef UPDATES_VERBOSE_OUTPUT - printf("[Updates] Failed. Read %d bytes.\n"); -#endif - if (lpFail) *lpFail = TRUE; - } - } - else - { - WCHAR wszPath[MAX_PATH]; - ZeroMemory(wszPath, MAX_PATH * sizeof(WCHAR)); - SHGetFolderPathW(NULL, SPECIAL_FOLDER_LEGACY, NULL, SHGFP_TYPE_CURRENT, wszPath); - wcscat_s(wszPath, MAX_PATH, _T(APP_RELATIVE_PATH)); - BOOL bRet = CreateDirectoryW(wszPath, NULL); - if (bRet || (!bRet && GetLastError() == ERROR_ALREADY_EXISTS)) - { - wcscat_s(wszPath, MAX_PATH, L"\\Update for " _T(PRODUCT_NAME) L" from "); - WCHAR wszURL[MAX_PATH]; - ZeroMemory(wszURL, MAX_PATH * sizeof(WCHAR)); - MultiByteToWideChar( - CP_UTF8, - MB_PRECOMPOSED, - url, - -1, - wszURL, - MAX_PATH - ); - if (wszURL[95]) - { - wszURL[94] = L'.'; - wszURL[95] = L'.'; - wszURL[96] = L'.'; - wszURL[97] = L'e'; - wszURL[98] = L'x'; - wszURL[99] = L'e'; - wszURL[100] = 0; - } - for (unsigned int i = 0; i < wszURL; ++i) - { - if (!wszURL[i]) + char* a2 = strchr(a1 + 24, '"'); + if (a2) { - break; - } - if (wszURL[i] == L'/') - { - wszURL[i] = L'\u2215'; - } - else if (wszURL[i] == L':') - { - wszURL[i] = L'\ua789'; - } - } - wcscat_s(wszPath, MAX_PATH, wszURL); -#ifdef UPDATES_VERBOSE_OUTPUT - wprintf(L"[Updates] Download path is \"%s\".\n", wszPath); -#endif - - BOOL bRet = DeleteFileW(wszPath); - if (bRet || (!bRet && GetLastError() == ERROR_FILE_NOT_FOUND)) - { - FILE* f = NULL; - if (!_wfopen_s( - &f, - wszPath, - L"wb" - ) && f) - { - BYTE* buffer = (BYTE*)malloc(UPDATES_BUFSIZ); - if (buffer != NULL) + a2[0] = 0; + printf("[Updates] Prerelease update URL: \"%s\"\n", a1 + 24); + url = a1 + 24; + bUpdatePreferStaging = FALSE; + if (wszInfoURL) { - DWORD dwRead = 0; - bRet = FALSE; - while (bRet = InternetReadFile( - hConnect, - buffer, - UPDATES_BUFSIZ, - &dwRead - )) + char* a3 = strstr(staging_buffer, "\"html_url\""); + if (a3) { - if (dwRead == 0) + char* a4 = strchr(a3 + 12, '"'); + if (a4) { - bIsUpdateAvailable = TRUE; -#ifdef UPDATES_VERBOSE_OUTPUT - printf("[Updates] Downloaded finished.\n"); -#endif - break; + a4[0] = 0; + printf("[Updates] Release notes URL: \"%s\"\n", a3 + 12); + MultiByteToWideChar( + CP_UTF8, + MB_PRECOMPOSED, + a3 + 12, + -1, + wszInfoURL, + dwInfoURLLen + ); } -#ifdef UPDATES_VERBOSE_OUTPUT - printf("[Updates] Downloaded %d bytes.\n", dwRead); -#endif - fwrite( - buffer, - sizeof(BYTE), - dwRead, - f - ); - dwRead = 0; - } - free(buffer); - } - fclose(f); - } - if (bIsUpdateAvailable) - { - bIsUpdateAvailable = FALSE; -#ifdef UPDATES_VERBOSE_OUTPUT - printf( - "[Updates] In order to install this update for the product \"" - PRODUCT_NAME - "\", please allow the elevation request.\n" - ); -#endif - - if (*toast) - { - notifier->lpVtbl->Hide(notifier, *toast); - (*toast)->lpVtbl->Release((*toast)); - (*toast) = NULL; - } - - SHELLEXECUTEINFO ShExecInfo = { 0 }; - ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); - ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; - ShExecInfo.hwnd = NULL; - ShExecInfo.lpVerb = L"runas"; - ShExecInfo.lpFile = wszPath; - ShExecInfo.lpParameters = L"/update_silent"; - ShExecInfo.lpDirectory = NULL; - ShExecInfo.nShow = SW_SHOW; - ShExecInfo.hInstApp = NULL; - if (ShellExecuteExW(&ShExecInfo) && ShExecInfo.hProcess) - { - WaitForSingleObject(ShExecInfo.hProcess, INFINITE); - DWORD dwExitCode = 0; - if (GetExitCodeProcess(ShExecInfo.hProcess, &dwExitCode) && !dwExitCode) - { - bIsUpdateAvailable = TRUE; -#ifdef UPDATES_VERBOSE_OUTPUT - printf("[Updates] Update successful, File Explorer will probably restart momentarly.\n"); -#endif - } - else - { - SetLastError(dwExitCode); -#ifdef UPDATES_VERBOSE_OUTPUT - printf("[Updates] Update failed because the following error has occured: %d.\n", dwExitCode); -#endif - } - CloseHandle(ShExecInfo.hProcess); - } - else - { - DWORD dwError = GetLastError(); - if (dwError == ERROR_CANCELLED) - { -#ifdef UPDATES_VERBOSE_OUTPUT - printf("[Updates] Update failed because the elevation request was denied.\n"); -#endif - } - else - { -#ifdef UPDATES_VERBOSE_OUTPUT - printf("[Updates] Update failed because the following error has occured: %d.\n", GetLastError()); -#endif } } } @@ -302,20 +155,247 @@ BOOL IsUpdateAvailableHelper( } InternetCloseHandle(hConnect); } + InternetCloseHandle(hInternet); + } + } + + if (!bUpdatePreferStaging && (hInternet = InternetOpenA( + UPDATES_USER_AGENT, + INTERNET_OPEN_TYPE_PRECONFIG, + NULL, + NULL, + 0 + ))) + { + HINTERNET hConnect = InternetOpenUrlA( + hInternet, + url, + NULL, + 0, + INTERNET_FLAG_RAW_DATA | + INTERNET_FLAG_RELOAD | + INTERNET_FLAG_RESYNCHRONIZE | + INTERNET_FLAG_NO_COOKIES | + INTERNET_FLAG_NO_UI | + INTERNET_FLAG_NO_CACHE_WRITE | + INTERNET_FLAG_DONT_CACHE, + ¶ms + ); + if (hConnect) + { + if (szCheckAgainst) + { + BOOL bRet = FALSE; + DWORD dwRead = 0; + char hash[DOSMODE_OFFSET + UPDATES_HASH_SIZE + 1]; + ZeroMemory(hash, DOSMODE_OFFSET + UPDATES_HASH_SIZE + 1); + if (bRet = InternetReadFile( + hConnect, + hash, + DOSMODE_OFFSET + UPDATES_HASH_SIZE, + &dwRead + ) && dwRead == DOSMODE_OFFSET + UPDATES_HASH_SIZE) + { +#ifdef UPDATES_VERBOSE_OUTPUT + printf("[Updates] Hash of remote file is \"%s\" (%s).\n", DOSMODE_OFFSET + hash, (hash[0] == 0x4D && hash[1] == 0x5A) ? "valid" : "invalid"); +#endif + if (hash[0] == 0x4D && hash[1] == 0x5A && _stricmp(DOSMODE_OFFSET + hash, szCheckAgainst)) + { + bIsUpdateAvailable = TRUE; + } + } + else + { +#ifdef UPDATES_VERBOSE_OUTPUT + printf("[Updates] Failed. Read %d bytes.\n"); +#endif + if (lpFail) *lpFail = TRUE; + } + } else { - if (lpFail) *lpFail = TRUE; + WCHAR wszPath[MAX_PATH]; + ZeroMemory(wszPath, MAX_PATH * sizeof(WCHAR)); + SHGetFolderPathW(NULL, SPECIAL_FOLDER_LEGACY, NULL, SHGFP_TYPE_CURRENT, wszPath); + wcscat_s(wszPath, MAX_PATH, _T(APP_RELATIVE_PATH)); + BOOL bRet = CreateDirectoryW(wszPath, NULL); + if (bRet || (!bRet && GetLastError() == ERROR_ALREADY_EXISTS)) + { + wcscat_s(wszPath, MAX_PATH, L"\\Update for " _T(PRODUCT_NAME) L" from "); + WCHAR wszURL[MAX_PATH]; + ZeroMemory(wszURL, MAX_PATH * sizeof(WCHAR)); + MultiByteToWideChar( + CP_UTF8, + MB_PRECOMPOSED, + url, + -1, + wszURL, + MAX_PATH + ); + if (wszURL[97]) + { + wszURL[96] = L'.'; + wszURL[97] = L'.'; + wszURL[98] = L'.'; + wszURL[99] = L'e'; + wszURL[100] = L'x'; + wszURL[101] = L'e'; + wszURL[102] = 0; + } + for (unsigned int i = 0; i < wszURL; ++i) + { + if (!wszURL[i]) + { + break; + } + if (wszURL[i] == L'/') + { + wszURL[i] = L'\u2215'; + } + else if (wszURL[i] == L':') + { + wszURL[i] = L'\ua789'; + } + } + wcscat_s(wszPath, MAX_PATH, wszURL); +#ifdef UPDATES_VERBOSE_OUTPUT + wprintf(L"[Updates] Download path is \"%s\".\n", wszPath); +#endif + + BOOL bRet = DeleteFileW(wszPath); + if (bRet || (!bRet && GetLastError() == ERROR_FILE_NOT_FOUND)) + { + FILE* f = NULL; + if (!_wfopen_s( + &f, + wszPath, + L"wb" + ) && f) + { + BYTE* buffer = (BYTE*)malloc(UPDATES_BUFSIZ); + if (buffer != NULL) + { + DWORD dwRead = 0; + bRet = FALSE; + while (bRet = InternetReadFile( + hConnect, + buffer, + UPDATES_BUFSIZ, + &dwRead + )) + { + if (dwRead == 0) + { + bIsUpdateAvailable = TRUE; +#ifdef UPDATES_VERBOSE_OUTPUT + printf("[Updates] Downloaded finished.\n"); +#endif + break; + } +#ifdef UPDATES_VERBOSE_OUTPUT + printf("[Updates] Downloaded %d bytes.\n", dwRead); +#endif + fwrite( + buffer, + sizeof(BYTE), + dwRead, + f + ); + dwRead = 0; + } + free(buffer); + } + fclose(f); + } + if (bIsUpdateAvailable) + { + bIsUpdateAvailable = FALSE; +#ifdef UPDATES_VERBOSE_OUTPUT + printf( + "[Updates] In order to install this update for the product \"" + PRODUCT_NAME + "\", please allow the elevation request.\n" + ); +#endif + + if (*toast) + { + notifier->lpVtbl->Hide(notifier, *toast); + (*toast)->lpVtbl->Release((*toast)); + (*toast) = NULL; + } + + SHELLEXECUTEINFO ShExecInfo = { 0 }; + ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); + ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; + ShExecInfo.hwnd = NULL; + ShExecInfo.lpVerb = L"runas"; + ShExecInfo.lpFile = wszPath; + ShExecInfo.lpParameters = L"/update_silent"; + ShExecInfo.lpDirectory = NULL; + ShExecInfo.nShow = SW_SHOW; + ShExecInfo.hInstApp = NULL; + if (ShellExecuteExW(&ShExecInfo) && ShExecInfo.hProcess) + { + WaitForSingleObject(ShExecInfo.hProcess, INFINITE); + DWORD dwExitCode = 0; + if (GetExitCodeProcess(ShExecInfo.hProcess, &dwExitCode) && !dwExitCode) + { + bIsUpdateAvailable = TRUE; +#ifdef UPDATES_VERBOSE_OUTPUT + printf("[Updates] Update successful, File Explorer will probably restart momentarly.\n"); +#endif + } + else + { + SetLastError(dwExitCode); +#ifdef UPDATES_VERBOSE_OUTPUT + printf("[Updates] Update failed because the following error has occured: %d.\n", dwExitCode); +#endif + } + CloseHandle(ShExecInfo.hProcess); + } + else + { + DWORD dwError = GetLastError(); + if (dwError == ERROR_CANCELLED) + { +#ifdef UPDATES_VERBOSE_OUTPUT + printf("[Updates] Update failed because the elevation request was denied.\n"); +#endif + } + else + { +#ifdef UPDATES_VERBOSE_OUTPUT + printf("[Updates] Update failed because the following error has occured: %d.\n", GetLastError()); +#endif + } + } + } + } + } } + InternetCloseHandle(hConnect); + } + else + { + if (lpFail) *lpFail = TRUE; } InternetCloseHandle(hInternet); } CloseHandle(params.hEvent); + if (staging_buffer) + { + free(staging_buffer); + staging_buffer = NULL; + } + return bIsUpdateAvailable; } -BOOL IsUpdateAvailable(LPCWSTR wszDataStore, char* szCheckAgainst, BOOL* lpFail) +BOOL IsUpdateAvailable(LPCWSTR wszDataStore, char* szCheckAgainst, BOOL* lpFail, WCHAR* wszInfoURL, DWORD dwInfoURLLen) { HKEY hKey = NULL; DWORD dwSize = 0; @@ -323,11 +403,12 @@ BOOL IsUpdateAvailable(LPCWSTR wszDataStore, char* szCheckAgainst, BOOL* lpFail) BOOL bIsPolicyMatch = FALSE; CHAR szUpdateURL[MAX_PATH]; ZeroMemory(szUpdateURL, MAX_PATH * sizeof(CHAR)); - strcat_s(szUpdateURL, MAX_PATH, DEFAULT_UPDATE_URL); + strcat_s(szUpdateURL, MAX_PATH, UPDATES_RELEASE_INFO_URL_STABLE); #ifdef UPDATES_VERBOSE_OUTPUT printf("[Updates] Checking against hash \"%s\"\n", szCheckAgainst); #endif DWORD dwUpdateTimeout = UPDATES_DEFAULT_TIMEOUT; + DWORD bUpdatePreferStaging = FALSE; RegCreateKeyExW( HKEY_CURRENT_USER, @@ -355,7 +436,20 @@ BOOL IsUpdateAvailable(LPCWSTR wszDataStore, char* szCheckAgainst, BOOL* lpFail) szUpdateURL, &dwSize ); + strcat_s(szUpdateURL, MAX_PATH, "/download/"); strcat_s(szUpdateURL, MAX_PATH, SETUP_UTILITY_NAME); + if (wszInfoURL) + { + dwSize = dwInfoURLLen; + RegQueryValueExW( + hKey, + L"UpdateURL", + 0, + NULL, + wszInfoURL, + &dwSize + ); + } dwSize = sizeof(DWORD); RegQueryValueExA( hKey, @@ -365,6 +459,29 @@ BOOL IsUpdateAvailable(LPCWSTR wszDataStore, char* szCheckAgainst, BOOL* lpFail) &dwUpdateTimeout, &dwSize ); + dwSize = sizeof(DWORD); + RegQueryValueExA( + hKey, + "UpdatePreferStaging", + 0, + NULL, + &bUpdatePreferStaging, + &dwSize + ); + if (bUpdatePreferStaging) + { + ZeroMemory(szUpdateURL, MAX_PATH * sizeof(CHAR)); + strcat_s(szUpdateURL, MAX_PATH, UPDATES_RELEASE_INFO_URL_STAGING); + dwSize = MAX_PATH; + RegQueryValueExA( + hKey, + "UpdateURLStaging", + 0, + NULL, + szUpdateURL, + &dwSize + ); + } RegCloseKey(hKey); } #ifdef UPDATES_VERBOSE_OUTPUT @@ -375,7 +492,10 @@ BOOL IsUpdateAvailable(LPCWSTR wszDataStore, char* szCheckAgainst, BOOL* lpFail) szCheckAgainst, dwUpdateTimeout, lpFail, - NULL, NULL, NULL + NULL, NULL, NULL, + bUpdatePreferStaging, + wszInfoURL, + dwInfoURLLen ); } @@ -392,9 +512,10 @@ BOOL UpdateProduct( BOOL bIsPolicyMatch = FALSE; CHAR szUpdateURL[MAX_PATH]; ZeroMemory(szUpdateURL, MAX_PATH * sizeof(CHAR)); - strcat_s(szUpdateURL, MAX_PATH, DEFAULT_UPDATE_URL); + strcat_s(szUpdateURL, MAX_PATH, UPDATES_RELEASE_INFO_URL_STABLE); DWORD dwUpdateTimeout = UPDATES_DEFAULT_TIMEOUT; + DWORD bUpdatePreferStaging = FALSE; RegCreateKeyExW( HKEY_CURRENT_USER, @@ -422,6 +543,7 @@ BOOL UpdateProduct( szUpdateURL, &dwSize ); + strcat_s(szUpdateURL, MAX_PATH, "/download/"); strcat_s(szUpdateURL, MAX_PATH, SETUP_UTILITY_NAME); dwSize = sizeof(DWORD); RegQueryValueExA( @@ -432,6 +554,29 @@ BOOL UpdateProduct( &dwUpdateTimeout, &dwSize ); + dwSize = sizeof(DWORD); + RegQueryValueExA( + hKey, + "UpdatePreferStaging", + 0, + NULL, + &bUpdatePreferStaging, + &dwSize + ); + if (bUpdatePreferStaging) + { + ZeroMemory(szUpdateURL, MAX_PATH * sizeof(CHAR)); + strcat_s(szUpdateURL, MAX_PATH, UPDATES_RELEASE_INFO_URL_STAGING); + dwSize = MAX_PATH; + RegQueryValueExA( + hKey, + "UpdateURLStaging", + 0, + NULL, + szUpdateURL, + &dwSize + ); + } RegCloseKey(hKey); } #ifdef UPDATES_VERBOSE_OUTPUT @@ -444,7 +589,9 @@ BOOL UpdateProduct( NULL, notifier, notifFactory, - toast + toast, + bUpdatePreferStaging, + NULL, 0 ); } @@ -459,6 +606,9 @@ BOOL InstallUpdatesIfAvailable( DWORD dwUpdatePolicy ) { + wchar_t wszInfoURL[MAX_PATH]; + ZeroMemory(wszInfoURL, MAX_PATH * sizeof(wchar_t)); + wcscat_s(wszInfoURL, MAX_PATH, _T(UPDATES_RELEASE_INFO_URL_STABLE)); wchar_t buf[TOAST_BUFSIZ]; DWORD dwLeftMost = 0; DWORD dwSecondLeft = 0; @@ -471,7 +621,7 @@ BOOL InstallUpdatesIfAvailable( __x_ABI_CWindows_CData_CXml_CDom_CIXmlDocument* inputXml = NULL; const wchar_t text[] = L"\r\n" + L"activationType=\"protocol\" launch=\"" _T(UPDATES_RELEASE_INFO_URL) L"\" duration=\"short\">\r\n" L" \r\n" L" \r\n" L" \r\n" @@ -568,7 +718,7 @@ BOOL InstallUpdatesIfAvailable( { const wchar_t text[] = L"\r\n" + L"activationType=\"protocol\" launch=\"" _T(UPDATES_RELEASE_INFO_URL) L"\" duration=\"long\">\r\n" L" \r\n" L" \r\n" L" \r\n" @@ -590,7 +740,7 @@ BOOL InstallUpdatesIfAvailable( { const wchar_t text[] = L"\r\n" + L"activationType=\"protocol\" launch=\"" _T(UPDATES_RELEASE_INFO_URL) L"\" duration=\"long\">\r\n" L" \r\n" L" \r\n" L" \r\n" @@ -637,7 +787,7 @@ BOOL InstallUpdatesIfAvailable( ComputeFileHash(dllName, hash, 100); BOOL bFail = FALSE; - if (IsUpdateAvailable(_T(REGPATH), hash, &bFail)) + if (IsUpdateAvailable(_T(REGPATH), hash, &bFail, wszInfoURL, MAX_PATH)) { printf("[Updates] An update is available.\n"); if ((dwOperation == UPDATES_OP_DEFAULT && dwUpdatePolicy == UPDATE_POLICY_AUTO) || (dwOperation == UPDATES_OP_INSTALL)) @@ -650,7 +800,7 @@ BOOL InstallUpdatesIfAvailable( { const wchar_t text[] = L"\r\n" + L"activationType=\"protocol\" launch=\"" _T(UPDATES_RELEASE_INFO_URL) L"\" duration=\"short\">\r\n" L" \r\n" L" \r\n" L" \r\n" @@ -691,7 +841,7 @@ BOOL InstallUpdatesIfAvailable( { const wchar_t text[] = L"\r\n" + L"activationType=\"protocol\" launch=\"%s\" duration=\"long\">\r\n" L" \r\n" L" \r\n" L" \r\n" @@ -701,10 +851,11 @@ BOOL InstallUpdatesIfAvailable( L" \r\n" L" \r\n"; + swprintf_s(buf, TOAST_BUFSIZ, text, wszInfoURL); __x_ABI_CWindows_CData_CXml_CDom_CIXmlDocument* inputXml = NULL; String2IXMLDocument( - text, - wcslen(text), + buf, + wcslen(buf), &inputXml, NULL ); @@ -741,7 +892,7 @@ BOOL InstallUpdatesIfAvailable( { const wchar_t text[] = L"\r\n" + L"activationType=\"protocol\" launch=\"" _T(UPDATES_RELEASE_INFO_URL) L"\" duration=\"short\">\r\n" L" \r\n" L" \r\n" L" \r\n" @@ -753,7 +904,7 @@ BOOL InstallUpdatesIfAvailable( L"\r\n"; const wchar_t text2[] = L"\r\n" + L"activationType=\"protocol\" launch=\"" _T(UPDATES_RELEASE_INFO_URL) L"\" duration=\"short\">\r\n" L" \r\n" L" \r\n" L" \r\n" diff --git a/ExplorerPatcher/updates.h b/ExplorerPatcher/updates.h index d83a7f2..f727a16 100644 --- a/ExplorerPatcher/updates.h +++ b/ExplorerPatcher/updates.h @@ -26,6 +26,10 @@ extern HMODULE hModule; #define UPDATES_BUFSIZ 10240 #define UPDATES_DEFAULT_TIMEOUT 600 +#define UPDATES_RELEASE_INFO_URL "https://github.com/valinet/ExplorerPatcher" +#define UPDATES_RELEASE_INFO_URL_STABLE "https://github.com/valinet/ExplorerPatcher/releases/latest" +#define UPDATES_RELEASE_INFO_URL_STAGING "https://api.github.com/repos/valinet/ExplorerPatcher/releases?per_page=1" + typedef struct IsUpdateAvailableParameters { HINTERNET hInternet; diff --git a/ExplorerPatcher/utility.h b/ExplorerPatcher/utility.h index c21faf2..d2b532a 100644 --- a/ExplorerPatcher/utility.h +++ b/ExplorerPatcher/utility.h @@ -28,7 +28,6 @@ #define EP_CLSID "{D17F1E1A-5919-4427-8F89-A1A8503CA3EB}" #define DOSMODE_OFFSET 78 #define SETUP_UTILITY_NAME "ep_setup.exe" -#define DEFAULT_UPDATE_URL "https://github.com/valinet/ExplorerPatcher/releases/latest/download/" #define TOAST_BUFSIZ 1024 #define SEH_REGPATH "Control Panel\\Quick Actions\\Control Center\\QuickActionsStateCapture\\ExplorerPatcher" diff --git a/version.h b/version.h index 8d09496..e735401 100644 --- a/version.h +++ b/version.h @@ -1,7 +1,7 @@ #define VER_MAJOR 22000 #define VER_MINOR 318 #define VER_BUILD_HI 38 -#define VER_BUILD_LO 8 +#define VER_BUILD_LO 9 #define VER_FLAGS VS_FF_PRERELEASE @@ -12,5 +12,5 @@ #define VER_STR(arg) #arg // The String form of the version numbers -#define VER_FILE_STRING VALUE "FileVersion", "22000.318.38.8" -#define VER_PRODUCT_STRING VALUE "ProductVersion", "22000.318.38.8" +#define VER_FILE_STRING VALUE "FileVersion", "22000.318.38.9" +#define VER_PRODUCT_STRING VALUE "ProductVersion", "22000.318.38.9"