Test
This commit is contained in:
64
nsisplugin/CloseIEWindows.c
Normal file
64
nsisplugin/CloseIEWindows.c
Normal file
@@ -0,0 +1,64 @@
|
||||
#include <windows.h>
|
||||
#include <nsis/pluginapi.h>
|
||||
#include <exdisp.h>
|
||||
|
||||
const LPWSTR LegacyUpdateSiteURLHttp = L"http://legacyupdate.net/";
|
||||
const LPWSTR LegacyUpdateSiteURLHttps = L"https://legacyupdate.net/";
|
||||
|
||||
PLUGIN_METHOD(CloseIEWindows) {
|
||||
PLUGIN_INIT();
|
||||
|
||||
// Find and close IE windows that might have the ActiveX control loaded
|
||||
IShellWindows *windows;
|
||||
HRESULT hr = CoCreateInstance(&CLSID_ShellWindows, NULL, CLSCTX_ALL, &IID_IShellWindows, (void **)&windows);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
long count;
|
||||
hr = IShellWindows_get_Count(windows, &count);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
VARIANT index = {0};
|
||||
index.vt = VT_I4;
|
||||
|
||||
for (long i = 0; i <= count; i++) {
|
||||
IDispatch *item;
|
||||
index.lVal = i;
|
||||
|
||||
hr = IShellWindows_Item(windows, index, &item);
|
||||
if (!SUCCEEDED(hr) || !item) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IWebBrowser2 *browser;
|
||||
hr = IDispatch_QueryInterface(item, &IID_IWebBrowser2, (void **)&browser);
|
||||
IDispatch_Release(item);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BSTR location;
|
||||
hr = IWebBrowser2_get_LocationURL(browser, &location);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
IWebBrowser2_Release(browser);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (wcsstr(location, LegacyUpdateSiteURLHttp) != NULL || wcsstr(location, LegacyUpdateSiteURLHttps) != NULL) {
|
||||
hr = IWebBrowser2_Quit(browser);
|
||||
}
|
||||
|
||||
SysFreeString(location);
|
||||
IWebBrowser2_Release(browser);
|
||||
}
|
||||
|
||||
end:
|
||||
if (windows) {
|
||||
IShellWindows_Release(windows);
|
||||
}
|
||||
|
||||
pushint(hr);
|
||||
}
|
377
nsisplugin/DialogInit.c
Normal file
377
nsisplugin/DialogInit.c
Normal file
@@ -0,0 +1,377 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT _WIN32_WINNT_VISTA
|
||||
|
||||
#include <windows.h>
|
||||
#include <nsis/pluginapi.h>
|
||||
#include <shlwapi.h>
|
||||
#include <uxtheme.h>
|
||||
#include <vsstyle.h>
|
||||
#include <windowsx.h>
|
||||
#include "main.h"
|
||||
#include "LoadImage.h"
|
||||
#include "Registry.h"
|
||||
#include "VersionInfo.h"
|
||||
|
||||
#ifndef WM_DWMCOMPOSITIONCHANGED
|
||||
#define WM_DWMCOMPOSITIONCHANGED 0x031e
|
||||
#endif
|
||||
|
||||
#define DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 19
|
||||
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
|
||||
#define DWMWA_CAPTION_COLOR 35
|
||||
#define DWMWA_SYSTEMBACKDROP_TYPE 38
|
||||
#define DWMWA_COLOR_NONE 0xFFFFFFFE
|
||||
#define DWMSBT_MAINWINDOW 2
|
||||
|
||||
#define IDI_BANNER_WORDMARK_LIGHT 1337
|
||||
#define IDI_BANNER_WORDMARK_DARK 1338
|
||||
#define IDI_BANNER_WORDMARK_GLOW 1339
|
||||
|
||||
typedef HRESULT (WINAPI *_DwmExtendFrameIntoClientArea)(HWND hWnd, const MARGINS *pMarInset);
|
||||
typedef HRESULT (WINAPI *_DwmIsCompositionEnabled)(BOOL *pfEnabled);
|
||||
typedef HRESULT (WINAPI *_DwmDefWindowProc)(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *plResult);
|
||||
typedef HRESULT (WINAPI *_DwmSetWindowAttribute)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute);
|
||||
typedef HRESULT (WINAPI *_SetWindowThemeAttribute)(HWND hwnd, enum WINDOWTHEMEATTRIBUTETYPE eAttribute, PVOID pvAttribute, DWORD cbAttribute);
|
||||
typedef BOOL (WINAPI *_IsThemeActive)();
|
||||
typedef HTHEME (WINAPI *_OpenThemeData)(HWND hwnd, LPCWSTR pszClassList);
|
||||
typedef HRESULT (WINAPI *_CloseThemeData)(HTHEME hTheme);
|
||||
typedef HRESULT (WINAPI *_DrawThemeBackground)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect);
|
||||
|
||||
static _DwmExtendFrameIntoClientArea $DwmExtendFrameIntoClientArea;
|
||||
static _DwmIsCompositionEnabled $DwmIsCompositionEnabled;
|
||||
static _DwmDefWindowProc $DwmDefWindowProc;
|
||||
static _DwmSetWindowAttribute $DwmSetWindowAttribute;
|
||||
static _SetWindowThemeAttribute $SetWindowThemeAttribute;
|
||||
static _IsThemeActive $IsThemeActive;
|
||||
static _OpenThemeData $OpenThemeData;
|
||||
static _CloseThemeData $CloseThemeData;
|
||||
static _DrawThemeBackground $DrawThemeBackground;
|
||||
|
||||
typedef enum Theme {
|
||||
ThemeUnknown = -1,
|
||||
ThemeClassic,
|
||||
ThemeBasic,
|
||||
ThemeAeroLight,
|
||||
ThemeAeroDark
|
||||
} Theme;
|
||||
|
||||
static HBITMAP g_bannerWordmark;
|
||||
static HBITMAP g_bannerWordmarkGlow;
|
||||
static HTHEME g_aeroTheme;
|
||||
static Theme g_theme = ThemeUnknown;
|
||||
|
||||
static WNDPROC g_dialogOrigWndProc;
|
||||
static WNDPROC g_bannerOrigWndProc;
|
||||
static WNDPROC g_bottomOrigWndProc;
|
||||
|
||||
static Theme GetTheme() {
|
||||
BOOL enabled;
|
||||
if (!$DwmIsCompositionEnabled || !$IsThemeActive || !SUCCEEDED($DwmIsCompositionEnabled(&enabled))) {
|
||||
return ThemeClassic;
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
DWORD light = 1;
|
||||
if (AtLeastWin10_1809()) {
|
||||
GetRegistryDword(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", L"AppsUseLightTheme", 0, &light);
|
||||
}
|
||||
return light ? ThemeAeroLight : ThemeAeroDark;
|
||||
}
|
||||
|
||||
return $IsThemeActive() ? ThemeBasic : ThemeClassic;
|
||||
}
|
||||
|
||||
static void ConfigureWindow() {
|
||||
HWND bannerWindow = GetDlgItem(g_hwndParent, 1046);
|
||||
HWND bannerDivider = GetDlgItem(g_hwndParent, 1047);
|
||||
HWND bottomDivider = GetDlgItem(g_hwndParent, 6900);
|
||||
if (!bannerWindow || !bannerDivider || !bottomDivider) {
|
||||
return;
|
||||
}
|
||||
|
||||
Theme theme = GetTheme();
|
||||
if (g_theme != theme) {
|
||||
g_theme = theme;
|
||||
MARGINS margins = {0};
|
||||
|
||||
if (theme >= ThemeAeroLight) {
|
||||
// Set glass area
|
||||
RECT rect;
|
||||
GetWindowRect(bannerWindow, &rect);
|
||||
margins.cyTopHeight = rect.bottom - rect.top;
|
||||
}
|
||||
|
||||
if ($DwmExtendFrameIntoClientArea) {
|
||||
$DwmExtendFrameIntoClientArea(g_hwndParent, &margins);
|
||||
}
|
||||
|
||||
ShowWindow(bannerDivider, theme >= ThemeBasic ? SW_HIDE : SW_SHOW);
|
||||
ShowWindow(bottomDivider, theme >= ThemeBasic ? SW_HIDE : SW_SHOW);
|
||||
|
||||
if (g_theme >= ThemeBasic) {
|
||||
DWORD wordmark = g_theme == ThemeAeroDark ? IDI_BANNER_WORDMARK_DARK : IDI_BANNER_WORDMARK_LIGHT;
|
||||
g_bannerWordmark = LoadPNGResource(NULL, MAKEINTRESOURCE(wordmark), L"PNG");
|
||||
if (g_theme >= ThemeAeroLight && AtMostWin7()) {
|
||||
g_bannerWordmarkGlow = LoadPNGResource(NULL, MAKEINTRESOURCE(IDI_BANNER_WORDMARK_GLOW), L"PNG");
|
||||
}
|
||||
} else {
|
||||
DeleteObject(g_bannerWordmark);
|
||||
DeleteObject(g_bannerWordmarkGlow);
|
||||
g_bannerWordmark = NULL;
|
||||
g_bannerWordmarkGlow = NULL;
|
||||
}
|
||||
|
||||
// Set dark mode state
|
||||
if (AtLeastWin10_1809() && $DwmSetWindowAttribute) {
|
||||
DWORD attr = AtLeastWin10_2004() ? DWMWA_USE_IMMERSIVE_DARK_MODE : DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1;
|
||||
DWORD value = g_theme == ThemeAeroDark;
|
||||
$DwmSetWindowAttribute(g_hwndParent, attr, &value, sizeof(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK BannerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
if (g_theme < ThemeBasic) {
|
||||
return CallWindowProc(g_bannerOrigWndProc, hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
switch (uMsg) {
|
||||
case WM_PAINT: {
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc = BeginPaint(hwnd, &ps);
|
||||
RECT rect;
|
||||
GetClientRect(hwnd, &rect);
|
||||
|
||||
// Draw base color for glass area
|
||||
FillRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
|
||||
|
||||
// Draw Aero Basic titlebar
|
||||
if (g_theme == ThemeBasic && g_aeroTheme && $DrawThemeBackground) {
|
||||
int state = GetActiveWindow() == g_hwndParent ? AW_S_TITLEBAR_ACTIVE : AW_S_TITLEBAR_INACTIVE;
|
||||
$DrawThemeBackground(g_aeroTheme, hdc, AW_TITLEBAR, state, &rect, NULL);
|
||||
}
|
||||
|
||||
float scale = (float)GetDeviceCaps(hdc, LOGPIXELSX) / 96.0f;
|
||||
|
||||
BLENDFUNCTION blendFunc;
|
||||
blendFunc.BlendOp = AC_SRC_OVER;
|
||||
blendFunc.BlendFlags = 0;
|
||||
blendFunc.SourceConstantAlpha = 0xFF;
|
||||
blendFunc.AlphaFormat = AC_SRC_ALPHA;
|
||||
|
||||
// Draw wordmark with alpha blending
|
||||
if (g_bannerWordmarkGlow) {
|
||||
HDC hdcMem = CreateCompatibleDC(hdc);
|
||||
HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, g_bannerWordmarkGlow);
|
||||
|
||||
BITMAP bitmap;
|
||||
GetObject(g_bannerWordmarkGlow, sizeof(bitmap), &bitmap);
|
||||
|
||||
LONG width = bitmap.bmWidth * scale;
|
||||
LONG height = bitmap.bmHeight * scale;
|
||||
LONG x = (rect.right - rect.left - width) / 2;
|
||||
LONG y = (rect.bottom - rect.top - height) / 2;
|
||||
|
||||
SetStretchBltMode(hdc, HALFTONE);
|
||||
AlphaBlend(hdc,
|
||||
x, y, width, height, hdcMem,
|
||||
0, 0, bitmap.bmWidth, bitmap.bmHeight, blendFunc);
|
||||
|
||||
SelectObject(hdcMem, hbmOld);
|
||||
DeleteDC(hdcMem);
|
||||
}
|
||||
|
||||
if (g_bannerWordmark) {
|
||||
HDC hdcMem = CreateCompatibleDC(hdc);
|
||||
HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, g_bannerWordmark);
|
||||
|
||||
BITMAP bitmap;
|
||||
GetObject(g_bannerWordmark, sizeof(bitmap), &bitmap);
|
||||
|
||||
LONG width = bitmap.bmWidth * scale;
|
||||
LONG height = bitmap.bmHeight * scale;
|
||||
LONG x = (rect.right - rect.left - width) / 2;
|
||||
LONG y = ((rect.bottom - rect.top - height) / 2) - (1 * scale);
|
||||
|
||||
SetStretchBltMode(hdc, HALFTONE);
|
||||
AlphaBlend(hdc,
|
||||
x, y, width, height, hdcMem,
|
||||
0, 0, bitmap.bmWidth, bitmap.bmHeight, blendFunc);
|
||||
|
||||
SelectObject(hdcMem, hbmOld);
|
||||
DeleteDC(hdcMem);
|
||||
}
|
||||
|
||||
EndPaint(hwnd, &ps);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_ERASEBKGND:
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
|
||||
case WM_NCHITTEST:
|
||||
// Pass through to parent
|
||||
return HTTRANSPARENT;
|
||||
}
|
||||
|
||||
if (!g_bannerOrigWndProc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return CallWindowProc(g_bannerOrigWndProc, hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK BottomWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
switch (uMsg) {
|
||||
case WM_PAINT: {
|
||||
// Draw command area background (grey with divider line)
|
||||
if (g_theme < ThemeBasic || !g_aeroTheme || !$DrawThemeBackground) {
|
||||
break;
|
||||
}
|
||||
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc = BeginPaint(hwnd, &ps);
|
||||
|
||||
RECT rect;
|
||||
GetClientRect(hwnd, &rect);
|
||||
$DrawThemeBackground(g_aeroTheme, hdc, AW_COMMANDAREA, 0, &rect, NULL);
|
||||
|
||||
EndPaint(hwnd, &ps);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_bottomOrigWndProc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return CallWindowProc(g_bottomOrigWndProc, hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
if (g_theme >= ThemeAeroLight && $DwmDefWindowProc) {
|
||||
LRESULT lRet = 0;
|
||||
if ($DwmDefWindowProc(hwnd, uMsg, wParam, lParam, &lRet)) {
|
||||
return lRet;
|
||||
}
|
||||
}
|
||||
|
||||
switch (uMsg) {
|
||||
case WM_THEMECHANGED:
|
||||
case WM_DWMCOMPOSITIONCHANGED:
|
||||
ConfigureWindow();
|
||||
break;
|
||||
|
||||
case WM_ACTIVATE:
|
||||
case WM_NCACTIVATE:
|
||||
// Redraw banner on activation
|
||||
if (g_theme == ThemeBasic) {
|
||||
InvalidateRect(GetDlgItem(hwnd, 1046), NULL, FALSE);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_NCHITTEST: {
|
||||
if (g_theme < ThemeBasic) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Allow drag in the header area
|
||||
HWND bannerWindow = GetDlgItem(hwnd, 1046);
|
||||
if (!bannerWindow) {
|
||||
break;
|
||||
}
|
||||
|
||||
POINT hit = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
|
||||
ScreenToClient(hwnd, &hit);
|
||||
|
||||
RECT rect;
|
||||
GetWindowRect(bannerWindow, &rect);
|
||||
rect.right -= rect.left;
|
||||
rect.bottom -= rect.top;
|
||||
rect.left = 0;
|
||||
rect.top = 0;
|
||||
|
||||
if (PtInRect(&rect, hit)) {
|
||||
return HTCAPTION;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_dialogOrigWndProc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return CallWindowProc(g_dialogOrigWndProc, hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static UINT_PTR NSISPluginCallback(enum NSPIM event) {
|
||||
// Does nothing, but keeping a callback registered prevents NSIS from unloading the plugin
|
||||
return 0;
|
||||
}
|
||||
|
||||
PLUGIN_METHOD(DialogInit) {
|
||||
PLUGIN_INIT();
|
||||
|
||||
if (g_dialogOrigWndProc) {
|
||||
return;
|
||||
}
|
||||
|
||||
extra->RegisterPluginCallback(g_hInstance, NSISPluginCallback);
|
||||
|
||||
// Get symbols
|
||||
HMODULE dwmapi = LoadLibrary(L"dwmapi.dll");
|
||||
if (dwmapi) {
|
||||
$DwmExtendFrameIntoClientArea = (_DwmExtendFrameIntoClientArea)GetProcAddress(dwmapi, "DwmExtendFrameIntoClientArea");
|
||||
$DwmIsCompositionEnabled = (_DwmIsCompositionEnabled)GetProcAddress(dwmapi, "DwmIsCompositionEnabled");
|
||||
$DwmDefWindowProc = (_DwmDefWindowProc)GetProcAddress(dwmapi, "DwmDefWindowProc");
|
||||
$DwmSetWindowAttribute = (_DwmSetWindowAttribute)GetProcAddress(dwmapi, "DwmSetWindowAttribute");
|
||||
}
|
||||
|
||||
HMODULE uxtheme = LoadLibrary(L"uxtheme.dll");
|
||||
if (uxtheme) {
|
||||
$SetWindowThemeAttribute = (_SetWindowThemeAttribute)GetProcAddress(uxtheme, "SetWindowThemeAttribute");
|
||||
$IsThemeActive = (_IsThemeActive)GetProcAddress(uxtheme, "IsThemeActive");
|
||||
$OpenThemeData = (_OpenThemeData)GetProcAddress(uxtheme, "OpenThemeData");
|
||||
$CloseThemeData = (_CloseThemeData)GetProcAddress(uxtheme, "CloseThemeData");
|
||||
$DrawThemeBackground = (_DrawThemeBackground)GetProcAddress(uxtheme, "DrawThemeBackground");
|
||||
}
|
||||
|
||||
// Get AeroWizard theme
|
||||
if ($OpenThemeData) {
|
||||
g_aeroTheme = $OpenThemeData(g_hwndParent, L"AeroWizard");
|
||||
}
|
||||
|
||||
// Hide title caption/icon
|
||||
if ($SetWindowThemeAttribute) {
|
||||
WTA_OPTIONS options;
|
||||
options.dwFlags = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON;
|
||||
options.dwMask = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON;
|
||||
$SetWindowThemeAttribute(g_hwndParent, WTA_NONCLIENT, &options, sizeof(options));
|
||||
}
|
||||
|
||||
// Enable Acrylic blur
|
||||
if (AtLeastWin11_21H1() && $DwmSetWindowAttribute) {
|
||||
// I stole this undocumented 1029 attr from Microsoft Store's StoreInstaller.exe
|
||||
BOOL modern = AtLeastWin11_22H2();
|
||||
DWORD attr = modern ? DWMWA_SYSTEMBACKDROP_TYPE : 1029;
|
||||
DWORD value = modern ? DWMSBT_MAINWINDOW : 1;
|
||||
$DwmSetWindowAttribute(g_hwndParent, attr, &value, sizeof(value));
|
||||
|
||||
// Hide caption background
|
||||
value = DWMWA_COLOR_NONE;
|
||||
$DwmSetWindowAttribute(g_hwndParent, DWMWA_CAPTION_COLOR, &value, sizeof(value));
|
||||
}
|
||||
|
||||
// Set up extended client frame
|
||||
ConfigureWindow();
|
||||
|
||||
// Set up window procedures
|
||||
HWND bannerWindow = GetDlgItem(g_hwndParent, 1046);
|
||||
HWND bottomWindow = GetDlgItem(g_hwndParent, 6901);
|
||||
g_dialogOrigWndProc = (WNDPROC)SetWindowLongPtr(g_hwndParent, GWLP_WNDPROC, (LONG_PTR)MainWndProc);
|
||||
g_bannerOrigWndProc = (WNDPROC)SetWindowLongPtr(bannerWindow, GWLP_WNDPROC, (LONG_PTR)BannerWndProc);
|
||||
g_bottomOrigWndProc = (WNDPROC)SetWindowLongPtr(bottomWindow, GWLP_WNDPROC, (LONG_PTR)BottomWndProc);
|
||||
}
|
602
nsisplugin/Exec.c
Normal file
602
nsisplugin/Exec.c
Normal file
@@ -0,0 +1,602 @@
|
||||
/*
|
||||
Copyright (C) 2002 Robert Rainwater <rrainwater@yahoo.com>
|
||||
Copyright (C) 2002-2023 Nullsoft and Contributors
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
*/
|
||||
#include <windows.h>
|
||||
#include <commctrl.h>
|
||||
#include <winnt.h>
|
||||
#include <nsis/pluginapi.h> // nsis plugin
|
||||
#include "main.h"
|
||||
|
||||
#if defined(_MSC_VER) && !defined(GetVersion)
|
||||
#if _MSC_VER >= 1500
|
||||
FORCEINLINE DWORD NoDepr_GetVersion() { __pragma(warning(push))__pragma(warning(disable:4996)) DWORD r = GetVersion(); __pragma(warning(pop)) return r; }
|
||||
#define GetVersion NoDepr_GetVersion
|
||||
#endif //~ _MSC_VER >= 1500
|
||||
#endif //~ _MSC_VER
|
||||
|
||||
#define TAB_REPLACE _T(" ")
|
||||
#define TAB_REPLACE_SIZE (sizeof(TAB_REPLACE) - sizeof(_T("")))
|
||||
#define TAB_REPLACE_CCH (TAB_REPLACE_SIZE / sizeof(_T("")))
|
||||
enum { MODE_IGNOREOUTPUT = 0, MODE_LINES = 1, MODE_STACK = 2 };
|
||||
|
||||
#define LOOPTIMEOUT 100
|
||||
static HWND g_hwndList;
|
||||
|
||||
static void ExecScript(BOOL log);
|
||||
static TCHAR *my_strstr(TCHAR *a, TCHAR *b);
|
||||
static unsigned int my_atoi(TCHAR *s);
|
||||
static int WINAPI AsExeWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow);
|
||||
|
||||
PLUGIN_METHOD(Exec) {
|
||||
PLUGIN_INIT();
|
||||
ExecScript(MODE_IGNOREOUTPUT);
|
||||
}
|
||||
|
||||
PLUGIN_METHOD(ExecToLog) {
|
||||
PLUGIN_INIT();
|
||||
ExecScript(extra->exec_flags->status_update & 1 ? MODE_LINES : MODE_IGNOREOUTPUT);
|
||||
}
|
||||
|
||||
PLUGIN_METHOD(ExecToStack) {
|
||||
PLUGIN_INIT();
|
||||
ExecScript(MODE_STACK);
|
||||
}
|
||||
|
||||
static BOOL IsLeadSurrogateUTF16(unsigned short c) { return c >= 0xd800 && c <= 0xdbff; }
|
||||
static BOOL IsTrailSurrogateUTF16(unsigned short c) { return c >= 0xdc00 && c <= 0xdfff; }
|
||||
|
||||
static PWSTR MyCharNext(PCWSTR p)
|
||||
{
|
||||
// Note: This is wrong for surrogate pair combining characters but CharNextW does
|
||||
// not support surrogate pairs correctly so we have to manually handle the pairs.
|
||||
if (!p[0]) return (PWSTR) p;
|
||||
if (IsLeadSurrogateUTF16(p[0]) && IsTrailSurrogateUTF16(p[1])) return (PWSTR) p + 2; // Current is a surrogate pair, we incorrectly assume that it is not followed by combining characters.
|
||||
if (IsLeadSurrogateUTF16(p[1]) && IsTrailSurrogateUTF16(p[2])) return (PWSTR) p + 1; // Next is a surrogate pair, we incorrectly assume that it is not a combining character for the current character.
|
||||
return (CharNextW)(p);
|
||||
}
|
||||
#define CharNextW MyCharNext
|
||||
|
||||
static void TruncateStringUTF16LE(LPWSTR Buffer, SIZE_T Length, LPCWSTR Overflow, SIZE_T lenOver) {
|
||||
if (Length) {
|
||||
LPWSTR p = &Buffer[Length - 1];
|
||||
UINT stripBaseCharIfCuttingCombining = TRUE;
|
||||
|
||||
// CharNextW is buggy on XP&2003 but we don't care enough to call GetStringTypeW (http://archives.miloush.net/michkap/archive/2005/01/30/363420.html)
|
||||
if (stripBaseCharIfCuttingCombining && lenOver) {
|
||||
WCHAR buf[] = { *p, Overflow[0], lenOver > 1 ? Overflow[1] : L' ', L'\0' };
|
||||
for (;;) {
|
||||
BOOL comb = CharNextW(buf) > buf + 1;
|
||||
if (!comb || p < Buffer) break;
|
||||
*((WORD*)((BYTE*)&buf[1])) = *((WORD*)((BYTE*)&buf[0]));
|
||||
buf[0] = *p;
|
||||
*p-- = L'\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (IsLeadSurrogateUTF16(*p)) {
|
||||
*p = L'\0'; // Avoid incomplete pair
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void TruncateStringMB(UINT Codepage, LPSTR Buffer, SIZE_T Length, unsigned short OverflowCh) {
|
||||
if (Length) {
|
||||
CHAR *p = &Buffer[Length - 1], buf[] = { *p, ' ', ' ', '\0' };
|
||||
|
||||
if (CharNextExA(Codepage, buf, 0) > buf + 1) { // Remove incomplete DBCS character?
|
||||
*p = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL IsWOW64() {
|
||||
#ifdef _WIN64
|
||||
return FALSE;
|
||||
#else
|
||||
typedef BOOL (WINAPI*ISWOW64PROCESS)(HANDLE, BOOL*);
|
||||
ISWOW64PROCESS pfIsWow64Process;
|
||||
typedef BOOL (WINAPI*ISWOW64PROCESS2)(HANDLE, USHORT*, USHORT*);
|
||||
ISWOW64PROCESS2 pfIsWow64Process2;
|
||||
HANDLE hProcess = GetCurrentProcess();
|
||||
HMODULE hK32 = GetModuleHandleA("KERNEL32");
|
||||
UINT_PTR retval;
|
||||
USHORT appmach, image_file_machine_unknown = 0;
|
||||
CHAR funcnam[16]
|
||||
#if defined(_MSC_VER) && (_MSC_VER-0 <= 1400)
|
||||
= "IsWow64Process2"; // MOVSD * 4
|
||||
#else
|
||||
; lstrcpyA(funcnam, "IsWow64Process2");
|
||||
#endif
|
||||
pfIsWow64Process2 = (ISWOW64PROCESS2) GetProcAddress(hK32, funcnam);
|
||||
if (pfIsWow64Process2 && pfIsWow64Process2(hProcess, &appmach, NULL)) {
|
||||
retval = image_file_machine_unknown != appmach;
|
||||
}
|
||||
else {
|
||||
BOOL wow64;
|
||||
pfIsWow64Process = (ISWOW64PROCESS) GetProcAddress(hK32, (funcnam[14] = '\0', funcnam));
|
||||
retval = (UINT_PTR) pfIsWow64Process;
|
||||
if (pfIsWow64Process && (retval = pfIsWow64Process(hProcess, &wow64))) {
|
||||
retval = wow64;
|
||||
}
|
||||
}
|
||||
return (BOOL) (UINT) retval;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Tim Kosse's LogMessage
|
||||
#ifdef UNICODE
|
||||
static void LogMessage(const TCHAR *pStr, BOOL bOEM) {
|
||||
#else
|
||||
static void LogMessage(TCHAR *pStr, BOOL bOEM) {
|
||||
#endif
|
||||
LVITEM item;
|
||||
int nItemCount;
|
||||
if (!g_hwndList) return;
|
||||
//if (!*pStr) return;
|
||||
#ifndef UNICODE
|
||||
if (bOEM == TRUE) OemToCharBuff(pStr, pStr, lstrlen(pStr));
|
||||
#endif
|
||||
nItemCount=(int) SendMessage(g_hwndList, LVM_GETITEMCOUNT, 0, 0);
|
||||
item.mask=LVIF_TEXT;
|
||||
item.pszText=(TCHAR *)pStr;
|
||||
item.cchTextMax=0;
|
||||
item.iItem=nItemCount, item.iSubItem=0;
|
||||
ListView_InsertItem(g_hwndList, &item);
|
||||
ListView_EnsureVisible(g_hwndList, item.iItem, 0);
|
||||
}
|
||||
|
||||
|
||||
void ExecScript(int mode) {
|
||||
TCHAR szRet[128];
|
||||
TCHAR meDLLPath[MAX_PATH];
|
||||
TCHAR *g_exec, *executor;
|
||||
TCHAR *pExec;
|
||||
int ignoreData = mode == MODE_IGNOREOUTPUT;
|
||||
int logMode = mode == MODE_LINES, stackMode = mode == MODE_STACK;
|
||||
unsigned int to, tabExpandLength = logMode ? TAB_REPLACE_CCH : 0, codepage;
|
||||
BOOL bOEM, forceNarrowInput = FALSE;
|
||||
|
||||
*szRet = _T('\0');
|
||||
|
||||
if (!IsWOW64()) {
|
||||
TCHAR* p;
|
||||
int nComSpecSize;
|
||||
|
||||
nComSpecSize = GetModuleFileName(g_hInstance, meDLLPath, MAX_PATH) + 2; // 2 chars for quotes
|
||||
g_exec = (TCHAR *)GlobalAlloc(GPTR, sizeof(TCHAR) * (g_stringsize+nComSpecSize+2)); // 1 for space, 1 for null
|
||||
p = meDLLPath + nComSpecSize - 2; // point p at null char of meDLLPath
|
||||
*g_exec = _T('"');
|
||||
executor = g_exec + 1;
|
||||
|
||||
// Look for the last '\' in path.
|
||||
do
|
||||
{
|
||||
if (*p == _T('\\'))
|
||||
break;
|
||||
p = CharPrev(meDLLPath, p);
|
||||
}
|
||||
while (p > meDLLPath);
|
||||
if (p == meDLLPath)
|
||||
{
|
||||
// bad path
|
||||
pushstring(_T("error"));
|
||||
GlobalFree(g_exec);
|
||||
return;
|
||||
}
|
||||
|
||||
*p = 0;
|
||||
GetTempFileName(meDLLPath, _T("ns"), 0, executor); // executor = new temp file name in module path.
|
||||
*p = _T('\\');
|
||||
if (CopyFile(meDLLPath, executor, FALSE)) // copy current DLL to temp file in module path.
|
||||
{
|
||||
HANDLE hFile, hMapping;
|
||||
LPBYTE pMapView;
|
||||
PIMAGE_NT_HEADERS pNTHeaders;
|
||||
hFile = CreateFile(executor, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING,0, 0);
|
||||
hMapping = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
|
||||
pMapView = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, 0);
|
||||
if (pMapView)
|
||||
{
|
||||
pNTHeaders = (PIMAGE_NT_HEADERS)(pMapView + ((PIMAGE_DOS_HEADER)pMapView)->e_lfanew);
|
||||
// Turning the copied DLL into a stripped down executable.
|
||||
pNTHeaders->FileHeader.Characteristics = IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_LOCAL_SYMS_STRIPPED |
|
||||
IMAGE_FILE_LINE_NUMS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE;
|
||||
// Windows character-mode user interface (CUI) subsystem.
|
||||
pNTHeaders->OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
|
||||
// g_hInst is assumed to be the very base of the DLL in memory.
|
||||
// WinMain will have the address of the WinMain function in memory.
|
||||
// Getting the difference gets you the relative location of the
|
||||
// WinMain function.
|
||||
pNTHeaders->OptionalHeader.AddressOfEntryPoint = (DWORD) ((DWORD_PTR)AsExeWinMain - (DWORD_PTR)g_hInstance);
|
||||
UnmapViewOfFile(pMapView);
|
||||
}
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
|
||||
lstrcat(g_exec, _T("\""));
|
||||
|
||||
// add space
|
||||
pExec = g_exec + lstrlen(g_exec);
|
||||
*pExec = _T(' ');
|
||||
pExec++;
|
||||
} else {
|
||||
executor = NULL;
|
||||
g_exec = (TCHAR *)GlobalAlloc(GPTR, sizeof(TCHAR) * (g_stringsize+1)); // 1 for NULL
|
||||
pExec = g_exec;
|
||||
}
|
||||
|
||||
to = 0; // default is no timeout
|
||||
bOEM = FALSE; // default is no OEM->ANSI conversion
|
||||
|
||||
g_hwndList = NULL;
|
||||
|
||||
// g_hwndParent = the caller, usually NSIS installer.
|
||||
if (g_hwndParent) // The window class name for dialog boxes is "#32770"
|
||||
g_hwndList = FindWindowEx(FindWindowEx(g_hwndParent, NULL, _T("#32770"), NULL), NULL, _T("SysListView32"), NULL);
|
||||
|
||||
// g_exec is the complete command to run: It has the copy of this DLL turned
|
||||
// into an executable right now.
|
||||
|
||||
params:
|
||||
// Get the command I need to run from the NSIS stack.
|
||||
popstring(pExec);
|
||||
if (my_strstr(pExec, _T("/TIMEOUT=")) == pExec) {
|
||||
TCHAR *szTimeout = pExec + 9;
|
||||
to = my_atoi(szTimeout);
|
||||
*pExec = 0;
|
||||
goto params;
|
||||
}
|
||||
if (!lstrcmpi(pExec, _T("/OEM"))) {
|
||||
bOEM = forceNarrowInput = TRUE;
|
||||
*pExec = 0;
|
||||
goto params;
|
||||
}
|
||||
if (!lstrcmpi(pExec, _T("/MBCS"))) {
|
||||
forceNarrowInput = TRUE;
|
||||
*pExec = 0;
|
||||
goto params;
|
||||
}
|
||||
|
||||
if (!pExec[0])
|
||||
{
|
||||
pushstring(_T("error"));
|
||||
if (pExec-2 >= g_exec)
|
||||
*(pExec-2) = _T('\0'); // skip space and quote
|
||||
if (executor) DeleteFile(executor);
|
||||
GlobalFree(g_exec);
|
||||
return;
|
||||
}
|
||||
|
||||
// Got all the params off the stack.
|
||||
|
||||
{
|
||||
STARTUPINFO si = { sizeof(si), };
|
||||
SECURITY_ATTRIBUTES sa = { sizeof(sa), };
|
||||
SECURITY_DESCRIPTOR sd = { 0, };
|
||||
PROCESS_INFORMATION pi;
|
||||
const BOOL isNT = sizeof(void*) > 4 || (GetVersion() < 0x80000000);
|
||||
HANDLE newstdout = 0, read_stdout = 0;
|
||||
HANDLE newstdin = 0, read_stdin = 0;
|
||||
int utfSource = sizeof(TCHAR) > 1 && !forceNarrowInput ? -1 : FALSE, utfOutput = sizeof(TCHAR) > 1;
|
||||
DWORD cbRead, dwLastOutput;
|
||||
DWORD dwExit = 0, waitResult = WAIT_TIMEOUT;
|
||||
static BYTE bufSrc[1024];
|
||||
BYTE *pSrc;
|
||||
SIZE_T cbSrcTot = sizeof(bufSrc), cbSrc = 0, cbSrcFree;
|
||||
TCHAR *bufOutput = 0, *pNewAlloc, *pD;
|
||||
SIZE_T cchAlloc, cbAlloc, cchFree;
|
||||
#ifndef _MSC_VER // Avoid GCC "may be used uninitialized in this function" warnings
|
||||
pD = NULL;
|
||||
cchAlloc = 0;
|
||||
#endif
|
||||
|
||||
pi.hProcess = pi.hThread = NULL;
|
||||
codepage = bOEM ? CP_OEMCP : CP_ACP;
|
||||
|
||||
if (!ignoreData) {
|
||||
cbAlloc = stackMode ? (g_stringsize * sizeof(TCHAR)) : sizeof(bufSrc) * 4, cchAlloc = cbAlloc / sizeof(TCHAR);
|
||||
pD = bufOutput = GlobalAlloc(GPTR, cbAlloc + sizeof(TCHAR)); // Include "hidden" space for a \0
|
||||
if (!bufOutput) {
|
||||
lstrcpy(szRet, _T("error"));
|
||||
goto done;
|
||||
}
|
||||
*bufOutput = _T('\0');
|
||||
}
|
||||
|
||||
sa.bInheritHandle = TRUE;
|
||||
sa.lpSecurityDescriptor = NULL;
|
||||
if (isNT) {
|
||||
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
|
||||
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
|
||||
sa.lpSecurityDescriptor = &sd;
|
||||
}
|
||||
|
||||
if (!CreatePipe(&read_stdout, &newstdout, &sa, 0)) {
|
||||
lstrcpy(szRet, _T("error"));
|
||||
goto done;
|
||||
}
|
||||
if (!CreatePipe(&read_stdin, &newstdin, &sa, 0)) {
|
||||
lstrcpy(szRet, _T("error"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
GetStartupInfo(&si); // Why?
|
||||
si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_HIDE;
|
||||
si.hStdInput = newstdin;
|
||||
si.hStdOutput = newstdout;
|
||||
si.hStdError = newstdout;
|
||||
if (!CreateProcess(NULL, g_exec, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
|
||||
lstrcpy(szRet, _T("error"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Now I'm talking with an executable copy of myself.
|
||||
dwLastOutput = GetTickCount();
|
||||
for (;;) {
|
||||
TCHAR bufCh[2];
|
||||
waitForProcess:
|
||||
waitResult = WaitForSingleObject(pi.hProcess, 0);
|
||||
GetExitCodeProcess(pi.hProcess, &dwExit);
|
||||
readMore:
|
||||
PeekNamedPipe(read_stdout, 0, 0, 0, &cbRead, NULL);
|
||||
if (!cbRead) {
|
||||
if (waitResult == WAIT_OBJECT_0) {
|
||||
break; // No data in the pipe and process ended, we are done
|
||||
}
|
||||
if (to && GetTickCount() > dwLastOutput+to) {
|
||||
TerminateProcess(pi.hProcess, -1);
|
||||
lstrcpy(szRet, _T("timeout"));
|
||||
}
|
||||
else {
|
||||
Sleep(LOOPTIMEOUT);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
dwLastOutput = GetTickCount();
|
||||
ReadFile(read_stdout, bufSrc + cbSrc, (DWORD) (cbSrcFree = cbSrcTot - cbSrc), &cbRead, NULL);
|
||||
cbSrcFree -= cbRead, cbSrc = cbSrcTot - cbSrcFree;
|
||||
pSrc = bufSrc;
|
||||
|
||||
if (utfSource < 0 && cbSrc) { // Simple UTF-16LE detection
|
||||
#ifdef UNICODE
|
||||
utfSource = IsTextUnicode(pSrc, (UINT) (cbSrc & ~1), NULL) != FALSE;
|
||||
#else
|
||||
utfSource = (cbSrc >= 3 && pSrc[0] && !pSrc[1]) || (cbSrc > 4 && pSrc[2] && !pSrc[3]); // Lame latin-only test
|
||||
utfSource |= (cbSrc > 3 && pSrc[0] == 0xFF && pSrc[1] == 0xFE && (pSrc[2] | pSrc[3])); // Lame BOM test
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ignoreData) {
|
||||
cbSrc = 0; // Overwrite the whole buffer every read
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!cbRead) {
|
||||
continue; // No new data, read more before trying to parse
|
||||
}
|
||||
|
||||
parseLines:
|
||||
cchFree = cchAlloc - (pD - bufOutput);
|
||||
for (;;) {
|
||||
DWORD cbSrcChar = 1, cchDstChar, i;
|
||||
*pD = _T('\0'); // Terminate output buffer because we can unexpectedly run out of data
|
||||
if (!cbSrc) {
|
||||
goto readMore;
|
||||
}
|
||||
|
||||
if (utfSource) { // UTF-16LE --> ?:
|
||||
if (cbSrc < 2) {
|
||||
goto readMore;
|
||||
}
|
||||
if (utfOutput) { // UTF-16LE --> UTF-16LE:
|
||||
bufCh[0] = ((TCHAR*)pSrc)[0], cbSrcChar = sizeof(WCHAR), cchDstChar = 1; // We only care about certain ASCII characters so we don't bother dealing with surrogate pairs.
|
||||
}
|
||||
else { // UTF-16LE --> DBCS
|
||||
// TODO: This is tricky because we need the complete base character (or surrogate pair) and all the trailing combining characters for a grapheme in the buffer before we can call WideCharToMultiByte.
|
||||
utfOutput = FALSE; // For now we just treat it as DBCS
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else { // DBCS --> ?:
|
||||
if (utfOutput) { // DBCS --> UTF-16LE:
|
||||
BOOL isMb = IsDBCSLeadByteEx(codepage, ((CHAR*)pSrc)[0]);
|
||||
if (isMb && cbSrc < ++cbSrcChar) {
|
||||
goto readMore;
|
||||
}
|
||||
cchDstChar = MultiByteToWideChar(codepage, 0, (CHAR*)pSrc, cbSrcChar, (WCHAR*) bufCh, 2);
|
||||
}
|
||||
else { // DBCS --> DBCS:
|
||||
bufCh[0] = ((CHAR*)pSrc)[0], cchDstChar = 1; // Note: OEM codepage will be converted by LogMessage
|
||||
}
|
||||
}
|
||||
|
||||
if (bufCh[0] == _T('\t') && tabExpandLength) { // Expand tab to spaces?
|
||||
if (cchFree < tabExpandLength) {
|
||||
goto resizeOutputBuffer;
|
||||
}
|
||||
lstrcpy(pD, TAB_REPLACE);
|
||||
pD += tabExpandLength, cchFree -= tabExpandLength;
|
||||
}
|
||||
else if (bufCh[0] == _T('\r') && logMode) {
|
||||
// Eating it
|
||||
}
|
||||
else if (bufCh[0] == _T('\n') && logMode) {
|
||||
LogMessage(bufOutput, bOEM); // Output has already been \0 terminated
|
||||
*(pD = bufOutput) = _T('\0'), cchFree = cchAlloc;
|
||||
}
|
||||
else {
|
||||
if (cchFree < cchDstChar) {
|
||||
SIZE_T cchOrgOffset;
|
||||
resizeOutputBuffer:
|
||||
if (stackMode) {
|
||||
ignoreData = TRUE; // Buffer was already maximum for the NSIS stack, we cannot handle more data
|
||||
if (utfOutput)
|
||||
TruncateStringUTF16LE((LPWSTR) bufOutput, pD - bufOutput, (LPCWSTR) bufCh, cchDstChar);
|
||||
else
|
||||
TruncateStringMB(codepage, (LPSTR) bufOutput, pD - bufOutput, bufCh[0]);
|
||||
goto waitForProcess;
|
||||
}
|
||||
cchAlloc += 1024, cbAlloc = cchAlloc / sizeof(TCHAR);
|
||||
pNewAlloc = GlobalReAlloc(bufOutput, cbAlloc + sizeof(TCHAR),GPTR|GMEM_MOVEABLE); // Include "hidden" space for a \0
|
||||
if (!pNewAlloc) {
|
||||
lstrcpy(szRet, _T("error"));
|
||||
ignoreData = TRUE;
|
||||
goto waitForProcess;
|
||||
}
|
||||
cchOrgOffset = pD - bufOutput;
|
||||
*(pD = (bufOutput = pNewAlloc) + cchOrgOffset) = _T('\0');
|
||||
goto parseLines;
|
||||
}
|
||||
for (i = 0; i < cchDstChar; ++i) {
|
||||
*pD++ = bufCh[i], --cchFree;
|
||||
}
|
||||
}
|
||||
pSrc += cbSrcChar, cbSrc -= cbSrcChar;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (stackMode) pushstring(bufOutput);
|
||||
if (logMode && *bufOutput) LogMessage(bufOutput,bOEM); // Write remaining output
|
||||
if (dwExit == STATUS_ILLEGAL_INSTRUCTION)
|
||||
lstrcpy(szRet, _T("error"));
|
||||
if (!szRet[0]) wsprintf(szRet,_T("%d"),dwExit);
|
||||
pushstring(szRet);
|
||||
CloseHandle(pi.hThread);
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(newstdout);
|
||||
CloseHandle(read_stdout);
|
||||
CloseHandle(newstdin);
|
||||
CloseHandle(read_stdin);
|
||||
if (pExec-2 >= g_exec)
|
||||
*(pExec-2) = _T('\0'); // skip space and quote
|
||||
if (executor)
|
||||
DeleteFile(executor);
|
||||
GlobalFree(g_exec);
|
||||
if (bufOutput)
|
||||
GlobalFree(bufOutput);
|
||||
}
|
||||
}
|
||||
|
||||
static TCHAR *my_strstr(TCHAR *a, TCHAR *b)
|
||||
{
|
||||
int l = lstrlen(b);
|
||||
while (lstrlen(a) >= l)
|
||||
{
|
||||
TCHAR c = a[l];
|
||||
a[l] = 0;
|
||||
if (!lstrcmpi(a, b))
|
||||
{
|
||||
a[l] = c;
|
||||
return a;
|
||||
}
|
||||
a[l] = c;
|
||||
a = CharNext(a);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned int my_atoi(TCHAR *s) {
|
||||
unsigned int v=0;
|
||||
if (*s == _T('0') && (s[1] == _T('x') || s[1] == _T('X'))) {
|
||||
s+=2;
|
||||
for (;;) {
|
||||
int c=*s++;
|
||||
if (c >= _T('0') && c <= _T('9')) c-=_T('0');
|
||||
else if (c >= _T('a') && c <= _T('f')) c-=_T('a')-10;
|
||||
else if (c >= _T('A') && c <= _T('F')) c-=_T('A')-10;
|
||||
else break;
|
||||
v<<=4;
|
||||
v+=c;
|
||||
}
|
||||
}
|
||||
else if (*s == _T('0') && s[1] <= _T('7') && s[1] >= _T('0')) {
|
||||
s++;
|
||||
for (;;) {
|
||||
int c=*s++;
|
||||
if (c >= _T('0') && c <= _T('7')) c-=_T('0');
|
||||
else break;
|
||||
v<<=3;
|
||||
v+=c;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (;;) {
|
||||
int c=*s++ - _T('0');
|
||||
if (c < 0 || c > 9) break;
|
||||
v*=10;
|
||||
v+=c;
|
||||
}
|
||||
}
|
||||
return (int)v;
|
||||
}
|
||||
|
||||
int WINAPI AsExeWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
|
||||
{
|
||||
DWORD Ret;
|
||||
STARTUPINFO si = {0};
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
TCHAR command_line[1024]; //BUGBUG
|
||||
TCHAR seekchar=_T(' ');
|
||||
TCHAR *cmdline;
|
||||
|
||||
si.cb = sizeof(si);
|
||||
// Make child process use this app's standard files. Not needed because the handles
|
||||
// we created when executing this process were inheritable.
|
||||
//si.dwFlags = STARTF_USESTDHANDLES;
|
||||
//si.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
|
||||
//si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
|
||||
//si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
|
||||
lstrcpyn(command_line, GetCommandLine(), 1024);
|
||||
|
||||
cmdline = command_line;
|
||||
if (*cmdline == _T('\"')) seekchar = *cmdline++;
|
||||
|
||||
while (*cmdline && *cmdline != seekchar) cmdline=CharNext(cmdline);
|
||||
cmdline=CharNext(cmdline);
|
||||
// skip any spaces before the arguments
|
||||
while (*cmdline && *cmdline == _T(' ')) cmdline++;
|
||||
|
||||
Ret = CreateProcess (NULL, cmdline,
|
||||
NULL, NULL,
|
||||
TRUE, 0,
|
||||
NULL, NULL,
|
||||
&si, &pi
|
||||
);
|
||||
|
||||
if (Ret)
|
||||
{
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
GetExitCodeProcess(pi.hProcess, &Ret);
|
||||
CloseHandle (pi.hProcess);
|
||||
CloseHandle (pi.hThread);
|
||||
ExitProcess(Ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExitProcess(STATUS_ILLEGAL_INSTRUCTION);
|
||||
}
|
||||
|
||||
return 0; // dummy
|
||||
}
|
122
nsisplugin/IsActivated.c
Normal file
122
nsisplugin/IsActivated.c
Normal file
@@ -0,0 +1,122 @@
|
||||
#include <windows.h>
|
||||
#include <nsis/pluginapi.h>
|
||||
#include "main.h"
|
||||
#include "WMI.h"
|
||||
#include "VersionInfo.h"
|
||||
#include "licdll.h"
|
||||
#include <slpublic.h>
|
||||
|
||||
typedef HRESULT (WINAPI *_SLOpen)(HSLC *);
|
||||
typedef HRESULT (WINAPI *_SLGetLicensingStatusInformation)(HSLC, const SLID *, DWORD, DWORD, UINT *, SL_LICENSING_STATUS **);
|
||||
typedef HRESULT (WINAPI *_SLClose)(HSLC);
|
||||
|
||||
static _SLOpen $SLOpen;
|
||||
static _SLClose $SLClose;
|
||||
static _SLGetLicensingStatusInformation $SLGetLicensingStatusInformation;
|
||||
|
||||
static BOOL g_loadedLicenseStatus = FALSE;
|
||||
static BOOL g_isActivated = TRUE;
|
||||
|
||||
PLUGIN_METHOD(IsActivated) {
|
||||
PLUGIN_INIT();
|
||||
|
||||
// Get the Operating System Version information as well as the CPU architecture.
|
||||
// We'll need this so that we activate the correct COM object on 64-bit versions
|
||||
// of Windows XP and Windows Server 2003.
|
||||
OSVERSIONINFOEX* versionInfo = GetVersionInfo();
|
||||
SYSTEM_INFO systemInfo;
|
||||
GetSystemInfo(&systemInfo);
|
||||
|
||||
// Activation is irrelevant prior to XP
|
||||
if (g_loadedLicenseStatus || !AtLeastWinXP2002()) {
|
||||
pushint(g_isActivated);
|
||||
return;
|
||||
}
|
||||
|
||||
g_loadedLicenseStatus = TRUE;
|
||||
|
||||
if (AtLeastWinVista()) {
|
||||
// Vista+: Ask the Software Licensing Service
|
||||
if (!$SLOpen) {
|
||||
HMODULE slc = LoadLibrary(L"slc.dll");
|
||||
$SLOpen = (_SLOpen)GetProcAddress(slc, "SLOpen");
|
||||
$SLClose = (_SLClose)GetProcAddress(slc, "SLClose");
|
||||
$SLGetLicensingStatusInformation = (_SLGetLicensingStatusInformation)GetProcAddress(slc, "SLGetLicensingStatusInformation");
|
||||
}
|
||||
|
||||
if (!$SLOpen || !$SLClose || !$SLGetLicensingStatusInformation) {
|
||||
TRACE(L"Failed to load slc.dll");
|
||||
pushint(1);
|
||||
return;
|
||||
}
|
||||
|
||||
HSLC slc;
|
||||
SL_LICENSING_STATUS *status;
|
||||
UINT count;
|
||||
HRESULT hr = $SLOpen(&slc);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
goto end_slc;
|
||||
}
|
||||
|
||||
hr = $SLGetLicensingStatusInformation(slc, &WINDOWS_SLID, 0, 0, &count, &status);
|
||||
if (!SUCCEEDED(hr) || count == 0) {
|
||||
goto end_slc;
|
||||
}
|
||||
|
||||
// Iterate through all statuses until we find one in Licensed status.
|
||||
g_isActivated = FALSE;
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (status[i].eStatus == SL_LICENSING_STATUS_LICENSED) {
|
||||
g_isActivated = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
end_slc:
|
||||
if (status) {
|
||||
LocalFree(status);
|
||||
}
|
||||
if (slc) {
|
||||
$SLClose(slc);
|
||||
}
|
||||
} else {
|
||||
// XP: Use private API
|
||||
ICOMLicenseAgent *agent;
|
||||
HRESULT hr;
|
||||
|
||||
// On XP and Server 2003 x64, we need to pass a different argument to CoCreateInstance.
|
||||
if (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
|
||||
hr = CoCreateInstance(&CLSID_COMLicenseAgent, NULL, CLSCTX_INPROC_SERVER | CLSCTX_ACTIVATE_64_BIT_SERVER, &IID_ICOMLicenseAgent, (void **)&agent);
|
||||
} else {
|
||||
hr = CoCreateInstance(&CLSID_COMLicenseAgent, NULL, CLSCTX_INPROC_SERVER, &IID_ICOMLicenseAgent, (void **)&agent);
|
||||
}
|
||||
|
||||
if (!SUCCEEDED(hr)) {
|
||||
TRACE(L"COMLicenseAgent load failed: %x", hr);
|
||||
goto end_xp;
|
||||
}
|
||||
|
||||
ULONG result;
|
||||
hr = ICOMLicenseAgent_Initialize(agent, 0xC475, 3, NULL, &result);
|
||||
if (!SUCCEEDED(hr) || result != 0) {
|
||||
TRACE(L"COMLicenseAgent init failed: %x", hr);
|
||||
goto end_xp;
|
||||
}
|
||||
|
||||
ULONG wpaLeft, evalLeft;
|
||||
hr = ICOMLicenseAgent_GetExpirationInfo(agent, &wpaLeft, &evalLeft);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
TRACE(L"COMLicenseAgent GetExpirationInfo failed: %x", hr);
|
||||
goto end_xp;
|
||||
}
|
||||
|
||||
g_isActivated = wpaLeft == MAXLONG;
|
||||
|
||||
end_xp:
|
||||
if (agent) {
|
||||
ICOMLicenseAgent_Release(agent);
|
||||
}
|
||||
}
|
||||
|
||||
pushint(g_isActivated);
|
||||
}
|
9
nsisplugin/IsAdmin.c
Normal file
9
nsisplugin/IsAdmin.c
Normal file
@@ -0,0 +1,9 @@
|
||||
#include <windows.h>
|
||||
#include <nsis/pluginapi.h>
|
||||
#include "User.h"
|
||||
|
||||
PLUGIN_METHOD(IsAdmin) {
|
||||
PLUGIN_INIT();
|
||||
|
||||
pushint(IsUserAdmin());
|
||||
}
|
67
nsisplugin/UpdateRoots.c
Normal file
67
nsisplugin/UpdateRoots.c
Normal file
@@ -0,0 +1,67 @@
|
||||
#include <windows.h>
|
||||
#include <nsis/pluginapi.h>
|
||||
#include <wincrypt.h>
|
||||
#include "HResult.h"
|
||||
|
||||
PLUGIN_METHOD(UpdateRoots) {
|
||||
PLUGIN_INIT();
|
||||
|
||||
HRESULT hr = E_FAIL;
|
||||
WCHAR stateStr[1024], store[1024], path[1024];
|
||||
popstring(stateStr);
|
||||
popstring(store);
|
||||
popstring(path);
|
||||
|
||||
if (!stateStr || !store || !path) {
|
||||
pushint(E_INVALIDARG);
|
||||
return;
|
||||
}
|
||||
|
||||
BOOL add;
|
||||
if (lstrcmpi(stateStr, L"/update") == 0) {
|
||||
add = TRUE;
|
||||
} else if (lstrcmpi(stateStr, L"/delete") == 0) {
|
||||
add = FALSE;
|
||||
} else {
|
||||
pushint(E_INVALIDARG);
|
||||
return;
|
||||
}
|
||||
|
||||
HCERTSTORE srcStore = CertOpenStore(CERT_STORE_PROV_FILENAME_W, 0, 0, CERT_STORE_READONLY_FLAG, path);
|
||||
if (!srcStore) {
|
||||
TRACE(L"CertOpenStore for %ls failed: %08x", path, hr);
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto end;
|
||||
}
|
||||
|
||||
HCERTSTORE dstStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, store);
|
||||
if (!dstStore) {
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
TRACE(L"CertOpenStore for %ls failed: %08x", store, hr);
|
||||
goto end;
|
||||
}
|
||||
|
||||
PCCERT_CONTEXT cert = NULL;
|
||||
while ((cert = CertEnumCertificatesInStore(srcStore, cert)) != NULL) {
|
||||
BOOL result = add
|
||||
? CertAddCertificateContextToStore(dstStore, cert, CERT_STORE_ADD_REPLACE_EXISTING, NULL)
|
||||
: CertDeleteCertificateFromStore(CertDuplicateCertificateContext(cert));
|
||||
if (!result) {
|
||||
TRACE(L"cert %ls in %ls failed: %d\n", add ? L"add" : L"delete", store, GetLastError());
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
hr = S_OK;
|
||||
|
||||
end:
|
||||
if (srcStore) {
|
||||
CertCloseStore(srcStore, 0);
|
||||
}
|
||||
if (dstStore) {
|
||||
CertCloseStore(dstStore, 0);
|
||||
}
|
||||
|
||||
pushint(hr);
|
||||
}
|
Reference in New Issue
Block a user