Browse Source

Option to receive pre-release versions via the updater

pull/492/head 22000.318.38.9_65aa7a7
Valentin Radu 4 years ago
parent
commit
65aa7a732a
  1. 7
      CHANGELOG.md
  2. 2
      ExplorerPatcher/settings.reg
  3. 503
      ExplorerPatcher/updates.c
  4. 4
      ExplorerPatcher/updates.h
  5. 1
      ExplorerPatcher/utility.h
  6. 6
      version.h

7
CHANGELOG.md

@ -13,11 +13,11 @@ Tested on build 22000.318.
* Implemented support for Windows 7 battery flyout (#274) * Implemented support for Windows 7 battery flyout (#274)
* Implemented `/extract` switch which unpacks the files from `ep_setup.exe` to disk (#396) (.1): * 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` - 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 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 "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) * 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) * 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) * 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) * 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) * 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" * Small reorganization of some options in "Properties"
* Option to receive pre-release versions, if available, when checking for updates (.9)
#### Fixes #### Fixes

2
ExplorerPatcher/settings.reg

@ -337,6 +337,8 @@
;x 0 Prompt to install available updates ;x 0 Prompt to install available updates
;x 2 Do not check for updates ;x 2 Do not check for updates
"UpdatePolicy"=dword:00000001 "UpdatePolicy"=dword:00000001
;b Receive pre-release versions, if available (not recommended)
"UpdatePreferStaging"=dword:00000000
;t ________________________ ;t ________________________
;y Check for updates ;y Check for updates
;;;EP_CHECK_FOR_UPDATES ;;;EP_CHECK_FOR_UPDATES

503
ExplorerPatcher/updates.c

@ -61,7 +61,10 @@ BOOL IsUpdateAvailableHelper(
BOOL* lpFail, BOOL* lpFail,
__x_ABI_CWindows_CUI_CNotifications_CIToastNotifier* notifier, __x_ABI_CWindows_CUI_CNotifications_CIToastNotifier* notifier,
__x_ABI_CWindows_CUI_CNotifications_CIToastNotificationFactory* notifFactory, __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; BOOL bIsUpdateAvailable = FALSE;
@ -73,17 +76,18 @@ BOOL IsUpdateAvailableHelper(
return bIsUpdateAvailable; return bIsUpdateAvailable;
} }
char* staging_buffer = NULL;
HINTERNET hInternet = NULL; HINTERNET hInternet = NULL;
if (hInternet = InternetOpenA(
UPDATES_USER_AGENT, if (bUpdatePreferStaging)
INTERNET_OPEN_TYPE_PRECONFIG,
NULL,
NULL,
0 //INTERNET_FLAG_ASYNC
))
{ {
//InternetSetOptionA(hInternet, INTERNET_OPTION_CONNECT_TIMEOUT, &dwUpdateTimeout, sizeof(DWORD)); if (hInternet = InternetOpenA(
//if (InternetSetStatusCallbackA(hInternet, IsUpdateAvailableHelperCallback) != INTERNET_INVALID_STATUS_CALLBACK) UPDATES_USER_AGENT,
INTERNET_OPEN_TYPE_PRECONFIG,
NULL,
NULL,
0
))
{ {
HINTERNET hConnect = InternetOpenUrlA( HINTERNET hConnect = InternetOpenUrlA(
hInternet, hInternet,
@ -99,223 +103,299 @@ BOOL IsUpdateAvailableHelper(
INTERNET_FLAG_DONT_CACHE, INTERNET_FLAG_DONT_CACHE,
&params &params
); );
/*if (!hConnect && GetLastError() == ERROR_IO_PENDING)
{
if (WaitForSingleObject(params.hEvent, dwUpdateTimeout) == WAIT_OBJECT_0)
{
hConnect = params.hInternet;
}
}*/
if (hConnect) if (hConnect)
{ {
if (szCheckAgainst) DWORD dwSize = 5000;
DWORD dwRead = dwSize;
staging_buffer = calloc(dwSize, sizeof(char));
if (staging_buffer)
{ {
BOOL bRet = FALSE; 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( if (bRet = InternetReadFile(
hConnect, hConnect,
hash, staging_buffer,
DOSMODE_OFFSET + UPDATES_HASH_SIZE, dwSize - 1,
&dwRead &dwRead
) && dwRead == DOSMODE_OFFSET + UPDATES_HASH_SIZE) ))
{ {
#ifdef UPDATES_VERBOSE_OUTPUT char* a1 = strstr(staging_buffer, "\"browser_download_url\"");
printf("[Updates] Hash of remote file is \"%s\" (%s).\n", DOSMODE_OFFSET + hash, (hash[0] == 0x4D && hash[1] == 0x5A) ? "valid" : "invalid"); if (a1)
#endif
if (hash[0] == 0x4D && hash[1] == 0x5A && _stricmp(DOSMODE_OFFSET + hash, szCheckAgainst))
{ {
bIsUpdateAvailable = TRUE; char* a2 = strchr(a1 + 24, '"');
if (a2)
{
a2[0] = 0;
printf("[Updates] Prerelease update URL: \"%s\"\n", a1 + 24);
url = a1 + 24;
bUpdatePreferStaging = FALSE;
if (wszInfoURL)
{
char* a3 = strstr(staging_buffer, "\"html_url\"");
if (a3)
{
char* a4 = strchr(a3 + 12, '"');
if (a4)
{
a4[0] = 0;
printf("[Updates] Release notes URL: \"%s\"\n", a3 + 12);
MultiByteToWideChar(
CP_UTF8,
MB_PRECOMPOSED,
a3 + 12,
-1,
wszInfoURL,
dwInfoURLLen
);
}
}
}
}
} }
} }
else }
{ 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,
&params
);
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 #ifdef UPDATES_VERBOSE_OUTPUT
printf("[Updates] Failed. Read %d bytes.\n"); printf("[Updates] Hash of remote file is \"%s\" (%s).\n", DOSMODE_OFFSET + hash, (hash[0] == 0x4D && hash[1] == 0x5A) ? "valid" : "invalid");
#endif #endif
if (lpFail) *lpFail = TRUE; if (hash[0] == 0x4D && hash[1] == 0x5A && _stricmp(DOSMODE_OFFSET + hash, szCheckAgainst))
{
bIsUpdateAvailable = TRUE;
} }
} }
else else
{ {
WCHAR wszPath[MAX_PATH]; #ifdef UPDATES_VERBOSE_OUTPUT
ZeroMemory(wszPath, MAX_PATH * sizeof(WCHAR)); printf("[Updates] Failed. Read %d bytes.\n");
SHGetFolderPathW(NULL, SPECIAL_FOLDER_LEGACY, NULL, SHGFP_TYPE_CURRENT, wszPath); #endif
wcscat_s(wszPath, MAX_PATH, _T(APP_RELATIVE_PATH)); if (lpFail) *lpFail = TRUE;
BOOL bRet = CreateDirectoryW(wszPath, NULL); }
if (bRet || (!bRet && GetLastError() == ERROR_ALREADY_EXISTS)) }
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[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)
{ {
wcscat_s(wszPath, MAX_PATH, L"\\Update for " _T(PRODUCT_NAME) L" from "); if (!wszURL[i])
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'.'; break;
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] == L'/')
{ {
if (!wszURL[i]) wszURL[i] = L'\u2215';
{ }
break; else if (wszURL[i] == L':')
} {
if (wszURL[i] == L'/') wszURL[i] = L'\ua789';
{
wszURL[i] = L'\u2215';
}
else if (wszURL[i] == L':')
{
wszURL[i] = L'\ua789';
}
} }
wcscat_s(wszPath, MAX_PATH, wszURL); }
wcscat_s(wszPath, MAX_PATH, wszURL);
#ifdef UPDATES_VERBOSE_OUTPUT #ifdef UPDATES_VERBOSE_OUTPUT
wprintf(L"[Updates] Download path is \"%s\".\n", wszPath); wprintf(L"[Updates] Download path is \"%s\".\n", wszPath);
#endif #endif
BOOL bRet = DeleteFileW(wszPath); BOOL bRet = DeleteFileW(wszPath);
if (bRet || (!bRet && GetLastError() == ERROR_FILE_NOT_FOUND)) if (bRet || (!bRet && GetLastError() == ERROR_FILE_NOT_FOUND))
{
FILE* f = NULL;
if (!_wfopen_s(
&f,
wszPath,
L"wb"
) && f)
{ {
FILE* f = NULL; BYTE* buffer = (BYTE*)malloc(UPDATES_BUFSIZ);
if (!_wfopen_s( if (buffer != NULL)
&f,
wszPath,
L"wb"
) && f)
{ {
BYTE* buffer = (BYTE*)malloc(UPDATES_BUFSIZ); DWORD dwRead = 0;
if (buffer != NULL) bRet = FALSE;
while (bRet = InternetReadFile(
hConnect,
buffer,
UPDATES_BUFSIZ,
&dwRead
))
{ {
DWORD dwRead = 0; if (dwRead == 0)
bRet = FALSE;
while (bRet = InternetReadFile(
hConnect,
buffer,
UPDATES_BUFSIZ,
&dwRead
))
{ {
if (dwRead == 0) bIsUpdateAvailable = TRUE;
{
bIsUpdateAvailable = TRUE;
#ifdef UPDATES_VERBOSE_OUTPUT #ifdef UPDATES_VERBOSE_OUTPUT
printf("[Updates] Downloaded finished.\n"); printf("[Updates] Downloaded finished.\n");
#endif #endif
break; break;
} }
#ifdef UPDATES_VERBOSE_OUTPUT #ifdef UPDATES_VERBOSE_OUTPUT
printf("[Updates] Downloaded %d bytes.\n", dwRead); printf("[Updates] Downloaded %d bytes.\n", dwRead);
#endif #endif
fwrite( fwrite(
buffer, buffer,
sizeof(BYTE), sizeof(BYTE),
dwRead, dwRead,
f f
); );
dwRead = 0; dwRead = 0;
}
free(buffer);
} }
fclose(f); free(buffer);
} }
if (bIsUpdateAvailable) fclose(f);
{ }
bIsUpdateAvailable = FALSE; if (bIsUpdateAvailable)
{
bIsUpdateAvailable = FALSE;
#ifdef UPDATES_VERBOSE_OUTPUT #ifdef UPDATES_VERBOSE_OUTPUT
printf( printf(
"[Updates] In order to install this update for the product \"" "[Updates] In order to install this update for the product \""
PRODUCT_NAME PRODUCT_NAME
"\", please allow the elevation request.\n" "\", please allow the elevation request.\n"
); );
#endif #endif
if (*toast) if (*toast)
{ {
notifier->lpVtbl->Hide(notifier, *toast); notifier->lpVtbl->Hide(notifier, *toast);
(*toast)->lpVtbl->Release((*toast)); (*toast)->lpVtbl->Release((*toast));
(*toast) = NULL; (*toast) = NULL;
} }
SHELLEXECUTEINFO ShExecInfo = { 0 }; SHELLEXECUTEINFO ShExecInfo = { 0 };
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
ShExecInfo.hwnd = NULL; ShExecInfo.hwnd = NULL;
ShExecInfo.lpVerb = L"runas"; ShExecInfo.lpVerb = L"runas";
ShExecInfo.lpFile = wszPath; ShExecInfo.lpFile = wszPath;
ShExecInfo.lpParameters = L"/update_silent"; ShExecInfo.lpParameters = L"/update_silent";
ShExecInfo.lpDirectory = NULL; ShExecInfo.lpDirectory = NULL;
ShExecInfo.nShow = SW_SHOW; ShExecInfo.nShow = SW_SHOW;
ShExecInfo.hInstApp = NULL; ShExecInfo.hInstApp = NULL;
if (ShellExecuteExW(&ShExecInfo) && ShExecInfo.hProcess) if (ShellExecuteExW(&ShExecInfo) && ShExecInfo.hProcess)
{
WaitForSingleObject(ShExecInfo.hProcess, INFINITE);
DWORD dwExitCode = 0;
if (GetExitCodeProcess(ShExecInfo.hProcess, &dwExitCode) && !dwExitCode)
{ {
WaitForSingleObject(ShExecInfo.hProcess, INFINITE); bIsUpdateAvailable = TRUE;
DWORD dwExitCode = 0;
if (GetExitCodeProcess(ShExecInfo.hProcess, &dwExitCode) && !dwExitCode)
{
bIsUpdateAvailable = TRUE;
#ifdef UPDATES_VERBOSE_OUTPUT #ifdef UPDATES_VERBOSE_OUTPUT
printf("[Updates] Update successful, File Explorer will probably restart momentarly.\n"); printf("[Updates] Update successful, File Explorer will probably restart momentarly.\n");
#endif #endif
} }
else else
{ {
SetLastError(dwExitCode); SetLastError(dwExitCode);
#ifdef UPDATES_VERBOSE_OUTPUT #ifdef UPDATES_VERBOSE_OUTPUT
printf("[Updates] Update failed because the following error has occured: %d.\n", dwExitCode); printf("[Updates] Update failed because the following error has occured: %d.\n", dwExitCode);
#endif #endif
}
CloseHandle(ShExecInfo.hProcess);
} }
else CloseHandle(ShExecInfo.hProcess);
}
else
{
DWORD dwError = GetLastError();
if (dwError == ERROR_CANCELLED)
{ {
DWORD dwError = GetLastError();
if (dwError == ERROR_CANCELLED)
{
#ifdef UPDATES_VERBOSE_OUTPUT #ifdef UPDATES_VERBOSE_OUTPUT
printf("[Updates] Update failed because the elevation request was denied.\n"); printf("[Updates] Update failed because the elevation request was denied.\n");
#endif #endif
} }
else else
{ {
#ifdef UPDATES_VERBOSE_OUTPUT #ifdef UPDATES_VERBOSE_OUTPUT
printf("[Updates] Update failed because the following error has occured: %d.\n", GetLastError()); printf("[Updates] Update failed because the following error has occured: %d.\n", GetLastError());
#endif #endif
}
} }
} }
} }
} }
} }
InternetCloseHandle(hConnect);
}
else
{
if (lpFail) *lpFail = TRUE;
} }
InternetCloseHandle(hConnect);
}
else
{
if (lpFail) *lpFail = TRUE;
} }
InternetCloseHandle(hInternet); InternetCloseHandle(hInternet);
} }
CloseHandle(params.hEvent); CloseHandle(params.hEvent);
if (staging_buffer)
{
free(staging_buffer);
staging_buffer = NULL;
}
return bIsUpdateAvailable; 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; HKEY hKey = NULL;
DWORD dwSize = 0; DWORD dwSize = 0;
@ -323,11 +403,12 @@ BOOL IsUpdateAvailable(LPCWSTR wszDataStore, char* szCheckAgainst, BOOL* lpFail)
BOOL bIsPolicyMatch = FALSE; BOOL bIsPolicyMatch = FALSE;
CHAR szUpdateURL[MAX_PATH]; CHAR szUpdateURL[MAX_PATH];
ZeroMemory(szUpdateURL, MAX_PATH * sizeof(CHAR)); 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 #ifdef UPDATES_VERBOSE_OUTPUT
printf("[Updates] Checking against hash \"%s\"\n", szCheckAgainst); printf("[Updates] Checking against hash \"%s\"\n", szCheckAgainst);
#endif #endif
DWORD dwUpdateTimeout = UPDATES_DEFAULT_TIMEOUT; DWORD dwUpdateTimeout = UPDATES_DEFAULT_TIMEOUT;
DWORD bUpdatePreferStaging = FALSE;
RegCreateKeyExW( RegCreateKeyExW(
HKEY_CURRENT_USER, HKEY_CURRENT_USER,
@ -355,7 +436,20 @@ BOOL IsUpdateAvailable(LPCWSTR wszDataStore, char* szCheckAgainst, BOOL* lpFail)
szUpdateURL, szUpdateURL,
&dwSize &dwSize
); );
strcat_s(szUpdateURL, MAX_PATH, "/download/");
strcat_s(szUpdateURL, MAX_PATH, SETUP_UTILITY_NAME); strcat_s(szUpdateURL, MAX_PATH, SETUP_UTILITY_NAME);
if (wszInfoURL)
{
dwSize = dwInfoURLLen;
RegQueryValueExW(
hKey,
L"UpdateURL",
0,
NULL,
wszInfoURL,
&dwSize
);
}
dwSize = sizeof(DWORD); dwSize = sizeof(DWORD);
RegQueryValueExA( RegQueryValueExA(
hKey, hKey,
@ -365,6 +459,29 @@ BOOL IsUpdateAvailable(LPCWSTR wszDataStore, char* szCheckAgainst, BOOL* lpFail)
&dwUpdateTimeout, &dwUpdateTimeout,
&dwSize &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); RegCloseKey(hKey);
} }
#ifdef UPDATES_VERBOSE_OUTPUT #ifdef UPDATES_VERBOSE_OUTPUT
@ -375,7 +492,10 @@ BOOL IsUpdateAvailable(LPCWSTR wszDataStore, char* szCheckAgainst, BOOL* lpFail)
szCheckAgainst, szCheckAgainst,
dwUpdateTimeout, dwUpdateTimeout,
lpFail, lpFail,
NULL, NULL, NULL NULL, NULL, NULL,
bUpdatePreferStaging,
wszInfoURL,
dwInfoURLLen
); );
} }
@ -392,9 +512,10 @@ BOOL UpdateProduct(
BOOL bIsPolicyMatch = FALSE; BOOL bIsPolicyMatch = FALSE;
CHAR szUpdateURL[MAX_PATH]; CHAR szUpdateURL[MAX_PATH];
ZeroMemory(szUpdateURL, MAX_PATH * sizeof(CHAR)); 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 dwUpdateTimeout = UPDATES_DEFAULT_TIMEOUT;
DWORD bUpdatePreferStaging = FALSE;
RegCreateKeyExW( RegCreateKeyExW(
HKEY_CURRENT_USER, HKEY_CURRENT_USER,
@ -422,6 +543,7 @@ BOOL UpdateProduct(
szUpdateURL, szUpdateURL,
&dwSize &dwSize
); );
strcat_s(szUpdateURL, MAX_PATH, "/download/");
strcat_s(szUpdateURL, MAX_PATH, SETUP_UTILITY_NAME); strcat_s(szUpdateURL, MAX_PATH, SETUP_UTILITY_NAME);
dwSize = sizeof(DWORD); dwSize = sizeof(DWORD);
RegQueryValueExA( RegQueryValueExA(
@ -432,6 +554,29 @@ BOOL UpdateProduct(
&dwUpdateTimeout, &dwUpdateTimeout,
&dwSize &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); RegCloseKey(hKey);
} }
#ifdef UPDATES_VERBOSE_OUTPUT #ifdef UPDATES_VERBOSE_OUTPUT
@ -444,7 +589,9 @@ BOOL UpdateProduct(
NULL, NULL,
notifier, notifier,
notifFactory, notifFactory,
toast toast,
bUpdatePreferStaging,
NULL, 0
); );
} }
@ -459,6 +606,9 @@ BOOL InstallUpdatesIfAvailable(
DWORD dwUpdatePolicy 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]; wchar_t buf[TOAST_BUFSIZ];
DWORD dwLeftMost = 0; DWORD dwLeftMost = 0;
DWORD dwSecondLeft = 0; DWORD dwSecondLeft = 0;
@ -471,7 +621,7 @@ BOOL InstallUpdatesIfAvailable(
__x_ABI_CWindows_CData_CXml_CDom_CIXmlDocument* inputXml = NULL; __x_ABI_CWindows_CData_CXml_CDom_CIXmlDocument* inputXml = NULL;
const wchar_t text[] = const wchar_t text[] =
L"<toast displayTimestamp=\"2021-08-29T00:00:00.000Z\" scenario=\"reminder\" " L"<toast displayTimestamp=\"2021-08-29T00:00:00.000Z\" scenario=\"reminder\" "
L"activationType=\"protocol\" launch=\"https://github.com/valinet/ExplorerPatcher/releases/latest\" duration=\"short\">\r\n" L"activationType=\"protocol\" launch=\"" _T(UPDATES_RELEASE_INFO_URL) L"\" duration=\"short\">\r\n"
L" <visual>\r\n" L" <visual>\r\n"
L" <binding template=\"ToastGeneric\">\r\n" L" <binding template=\"ToastGeneric\">\r\n"
L" <text><![CDATA[Update successful]]></text>\r\n" L" <text><![CDATA[Update successful]]></text>\r\n"
@ -568,7 +718,7 @@ BOOL InstallUpdatesIfAvailable(
{ {
const wchar_t text[] = const wchar_t text[] =
L"<toast displayTimestamp=\"2021-08-29T00:00:00.000Z\" scenario=\"reminder\" " L"<toast displayTimestamp=\"2021-08-29T00:00:00.000Z\" scenario=\"reminder\" "
L"activationType=\"protocol\" launch=\"https://github.com/valinet/ExplorerPatcher/releases/latest\" duration=\"long\">\r\n" L"activationType=\"protocol\" launch=\"" _T(UPDATES_RELEASE_INFO_URL) L"\" duration=\"long\">\r\n"
L" <visual>\r\n" L" <visual>\r\n"
L" <binding template=\"ToastGeneric\">\r\n" L" <binding template=\"ToastGeneric\">\r\n"
L" <text><![CDATA[Downloading and installing updates]]></text>\r\n" L" <text><![CDATA[Downloading and installing updates]]></text>\r\n"
@ -590,7 +740,7 @@ BOOL InstallUpdatesIfAvailable(
{ {
const wchar_t text[] = const wchar_t text[] =
L"<toast displayTimestamp=\"2021-08-29T00:00:00.000Z\" scenario=\"reminder\" " L"<toast displayTimestamp=\"2021-08-29T00:00:00.000Z\" scenario=\"reminder\" "
L"activationType=\"protocol\" launch=\"https://github.com/valinet/ExplorerPatcher/releases/latest\" duration=\"long\">\r\n" L"activationType=\"protocol\" launch=\"" _T(UPDATES_RELEASE_INFO_URL) L"\" duration=\"long\">\r\n"
L" <visual>\r\n" L" <visual>\r\n"
L" <binding template=\"ToastGeneric\">\r\n" L" <binding template=\"ToastGeneric\">\r\n"
L" <text><![CDATA[Checking for updates]]></text>\r\n" L" <text><![CDATA[Checking for updates]]></text>\r\n"
@ -637,7 +787,7 @@ BOOL InstallUpdatesIfAvailable(
ComputeFileHash(dllName, hash, 100); ComputeFileHash(dllName, hash, 100);
BOOL bFail = FALSE; 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"); printf("[Updates] An update is available.\n");
if ((dwOperation == UPDATES_OP_DEFAULT && dwUpdatePolicy == UPDATE_POLICY_AUTO) || (dwOperation == UPDATES_OP_INSTALL)) if ((dwOperation == UPDATES_OP_DEFAULT && dwUpdatePolicy == UPDATE_POLICY_AUTO) || (dwOperation == UPDATES_OP_INSTALL))
@ -650,7 +800,7 @@ BOOL InstallUpdatesIfAvailable(
{ {
const wchar_t text[] = const wchar_t text[] =
L"<toast displayTimestamp=\"2021-08-29T00:00:00.000Z\" scenario=\"reminder\" " L"<toast displayTimestamp=\"2021-08-29T00:00:00.000Z\" scenario=\"reminder\" "
L"activationType=\"protocol\" launch=\"https://github.com/valinet/ExplorerPatcher/releases/latest\" duration=\"short\">\r\n" L"activationType=\"protocol\" launch=\"" _T(UPDATES_RELEASE_INFO_URL) L"\" duration=\"short\">\r\n"
L" <visual>\r\n" L" <visual>\r\n"
L" <binding template=\"ToastGeneric\">\r\n" L" <binding template=\"ToastGeneric\">\r\n"
L" <text><![CDATA[Update failed]]></text>\r\n" L" <text><![CDATA[Update failed]]></text>\r\n"
@ -691,7 +841,7 @@ BOOL InstallUpdatesIfAvailable(
{ {
const wchar_t text[] = const wchar_t text[] =
L"<toast displayTimestamp=\"2021-08-29T00:00:00.000Z\" scenario=\"reminder\" " L"<toast displayTimestamp=\"2021-08-29T00:00:00.000Z\" scenario=\"reminder\" "
L"activationType=\"protocol\" launch=\"https://github.com/valinet/ExplorerPatcher/releases/latest\" duration=\"long\">\r\n" L"activationType=\"protocol\" launch=\"%s\" duration=\"long\">\r\n"
L" <visual>\r\n" L" <visual>\r\n"
L" <binding template=\"ToastGeneric\">\r\n" L" <binding template=\"ToastGeneric\">\r\n"
L" <text><![CDATA[New version available]]></text>\r\n" L" <text><![CDATA[New version available]]></text>\r\n"
@ -701,10 +851,11 @@ BOOL InstallUpdatesIfAvailable(
L" </visual>\r\n" L" </visual>\r\n"
L" <audio src=\"ms-winsoundevent:Notification.Default\" loop=\"false\" silent=\"false\"/>\r\n" L" <audio src=\"ms-winsoundevent:Notification.Default\" loop=\"false\" silent=\"false\"/>\r\n"
L"</toast>\r\n"; L"</toast>\r\n";
swprintf_s(buf, TOAST_BUFSIZ, text, wszInfoURL);
__x_ABI_CWindows_CData_CXml_CDom_CIXmlDocument* inputXml = NULL; __x_ABI_CWindows_CData_CXml_CDom_CIXmlDocument* inputXml = NULL;
String2IXMLDocument( String2IXMLDocument(
text, buf,
wcslen(text), wcslen(buf),
&inputXml, &inputXml,
NULL NULL
); );
@ -741,7 +892,7 @@ BOOL InstallUpdatesIfAvailable(
{ {
const wchar_t text[] = const wchar_t text[] =
L"<toast displayTimestamp=\"2021-08-29T00:00:00.000Z\" scenario=\"reminder\" " L"<toast displayTimestamp=\"2021-08-29T00:00:00.000Z\" scenario=\"reminder\" "
L"activationType=\"protocol\" launch=\"https://github.com/valinet/ExplorerPatcher/releases/latest\" duration=\"short\">\r\n" L"activationType=\"protocol\" launch=\"" _T(UPDATES_RELEASE_INFO_URL) L"\" duration=\"short\">\r\n"
L" <visual>\r\n" L" <visual>\r\n"
L" <binding template=\"ToastGeneric\">\r\n" L" <binding template=\"ToastGeneric\">\r\n"
L" <text><![CDATA[No updates are available]]></text>\r\n" L" <text><![CDATA[No updates are available]]></text>\r\n"
@ -753,7 +904,7 @@ BOOL InstallUpdatesIfAvailable(
L"</toast>\r\n"; L"</toast>\r\n";
const wchar_t text2[] = const wchar_t text2[] =
L"<toast displayTimestamp=\"2021-08-29T00:00:00.000Z\" scenario=\"reminder\" " L"<toast displayTimestamp=\"2021-08-29T00:00:00.000Z\" scenario=\"reminder\" "
L"activationType=\"protocol\" launch=\"https://github.com/valinet/ExplorerPatcher/releases/latest\" duration=\"short\">\r\n" L"activationType=\"protocol\" launch=\"" _T(UPDATES_RELEASE_INFO_URL) L"\" duration=\"short\">\r\n"
L" <visual>\r\n" L" <visual>\r\n"
L" <binding template=\"ToastGeneric\">\r\n" L" <binding template=\"ToastGeneric\">\r\n"
L" <text><![CDATA[Unable to check for updates]]></text>\r\n" L" <text><![CDATA[Unable to check for updates]]></text>\r\n"

4
ExplorerPatcher/updates.h

@ -26,6 +26,10 @@ extern HMODULE hModule;
#define UPDATES_BUFSIZ 10240 #define UPDATES_BUFSIZ 10240
#define UPDATES_DEFAULT_TIMEOUT 600 #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 typedef struct IsUpdateAvailableParameters
{ {
HINTERNET hInternet; HINTERNET hInternet;

1
ExplorerPatcher/utility.h

@ -28,7 +28,6 @@
#define EP_CLSID "{D17F1E1A-5919-4427-8F89-A1A8503CA3EB}" #define EP_CLSID "{D17F1E1A-5919-4427-8F89-A1A8503CA3EB}"
#define DOSMODE_OFFSET 78 #define DOSMODE_OFFSET 78
#define SETUP_UTILITY_NAME "ep_setup.exe" #define SETUP_UTILITY_NAME "ep_setup.exe"
#define DEFAULT_UPDATE_URL "https://github.com/valinet/ExplorerPatcher/releases/latest/download/"
#define TOAST_BUFSIZ 1024 #define TOAST_BUFSIZ 1024
#define SEH_REGPATH "Control Panel\\Quick Actions\\Control Center\\QuickActionsStateCapture\\ExplorerPatcher" #define SEH_REGPATH "Control Panel\\Quick Actions\\Control Center\\QuickActionsStateCapture\\ExplorerPatcher"

6
version.h

@ -1,7 +1,7 @@
#define VER_MAJOR 22000 #define VER_MAJOR 22000
#define VER_MINOR 318 #define VER_MINOR 318
#define VER_BUILD_HI 38 #define VER_BUILD_HI 38
#define VER_BUILD_LO 8 #define VER_BUILD_LO 9
#define VER_FLAGS VS_FF_PRERELEASE #define VER_FLAGS VS_FF_PRERELEASE
@ -12,5 +12,5 @@
#define VER_STR(arg) #arg #define VER_STR(arg) #arg
// The String form of the version numbers // The String form of the version numbers
#define VER_FILE_STRING VALUE "FileVersion", "22000.318.38.8" #define VER_FILE_STRING VALUE "FileVersion", "22000.318.38.9"
#define VER_PRODUCT_STRING VALUE "ProductVersion", "22000.318.38.8" #define VER_PRODUCT_STRING VALUE "ProductVersion", "22000.318.38.9"

Loading…
Cancel
Save