Test
This commit is contained in:
18
launcher/CplTasks.xml
Normal file
18
launcher/CplTasks.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<applications xmlns="http://schemas.microsoft.com/windows/cpltasks/v1" xmlns:sh="http://schemas.microsoft.com/windows/tasks/v1">
|
||||
<application id="{FFBE8D44-E9CF-4DD8-9FD6-976802C94D9C}">
|
||||
<sh:task id="{9943E8C8-748D-47CE-AE10-9FA4A80ED28B}" needsElevation="true">
|
||||
<sh:name>@"%ProgramFiles%\Legacy Update\LegacyUpdate.exe",-3</sh:name>
|
||||
<sh:keywords>legacy update;legacyupdate;update;windows;microsoft;driver;security;software;</sh:keywords>
|
||||
<sh:command>"%ProgramFiles%\Legacy Update\LegacyUpdate.exe"</sh:command>
|
||||
</sh:task>
|
||||
|
||||
<category id="5">
|
||||
<sh:task idref="{9943E8C8-748D-47CE-AE10-9FA4A80ED28B}" />
|
||||
</category>
|
||||
|
||||
<category id="10">
|
||||
<sh:task idref="{9943E8C8-748D-47CE-AE10-9FA4A80ED28B}" />
|
||||
</category>
|
||||
</application>
|
||||
</applications>
|
298
launcher/InitRunOnce.c
Normal file
298
launcher/InitRunOnce.c
Normal file
@@ -0,0 +1,298 @@
|
||||
#include <windows.h>
|
||||
#include <commctrl.h>
|
||||
#include "MsgBox.h"
|
||||
#include "VersionInfo.h"
|
||||
#include "LoadImage.h"
|
||||
|
||||
#define HK_RUNCMD 1
|
||||
|
||||
typedef DWORD (__fastcall *_ThemeWaitForServiceReady)(DWORD timeout);
|
||||
typedef DWORD (__fastcall *_ThemeWatchForStart)();
|
||||
|
||||
static const COLORREF WallpaperColorWin2k = RGB(58, 110, 165); // #3a6ea5
|
||||
static const COLORREF WallpaperColorWinXP = RGB( 0, 78, 152); // #004e98
|
||||
static const COLORREF WallpaperColorWin8 = RGB(32, 103, 178); // #2067b2
|
||||
static const COLORREF WallpaperColorWin10 = RGB(24, 0, 82); // #180052
|
||||
|
||||
static const WCHAR RunOnceClassName[] = L"LegacyUpdateRunOnce";
|
||||
|
||||
static HANDLE g_cmdHandle;
|
||||
|
||||
static void StartThemes() {
|
||||
// Ask UxInit.dll to ask the Themes service to start a session for this desktop. Themes doesn't automatically start a
|
||||
// session for the SYSTEM desktop, so we need to ask it to. This matches what msoobe.exe does on first boot.
|
||||
|
||||
// Windows 7 moves this to UxInit.dll
|
||||
HMODULE shsvcs = LoadLibrary(L"UxInit.dll");
|
||||
if (!shsvcs) {
|
||||
shsvcs = LoadLibrary(L"shsvcs.dll");
|
||||
if (!shsvcs) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Get functions by ordinals
|
||||
_ThemeWaitForServiceReady $ThemeWaitForServiceReady = (_ThemeWaitForServiceReady)GetProcAddress(shsvcs, MAKEINTRESOURCEA(2));
|
||||
_ThemeWatchForStart $ThemeWatchForStart = (_ThemeWatchForStart)GetProcAddress(shsvcs, MAKEINTRESOURCEA(1));
|
||||
|
||||
// 1. Wait up to 1000ms for Themes to start
|
||||
if ($ThemeWaitForServiceReady) {
|
||||
$ThemeWaitForServiceReady(1000);
|
||||
}
|
||||
|
||||
// 2. Prompt Themes to start a session for the SYSTEM desktop
|
||||
if ($ThemeWatchForStart) {
|
||||
$ThemeWatchForStart();
|
||||
}
|
||||
|
||||
FreeLibrary(shsvcs);
|
||||
}
|
||||
|
||||
static BOOL RunCmd(LPPROCESS_INFORMATION processInfo) {
|
||||
WCHAR cmd[MAX_PATH];
|
||||
ExpandEnvironmentStrings(L"%SystemRoot%\\System32\\cmd.exe", cmd, ARRAYSIZE(cmd));
|
||||
|
||||
STARTUPINFO startupInfo = {0};
|
||||
startupInfo.cb = sizeof(startupInfo);
|
||||
|
||||
if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &startupInfo, processInfo)) {
|
||||
MsgBox(NULL, L"Launching cmd.exe failed", NULL, MB_OK | MB_ICONERROR);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CloseHandle(processInfo->hThread);
|
||||
g_cmdHandle = processInfo->hProcess;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK RunOnceWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
switch (message) {
|
||||
case WM_NCHITTEST:
|
||||
// Don't accept any mouse input
|
||||
return HTNOWHERE;
|
||||
|
||||
case WM_HOTKEY: {
|
||||
// Shift-F10 to run cmd
|
||||
if (wParam == HK_RUNCMD) {
|
||||
DWORD exitCode;
|
||||
if (!g_cmdHandle || (GetExitCodeProcess(g_cmdHandle, &exitCode) && exitCode != STILL_ACTIVE)) {
|
||||
PROCESS_INFORMATION processInfo;
|
||||
RunCmd(&processInfo);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, message, wParam, lParam);;
|
||||
}
|
||||
|
||||
static void CreateRunOnceWindow() {
|
||||
// Init common controls
|
||||
INITCOMMONCONTROLSEX initComctl = {0};
|
||||
initComctl.dwSize = sizeof(initComctl);
|
||||
initComctl.dwICC = ICC_WIN95_CLASSES;
|
||||
InitCommonControlsEx(&initComctl);
|
||||
|
||||
// Create window
|
||||
WNDCLASS wndClass = {0};
|
||||
wndClass.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC | CS_NOCLOSE;
|
||||
wndClass.lpfnWndProc = RunOnceWndProc;
|
||||
wndClass.hInstance = GetModuleHandle(NULL);
|
||||
wndClass.lpszClassName = RunOnceClassName;
|
||||
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
|
||||
if (!RegisterClass(&wndClass)) {
|
||||
TRACE(L"RegisterClass failed: %d", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
HWND hwnd = CreateWindowEx(
|
||||
WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE,
|
||||
wndClass.lpszClassName,
|
||||
L"Legacy Update",
|
||||
WS_POPUP,
|
||||
0, 0, 0, 0,
|
||||
NULL, NULL,
|
||||
wndClass.hInstance,
|
||||
NULL
|
||||
);
|
||||
if (!hwnd) {
|
||||
TRACE(L"CreateWindow failed: %d", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
// Register hotkey
|
||||
RegisterHotKey(hwnd, HK_RUNCMD, MOD_SHIFT, VK_F10);
|
||||
|
||||
// Check if the display is 8-bit color or lower
|
||||
HDC dc = GetDC(NULL);
|
||||
int bpp = GetDeviceCaps(dc, BITSPIXEL);
|
||||
ReleaseDC(NULL, dc);
|
||||
if (bpp >= 8) {
|
||||
// Set the wallpaper color
|
||||
COLORREF color = GetSysColor(COLOR_DESKTOP);
|
||||
if (AtLeastWin10()) {
|
||||
color = WallpaperColorWin10;
|
||||
} else if (AtLeastWin8()) {
|
||||
color = WallpaperColorWin8;
|
||||
} else if ((IsWinXP2002() || IsWinXP2003()) && color == RGB(0, 0, 0)) {
|
||||
// XP uses a black wallpaper in fast user switching mode. Override to the default blue.
|
||||
color = WallpaperColorWinXP;
|
||||
}
|
||||
SetSysColors(1, (const INT[1]){COLOR_DESKTOP}, (const COLORREF[1]){color});
|
||||
|
||||
DWORD width = GetSystemMetrics(SM_CXSCREEN);
|
||||
DWORD height = GetSystemMetrics(SM_CYSCREEN);
|
||||
HBITMAP wallpaper;
|
||||
|
||||
if (IsWin7()) {
|
||||
// 7: Bitmap in oobe dir
|
||||
WCHAR bmpPath[MAX_PATH];
|
||||
ExpandEnvironmentStrings(L"%SystemRoot%\\System32\\oobe\\background.bmp", bmpPath, ARRAYSIZE(bmpPath));
|
||||
wallpaper = LoadImage(NULL, bmpPath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
|
||||
} else if (IsWinVista()) {
|
||||
// Vista: Resources in ooberesources.dll
|
||||
WCHAR ooberesPath[MAX_PATH];
|
||||
ExpandEnvironmentStrings(L"%SystemRoot%\\System32\\oobe\\ooberesources.dll", ooberesPath, ARRAYSIZE(ooberesPath));
|
||||
HMODULE ooberes = LoadLibrary(ooberesPath);
|
||||
if (ooberes) {
|
||||
// Width logic is the same used by Vista msoobe.dll
|
||||
LPWSTR resource = GetSystemMetrics(SM_CXSCREEN) < 1200 ? L"OOBE_BACKGROUND_0" : L"OOBE_BACKGROUND_LARGE_0";
|
||||
wallpaper = LoadPNGResource(ooberes, resource, RT_RCDATA);
|
||||
}
|
||||
FreeLibrary(ooberes);
|
||||
}
|
||||
|
||||
if (wallpaper) {
|
||||
// Write to disk
|
||||
WCHAR tempPath[MAX_PATH];
|
||||
ExpandEnvironmentStrings(L"%ProgramData%\\Legacy Update\\background.bmp", tempPath, ARRAYSIZE(tempPath));
|
||||
if (GetFileAttributes(tempPath) != INVALID_FILE_ATTRIBUTES || ScaleAndWriteToBMP(wallpaper, width, height, tempPath)) {
|
||||
SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, (PVOID)tempPath, SPIF_SENDWININICHANGE);
|
||||
}
|
||||
|
||||
DeleteObject(wallpaper);
|
||||
}
|
||||
}
|
||||
|
||||
ShowWindow(hwnd, SW_SHOW);
|
||||
UpdateWindow(hwnd);
|
||||
}
|
||||
|
||||
static BOOL IsSystemUser() {
|
||||
BOOL result = FALSE;
|
||||
PTOKEN_USER tokenInfo;
|
||||
PSID systemSid;
|
||||
HANDLE token;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
DWORD tokenInfoLen;
|
||||
GetTokenInformation(token, TokenUser, NULL, 0, &tokenInfoLen);
|
||||
tokenInfo = (PTOKEN_USER)LocalAlloc(LPTR, tokenInfoLen);
|
||||
if (!GetTokenInformation(token, TokenUser, tokenInfo, tokenInfoLen, &tokenInfoLen)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
DWORD sidSize = SECURITY_MAX_SID_SIZE;
|
||||
systemSid = LocalAlloc(LPTR, sidSize);
|
||||
if (!CreateWellKnownSid(WinLocalSystemSid, NULL, systemSid, &sidSize)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
result = EqualSid(tokenInfo->User.Sid, systemSid);
|
||||
|
||||
end:
|
||||
if (tokenInfo) {
|
||||
LocalFree(tokenInfo);
|
||||
}
|
||||
if (systemSid) {
|
||||
LocalFree(systemSid);
|
||||
}
|
||||
if (token) {
|
||||
CloseHandle(token);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void RunOnce() {
|
||||
#ifndef _DEBUG
|
||||
// Only relevant if we're SYSTEM
|
||||
if (!IsSystemUser()) {
|
||||
PostQuitMessage(1);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Start Themes on this desktop
|
||||
StartThemes();
|
||||
|
||||
// Find and hide the FirstUxWnd window, if it exists (Windows 7+)
|
||||
HWND firstUxWnd = FindWindow(L"FirstUxWndClass", NULL);
|
||||
if (firstUxWnd) {
|
||||
ShowWindow(firstUxWnd, SW_HIDE);
|
||||
}
|
||||
|
||||
// Set up our window
|
||||
CreateRunOnceWindow();
|
||||
|
||||
// Construct path to LegacyUpdateSetup.exe
|
||||
WCHAR setupPath[MAX_PATH];
|
||||
GetModuleFileName(NULL, setupPath, ARRAYSIZE(setupPath));
|
||||
wcsrchr(setupPath, L'\\')[1] = L'\0';
|
||||
wcsncat(setupPath, L"LegacyUpdateSetup.exe", ARRAYSIZE(setupPath) - wcslen(setupPath) - 1);
|
||||
|
||||
// Execute and wait for completion
|
||||
STARTUPINFO startupInfo = {0};
|
||||
startupInfo.cb = sizeof(startupInfo);
|
||||
|
||||
PROCESS_INFORMATION processInfo = {0};
|
||||
LPWSTR cmdLine = (LPWSTR)LocalAlloc(LPTR, 4096 * sizeof(WCHAR));
|
||||
wsprintf(cmdLine, L"\"%ls\" /runonce", setupPath);
|
||||
if (!CreateProcess(setupPath, cmdLine, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &startupInfo, &processInfo)) {
|
||||
#ifdef _DEBUG
|
||||
// Run cmd.exe instead
|
||||
if (!RunCmd(&processInfo)) {
|
||||
PostQuitMessage(0);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
MsgBox(NULL, L"Continuing Legacy Update setup failed", NULL, MB_OK | MB_ICONERROR);
|
||||
PostQuitMessage(0);
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
CloseHandle(processInfo.hThread);
|
||||
|
||||
// Wait for it to finish, while running a message loop
|
||||
MSG msg;
|
||||
while (WaitForSingleObject(processInfo.hProcess, 100) == WAIT_TIMEOUT) {
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(processInfo.hProcess);
|
||||
|
||||
// Don't let SYSTEM cmd keep running beyond runonce
|
||||
if (g_cmdHandle) {
|
||||
TerminateProcess(g_cmdHandle, 0);
|
||||
CloseHandle(g_cmdHandle);
|
||||
}
|
||||
|
||||
// Show FirstUxWnd again
|
||||
if (firstUxWnd) {
|
||||
ShowWindow(firstUxWnd, SW_SHOW);
|
||||
}
|
||||
|
||||
PostQuitMessage(0);
|
||||
}
|
205
launcher/LaunchUpdateSite.c
Normal file
205
launcher/LaunchUpdateSite.c
Normal file
@@ -0,0 +1,205 @@
|
||||
#include "stdafx.h"
|
||||
#include "main.h"
|
||||
#include "resource.h"
|
||||
#include <exdisp.h>
|
||||
#include "Exec.h"
|
||||
#include "HResult.h"
|
||||
#include "MsgBox.h"
|
||||
#include "RegisterServer.h"
|
||||
#include "Registry.h"
|
||||
#include "SelfElevate.h"
|
||||
#include "User.h"
|
||||
#include "VersionInfo.h"
|
||||
|
||||
const LPWSTR UpdateSiteURLHttp = L"http://legacyupdate.net/windowsupdate/v6/";
|
||||
const LPWSTR UpdateSiteURLHttps = L"https://legacyupdate.net/windowsupdate/v6/";
|
||||
const LPWSTR UpdateSiteFirstRunFlag = L"?firstrun=true";
|
||||
|
||||
DEFINE_GUID(IID_ILegacyUpdateCtrl, 0xC33085BB, 0xC3E1, 0x4D27, 0xA2, 0x14, 0xAF, 0x01, 0x95, 0x3D, 0xF5, 0xE5);
|
||||
DEFINE_GUID(CLSID_LegacyUpdateCtrl, 0xAD28E0DF, 0x5F5A, 0x40B5, 0x94, 0x32, 0x85, 0xEF, 0xD9, 0x7D, 0x1F, 0x9F);
|
||||
|
||||
static const LPWSTR GetUpdateSiteURL() {
|
||||
// Fallback: Use SSL only on Vista and up
|
||||
BOOL useHTTPS = AtLeastWinVista();
|
||||
|
||||
// Get the Windows Update website URL set by Legacy Update setup
|
||||
LPWSTR data;
|
||||
DWORD size;
|
||||
HRESULT hr = GetRegistryString(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate", L"URL", KEY_WOW64_64KEY, &data, &size);
|
||||
if (SUCCEEDED(hr)) {
|
||||
// Return based on the URL value
|
||||
if (wcscmp(data, UpdateSiteURLHttps) == 0) {
|
||||
useHTTPS = TRUE;
|
||||
} else if (wcscmp(data, UpdateSiteURLHttp) == 0) {
|
||||
useHTTPS = FALSE;
|
||||
}
|
||||
LocalFree(data);
|
||||
}
|
||||
|
||||
return useHTTPS ? UpdateSiteURLHttps : UpdateSiteURLHttp;
|
||||
}
|
||||
|
||||
void LaunchUpdateSite(int argc, LPWSTR *argv, int nCmdShow) {
|
||||
HRESULT hr = S_OK;
|
||||
IWebBrowser2 *browser;
|
||||
VARIANT url;
|
||||
VARIANT flags;
|
||||
VARIANT nullVariant;
|
||||
LPTSTR siteURL;
|
||||
HMONITOR monitor;
|
||||
|
||||
// If running on 2k/XP, make sure we're elevated. If not, show Run As prompt.
|
||||
if (!AtLeastWinVista() && !IsUserAdmin()) {
|
||||
LPWSTR args = (LPWSTR)LocalAlloc(LPTR, 512 * sizeof(WCHAR));
|
||||
wsprintf(args, L"/launch %ls", argc > 0 ? argv[0] : L"");
|
||||
hr = SelfElevate(args, NULL);
|
||||
|
||||
// Access denied happens when the user clicks No/Cancel.
|
||||
if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) {
|
||||
hr = S_OK;
|
||||
}
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Can we instantiate our own ActiveX control? If not, try to register it.
|
||||
hr = CoCreateInstance(&CLSID_LegacyUpdateCtrl, NULL, CLSCTX_LOCAL_SERVER, &IID_ILegacyUpdateCtrl, (void **)&browser);
|
||||
if (hr == REGDB_E_CLASSNOTREG) {
|
||||
hr = RegisterServer(0, TRUE, TRUE);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
hr = CoCreateInstance(&CLSID_LegacyUpdateCtrl, NULL, CLSCTX_LOCAL_SERVER, &IID_ILegacyUpdateCtrl, (void **)&browser);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
IUnknown_Release(browser);
|
||||
} else if (!SUCCEEDED(hr)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Spawn an IE window via the COM interface. This ensures the page opens in IE (ShellExecute uses
|
||||
// default browser), and avoids hardcoding a path to iexplore.exe. Also conveniently allows testing
|
||||
// on Windows 11 (iexplore.exe redirects to Edge, but COM still works). Same strategy as used by
|
||||
// Wupdmgr.exe and Muweb.dll,LaunchMUSite.
|
||||
hr = CoCreateInstance(&CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, &IID_IWebBrowser2, (void **)&browser);
|
||||
if (hr == REGDB_E_CLASSNOTREG) {
|
||||
// Handle case where the user has uninstalled Internet Explorer using Programs and Features.
|
||||
OSVERSIONINFOEX *versionInfo = GetVersionInfo();
|
||||
|
||||
// Windows 8+: Directly prompt to reinstall IE using Fondue.exe.
|
||||
if (AtLeastWin8()) {
|
||||
SYSTEM_INFO systemInfo;
|
||||
GetSystemInfo(&systemInfo);
|
||||
LPCTSTR archSuffix = systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ? L"amd64" : L"x86";
|
||||
|
||||
WCHAR fondue[MAX_PATH];
|
||||
ExpandEnvironmentStrings(L"%SystemRoot%\\System32\\fondue.exe", fondue, ARRAYSIZE(fondue));
|
||||
|
||||
WCHAR fondueArgs[256];
|
||||
wsprintf(fondueArgs, L"/enable-feature:Internet-Explorer-Optional-%ls", archSuffix);
|
||||
hr = Exec(NULL, fondue, fondueArgs, NULL, SW_SHOWDEFAULT, FALSE, NULL);
|
||||
if (SUCCEEDED(hr)) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
// Tell the user what they need to do, then open the Optional Features dialog.
|
||||
WCHAR message[4096];
|
||||
LoadString(GetModuleHandle(NULL), IDS_IENOTINSTALLED, message, ARRAYSIZE(message));
|
||||
MsgBox(NULL, message, NULL, MB_OK | MB_ICONEXCLAMATION);
|
||||
|
||||
WCHAR optionalFeatures[MAX_PATH];
|
||||
ExpandEnvironmentStrings(L"%SystemRoot%\\System32\\OptionalFeatures.exe", optionalFeatures, ARRAYSIZE(optionalFeatures));
|
||||
Exec(NULL, optionalFeatures, NULL, NULL, SW_SHOWDEFAULT, FALSE, NULL);
|
||||
hr = S_OK;
|
||||
goto end;
|
||||
} else if (!SUCCEEDED(hr)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Can we connect with https? WinInet will throw an error if not.
|
||||
siteURL = GetUpdateSiteURL();
|
||||
|
||||
// Is this a first run launch? Append first run flag if so.
|
||||
if (argc > 0 && lstrcmpi(argv[0], L"/firstrun") == 0) {
|
||||
WCHAR newSiteURL[256];
|
||||
wsprintf(newSiteURL, L"%s%s", siteURL, UpdateSiteFirstRunFlag);
|
||||
siteURL = newSiteURL;
|
||||
}
|
||||
|
||||
VariantInit(&url);
|
||||
url.vt = VT_BSTR;
|
||||
url.bstrVal = SysAllocString(siteURL);
|
||||
|
||||
VariantInit(&flags);
|
||||
flags.vt = VT_I4;
|
||||
flags.lVal = 0;
|
||||
|
||||
VariantInit(&nullVariant);
|
||||
|
||||
hr = IWebBrowser2_Navigate2(browser, &url, &flags, &nullVariant, &nullVariant, &nullVariant);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
HWND ieHwnd;
|
||||
hr = IWebBrowser2_get_HWND(browser, (SHANDLE_PTR *)&ieHwnd);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Are we on a small display? If so, resize and maximise the window.
|
||||
monitor = MonitorFromWindow(ieHwnd, MONITOR_DEFAULTTONEAREST);
|
||||
MONITORINFO monitorInfo;
|
||||
monitorInfo.cbSize = sizeof(MONITORINFO);
|
||||
|
||||
if (GetMonitorInfo(monitor, &monitorInfo) > 0) {
|
||||
LONG workWidth = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
|
||||
LONG workHeight = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
|
||||
|
||||
LONG width, height;
|
||||
IWebBrowser2_get_Width(browser, &width);
|
||||
IWebBrowser2_get_Height(browser, &height);
|
||||
|
||||
if (width < 800) {
|
||||
width = workWidth < 800 ? workWidth : 800;
|
||||
IWebBrowser2_put_Width(browser, width);
|
||||
}
|
||||
if (height < 600) {
|
||||
height = workHeight < 600 ? workHeight : 600;
|
||||
IWebBrowser2_put_Height(browser, height);
|
||||
}
|
||||
|
||||
LONG left, top;
|
||||
IWebBrowser2_get_Left(browser, &left);
|
||||
IWebBrowser2_get_Top(browser, &top);
|
||||
|
||||
if (left + width > workWidth) {
|
||||
IWebBrowser2_put_Left(browser, 0);
|
||||
}
|
||||
if (top + height > workHeight) {
|
||||
IWebBrowser2_put_Top(browser, 0);
|
||||
}
|
||||
|
||||
if (workWidth <= 1152) {
|
||||
ShowWindow(ieHwnd, SW_MAXIMIZE);
|
||||
}
|
||||
}
|
||||
|
||||
IWebBrowser2_put_Visible(browser, TRUE);
|
||||
|
||||
// Focus the window, since it seems to not always get focus as it should.
|
||||
SetForegroundWindow(ieHwnd);
|
||||
|
||||
end:
|
||||
if (!SUCCEEDED(hr)) {
|
||||
MsgBox(NULL, GetMessageForHresult(hr), NULL, MB_ICONEXCLAMATION);
|
||||
}
|
||||
|
||||
browser = NULL;
|
||||
CoUninitialize();
|
||||
PostQuitMessage(0);
|
||||
}
|
11
launcher/Log.c
Normal file
11
launcher/Log.c
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "WULog.h"
|
||||
#include "MsgBox.h"
|
||||
|
||||
void LaunchLog(int nCmdShow) {
|
||||
HRESULT hr = ViewWindowsUpdateLog(nCmdShow);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
MsgBox(NULL, GetMessageForHresult(hr), NULL, MB_OK);
|
||||
}
|
||||
|
||||
PostQuitMessage(hr);
|
||||
}
|
8
launcher/Makefile
Normal file
8
launcher/Makefile
Normal file
@@ -0,0 +1,8 @@
|
||||
all:
|
||||
+$(MAKE) -f Makefile.actual ARCH=32
|
||||
+$(MAKE) -f Makefile.actual ARCH=64
|
||||
|
||||
clean:
|
||||
rm -rf obj
|
||||
|
||||
.PHONY: all clean
|
126
launcher/Makefile.actual
Normal file
126
launcher/Makefile.actual
Normal file
@@ -0,0 +1,126 @@
|
||||
FILES = \
|
||||
$(wildcard *.c) \
|
||||
../shared/Exec.c \
|
||||
../shared/HResult.c \
|
||||
../shared/LegacyUpdate.c \
|
||||
../shared/LoadImage.c \
|
||||
../shared/Registry.c \
|
||||
../shared/VersionInfo.c \
|
||||
../shared/Wow64.c
|
||||
RCFILES = resource.rc
|
||||
DEFFILES = ../LegacyUpdate/LegacyUpdate.def
|
||||
|
||||
ARCH ?= 32
|
||||
|
||||
ifeq ($(ARCH),64)
|
||||
TAG = x86_64
|
||||
else
|
||||
TAG = i686
|
||||
endif
|
||||
|
||||
PREFIX = $(TAG)-w64-mingw32-
|
||||
|
||||
BIN = obj/LegacyUpdate$(ARCH).exe
|
||||
OBJ = $(foreach file,$(FILES),obj/$(notdir $(basename $(file)).$(TAG).o))
|
||||
RES = $(foreach file,$(RCFILES),obj/$(notdir $(basename $(file)).$(TAG).res))
|
||||
DEFDLL = $(foreach file,$(DEFFILES),obj/lib$(notdir $(basename $(file)).$(TAG).a))
|
||||
|
||||
CC = $(PREFIX)g++
|
||||
RC = $(PREFIX)windres
|
||||
DLLTOOL = $(PREFIX)dlltool
|
||||
|
||||
override DEBUG := $(or $(DEBUG),1)
|
||||
|
||||
CFLAGS = \
|
||||
-mwindows \
|
||||
-municode \
|
||||
-DUNICODE \
|
||||
-D_UNICODE \
|
||||
$(if $(filter 1,$(DEBUG)),-D_DEBUG -g,-DNDEBUG -Os) \
|
||||
-s \
|
||||
-fPIE \
|
||||
-ffunction-sections \
|
||||
-fdata-sections \
|
||||
-fno-unwind-tables \
|
||||
-fno-asynchronous-unwind-tables \
|
||||
-fno-exceptions \
|
||||
-flto \
|
||||
-Wno-write-strings \
|
||||
-I../include \
|
||||
-I../shared \
|
||||
-include stdafx.h
|
||||
|
||||
CXXFLAGS = \
|
||||
$(CFLAGS) \
|
||||
-std=c++11 \
|
||||
-fno-rtti
|
||||
|
||||
LDFLAGS = \
|
||||
-nodefaultlibs \
|
||||
-nostartfiles \
|
||||
-nostdlib \
|
||||
-Wl,--gc-sections \
|
||||
-Wl,--no-seh \
|
||||
-Wl,--nxcompat \
|
||||
-Wl,--enable-auto-image-base \
|
||||
-Wl,--enable-stdcall-fixup \
|
||||
-Wl,--strip-all \
|
||||
-Lobj \
|
||||
-lmsvcrt \
|
||||
-lgcc \
|
||||
-lpsapi \
|
||||
-lkernel32 \
|
||||
-luser32 \
|
||||
-lole32 \
|
||||
-loleaut32 \
|
||||
-ladvapi32 \
|
||||
-lcomctl32 \
|
||||
-lshell32 \
|
||||
-lversion \
|
||||
-lgdi32 \
|
||||
-lmsimg32
|
||||
|
||||
RCFLAGS = \
|
||||
-O coff \
|
||||
-I../shared
|
||||
|
||||
ifeq ($(ARCH),64)
|
||||
LDFLAGS += -Wl,-ewWinMain
|
||||
RCFLAGS += -F pe-x86-64
|
||||
else
|
||||
CFLAGS += -march=i486
|
||||
LDFLAGS += -Wl,-e_wWinMain
|
||||
RCFLAGS += -F pe-i386
|
||||
endif
|
||||
|
||||
all: before-all $(DEFDLL) $(BIN)
|
||||
ifeq ($(SIGN),1)
|
||||
../build/sign.sh $(BIN)
|
||||
endif
|
||||
|
||||
before-all:
|
||||
mkdir -p obj
|
||||
|
||||
$(BIN): $(OBJ) $(RES)
|
||||
$(CC) $^ $(CFLAGS) $(LDFLAGS) -o $@
|
||||
|
||||
obj/%.$(TAG).o: %.c
|
||||
$(CC) -x c $< $(CFLAGS) -c -o $@
|
||||
|
||||
obj/%.$(TAG).o: ../shared/%.c
|
||||
$(CC) -x c $< $(CFLAGS) -c -o $@
|
||||
|
||||
obj/%.$(TAG).res: %.rc
|
||||
$(RC) $< $(RCFLAGS) -o $@
|
||||
|
||||
obj/lib%.$(TAG).a: ../LegacyUpdate/%.def
|
||||
$(DLLTOOL) -d $< -l $@ -D $(notdir $(basename $<).dll)
|
||||
|
||||
clean:
|
||||
rm -rf obj
|
||||
|
||||
test:
|
||||
+$(MAKE) DEBUG=$(DEBUG)
|
||||
./obj/LegacyUpdate.exe
|
||||
|
||||
.PHONY: all before-all clean test
|
82
launcher/MsgBox.c
Normal file
82
launcher/MsgBox.c
Normal file
@@ -0,0 +1,82 @@
|
||||
#include "stdafx.h"
|
||||
#include "main.h"
|
||||
#include "resource.h"
|
||||
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT _WIN32_WINNT_VISTA
|
||||
#include <commctrl.h>
|
||||
|
||||
typedef HRESULT (WINAPI *_TaskDialogIndirect)(const TASKDIALOGCONFIG *pTaskConfig, int *pnButton, int *pnRadioButton, BOOL *pfVerificationFlagChecked);
|
||||
|
||||
static BOOL _loadedTaskDialog = FALSE;
|
||||
static _TaskDialogIndirect $TaskDialogIndirect;
|
||||
|
||||
int MsgBox(HWND hwnd, LPCTSTR instruction, LPCTSTR body, UINT type) {
|
||||
if (!_loadedTaskDialog) {
|
||||
_loadedTaskDialog = TRUE;
|
||||
$TaskDialogIndirect = (_TaskDialogIndirect)GetProcAddress(LoadLibrary(L"comctl32.dll"), "TaskDialogIndirect");
|
||||
}
|
||||
|
||||
// Play the sound matching the icon, because MB_USERICON doesn't play a sound
|
||||
MessageBeep(type & 0x000000F0);
|
||||
type = (type & ~0x000000F0) | MB_USERICON;
|
||||
|
||||
if (!$TaskDialogIndirect) {
|
||||
LPWSTR finalBody = (LPWSTR)instruction;
|
||||
if (body && lstrlen(body) > 0) {
|
||||
size_t length = lstrlen(instruction) + lstrlen(body) + 3;
|
||||
finalBody = (LPWSTR)LocalAlloc(LPTR, length * sizeof(TCHAR));
|
||||
wsprintf(finalBody, L"%s\n\n%s", instruction, body);
|
||||
}
|
||||
|
||||
MSGBOXPARAMS params = { 0 };
|
||||
params.cbSize = sizeof(MSGBOXPARAMS);
|
||||
params.hwndOwner = hwnd;
|
||||
params.hInstance = GetModuleHandle(NULL);
|
||||
params.lpszText = finalBody;
|
||||
params.lpszCaption = L"Legacy Update";
|
||||
params.dwStyle = type;
|
||||
params.lpszIcon = MAKEINTRESOURCE(IDI_APPICON);
|
||||
int result = MessageBoxIndirect(¶ms);
|
||||
|
||||
if (finalBody != body) {
|
||||
LocalFree(finalBody);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
TASKDIALOG_COMMON_BUTTON_FLAGS buttons;
|
||||
DWORD flags = TDF_POSITION_RELATIVE_TO_WINDOW;
|
||||
|
||||
switch (type & 0x0000000F) {
|
||||
case MB_OK:
|
||||
buttons = TDCBF_OK_BUTTON;
|
||||
flags |= TDF_ALLOW_DIALOG_CANCELLATION;
|
||||
break;
|
||||
case MB_OKCANCEL:
|
||||
buttons = TDCBF_OK_BUTTON | TDCBF_CANCEL_BUTTON;
|
||||
flags |= TDF_ALLOW_DIALOG_CANCELLATION;
|
||||
break;
|
||||
case MB_YESNO:
|
||||
buttons = TDCBF_YES_BUTTON | TDCBF_NO_BUTTON;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
TASKDIALOGCONFIG config = { 0 };
|
||||
config.cbSize = sizeof(TASKDIALOGCONFIG);
|
||||
config.hwndParent = hwnd;
|
||||
config.hInstance = GetModuleHandle(NULL);
|
||||
config.dwFlags = flags;
|
||||
config.dwCommonButtons = buttons;
|
||||
config.pszWindowTitle = L"Legacy Update";
|
||||
config.pszMainInstruction = instruction;
|
||||
config.pszContent = body;
|
||||
config.pszMainIcon = MAKEINTRESOURCE(IDI_APPICON);
|
||||
|
||||
int button;
|
||||
$TaskDialogIndirect(&config, &button, NULL, NULL);
|
||||
return button;
|
||||
}
|
5
launcher/MsgBox.h
Normal file
5
launcher/MsgBox.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
int MsgBox(HWND hwnd, LPCTSTR instruction, LPCTSTR body, UINT type);
|
40
launcher/Options.c
Normal file
40
launcher/Options.c
Normal file
@@ -0,0 +1,40 @@
|
||||
#include <windows.h>
|
||||
#include "Exec.h"
|
||||
#include "VersionInfo.h"
|
||||
#include "Wow64.h"
|
||||
|
||||
void LaunchOptions(int nCmdShow) {
|
||||
#if !_WIN64
|
||||
// Some issues arise from the working directory being SysWOW64 rather than System32. Notably,
|
||||
// Windows Vista - 8.1 don't have wuauclt.exe in SysWOW64. Disable WOW64 redirection temporarily
|
||||
// to work around this.
|
||||
PVOID oldValue;
|
||||
BOOL isRedirected = DisableWow64FsRedirection(&oldValue);
|
||||
#endif
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
if (AtLeastWin10()) {
|
||||
// Windows 10+: Open Settings app
|
||||
hr = Exec(NULL, L"ms-settings:windowsupdate-options", NULL, NULL, SW_SHOWDEFAULT, FALSE, NULL);
|
||||
} else if (AtLeastWinVista()) {
|
||||
// Windows Vista, 7, 8: Open Windows Update control panel
|
||||
WCHAR wuauclt[MAX_PATH];
|
||||
ExpandEnvironmentStrings(L"%SystemRoot%\\System32\\wuauclt.exe", wuauclt, ARRAYSIZE(wuauclt));
|
||||
hr = Exec(NULL, wuauclt, L"/ShowOptions", NULL, SW_SHOWDEFAULT, FALSE, NULL);
|
||||
} else {
|
||||
// Windows 2000, XP: Open Automatic Updates control panel
|
||||
WCHAR wuaucpl[MAX_PATH];
|
||||
ExpandEnvironmentStrings(L"%SystemRoot%\\System32\\wuaucpl.cpl", wuaucpl, ARRAYSIZE(wuaucpl));
|
||||
hr = Exec(NULL, wuaucpl, NULL, NULL, SW_SHOWDEFAULT, FALSE, NULL);
|
||||
}
|
||||
|
||||
#if !_WIN64
|
||||
// Revert WOW64 redirection if we changed it
|
||||
if (isRedirected) {
|
||||
RevertWow64FsRedirection(oldValue);
|
||||
}
|
||||
#endif
|
||||
|
||||
PostQuitMessage(hr);
|
||||
}
|
153
launcher/RegisterServer.c
Normal file
153
launcher/RegisterServer.c
Normal file
@@ -0,0 +1,153 @@
|
||||
#include <windows.h>
|
||||
#include "Exec.h"
|
||||
#include "HResult.h"
|
||||
#include "LegacyUpdate.h"
|
||||
#include "MsgBox.h"
|
||||
#include "Registry.h"
|
||||
#include "SelfElevate.h"
|
||||
#include "User.h"
|
||||
#include "VersionInfo.h"
|
||||
#include "Wow64.h"
|
||||
|
||||
static HRESULT RegisterDllInternal(LPWSTR path, BOOL state) {
|
||||
HMODULE module = LoadLibrary(path);
|
||||
if (!module) {
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
FARPROC proc = GetProcAddress(module, state ? "DllRegisterServer" : "DllUnregisterServer");
|
||||
if (!proc) {
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto end;
|
||||
}
|
||||
|
||||
hr = ((HRESULT (WINAPI *)())proc)();
|
||||
|
||||
end:
|
||||
if (module) {
|
||||
FreeLibrary(module);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT RegisterDllExternal(LPWSTR path, BOOL state) {
|
||||
WCHAR regsvr32[MAX_PATH];
|
||||
ExpandEnvironmentStrings(L"%SystemRoot%\\System32\\regsvr32.exe", regsvr32, ARRAYSIZE(regsvr32));
|
||||
|
||||
LPWSTR args = (LPWSTR)LocalAlloc(LPTR, (lstrlen(path) + 6) * sizeof(WCHAR));
|
||||
wsprintf(args, L"/s %ls\"%ls\"", state ? L"" : L"/u ", path);
|
||||
|
||||
DWORD status;
|
||||
HRESULT hr = Exec(NULL, regsvr32, args, NULL, SW_HIDE, TRUE, &status);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (status != 0) {
|
||||
// Run again without /s, so the user can see the error
|
||||
wsprintf(args, L"%ls\"%ls\"", state ? L"" : L"/u ", path);
|
||||
hr = Exec(NULL, regsvr32, args, NULL, SW_SHOWDEFAULT, TRUE, &status);
|
||||
}
|
||||
|
||||
return status == 0 ? S_OK : E_FAIL;
|
||||
}
|
||||
|
||||
HRESULT RegisterServer(HWND hwnd, BOOL state, BOOL forLaunch) {
|
||||
// Ensure elevation
|
||||
HRESULT hr = S_OK;
|
||||
LPWSTR installPath;
|
||||
LPWSTR dllPath;
|
||||
|
||||
if (!IsUserAdmin()) {
|
||||
LPWSTR args = (LPWSTR)LocalAlloc(LPTR, 512 * sizeof(WCHAR));
|
||||
wsprintf(args, L"%ls %i", state ? L"/regserver" : L"/unregserver", hwnd);
|
||||
DWORD code;
|
||||
hr = SelfElevate(args, &code);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
// Ignore error on cancelling UAC dialog
|
||||
if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) {
|
||||
hr = S_OK;
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
|
||||
hr = HRESULT_FROM_WIN32(code);
|
||||
goto end;
|
||||
}
|
||||
|
||||
hr = GetInstallPath(&installPath);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
dllPath = (LPWSTR)LocalAlloc(LPTR, MAX_PATH * sizeof(WCHAR));
|
||||
wsprintf(dllPath, L"%ls\\LegacyUpdate.dll", installPath);
|
||||
|
||||
#ifdef _DEBUG
|
||||
// Warn if registration path differs, to help with debugging
|
||||
LPWSTR currentPath;
|
||||
hr = GetRegistryString(HKEY_CLASSES_ROOT, L"CLSID\\{AD28E0DF-5F5A-40B5-9432-85EFD97D1F9F}\\InprocServer32", NULL, KEY_WOW64_64KEY, ¤tPath, NULL);
|
||||
if (SUCCEEDED(hr) && wcscmp(currentPath, dllPath) != 0) {
|
||||
if (MsgBox(hwnd, L"DEBUG: Native dll currently registered at a different path. Override?", currentPath, MB_YESNO) != IDYES) {
|
||||
hr = S_OK;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
hr = RegisterDllInternal(dllPath, state);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
// Try external registration
|
||||
if (SUCCEEDED(RegisterDllExternal(dllPath, state))) {
|
||||
hr = S_OK;
|
||||
} else {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
#if _WIN64
|
||||
if (!SUCCEEDED(hr)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
wsprintf(dllPath, L"%ls\\LegacyUpdate32.dll", installPath);
|
||||
|
||||
#ifdef _DEBUG
|
||||
// Warn if registration path differs, to help with debugging
|
||||
hr = GetRegistryString(HKEY_CLASSES_ROOT, L"CLSID\\{AD28E0DF-5F5A-40B5-9432-85EFD97D1F9F}\\InprocServer32", NULL, KEY_WOW64_32KEY, ¤tPath, NULL);
|
||||
if (SUCCEEDED(hr) && wcscmp(currentPath, dllPath) != 0) {
|
||||
if (MsgBox(hwnd, L"DEBUG: 32-bit dll currently registered at a different path. Override?", currentPath, MB_YESNO) != IDYES) {
|
||||
hr = S_OK;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
hr = RegisterDllExternal(dllPath, state);
|
||||
#endif
|
||||
|
||||
end:
|
||||
if (installPath) {
|
||||
LocalFree(installPath);
|
||||
}
|
||||
|
||||
if (dllPath) {
|
||||
LocalFree(dllPath);
|
||||
}
|
||||
|
||||
if (!SUCCEEDED(hr)) {
|
||||
LPWSTR title = state
|
||||
? L"Failed to register Legacy Update ActiveX control"
|
||||
: L"Failed to unregister Legacy Update ActiveX control";
|
||||
MsgBox(hwnd, title, GetMessageForHresult(hr), MB_ICONERROR);
|
||||
}
|
||||
|
||||
if (!forLaunch) {
|
||||
PostQuitMessage(hr);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
5
launcher/RegisterServer.h
Normal file
5
launcher/RegisterServer.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
HRESULT RegisterServer(HWND hwnd, BOOL state, BOOL forLaunch);
|
12
launcher/SelfElevate.c
Normal file
12
launcher/SelfElevate.c
Normal file
@@ -0,0 +1,12 @@
|
||||
#include "SelfElevate.h"
|
||||
#include <windows.h>
|
||||
#include "Exec.h"
|
||||
#include "VersionInfo.h"
|
||||
|
||||
HRESULT SelfElevate(LPWSTR args, LPDWORD code) {
|
||||
LPWSTR fileName;
|
||||
GetOwnFileName(&fileName);
|
||||
HRESULT hr = Exec(L"runas", fileName, args, NULL, SW_SHOWDEFAULT, TRUE, code);
|
||||
LocalFree(fileName);
|
||||
return hr;
|
||||
}
|
5
launcher/SelfElevate.h
Normal file
5
launcher/SelfElevate.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
HRESULT SelfElevate(LPWSTR args, LPDWORD code);
|
138
launcher/main.c
Normal file
138
launcher/main.c
Normal file
@@ -0,0 +1,138 @@
|
||||
#include "stdafx.h"
|
||||
#include "main.h"
|
||||
#include "resource.h"
|
||||
#include <windows.h>
|
||||
#include <commctrl.h>
|
||||
#include "MsgBox.h"
|
||||
#include "RegisterServer.h"
|
||||
#include "Startup.h"
|
||||
|
||||
HINSTANCE g_hInstance;
|
||||
|
||||
extern void LaunchUpdateSite(int argc, LPWSTR *argv, int nCmdShow);
|
||||
extern void LaunchOptions(int nCmdShow);
|
||||
extern void LaunchLog(int nCmdShow);
|
||||
extern void RunOnce();
|
||||
|
||||
typedef enum Action {
|
||||
ActionLaunch,
|
||||
ActionOptions,
|
||||
ActionLog,
|
||||
ActionRunOnce,
|
||||
ActionRegServer,
|
||||
ActionUnregServer
|
||||
} Action;
|
||||
|
||||
static const LPWSTR actions[] = {
|
||||
L"/launch",
|
||||
L"/options",
|
||||
L"/log",
|
||||
L"/runonce",
|
||||
L"/regserver",
|
||||
L"/unregserver",
|
||||
NULL
|
||||
};
|
||||
|
||||
EXTERN_C __declspec(dllexport)
|
||||
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
|
||||
g_hInstance = hInstance;
|
||||
Startup();
|
||||
|
||||
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
ExitProcess(hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
int argc;
|
||||
LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||
|
||||
LPWSTR actionFlag = L"/launch";
|
||||
if (argc > 1) {
|
||||
actionFlag = argv[1];
|
||||
}
|
||||
|
||||
// All remaining args past the action
|
||||
LPWSTR *flags = {0};
|
||||
int flagsCount = 0;
|
||||
if (argc > 2) {
|
||||
flags = &argv[2];
|
||||
flagsCount = argc - 2;
|
||||
}
|
||||
|
||||
Action action = -1;
|
||||
|
||||
for (int i = 0; actions[i] != NULL; i++) {
|
||||
if (wcscmp(actionFlag, actions[i]) == 0) {
|
||||
action = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case ActionLaunch:
|
||||
LaunchUpdateSite(flagsCount, flags, nCmdShow);
|
||||
break;
|
||||
|
||||
case ActionOptions:
|
||||
LaunchOptions(nCmdShow);
|
||||
break;
|
||||
|
||||
case ActionLog:
|
||||
LaunchLog(nCmdShow);
|
||||
break;
|
||||
|
||||
case ActionRunOnce:
|
||||
RunOnce();
|
||||
break;
|
||||
|
||||
case ActionRegServer:
|
||||
case ActionUnregServer: {
|
||||
BOOL state = action == ActionRegServer;
|
||||
HWND hwnd = flagsCount > 0 ? (HWND)(intptr_t)wcstol(flags[0], NULL, 10) : 0;
|
||||
RegisterServer(hwnd, state, FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
const LPWSTR usage = L""
|
||||
L"LegacyUpdate.exe [/launch|/regserver|/unregserver]\n"
|
||||
L"\n"
|
||||
L"/launch\n"
|
||||
L" Launch Legacy Update website in Internet Explorer\n"
|
||||
L"\n"
|
||||
L"/options\n"
|
||||
L" Open the Windows Update Options control panel\n"
|
||||
L"\n"
|
||||
L"/log\n"
|
||||
L" Open the Windows Update log file\n"
|
||||
L"\n"
|
||||
L"/regserver\n"
|
||||
L" Register ActiveX control\n"
|
||||
L"\n"
|
||||
L"/unregserver\n"
|
||||
L" Unregister ActiveX control\n"
|
||||
L"\n"
|
||||
L"If no parameters are provided, /launch is assumed.";
|
||||
MsgBox(NULL, L"LegacyUpdate.exe usage", usage, MB_OK);
|
||||
PostQuitMessage(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, NULL, 0, 0) == 1) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
|
||||
switch (msg.message) {
|
||||
case WM_QUIT:
|
||||
case WM_DESTROY:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CoUninitialize();
|
||||
ExitProcess(msg.wParam);
|
||||
return msg.wParam;
|
||||
}
|
1
launcher/main.h
Normal file
1
launcher/main.h
Normal file
@@ -0,0 +1 @@
|
||||
EXTERN_C HINSTANCE g_hInstance;
|
30
launcher/manifest.xml
Normal file
30
launcher/manifest.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity type="Win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> <!-- Windows Vista -->
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> <!-- Windows 7 -->
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> <!-- Windows 8 -->
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> <!-- Windows 8.1 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> <!-- Windows 10 -->
|
||||
</application>
|
||||
</compatibility>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</assembly>
|
11
launcher/resource.h
Normal file
11
launcher/resource.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#define IDR_CPLTASKS 202
|
||||
|
||||
#define IDI_APPICON 100
|
||||
|
||||
#define IDS_LEGACYUPDATEOCX 1
|
||||
#define IDS_LEGACYUPDATE 2
|
||||
#define IDS_CHECKFORUPDATES 3
|
||||
#define IDS_CHECKFORUPDATES_ALT 4
|
||||
#define IDS_IENOTINSTALLED 5
|
||||
|
||||
#define ID_MANIFEST 1
|
95
launcher/resource.rc
Normal file
95
launcher/resource.rc
Normal file
@@ -0,0 +1,95 @@
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
#include <windows.h>
|
||||
#include "Version.h"
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United States) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(65001)
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,VERSION_BUILD
|
||||
PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,VERSION_BUILD
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Hashbang Productions"
|
||||
VALUE "FileDescription", "Legacy Update"
|
||||
VALUE "FileVersion", VERSION_STRING
|
||||
VALUE "InternalName", "LegacyUpdate.exe"
|
||||
VALUE "LegalCopyright", "© Hashbang Productions. All rights reserved."
|
||||
VALUE "OriginalFilename", "LegacyUpdate.exe"
|
||||
VALUE "ProductName", "Legacy Update"
|
||||
VALUE "ProductVersion", VERSION_STRING
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
IDI_APPICON ICON "../LegacyUpdate/icon.ico"
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// XML
|
||||
//
|
||||
|
||||
IDR_CPLTASKS XML "CplTasks.xml"
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// String Table
|
||||
//
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_LEGACYUPDATEOCX "Legacy Update Control"
|
||||
IDS_LEGACYUPDATE "Legacy Update"
|
||||
IDS_CHECKFORUPDATES "Check for updates"
|
||||
IDS_CHECKFORUPDATES_ALT "Check for software and driver updates via Legacy Update."
|
||||
IDS_IENOTINSTALLED "Internet Explorer is not installed. Use Optional Features in Control Panel to install it before using Legacy Update."
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Manifest
|
||||
//
|
||||
|
||||
ID_MANIFEST RT_MANIFEST "manifest.xml"
|
||||
|
||||
#endif // English (United States) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
23
launcher/stdafx.h
Normal file
23
launcher/stdafx.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef STRICT
|
||||
#define STRICT
|
||||
#endif
|
||||
|
||||
#define WINVER _WIN32_WINNT_WIN2K
|
||||
#define _WIN32_WINNT _WIN32_WINNT_WIN2K
|
||||
|
||||
// Use msvcrt stdio functions
|
||||
#define __USE_MINGW_ANSI_STDIO 0
|
||||
|
||||
// Enable comctl 6.0 (visual styles)
|
||||
#define ISOLATION_AWARE_ENABLED 1
|
||||
|
||||
// Enable COM C interfaces
|
||||
#define CINTERFACE
|
||||
#define COBJMACROS
|
||||
#define INITGUID
|
||||
|
||||
#include "resource.h"
|
||||
#include <windows.h>
|
||||
#include "Trace.h"
|
Reference in New Issue
Block a user