mirror of
https://github.com/modernw/App-Installer-For-Windows-8.x-Reset.git
synced 2026-04-11 17:57:19 +10:00
1730 lines
57 KiB
C++
1730 lines
57 KiB
C++
#include <Windows.h>
|
||
#include <set>
|
||
#include <msclr/marshal_cppstd.h>
|
||
#include <ShObjIdl.h>
|
||
#include <ShlObj.h> // KNOWNFOLDERID, SHGetKnownFolderPath
|
||
#include <commdlg.h> // OPENFILENAME
|
||
#include <comdef.h> // _com_error
|
||
#include <winhttp.h> // WinHTTP
|
||
#include <MsHTML.h>
|
||
#include <ExDisp.h>
|
||
#include <atlbase.h>
|
||
#include <fstream>
|
||
#include <comdef.h>
|
||
#include <vcclr.h>
|
||
#include <map>
|
||
#include <commdlg.h>
|
||
#include <rapidjson\document.h>
|
||
#include <rapidjson\writer.h>
|
||
#include <rapidjson\stringbuffer.h>
|
||
#include <tlhelp32.h>
|
||
#include <Psapi.h>
|
||
#include <cliext/vector>
|
||
#include <cliext/utility>
|
||
#include "module.h"
|
||
#include "themeinfo.h"
|
||
#include "mpstr.h"
|
||
#include "initfile.h"
|
||
#include "vemani.h"
|
||
#include "ieshell.h"
|
||
#include "localeex.h"
|
||
#include "download.h"
|
||
#include "bridge.h"
|
||
#include "rctools.h"
|
||
#include "nstring.h"
|
||
#include "resmap.h"
|
||
#include "nstring.h"
|
||
#include "raii.h"
|
||
|
||
using namespace System;
|
||
using namespace System::Runtime::InteropServices;
|
||
using namespace System::IO::Compression;
|
||
using namespace System::Text;
|
||
|
||
#ifdef _DEBUG
|
||
#define DEBUGMODE true
|
||
#else
|
||
#define DEBUGMODE false
|
||
#endif
|
||
#define JS_SAFE [MarshalAs (UnmanagedType::SafeArray, SafeArraySubType = VarEnum::VT_VARIANT)]
|
||
struct iconhandle
|
||
{
|
||
HICON hIcon = nullptr;
|
||
iconhandle (HICON hIcon = nullptr): hIcon (hIcon) {}
|
||
~iconhandle () { try { if (hIcon) DestroyIcon (hIcon); hIcon = nullptr; } catch (...) {} }
|
||
};
|
||
|
||
LPCWSTR g_lpAppId = L"WindowsModern.PracticalToolsProject!Settings";
|
||
LPCWSTR g_idInVe = L"Settings";
|
||
LPCWSTR g_wndclass = L"Win32_WebUI_WindowsModern_Settings";
|
||
iconhandle g_hIconMain (LoadRCIcon (IDI_ICON_MAIN));
|
||
initfile g_initfile (CombinePath (GetProgramRootDirectoryW (), L"config.ini"));
|
||
vemanifest g_vemani (
|
||
IsFileExists (CombinePath (GetProgramRootDirectoryW (), L"VisualElementsManifest.xml")) ?
|
||
CombinePath (GetProgramRootDirectoryW (), L"VisualElementsManifest.xml") :
|
||
CombinePath (GetProgramRootDirectoryW (), L"Settings.VisualElementsManifest.xml")
|
||
);
|
||
resxmldoc g_scaleres (
|
||
IsFileExists (CombinePath (GetProgramRootDirectoryW (), L"VisualElements\\scale.xml")) ?
|
||
CombinePath (GetProgramRootDirectoryW (), L"VisualElements\\scale.xml") :
|
||
CombinePath (GetProgramRootDirectoryW (), L"VisualElementsManifest.xml")
|
||
);
|
||
ref class MainHtmlWnd;
|
||
msclr::gcroot <MainHtmlWnd ^> g_mainwnd;
|
||
std::wstring g_lastfile;
|
||
inline std::wstring ToStdWString (const std::wstring &str) { return str; }
|
||
std::string GetSuitableLanguageValue (const std::map <std::nstring, std::string> &map, const std::nstring &localename)
|
||
{
|
||
for (auto &it : map) if (it.first == localename) return it.second;
|
||
for (auto &it : map) if (LocaleNameCompare (pugi::as_wide (it.first), pugi::as_wide (localename))) return it.second;
|
||
for (auto &it : map) if (IsNormalizeStringEquals (GetLocaleRestrictedCodeA (it.first), GetLocaleRestrictedCodeA (localename))) return it.second;
|
||
for (auto &it : map) if (LocaleNameCompare (pugi::as_wide (GetLocaleRestrictedCodeA (it.first)), pugi::as_wide (GetLocaleRestrictedCodeA (localename)))) return it.second;
|
||
return "";
|
||
}
|
||
std::string GetSuitableLanguageValue (const std::map <std::nstring, std::string> &map)
|
||
{
|
||
if (map.empty ()) return "";
|
||
std::string ret = GetSuitableLanguageValue (map, pugi::as_utf8 (GetComputerLocaleCodeW ()));
|
||
if (ret.empty ()) ret = GetSuitableLanguageValue (map, "en-US");
|
||
if (ret.empty ()) ret = map.begin ()->second;
|
||
return ret;
|
||
}
|
||
struct xmlstrres
|
||
{
|
||
pugi::xml_document doc;
|
||
bool isvalid = false;
|
||
void destroy ()
|
||
{
|
||
if (isvalid) doc.reset ();
|
||
isvalid = false;
|
||
}
|
||
bool create (const std::wstring &filepath)
|
||
{
|
||
destroy ();
|
||
auto res = doc.load_file (filepath.c_str ());
|
||
return isvalid = res;
|
||
}
|
||
xmlstrres (const std::wstring &filepath) { create (filepath); }
|
||
~xmlstrres () { destroy (); }
|
||
std::string get (const std::string &id) const
|
||
{
|
||
auto root = doc.first_child ();
|
||
auto nodes = root.children ();
|
||
for (auto &it : nodes)
|
||
{
|
||
if (IsNormalizeStringEquals (std::string (it.attribute ("id").as_string ()), id))
|
||
{
|
||
auto strings = it.children ();
|
||
std::map <std::nstring, std::string> lang_value;
|
||
for (auto &sub : strings)
|
||
{
|
||
std::nstring lang = sub.attribute ("name").as_string ();
|
||
if (!lang.empty ()) lang_value [lang] = sub.text ().get ();
|
||
}
|
||
return GetSuitableLanguageValue (lang_value);
|
||
}
|
||
}
|
||
return "";
|
||
}
|
||
std::wstring get (const std::wstring &id) const { return pugi::as_wide (get (pugi::as_utf8 (id))); }
|
||
std::wstring operator [] (const std::wstring &id) const { return get (id); }
|
||
std::wstring operator [] (const std::wstring &id) { return get (id); }
|
||
std::string operator [] (const std::string &id) const { return get (id); }
|
||
std::string operator [] (const std::string &id) { return get (id); }
|
||
};
|
||
xmlstrres g_winjspri (CombinePath (GetProgramRootDirectoryW (), L"locale\\resources.xml"));
|
||
std::vector <std::wstring> g_cmdargs;
|
||
|
||
size_t ExploreFile (HWND hParent, std::vector <std::wstring> &results, LPWSTR lpFilter = L"Windows Store App Package (*.appx; *.appxbundle)\0*.appx;*.appxbundle", DWORD dwFlags = OFN_EXPLORER | OFN_ALLOWMULTISELECT | OFN_PATHMUSTEXIST, const std::wstring &swWndTitle = std::wstring (L"Please select the file(-s): "), const std::wstring &swInitDir = GetFileDirectoryW (g_lastfile))
|
||
{
|
||
results.clear ();
|
||
const DWORD BUFFER_SIZE = 65536; // 64KB
|
||
std::vector <WCHAR> buffer (BUFFER_SIZE, 0);
|
||
OPENFILENAME ofn;
|
||
ZeroMemory (&ofn, sizeof (ofn));
|
||
ofn.hwndOwner = hParent;
|
||
ofn.lpstrFile = (LPWSTR)buffer.data ();
|
||
ofn.nMaxFile = BUFFER_SIZE;
|
||
ofn.lpstrFilter = lpFilter;
|
||
ofn.nFilterIndex = 1;
|
||
ofn.lpstrTitle = swWndTitle.c_str ();
|
||
ofn.Flags = dwFlags;
|
||
ofn.lpstrInitialDir = swInitDir.c_str ();
|
||
ofn.lStructSize = sizeof (ofn);
|
||
if (GetOpenFileNameW (&ofn))
|
||
{
|
||
LPCWSTR p = buffer.data ();
|
||
std::wstring dir = p;
|
||
p += dir.length () + 1;
|
||
if (*p == 0) results.push_back (dir);
|
||
else
|
||
{
|
||
while (*p)
|
||
{
|
||
std::wstring fullPath = dir + L"\\" + p;
|
||
results.push_back (fullPath);
|
||
p += wcslen (p) + 1;
|
||
}
|
||
}
|
||
if (!results.empty ()) g_lastfile = results.back ();
|
||
}
|
||
return results.size ();
|
||
}
|
||
HRESULT GetWebBrowser2Interface (System::Windows::Forms::WebBrowser ^fwb, IWebBrowser2 **output)
|
||
{
|
||
if (fwb == nullptr || output == nullptr) return E_INVALIDARG;
|
||
*output = nullptr;
|
||
Object ^activeX = fwb->ActiveXInstance;
|
||
if (activeX == nullptr) return E_FAIL;
|
||
IntPtr pUnk = Marshal::GetIUnknownForObject (activeX);
|
||
if (pUnk == IntPtr::Zero) return E_FAIL;
|
||
HRESULT hr = ((IUnknown *)pUnk.ToPointer ())->QueryInterface (IID_IWebBrowser2, (void **)output);
|
||
Marshal::Release (pUnk);
|
||
return hr;
|
||
}
|
||
bool IsWindows10 ()
|
||
{
|
||
#pragma warning(push)
|
||
#pragma warning(disable:4996)
|
||
OSVERSIONINFOEX osvi = {0};
|
||
osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
|
||
osvi.dwMajorVersion = 10;
|
||
DWORDLONG conditionMask = 0;
|
||
VER_SET_CONDITION (conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
|
||
if (VerifyVersionInfoW (&osvi, VER_MAJORVERSION, conditionMask)) return TRUE;
|
||
DWORD error = GetLastError ();
|
||
return (error == ERROR_OLD_WIN_VERSION) ? FALSE : FALSE;
|
||
#pragma warning(pop)
|
||
}
|
||
[ComVisible (true)]
|
||
public ref class _I_InitConfig
|
||
{
|
||
public:
|
||
Win32::InitConfig ^Create (String ^filepath) { return gcnew Win32::InitConfig (filepath); }
|
||
Win32::InitConfig ^GetConfig () { return Create (CStringToMPString (g_initfile.filepath)); }
|
||
};
|
||
[ComVisible (true)]
|
||
public ref class _I_VisualElement
|
||
{
|
||
protected:
|
||
String ^appid;
|
||
public:
|
||
_I_VisualElement (String ^appid): appid (appid) {}
|
||
_I_VisualElement (): appid (String::Empty) {}
|
||
property String ^Id { String ^get () { return appid; } void set (String ^value) { appid = value; } }
|
||
#define PROPERTY_VELEMENT(_PropertyName_, _MethodName_) \
|
||
property String ^_PropertyName_ { \
|
||
String ^get() { \
|
||
return CStringToMPString(g_vemani._MethodName_(MPStringToStdW(appid))); \
|
||
} \
|
||
}
|
||
PROPERTY_VELEMENT (DisplayName, display_name)
|
||
PROPERTY_VELEMENT (Logo, logo)
|
||
PROPERTY_VELEMENT (SmallLogo, small_logo)
|
||
property String ^ForegroundText { String ^get () { return g_vemani.foreground_text (MPStringToStdW (appid)) == vemanifest::TextColor::light ? "light" : "dark"; }}
|
||
PROPERTY_VELEMENT (Lnk32x32Logo, lnk_32x32_logo)
|
||
PROPERTY_VELEMENT (ItemDisplayLogo, item_display_logo)
|
||
property bool ShowNameOnTile { bool get () { return g_vemani.show_name_on_tile (MPStringToStdW (appid)); }}
|
||
PROPERTY_VELEMENT (BackgroundColor, background_color)
|
||
PROPERTY_VELEMENT (SplashScreenImage, splash_screen_image)
|
||
PROPERTY_VELEMENT (SplashScreenBackgroundColor, splash_screen_backgroundcolor)
|
||
PROPERTY_VELEMENT (SplashScreenBackgroundColorDarkMode, splash_screen_backgroundcolor_darkmode)
|
||
#ifdef PROPERTY_VELEMENT
|
||
#undef PROPERTY_VELEMENT
|
||
#endif
|
||
Object ^Get (String ^propertyName)
|
||
{
|
||
String ^str = propertyName->ToLower ()->Trim ();
|
||
if (str == "displayname") return DisplayName;
|
||
else if (str == "logo") return Logo;
|
||
else if (str == "smalllogo") return SmallLogo;
|
||
else if (str == "foregroundtext") return ForegroundText;
|
||
else if (str == "lnk32x32logo") return Lnk32x32Logo;
|
||
else if (str == "shownameontile") return ShowNameOnTile;
|
||
else if (str == "backgroundcolor") return BackgroundColor;
|
||
else if (str == "splashscreenimage") return SplashScreenImage;
|
||
else if (str == "splashscreenbackgroundcolor") return SplashScreenBackgroundColor;
|
||
else if (str == "splashscreenbackgroundcolordarkmode") return SplashScreenBackgroundColorDarkMode;
|
||
return String::Empty;
|
||
}
|
||
Object ^operator [] (String ^propertyName) { return Get (propertyName); }
|
||
};
|
||
[ComVisible (true)]
|
||
public ref class _I_VisualElements
|
||
{
|
||
public:
|
||
array <String ^> ^GetIds ()
|
||
{
|
||
std::vector <std::wstring> res;
|
||
g_vemani.app_ids (res);
|
||
auto ret = gcnew array <String ^> (res.size ());
|
||
for (size_t i = 0; i < res.size (); i ++) ret [i] = CStringToMPString (res [i]);
|
||
return ret;
|
||
}
|
||
String ^GetIdsToJson () { return StringArrayToJson (GetIds ()); }
|
||
_I_VisualElement ^Get (String ^id) { return gcnew _I_VisualElement (id); }
|
||
_I_VisualElement ^operator [] (String ^id) { return Get (id); }
|
||
#define ATTRIBUTE_METHODS(_FunctionName_, _MethodName_) \
|
||
String^ _FunctionName_(String^ appid) { \
|
||
return CStringToMPString(g_vemani._MethodName_(MPStringToStdW(appid))); \
|
||
}
|
||
ATTRIBUTE_METHODS (DisplayName, display_name)
|
||
ATTRIBUTE_METHODS (Logo, logo)
|
||
ATTRIBUTE_METHODS (SmallLogo, small_logo)
|
||
String ^ForegroundText (String ^appid)
|
||
{
|
||
return g_vemani.foreground_text (MPStringToStdW (appid)) == vemanifest::TextColor::light ? "light" : "dark";
|
||
}
|
||
ATTRIBUTE_METHODS (Lnk32x32Logo, lnk_32x32_logo)
|
||
ATTRIBUTE_METHODS (ItemDisplayLogo, item_display_logo)
|
||
bool ShowNameOnTile (String ^appid) { return g_vemani.show_name_on_tile (MPStringToStdW (appid)); }
|
||
ATTRIBUTE_METHODS (BackgroundColor, background_color)
|
||
ATTRIBUTE_METHODS (SplashScreenImage, splash_screen_image)
|
||
ATTRIBUTE_METHODS (SplashScreenBackgroundColor, splash_screen_backgroundcolor)
|
||
ATTRIBUTE_METHODS (SplashScreenBackgroundColorDarkMode, splash_screen_backgroundcolor_darkmode)
|
||
#ifdef ATTRIBUTE_METHODS
|
||
#undef ATTRIBUTE_METHODS
|
||
#endif
|
||
Object ^GetValue (String ^appid, String ^attributeName)
|
||
{
|
||
auto attr = attributeName->ToLower ()->Trim ();
|
||
if (attr == "displayname") return DisplayName (appid);
|
||
else if (attr == "logo") return Logo (appid);
|
||
else if (attr == "smalllogo") return SmallLogo (appid);
|
||
else if (attr == "foregroundtext") return ForegroundText (appid);
|
||
else if (attr == "lnk32x32logo") return Lnk32x32Logo (appid);
|
||
else if (attr == "itemdisplaylogo") return ItemDisplayLogo (appid);
|
||
else if (attr == "shownameontile") return ShowNameOnTile (appid);
|
||
else if (attr == "backgroundcolor") return BackgroundColor (appid);
|
||
else if (attr == "splashscreenimage") return SplashScreenImage (appid);
|
||
else if (attr == "splashscreenbackgroundcolor") return SplashScreenBackgroundColor (appid);
|
||
else if (attr == "splashscreenbackgroundcolordarkmode") return SplashScreenBackgroundColorDarkMode (appid);
|
||
else return String::Empty;
|
||
}
|
||
};
|
||
[ComVisible (true)]
|
||
public ref class _I_Bridge_Base
|
||
{
|
||
protected:
|
||
_I_String ^str = gcnew _I_String ();
|
||
_I_InitConfig ^initconfig = gcnew _I_InitConfig ();
|
||
_I_Storage ^storage = gcnew _I_Storage ();
|
||
public:
|
||
property _I_String ^String { _I_String ^get () { return str; }}
|
||
property _I_InitConfig ^Config { _I_InitConfig ^get () { return initconfig; }}
|
||
property _I_Storage ^Storage { _I_Storage ^get () { return storage; }}
|
||
};
|
||
[ComVisible (true)]
|
||
public interface class IScriptBridge
|
||
{
|
||
public:
|
||
virtual Object ^CallEvent (String ^funcName, Object ^e) = 0;
|
||
};
|
||
[ComVisible (true)]
|
||
public ref class _I_Window
|
||
{
|
||
private:
|
||
IScriptBridge ^wndinst = nullptr;
|
||
public:
|
||
_I_Window (IScriptBridge ^wnd): wndinst (wnd) {}
|
||
Object ^CallEvent (String ^name, ... array <Object ^> ^args) { return wndinst->CallEvent (name, args [0]); }
|
||
};
|
||
[ComVisible (true)]
|
||
public ref class _I_UI
|
||
{
|
||
private:
|
||
System::Windows::Forms::Form ^wndinst = nullptr;
|
||
public:
|
||
ref struct _I_UI_Size
|
||
{
|
||
private:
|
||
int m_width = 0;
|
||
int m_height = 0;
|
||
public:
|
||
property int width { int get () { return m_width; } }
|
||
property int height { int get () { return m_height; }}
|
||
property int Width { int get () { return m_width; } }
|
||
property int Height { int get () { return m_height; }}
|
||
int getWidth () { return m_width; }
|
||
int getHeight () { return m_height; }
|
||
_I_UI_Size (int w, int h): m_width (w), m_height (h) {}
|
||
};
|
||
_I_UI (System::Windows::Forms::Form ^wnd): wndinst (wnd) {}
|
||
property int DPIPercent { int get () { return GetDPI (); }}
|
||
property double DPI { double get () { return DPIPercent * 0.01; }}
|
||
property _I_UI_Size ^WndSize { _I_UI_Size ^get () { return gcnew _I_UI_Size (wndinst->Width, wndinst->Height); } }
|
||
property _I_UI_Size ^ClientSize { _I_UI_Size ^get () { auto cs = wndinst->ClientSize; return gcnew _I_UI_Size (cs.Width, cs.Height); } }
|
||
property String ^ThemeColor { String ^get () { return ColorToHtml (GetDwmThemeColor ()); } }
|
||
property bool DarkMode { bool get () { return IsAppInDarkMode (); }}
|
||
property String ^HighContrast
|
||
{
|
||
String ^get ()
|
||
{
|
||
auto highc = GetHighContrastTheme ();
|
||
switch (highc)
|
||
{
|
||
case HighContrastTheme::None: return "none";
|
||
break;
|
||
case HighContrastTheme::Black: return "black";
|
||
break;
|
||
case HighContrastTheme::White: return "white";
|
||
break;
|
||
case HighContrastTheme::Other: return "high";
|
||
break;
|
||
default: return "none";
|
||
break;
|
||
}
|
||
return "none";
|
||
}
|
||
}
|
||
};
|
||
[ComVisible (true)]
|
||
public ref class _I_Locale
|
||
{
|
||
public:
|
||
property String ^CurrentLocale { String ^get () { return CStringToMPString (GetComputerLocaleCodeW ()); } }
|
||
property LCID CurrentLCID { LCID get () { return LocaleCodeToLcid (GetComputerLocaleCodeW ()); } }
|
||
String ^ToLocaleName (LCID lcid) { return CStringToMPString (LcidToLocaleCodeW (lcid)); }
|
||
LCID ToLCID (String ^localename) { return LocaleCodeToLcidW (MPStringToStdW (localename)); }
|
||
Object ^LocaleInfo (LCID lcid, LCTYPE lctype) { return CStringToMPString (GetLocaleInfoW (lcid, lctype)); }
|
||
Object ^LocaleInfoEx (String ^localeName, LCTYPE lctype)
|
||
{
|
||
std::wstring output = L"";
|
||
int ret = GetLocaleInfoEx (MPStringToStdW (localeName), lctype, output);
|
||
if (output.empty ()) return ret;
|
||
else return CStringToMPString (output);
|
||
}
|
||
};
|
||
[ComVisible (true)]
|
||
public ref class _I_System
|
||
{
|
||
private:
|
||
_I_Resources ^ires = gcnew _I_Resources ();
|
||
_I_Locale ^ilocale = gcnew _I_Locale ();
|
||
public:
|
||
property _I_Resources ^Resources { _I_Resources ^get () { return ires; } }
|
||
property _I_Locale ^Locale { _I_Locale ^get () { return ilocale; } }
|
||
property bool IsWindows10
|
||
{
|
||
bool get ()
|
||
{
|
||
OSVERSIONINFOEX osvi = {0};
|
||
osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
|
||
osvi.dwMajorVersion = 10;
|
||
DWORDLONG conditionMask = 0;
|
||
VER_SET_CONDITION (conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
|
||
if (VerifyVersionInfoW (&osvi, VER_MAJORVERSION, conditionMask)) return TRUE;
|
||
DWORD error = GetLastError ();
|
||
return (error == ERROR_OLD_WIN_VERSION) ? FALSE : FALSE;
|
||
}
|
||
}
|
||
};
|
||
public ref class _I_System2: public _I_System
|
||
{
|
||
protected:
|
||
_I_UI ^ui;
|
||
public:
|
||
_I_System2 (System::Windows::Forms::Form ^wnd)
|
||
{
|
||
ui = gcnew _I_UI (wnd);
|
||
}
|
||
property _I_UI ^UI { _I_UI ^get () { return ui; } }
|
||
};
|
||
[ComVisible (true)]
|
||
public ref class _I_Bridge_Base2: public _I_Bridge_Base
|
||
{
|
||
protected:
|
||
_I_Window ^window;
|
||
public:
|
||
_I_Bridge_Base2 (IScriptBridge ^iscr)
|
||
{
|
||
window = gcnew _I_Window (iscr);
|
||
}
|
||
property _I_Window ^Window { _I_Window ^get () { return window; }}
|
||
};
|
||
[ComVisible (true)]
|
||
public ref class _I_Bridge_Base3: public _I_Bridge_Base2
|
||
{
|
||
protected:
|
||
_I_System2 ^system;
|
||
public:
|
||
_I_Bridge_Base3 (IScriptBridge ^iscr, System::Windows::Forms::Form ^form): _I_Bridge_Base2 (iscr)
|
||
{
|
||
system = gcnew _I_System2 (form);
|
||
}
|
||
property _I_System2 ^System { _I_System2 ^get () { return system; }}
|
||
};
|
||
[ComVisible (true)]
|
||
public ref class _I_IEFrame_Base
|
||
{
|
||
public:
|
||
property int Version { int get () { return GetInternetExplorerVersionMajor (); }}
|
||
String ^ParseHtmlColor (String ^color)
|
||
{
|
||
auto dcolor = Drawing::ColorTranslator::FromHtml (color);
|
||
{
|
||
rapidjson::Document doc;
|
||
doc.SetObject ();
|
||
auto &alloc = doc.GetAllocator ();
|
||
doc.AddMember ("r", (uint16_t)dcolor.R, alloc);
|
||
doc.AddMember ("g", (uint16_t)dcolor.G, alloc);
|
||
doc.AddMember ("b", (uint16_t)dcolor.B, alloc);
|
||
doc.AddMember ("a", (uint16_t)dcolor.A, alloc);
|
||
rapidjson::StringBuffer buffer;
|
||
rapidjson::Writer <rapidjson::StringBuffer> writer (buffer);
|
||
doc.Accept (writer);
|
||
std::string utf8 = buffer.GetString ();
|
||
std::wstring_convert <std::codecvt_utf8 <wchar_t>> conv;
|
||
return CStringToMPString (conv.from_bytes (utf8));
|
||
}
|
||
return "{}";
|
||
}
|
||
};
|
||
int ExecuteProgram (
|
||
const std::wstring &cmdline,
|
||
const std::wstring &file,
|
||
int wndshowmode,
|
||
bool wait,
|
||
const std::wstring &execdir = L"")
|
||
{
|
||
STARTUPINFOW si;
|
||
PROCESS_INFORMATION pi;
|
||
ZeroMemory (&si, sizeof (si));
|
||
ZeroMemory (&pi, sizeof (pi));
|
||
si.cb = sizeof (si);
|
||
si.dwFlags = STARTF_USESHOWWINDOW;
|
||
si.wShowWindow = static_cast <WORD> (wndshowmode);
|
||
std::vector <WCHAR> buf (cmdline.capacity () + 1);
|
||
wcscpy (buf.data (), cmdline.c_str ());
|
||
LPCWSTR workdir = IsNormalizeStringEmpty (execdir) ? NULL : execdir.c_str ();
|
||
BOOL ok = CreateProcessW (
|
||
IsNormalizeStringEmpty (file) ? NULL : file.c_str (), // Ӧ<>ó<EFBFBD><C3B3><EFBFBD>·<EFBFBD><C2B7>
|
||
IsNormalizeStringEmpty (cmdline) ? NULL : buf.data (), // <20><><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD><D0B1><EFBFBD><EFBFBD><EFBFBD>д
|
||
NULL, // <20><><EFBFBD>̰<EFBFBD>ȫ<EFBFBD><C8AB><EFBFBD><EFBFBD>
|
||
NULL, // <20>̰߳<DFB3>ȫ<EFBFBD><C8AB><EFBFBD><EFBFBD>
|
||
FALSE, // <20><><EFBFBD>̳о<CCB3><D0BE><EFBFBD>
|
||
0, // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־
|
||
NULL, // ʹ<>ø<EFBFBD><C3B8><EFBFBD><EFBFBD>̻<EFBFBD><CCBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
workdir, // <20><><EFBFBD><EFBFBD>Ŀ¼
|
||
&si,
|
||
&pi
|
||
);
|
||
if (!ok) return static_cast <int> (GetLastError ());
|
||
if (wait) WaitForSingleObject (pi.hProcess, INFINITE);
|
||
CloseHandle (pi.hThread);
|
||
CloseHandle (pi.hProcess);
|
||
return 0;
|
||
}
|
||
bool KillProcessByFilePath (
|
||
const std::wstring &filepath,
|
||
bool multiple = false,
|
||
bool isonlyname = false
|
||
)
|
||
{
|
||
if (filepath.empty ()) return false;
|
||
std::wstring targetPath = filepath;
|
||
std::wstring targetName;
|
||
if (isonlyname)
|
||
{
|
||
size_t pos = filepath.find_last_of (L"\\/");
|
||
if (pos != std::wstring::npos) targetName = filepath.substr (pos + 1);
|
||
else targetName = filepath; // ֱ<><D6B1><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>
|
||
}
|
||
HANDLE hSnap = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
|
||
if (hSnap == INVALID_HANDLE_VALUE) return false;
|
||
PROCESSENTRY32W pe;
|
||
pe.dwSize = sizeof (pe);
|
||
bool killed = false;
|
||
if (Process32FirstW (hSnap, &pe))
|
||
{
|
||
do
|
||
{
|
||
bool match = false;
|
||
if (isonlyname)
|
||
{
|
||
if (PathEquals (pe.szExeFile, targetName.c_str ())) match = true;
|
||
}
|
||
else
|
||
{
|
||
// <20>Ƚ<EFBFBD><C8BD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><C2B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ QueryFullProcessImageNameW
|
||
HANDLE hProc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_TERMINATE, FALSE, pe.th32ProcessID);
|
||
if (hProc)
|
||
{
|
||
wchar_t exePath [MAX_PATH] = {0};
|
||
DWORD sz = MAX_PATH;
|
||
|
||
if (QueryFullProcessImageNameW (hProc, 0, exePath, &sz))
|
||
{
|
||
if (_wcsicmp (exePath, targetPath.c_str ()) == 0)
|
||
match = true;
|
||
}
|
||
CloseHandle (hProc);
|
||
}
|
||
}
|
||
if (match)
|
||
{
|
||
HANDLE hProc = OpenProcess (PROCESS_TERMINATE, FALSE, pe.th32ProcessID);
|
||
if (hProc)
|
||
{
|
||
TerminateProcess (hProc, 1);
|
||
CloseHandle (hProc);
|
||
killed = true;
|
||
}
|
||
if (!multiple) break;
|
||
}
|
||
|
||
} while (Process32NextW (hSnap, &pe));
|
||
}
|
||
CloseHandle (hSnap);
|
||
return killed;
|
||
}
|
||
static std::wstring QueryVersionString (const BYTE *data, const std::wstring &langCode,
|
||
const wchar_t *key)
|
||
{
|
||
wchar_t query [256] = {0};
|
||
wsprintfW (query, L"\\StringFileInfo\\%s\\%s", langCode.c_str (), key);
|
||
LPWSTR value = nullptr;
|
||
UINT len = 0;
|
||
if (VerQueryValueW (data, query, (LPVOID *)&value, &len) && value)
|
||
return std::wstring (value ? value : L"", len);
|
||
return L"";
|
||
}
|
||
rapidjson::Document GetFileVersionAsJson (const std::wstring &filePath)
|
||
{
|
||
rapidjson::Document doc;
|
||
doc.SetObject ();
|
||
auto &alloc = doc.GetAllocator ();
|
||
DWORD dummy = 0;
|
||
DWORD size = GetFileVersionInfoSizeW (filePath.c_str (), &dummy);
|
||
if (size == 0)
|
||
{
|
||
doc.AddMember ("error", "No version info", alloc);
|
||
return doc;
|
||
}
|
||
std::vector <BYTE> data (size);
|
||
if (!GetFileVersionInfoW (filePath.c_str (), 0, size, data.data ()))
|
||
{
|
||
doc.AddMember ("error", "GetFileVersionInfoW failed", alloc);
|
||
return doc;
|
||
}
|
||
struct LANGANDCODEPAGE
|
||
{
|
||
WORD wLanguage;
|
||
WORD wCodePage;
|
||
};
|
||
LANGANDCODEPAGE *lpTranslate = nullptr;
|
||
UINT cbTranslate = 0;
|
||
if (!VerQueryValueW (data.data (),
|
||
L"\\VarFileInfo\\Translation",
|
||
(LPVOID *)&lpTranslate,
|
||
&cbTranslate))
|
||
{
|
||
doc.AddMember ("error", "No Translation", alloc);
|
||
return doc;
|
||
}
|
||
wchar_t langCode [20] = {};
|
||
wsprintfW (langCode, L"%04x%04x",
|
||
lpTranslate [0].wLanguage,
|
||
lpTranslate [0].wCodePage);
|
||
std::wstring lc = langCode;
|
||
const wchar_t *keys [] =
|
||
{
|
||
L"CompanyName",
|
||
L"FileDescription",
|
||
L"FileVersion",
|
||
L"InternalName",
|
||
L"OriginalFilename",
|
||
L"ProductName",
|
||
L"ProductVersion",
|
||
L"LegalCopyright"
|
||
};
|
||
for (auto key : keys)
|
||
{
|
||
std::wstring val = QueryVersionString (data.data (), lc, key);
|
||
if (!val.empty ())
|
||
{
|
||
rapidjson::Value k;
|
||
k.SetString (WStringToString (key, CP_UTF8).c_str (), alloc);
|
||
rapidjson::Value v;
|
||
v.SetString (WStringToString (val, CP_UTF8).c_str (), alloc);
|
||
doc.AddMember (k, v, alloc);
|
||
}
|
||
}
|
||
VS_FIXEDFILEINFO *ffi = nullptr;
|
||
UINT ffiLen = 0;
|
||
if (VerQueryValueW (data.data (), L"\\", (LPVOID *)&ffi, &ffiLen))
|
||
{
|
||
if (ffi && ffiLen)
|
||
{
|
||
wchar_t ver [64];
|
||
wsprintfW (ver, L"%u.%u.%u.%u",
|
||
HIWORD (ffi->dwFileVersionMS),
|
||
LOWORD (ffi->dwFileVersionMS),
|
||
HIWORD (ffi->dwFileVersionLS),
|
||
LOWORD (ffi->dwFileVersionLS));
|
||
doc.AddMember ("FileVersionRaw",
|
||
rapidjson::Value ().SetString (WStringToString (ver, CP_UTF8).c_str (), alloc),
|
||
alloc);
|
||
}
|
||
}
|
||
return doc;
|
||
}
|
||
size_t ExploreSaveFile (
|
||
HWND hParent,
|
||
std::vector<std::wstring> &results,
|
||
LPWSTR lpFilter = L"Windows Store App Package (*.appx; *.appxbundle)\0*.appx;*.appxbundle",
|
||
const std::wstring &lpDefExt = L"appx",
|
||
DWORD dwFlags = OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY,
|
||
const std::wstring &swWndTitle = std::wstring (L"Please select the file to save: "),
|
||
const std::wstring &swInitDir = GetFileDirectoryW (g_lastfile))
|
||
{
|
||
results.clear ();
|
||
const DWORD BUFFER_SIZE = 65536; // 64KB
|
||
std::vector <WCHAR> buffer (BUFFER_SIZE, 0);
|
||
OPENFILENAME ofn;
|
||
ZeroMemory (&ofn, sizeof (ofn));
|
||
ofn.hwndOwner = hParent;
|
||
ofn.lpstrFile = buffer.data ();
|
||
ofn.nMaxFile = BUFFER_SIZE;
|
||
ofn.lpstrFilter = lpFilter;
|
||
ofn.nFilterIndex = 1;
|
||
ofn.lpstrTitle = swWndTitle.c_str ();
|
||
ofn.lpstrDefExt = lpDefExt.c_str ();
|
||
ofn.Flags = dwFlags;
|
||
ofn.lpstrInitialDir = swInitDir.c_str ();
|
||
ofn.lStructSize = sizeof (ofn);
|
||
if (GetSaveFileNameW (&ofn))
|
||
{
|
||
std::wstring filePath = buffer.data ();
|
||
results.push_back (filePath);
|
||
g_lastfile = filePath;
|
||
}
|
||
return results.size ();
|
||
}
|
||
|
||
[ComVisible (true)]
|
||
public ref class SplashForm: public System::Windows::Forms::Form
|
||
{
|
||
public:
|
||
using PictureBox = System::Windows::Forms::PictureBox;
|
||
using Timer = System::Windows::Forms::Timer;
|
||
private:
|
||
PictureBox ^picbox;
|
||
Timer ^timer;
|
||
System::Drawing::Image ^splashimg = nullptr;
|
||
System::Drawing::Color background = System::Drawing::Color::Transparent;
|
||
// System::Windows::Forms ^parent = nullptr;
|
||
double opastep = 0.05;
|
||
void InitForm ()
|
||
{
|
||
this->DoubleBuffered = true;
|
||
InitializeComponent ();
|
||
this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::None;
|
||
this->StartPosition = System::Windows::Forms::FormStartPosition::Manual;
|
||
this->ShowInTaskbar = false;
|
||
this->AllowTransparency = true;
|
||
this->Opacity = 1.0;
|
||
}
|
||
void InitializeComponent ()
|
||
{
|
||
double dDpi = GetDPI () * 0.01;
|
||
this->picbox = gcnew System::Windows::Forms::PictureBox ();
|
||
this->picbox->Size = System::Drawing::Size (620 * dDpi, 300 * dDpi);
|
||
this->picbox->BackColor = System::Drawing::Color::Transparent;
|
||
picbox->Anchor = System::Windows::Forms::AnchorStyles::None;
|
||
picbox->SizeMode = System::Windows::Forms::PictureBoxSizeMode::Zoom;
|
||
}
|
||
void OnFadeTimer (Object ^sender, EventArgs ^e)
|
||
{
|
||
auto fadeTimer = timer;
|
||
auto opacityStep = opastep;
|
||
if (this->Opacity > 0)
|
||
{
|
||
this->Opacity -= opacityStep;
|
||
}
|
||
else
|
||
{
|
||
fadeTimer->Stop ();
|
||
this->Close ();
|
||
}
|
||
}
|
||
void OnLoad (Object ^sender, EventArgs ^e)
|
||
{
|
||
this->ChangePosAndSize ();
|
||
this->Visible = true;
|
||
}
|
||
void OnResize (Object ^sender, EventArgs ^e)
|
||
{
|
||
if (IsHandleCreated && picbox->IsHandleCreated)
|
||
{
|
||
Drawing::Size sz = this->ClientSize;
|
||
this->picbox->Location = Drawing::Point (
|
||
(sz.Width - picbox->Width) * 0.5,
|
||
(sz.Height - picbox->Height) * 0.5
|
||
);
|
||
}
|
||
}
|
||
void OnResizeOwner (Object ^sender, EventArgs ^e) { this->ChangePosAndSize (); }
|
||
void OnLocationChangedOwner (Object ^sender, EventArgs ^e) { this->ChangePosAndSize (); }
|
||
protected:
|
||
virtual void OnHandleCreated (EventArgs^ e) override
|
||
{
|
||
Form::OnHandleCreated (e);
|
||
if (Environment::OSVersion->Version->Major >= 6)
|
||
{
|
||
INT mr = 0;
|
||
MARGINS margins = {mr, mr, mr, mr};
|
||
HRESULT hr = DwmExtendFrameIntoClientArea ((HWND)this->Handle.ToPointer (), &margins);
|
||
}
|
||
}
|
||
public:
|
||
SplashForm (System::String ^imgpath, System::Drawing::Color backcolor, System::Windows::Forms::Form ^owner)
|
||
{
|
||
if (owner != nullptr) this->Owner = owner;
|
||
InitForm ();
|
||
std::wstring filefullpath = MPStringToStdW (imgpath);
|
||
if (filefullpath.find (L'%') != filefullpath.npos) filefullpath = ProcessEnvVars (filefullpath);
|
||
filefullpath = GetFullPathName (imgpath ? MPStringToStdW (imgpath) : L"");
|
||
try
|
||
{
|
||
auto img = System::Drawing::Image::FromFile (gcnew System::String (filefullpath.c_str ()));
|
||
if (img != nullptr)
|
||
{
|
||
splashimg = img;
|
||
picbox->Image = img;
|
||
}
|
||
}
|
||
catch (...) {}
|
||
if (splashimg) picbox->Image = splashimg;
|
||
try
|
||
{
|
||
if (backcolor != Drawing::Color::Transparent)
|
||
{
|
||
background = backcolor;
|
||
picbox->BackColor = backcolor;
|
||
this->BackColor = backcolor;
|
||
}
|
||
else
|
||
{
|
||
picbox->BackColor = background;
|
||
this->BackColor = background;
|
||
}
|
||
}
|
||
catch (...) {}
|
||
if (this->Owner != nullptr)
|
||
{
|
||
this->Owner->Resize += gcnew System::EventHandler (this, &SplashForm::OnResizeOwner);
|
||
this->Owner->LocationChanged += gcnew System::EventHandler (this, &SplashForm::OnLocationChangedOwner);
|
||
}
|
||
this->Controls->Add (picbox);
|
||
this->Resize += gcnew EventHandler (this, &SplashForm::OnResize);
|
||
timer = gcnew System::Windows::Forms::Timer ();
|
||
timer->Interval = 15;
|
||
timer->Tick += gcnew System::EventHandler (this, &SplashForm::OnFadeTimer);
|
||
this->Load += gcnew EventHandler (this, &SplashForm::OnLoad);
|
||
}
|
||
void ReInit ()
|
||
{
|
||
InitForm ();
|
||
picbox = gcnew System::Windows::Forms::PictureBox ();
|
||
picbox->BackColor = background;
|
||
if (splashimg) picbox->Image = splashimg;
|
||
picbox->SizeMode = System::Windows::Forms::PictureBoxSizeMode::Zoom;
|
||
picbox->Anchor = System::Windows::Forms::AnchorStyles::None;
|
||
double dDpi = GetDPI () * 0.01;
|
||
picbox->Size = Drawing::Size (620 * dDpi, 300 * dDpi);
|
||
this->BackColor = background;
|
||
this->Controls->Clear ();
|
||
this->Controls->Add (picbox);
|
||
timer = gcnew System::Windows::Forms::Timer ();
|
||
timer->Interval = 15;
|
||
timer->Tick += gcnew EventHandler (this, &SplashForm::OnFadeTimer);
|
||
this->Resize += gcnew EventHandler (this, &SplashForm::OnResize);
|
||
this->Load += gcnew EventHandler (this, &SplashForm::OnLoad);
|
||
ChangePosAndSize ();
|
||
this->Opacity = 1.0;
|
||
}
|
||
void ChangePosAndSize ()
|
||
{
|
||
if (this->Owner && this->Owner->IsHandleCreated)
|
||
{
|
||
this->Owner->Update ();
|
||
System::Drawing::Point pt = this->Owner->PointToScreen (this->Owner->ClientRectangle.Location);
|
||
this->Location = pt;
|
||
this->Size = this->Owner->ClientSize;
|
||
}
|
||
else if (this->Parent && this->Parent->IsHandleCreated)
|
||
{
|
||
this->Parent->Update ();
|
||
System::Drawing::Point pt = this->Parent->PointToScreen (this->Parent->ClientRectangle.Location);
|
||
this->Location = pt;
|
||
this->Size = this->Parent->ClientSize;
|
||
}
|
||
if (IsHandleCreated && picbox->IsHandleCreated)
|
||
{
|
||
Drawing::Size sz = this->ClientSize;
|
||
this->picbox->Location = Drawing::Point (
|
||
(sz.Width - picbox->Width) * 0.5,
|
||
(sz.Height - picbox->Height) * 0.5
|
||
);
|
||
}
|
||
}
|
||
void SetSplashImage (System::Drawing::Image ^img) { if (picbox && picbox->IsHandleCreated) { splashimg = img; picbox->Image = splashimg; } else splashimg = img; }
|
||
void SetSplashImage (System::String ^imgpath) { try { SetSplashImage (System::Drawing::Image::FromFile (imgpath)); } catch (...) {} }
|
||
void SetSplashImage (const std::wstring &imgpath) { SetSplashImage (CStringToMPString (imgpath)); }
|
||
void SetSplashBackgroundColor (System::Drawing::Color color) { background = color; picbox->BackColor = color; this->BackColor = color; }
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ
|
||
void FadeOut () { timer->Start (); }
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ
|
||
void FadeAway () { timer->Start (); }
|
||
~SplashForm ()
|
||
{
|
||
if (this->Owner != nullptr)
|
||
{
|
||
this->Owner->Resize -= gcnew System::EventHandler (this, &SplashForm::OnResizeOwner);
|
||
this->Owner->LocationChanged -= gcnew System::EventHandler (this, &SplashForm::OnLocationChangedOwner);
|
||
}
|
||
}
|
||
};
|
||
uint64_t GetFileSize (String ^filepath)
|
||
{
|
||
FileInfo ^fi = gcnew FileInfo (filepath);
|
||
if (!fi->Exists) return -1;
|
||
return fi->Length;
|
||
}
|
||
bool CopyFileWithDialog (const std::wstring &src, const std::wstring &dst)
|
||
{
|
||
HRESULT hr = CoInitializeEx (NULL, COINIT_APARTMENTTHREADED);
|
||
if (FAILED (hr)) return false;
|
||
CComPtr <IFileOperation> pfo;
|
||
hr = pfo.CoCreateInstance (CLSID_FileOperation);
|
||
if (FAILED (hr)) return false;
|
||
pfo->SetOperationFlags (
|
||
FOF_NOCONFIRMMKDIR |
|
||
FOF_ALLOWUNDO
|
||
);
|
||
CComPtr <IShellItem> psiSrc;
|
||
CComPtr <IShellItem> psiDst;
|
||
hr = SHCreateItemFromParsingName (
|
||
src.c_str (),
|
||
NULL,
|
||
IID_PPV_ARGS (&psiSrc)
|
||
);
|
||
if (FAILED (hr)) return false;
|
||
std::wstring dstDir = GetFileDirectoryW (dst);
|
||
hr = SHCreateItemFromParsingName (
|
||
dstDir.c_str (),
|
||
NULL,
|
||
IID_PPV_ARGS (&psiDst)
|
||
);
|
||
if (FAILED (hr)) return false;
|
||
hr = pfo->CopyItem (psiSrc, psiDst, NULL, NULL);
|
||
if (FAILED (hr)) return false;
|
||
hr = pfo->PerformOperations ();
|
||
bool ok = SUCCEEDED (hr);
|
||
return ok;
|
||
}
|
||
// pkginfo <20>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> UTF8 <20><><EFBFBD><EFBFBD>Ϊ themeinfo.json <20>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>ѹ<EFBFBD><D1B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ¼<C4BF><C2BC>
|
||
// <20><><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD>ѹ<EFBFBD><D1B9><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4>ڣ<EFBFBD><DAA3><EFBFBD>Ϊ<EFBFBD>˷<EFBFBD><CBB7><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>Ϣ<EFBFBD><CFA2><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD>ѹ<EFBFBD><D1B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ<EFBFBD><D1B9><EFBFBD>Ϻ<EFBFBD><CFBA><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>ڴ<EFBFBD><DAB4><EFBFBD><EFBFBD><EFBFBD>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD>
|
||
void CompressToThemePackage (String ^srcfolder, String ^destfile, String ^pkginfo, String ^id)
|
||
{
|
||
if (!Directory::Exists (srcfolder))
|
||
throw gcnew DirectoryNotFoundException (srcfolder);
|
||
|
||
if (File::Exists (destfile))
|
||
File::Delete (destfile);
|
||
|
||
FileStream^ fs = gcnew FileStream (destfile, FileMode::CreateNew);
|
||
ZipArchive^ zip = gcnew ZipArchive (fs, ZipArchiveMode::Create);
|
||
|
||
try
|
||
{
|
||
array<String^>^ files = Directory::GetFiles (srcfolder, "*", SearchOption::AllDirectories);
|
||
for each (String^ file in files)
|
||
{
|
||
String^ relativePath = file->Substring (srcfolder->Length);
|
||
|
||
// ȥ<><C8A5><EFBFBD><EFBFBD>ͷ<EFBFBD>ķָ<C4B7><D6B8><EFBFBD>
|
||
if (relativePath->StartsWith (Path::DirectorySeparatorChar.ToString ()) ||
|
||
relativePath->StartsWith (Path::AltDirectorySeparatorChar.ToString ()))
|
||
{
|
||
relativePath = relativePath->Substring (1);
|
||
}
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> custom.css <20><EFBFBD><CDB8><EFBFBD>Ϊ {id}.css
|
||
if (relativePath->Equals ("custom.css", StringComparison::OrdinalIgnoreCase))
|
||
{
|
||
relativePath = id->Trim () + ".css";
|
||
}
|
||
|
||
ZipArchiveEntry^ entry = zip->CreateEntry (relativePath, CompressionLevel::Optimal);
|
||
Stream^ entryStream = entry->Open ();
|
||
FileStream^ fileStream = gcnew FileStream (file, FileMode::Open, FileAccess::Read);
|
||
|
||
array<Byte>^ buffer = gcnew array<Byte> (4096);
|
||
int bytesRead;
|
||
while ((bytesRead = fileStream->Read (buffer, 0, buffer->Length)) > 0)
|
||
{
|
||
entryStream->Write (buffer, 0, bytesRead);
|
||
}
|
||
|
||
fileStream->Close ();
|
||
entryStream->Close ();
|
||
}
|
||
|
||
// <20><><EFBFBD><EFBFBD> themeinfo.json
|
||
ZipArchiveEntry^ infoEntry = zip->CreateEntry ("themeinfo.json", CompressionLevel::Optimal);
|
||
Stream^ infoStream = infoEntry->Open ();
|
||
array<Byte>^ infoBytes = Encoding::UTF8->GetBytes (pkginfo);
|
||
infoStream->Write (infoBytes, 0, infoBytes->Length);
|
||
infoStream->Close ();
|
||
}
|
||
finally
|
||
{
|
||
delete zip;
|
||
delete fs;
|
||
}
|
||
}
|
||
String ^GetThemePackageInfo (String ^pkgfile)
|
||
{
|
||
if (!File::Exists (pkgfile)) throw gcnew FileNotFoundException ("Theme package not found.", pkgfile);
|
||
FileStream^ fs = gcnew FileStream (pkgfile, FileMode::Open, FileAccess::Read);
|
||
ZipArchive^ zip = gcnew ZipArchive (fs, ZipArchiveMode::Read);
|
||
try
|
||
{
|
||
ZipArchiveEntry^ infoEntry = zip->GetEntry ("themeinfo.json");
|
||
if (infoEntry == nullptr)
|
||
throw gcnew InvalidDataException ("themeinfo.json not found in theme package.");
|
||
Stream^ stream = infoEntry->Open ();
|
||
StreamReader^ reader = gcnew StreamReader (stream, Encoding::UTF8);
|
||
String^ json = reader->ReadToEnd ();
|
||
reader->Close ();
|
||
stream->Close ();
|
||
return json;
|
||
}
|
||
finally
|
||
{
|
||
delete zip;
|
||
delete fs;
|
||
}
|
||
}
|
||
void ExtractThemePackage (String ^pkgfile, String ^destfolder)
|
||
{
|
||
if (!File::Exists (pkgfile)) throw gcnew FileNotFoundException ("Theme package not found.", pkgfile);
|
||
if (Directory::Exists (destfolder)) Directory::Delete (destfolder);
|
||
if (!Directory::Exists (destfolder)) Directory::CreateDirectory (destfolder);
|
||
FileStream^ fs = gcnew FileStream (pkgfile, FileMode::Open, FileAccess::Read);
|
||
ZipArchive^ zip = gcnew ZipArchive (fs, ZipArchiveMode::Read);
|
||
try
|
||
{
|
||
for each (ZipArchiveEntry^ entry in zip->Entries)
|
||
{
|
||
String^ outPath = Path::Combine (destfolder, entry->FullName);
|
||
|
||
// Ŀ¼<C4BF><C2BC>
|
||
if (String::IsNullOrEmpty (entry->Name))
|
||
{
|
||
if (!Directory::Exists (outPath))
|
||
Directory::CreateDirectory (outPath);
|
||
continue;
|
||
}
|
||
|
||
// ȷ<><C8B7>Ŀ¼<C4BF><C2BC><EFBFBD><EFBFBD>
|
||
String^ dir = Path::GetDirectoryName (outPath);
|
||
if (!String::IsNullOrEmpty (dir) && !Directory::Exists (dir))
|
||
Directory::CreateDirectory (dir);
|
||
|
||
// д<>ļ<EFBFBD>
|
||
Stream^ inStream = entry->Open ();
|
||
FileStream^ outStream = gcnew FileStream (
|
||
outPath,
|
||
FileMode::Create,
|
||
FileAccess::Write
|
||
);
|
||
|
||
array<Byte>^ buffer = gcnew array<Byte> (4096);
|
||
int bytesRead;
|
||
while ((bytesRead = inStream->Read (buffer, 0, buffer->Length)) > 0)
|
||
{
|
||
outStream->Write (buffer, 0, bytesRead);
|
||
}
|
||
|
||
outStream->Close ();
|
||
inStream->Close ();
|
||
}
|
||
}
|
||
finally
|
||
{
|
||
delete zip;
|
||
delete fs;
|
||
}
|
||
}
|
||
[ComVisible (true)]
|
||
public ref class MainHtmlWnd: public System::Windows::Forms::Form, public IScriptBridge
|
||
{
|
||
public:
|
||
using WebBrowser = System::Windows::Forms::WebBrowser;
|
||
private:
|
||
WebBrowser ^webui;
|
||
SplashForm ^splash;
|
||
ITaskbarList3 *taskbar = nullptr;
|
||
public:
|
||
[ComVisible (true)]
|
||
ref class _I_UI2: public _I_UI
|
||
{
|
||
private:
|
||
MainHtmlWnd ^wndinst = nullptr;
|
||
public:
|
||
_I_UI2 (MainHtmlWnd ^wnd): wndinst (wnd), _I_UI (wnd) {}
|
||
property String ^SplashImage
|
||
{
|
||
String ^get ()
|
||
{
|
||
auto uri = gcnew Uri (CStringToMPString (wndinst->GetSuitSplashImage ()));
|
||
return uri->AbsoluteUri;
|
||
}
|
||
}
|
||
property String ^SplashBackgroundColor
|
||
{
|
||
String ^get ()
|
||
{
|
||
std::wnstring ret = L"";
|
||
auto personal = g_initfile [L"Personalization"];
|
||
auto thememode = personal [L"AppInstaller:ThemeMode"];
|
||
auto custommode = personal [L"AppInstaller:CustomThemeMode"];
|
||
bool nowdark =
|
||
IsNormalizeStringEquals (thememode.read_wstring ().c_str (), L"dark") ||
|
||
IsNormalizeStringEquals (thememode.read_wstring ().c_str (), L"auto") && IsAppInDarkMode () ||
|
||
IsNormalizeStringEquals (thememode.read_wstring ().c_str (), L"custom") && IsNormalizeStringEquals (custommode.read_wstring ().c_str (), L"dark") ||
|
||
IsNormalizeStringEquals (thememode.read_wstring ().c_str (), L"custom") && IsNormalizeStringEquals (custommode.read_wstring ().c_str (), L"auto") && IsAppInDarkMode ();
|
||
if (nowdark) ret = g_vemani.splash_screen_backgroundcolor_darkmode (g_idInVe);
|
||
else ret = g_vemani.splash_screen_backgroundcolor (g_idInVe);
|
||
if (ret.empty ()) ret = g_vemani.splash_screen_backgroundcolor (g_idInVe);
|
||
if (ret.empty ()) ret = g_vemani.background_color (g_idInVe);
|
||
return CStringToMPString (ret);
|
||
}
|
||
}
|
||
void ShowSplash () { if (wndinst->SplashScreen->IsHandleCreated) wndinst->SplashScreen->Show (); else wndinst->SplashScreen->ReInit (); }
|
||
void FadeAwaySplash () { wndinst->SplashScreen->FadeAway (); }
|
||
void FadeOutSplash () { wndinst->SplashScreen->FadeOut (); }
|
||
};
|
||
[ComVisible (true)]
|
||
ref class _I_VisualElements2: public _I_VisualElements
|
||
{
|
||
public:
|
||
property _I_VisualElement ^Current {_I_VisualElement ^get () { return Get (CStringToMPString (g_idInVe)); }}
|
||
};
|
||
[ComVisible (true)]
|
||
ref class IBridge: public _I_Bridge_Base2
|
||
{
|
||
private:
|
||
MainHtmlWnd ^wndinst = nullptr;
|
||
bool hasjump1 = false,
|
||
hasjump2 = false,
|
||
hasexec = false;
|
||
public:
|
||
using String = System::String;
|
||
[ComVisible (true)]
|
||
ref class _I_IEFrame: public _I_IEFrame_Base
|
||
{
|
||
private:
|
||
MainHtmlWnd ^wndinst = nullptr;
|
||
public:
|
||
_I_IEFrame (MainHtmlWnd ^wnd): wndinst (wnd) {}
|
||
property int Scale
|
||
{
|
||
int get () { return wndinst->PageScale; }
|
||
void set (int value) { return wndinst->PageScale = value; }
|
||
}
|
||
};
|
||
[ComVisible (true)]
|
||
ref class _I_System3: public _I_System
|
||
{
|
||
protected:
|
||
_I_UI2 ^ui2;
|
||
public:
|
||
_I_System3 (MainHtmlWnd ^wnd)
|
||
{
|
||
ui2 = gcnew _I_UI2 (wnd);
|
||
}
|
||
property _I_UI2 ^UI { _I_UI2 ^get () { return ui2; } }
|
||
};
|
||
[ComVisible (true)]
|
||
ref class _I_Process
|
||
{
|
||
public:
|
||
using String = System::String;
|
||
ref class ProcessWorker
|
||
{
|
||
_I_Process ^parent;
|
||
public:
|
||
ProcessWorker (_I_Process ^parent): parent (parent) {}
|
||
ProcessWorker (): parent (gcnew _I_Process ()) {}
|
||
String ^cmdline = String::Empty;
|
||
String ^filepath = String::Empty;
|
||
int wndtype = SW_NORMAL;
|
||
String ^runpath = String::Empty;
|
||
Object ^callback = nullptr;
|
||
void Work ()
|
||
{
|
||
int ret = parent->Run (cmdline, filepath, wndtype, true, runpath);
|
||
if (callback)
|
||
{
|
||
try
|
||
{
|
||
callback->GetType ()->InvokeMember (
|
||
"call",
|
||
BindingFlags::InvokeMethod,
|
||
nullptr,
|
||
callback,
|
||
gcnew array<Object^>{ 1, ret }
|
||
);
|
||
}
|
||
catch (...) {}
|
||
}
|
||
}
|
||
};
|
||
public:
|
||
int Run (String ^cmdline, String ^filepath, int wndtype, bool wait, String ^runpath)
|
||
{
|
||
return ExecuteProgram (
|
||
MPStringToStdW (cmdline),
|
||
MPStringToStdW (filepath),
|
||
wndtype,
|
||
wait,
|
||
MPStringToStdW (runpath)
|
||
);
|
||
}
|
||
void RunAsync (String ^cmdline, String ^filepath, int wndtype, String ^runpath, Object ^callback)
|
||
{
|
||
auto worker = gcnew ProcessWorker (this);
|
||
worker->cmdline = cmdline;
|
||
worker->filepath = filepath;
|
||
worker->wndtype = wndtype;
|
||
worker->runpath = runpath;
|
||
worker->callback = callback;
|
||
Thread^ th = gcnew Thread (gcnew ThreadStart (worker, &ProcessWorker::Work));
|
||
th->IsBackground = true;
|
||
th->Start ();
|
||
}
|
||
bool Kill (String ^filename, bool allproc, bool onlyname) { return KillProcessByFilePath (MPStringToStdW (filename), allproc, onlyname); }
|
||
};
|
||
[ComVisible (true)]
|
||
ref class _I_ResourcePri
|
||
{
|
||
public:
|
||
using String = System::String;
|
||
String ^GetString (String ^uri)
|
||
{
|
||
auto ret = g_winjspri.get (MPStringToStdW (uri));
|
||
auto retstr = CStringToMPString (ret);
|
||
return retstr;
|
||
}
|
||
};
|
||
private:
|
||
_I_IEFrame ^ieframe;
|
||
_I_System3 ^sys;
|
||
_I_VisualElements2 ^ve;
|
||
_I_Download ^download;
|
||
_I_Process ^proc;
|
||
_I_ResourcePri ^winjs_res;
|
||
public:
|
||
IBridge (MainHtmlWnd ^wnd): wndinst (wnd), _I_Bridge_Base2 (wnd)
|
||
{
|
||
ieframe = gcnew _I_IEFrame (wnd);
|
||
sys = gcnew _I_System3 (wnd);
|
||
storage = gcnew _I_Storage ();
|
||
ve = gcnew _I_VisualElements2 ();
|
||
download = gcnew _I_Download ();
|
||
proc = gcnew _I_Process ();
|
||
winjs_res = gcnew _I_ResourcePri ();
|
||
}
|
||
property _I_IEFrame ^IEFrame { _I_IEFrame ^get () { return ieframe; }}
|
||
property _I_System3 ^System { _I_System3 ^get () { return sys; }}
|
||
property _I_VisualElements2 ^VisualElements { _I_VisualElements2 ^get () { return ve; } }
|
||
property _I_Download ^Download { _I_Download ^get () { return download; }}
|
||
property _I_Process ^Process { _I_Process ^get () { return proc; }}
|
||
property _I_ResourcePri ^WinJsStringRes { _I_ResourcePri ^get () { return winjs_res; }}
|
||
property _I_ResourcePri ^StringResources { _I_ResourcePri ^get () { return winjs_res; }}
|
||
String ^FormatDateTime (String ^fmt, String ^jsDate) { return FormatString (fmt, Convert::ToDateTime (jsDate)); }
|
||
property String ^CmdArgs { String ^get () { return CStringToMPString (StringArrayToJson (g_cmdargs)); }}
|
||
property bool Jump1 { bool get () { return hasjump1; } void set (bool value) { hasjump1 = value; } }
|
||
property bool Jump2 { bool get () { return hasjump2; } void set (bool value) { hasjump2 = value; } }
|
||
property bool Exec1 { bool get () { return hasexec; } void set (bool value) { hasexec = value; } }
|
||
property double TBProgress { void set (double value) { wndinst->TProgressPercent = value; }}
|
||
property DWORD TBState { void set (DWORD value) { wndinst->TProgressState = (TBPFLAG)value; }}
|
||
String ^GetVersionInfoToJSON (String ^filepath)
|
||
{
|
||
auto doc = GetFileVersionAsJson (MPStringToStdW (filepath));
|
||
rapidjson::StringBuffer buffer;
|
||
rapidjson::Writer <rapidjson::StringBuffer> writer (buffer);
|
||
doc.Accept (writer);
|
||
return CStringToMPString (StringToWString (buffer.GetString (), CP_UTF8));
|
||
}
|
||
String ^SelectFilesToJSON (String ^filter, DWORD flags, String ^wndtitle, String ^initdir)
|
||
{
|
||
std::vector <std::wstring> ret;
|
||
std::wstring filterbuf = MPStringToStdW (filter) + L'|||';
|
||
for (auto &it : filterbuf) if (it == L'|') it = L'\0';
|
||
ExploreFile (wndinst->InvokeGetHWND (), ret, (LPWSTR)filterbuf.c_str (), flags, MPStringToStdW (wndtitle), MPStringToStdW (initdir));
|
||
return CStringToMPString (StringArrayToJson (ret));
|
||
}
|
||
uint64_t GetFileSize (String ^filepath) { return ::GetFileSize (filepath); }
|
||
bool ShellCopyFile (String ^src, String ^desc) { return CopyFileWithDialog (MPStringToStdW (src), MPStringToStdW (desc)); }
|
||
String ^GetSavePath (String ^filter, String ^defext, DWORD flags, String ^wndtitle, String ^initdir)
|
||
{
|
||
std::vector <std::wstring> ret;
|
||
std::wstring filterbuf = MPStringToStdW (filter) + L'|||';
|
||
for (auto &it : filterbuf) if (it == L'|') it = L'\0';
|
||
ExploreSaveFile (wndinst->InvokeGetHWND (), ret, (LPWSTR)filterbuf.data (), MPStringToStdW (defext), flags, MPStringToStdW (wndtitle), MPStringToStdW (initdir));
|
||
for (auto &it : ret) if (!IsNormalizeStringEmpty (it)) return CStringToMPString (it);
|
||
return "";
|
||
}
|
||
void CompressTheme (String ^srcfolder, String ^destfile, String ^pkginfo, String ^id) { CompressToThemePackage (srcfolder, destfile, pkginfo, id); }
|
||
String ^GetThemePkgInfo (String ^themepkg) { return GetThemePackageInfo (themepkg); }
|
||
void ExtraceThemePkg (String ^src, String ^desc) { ExtractThemePackage (src, desc); }
|
||
bool CopyFile (String^ srcFile, String^ destFile, bool cover)
|
||
{
|
||
try
|
||
{
|
||
if (String::IsNullOrEmpty (srcFile) || String::IsNullOrEmpty (destFile))
|
||
return false;
|
||
|
||
if (!File::Exists (srcFile))
|
||
throw gcnew FileNotFoundException ("Source file not found.", srcFile);
|
||
|
||
// ȷ<><C8B7>Ŀ<EFBFBD><C4BF>Ŀ¼<C4BF><C2BC><EFBFBD><EFBFBD>
|
||
String^ destDir = Path::GetDirectoryName (destFile);
|
||
if (!String::IsNullOrEmpty (destDir) && !Directory::Exists (destDir))
|
||
{
|
||
Directory::CreateDirectory (destDir);
|
||
}
|
||
|
||
// overwrite = true
|
||
File::Copy (srcFile, destFile, cover);
|
||
return true;
|
||
}
|
||
catch (Exception^)
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
void CloseWindow ()
|
||
{
|
||
if (wndinst && wndinst->IsHandleCreated) wndinst->Close ();
|
||
}
|
||
};
|
||
protected:
|
||
property WebBrowser ^WebUI { WebBrowser ^get () { return this->webui; } }
|
||
property SplashForm ^SplashScreen { SplashForm ^get () { return this->splash; } }
|
||
property int DPIPercent { int get () { return GetDPI (); }}
|
||
property double DPI { double get () { return DPIPercent * 0.01; }}
|
||
virtual void OnHandleCreated (EventArgs ^e) override
|
||
{
|
||
::SetClassLongPtrW ((HWND)this->Handle.ToPointer (), GCLP_HBRBACKGROUND, (LONG_PTR)g_wndclass);
|
||
Form::OnHandleCreated (e);
|
||
}
|
||
void InitSize ()
|
||
{
|
||
unsigned ww = 0, wh = 0;
|
||
auto &ini = g_initfile;
|
||
auto setsect = ini ["Settings"];
|
||
auto savepos = setsect [L"Settings:SavePosAndSizeBeforeCancel"];
|
||
auto lastw = setsect [L"Settings:LastWidth"];
|
||
auto lasth = setsect [L"Settings:LastHeight"];
|
||
auto defw = setsect [L"Settings:DefaultWidth"];
|
||
auto defh = setsect [L"Settings:DefaultHeight"];
|
||
auto minw = setsect [L"Settings:MinimumWidth"];
|
||
auto minh = setsect [L"Settings:MinimumHeight"];
|
||
auto lasts = setsect [L"Settings:LastWndState"];
|
||
if (savepos.read_bool ())
|
||
{
|
||
ww = lastw.read_uint (defw.read_uint (rcInt (IDS_DEFAULTWIDTH)));
|
||
wh = lasth.read_uint (defh.read_uint (rcInt (IDS_DEFAULTHEIGHT)));
|
||
}
|
||
else
|
||
{
|
||
ww = defw.read_uint (rcInt (IDS_DEFAULTWIDTH));
|
||
wh = defh.read_uint (rcInt (IDS_DEFAULTHEIGHT));
|
||
}
|
||
this->ClientSize = System::Drawing::Size (ww * DPI, wh * DPI);
|
||
int hborder = this->Size.Width - this->ClientSize.Width,
|
||
vborder = this->Size.Height - this->ClientSize.Height;
|
||
this->MinimumSize = System::Drawing::Size (
|
||
minw.read_uint (rcInt (IDS_MINWIDTH)) * DPI + hborder,
|
||
minh.read_uint (rcInt (IDS_MINHIEHGT)) * DPI + vborder
|
||
);
|
||
this->WindowState = (System::Windows::Forms::FormWindowState)lasts.read_int ((int)System::Windows::Forms::FormWindowState::Normal);
|
||
}
|
||
void Init ()
|
||
{
|
||
this->Visible = false;
|
||
this->webui = gcnew System::Windows::Forms::WebBrowser ();
|
||
this->SuspendLayout ();
|
||
this->webui->Dock = System::Windows::Forms::DockStyle::Fill;
|
||
this->webui->IsWebBrowserContextMenuEnabled = DEBUGMODE;
|
||
this->webui->AllowWebBrowserDrop = false;
|
||
this->Controls->Add (this->webui);
|
||
if (g_hIconMain.hIcon)
|
||
{
|
||
try { this->Icon = System::Drawing::Icon::FromHandle (IntPtr (g_hIconMain.hIcon)); }
|
||
catch (...) {}
|
||
}
|
||
this->Text = GetRCStringCli (IDS_WINTITLE);
|
||
this->ResumeLayout (false);
|
||
webui->ObjectForScripting = gcnew IBridge (this);
|
||
this->webui->DocumentCompleted += gcnew System::Windows::Forms::WebBrowserDocumentCompletedEventHandler (this, &MainHtmlWnd::OnDocumentCompleted);
|
||
this->webui->PreviewKeyDown += gcnew System::Windows::Forms::PreviewKeyDownEventHandler (this, &MainHtmlWnd::OnPreviewKeyDown_WebBrowser);
|
||
this->Resize += gcnew System::EventHandler (this, &MainHtmlWnd::OnResize);
|
||
this->Load += gcnew EventHandler (this, &MainHtmlWnd::OnCreate);
|
||
this->ResizeEnd += gcnew EventHandler (this, &MainHtmlWnd::OnResizeEnd);
|
||
}
|
||
void OnDocumentCompleted (Object ^sender, System::Windows::Forms::WebBrowserDocumentCompletedEventArgs ^e)
|
||
{
|
||
static bool issetdpi = false;
|
||
if (!issetdpi)
|
||
{
|
||
issetdpi = true;
|
||
ExecScript ("Bridge.Frame.scale = Bridge.Frame.scale * Bridge.UI.dpi");
|
||
}
|
||
ExecScript ("Windows.UI.DPI.mode = 1");
|
||
if (e->Url->ToString () == webui->Url->ToString ())
|
||
{
|
||
auto &ini = g_initfile;
|
||
splash->FadeAway ();
|
||
}
|
||
}
|
||
void OnCreate (System::Object ^sender, System::EventArgs ^e)
|
||
{
|
||
splash->Owner = this;
|
||
splash->ChangePosAndSize ();
|
||
splash->Show ();
|
||
splash->Update ();
|
||
splash->SetSplashImage (GetSuitSplashImage ());
|
||
System::Windows::Forms::Application::DoEvents ();
|
||
auto htmlpath = CombinePath (GetProgramRootDirectoryW (), L"html\\settings.html");
|
||
webui->Navigate (CStringToMPString (htmlpath));
|
||
if (!IsFileExists (htmlpath))
|
||
{
|
||
std::wstring msg = L"Error: cannot find file \"" + htmlpath + L"\".";
|
||
MessageBoxW (InvokeGetHWND (), msg.c_str (), GetRCStringSW (IDS_WINTITLE).c_str (), MB_ICONERROR);
|
||
this->Close ();
|
||
return;
|
||
}
|
||
}
|
||
void OnPreviewKeyDown_WebBrowser (System::Object ^sender, System::Windows::Forms::PreviewKeyDownEventArgs ^e)
|
||
{
|
||
if (e->KeyCode == System::Windows::Forms::Keys::F5 || (e->KeyCode == System::Windows::Forms::Keys::R && e->Control))
|
||
e->IsInputKey = true;
|
||
}
|
||
void ResponseSplashChange ()
|
||
{
|
||
splash->SetSplashImage (GetSuitSplashImage ());
|
||
//ExecScript (
|
||
// "(function () {"
|
||
// "var splash = Page.splash;"
|
||
// "if (!splash) return null;"
|
||
// "splash.imagesrc = Bridge.UI.Splash.imageurl;"
|
||
// "splash.background = Bridge.UI.Splash.backcolor;"
|
||
// "var progress = splash.content.querySelector (\"progress\");"
|
||
// "if (Bridge.Frame.WindowSize.height / Bridge.UI.dpi < 500) {"
|
||
// "if (progress.classList.contains(\"win-ring\")) progress.classList.remove(\"win-ring\");}"
|
||
// "else { if (!progress.classList.contains(\"win-ring\")) progress.classList.add(\"win-ring\"); }"
|
||
// "}) ();"
|
||
//);
|
||
}
|
||
void OnResize (Object ^sender, EventArgs ^e) { ResizeEvent (); }
|
||
void OnResizeEnd (Object ^sender, EventArgs ^e) {}
|
||
std::wstring GetSuitSplashImage ()
|
||
{
|
||
int limitw = 800 * DPI;
|
||
int limith = 600 * DPI;
|
||
std::wstring tag = L"settings-splash";
|
||
int noww = this->Width;
|
||
int nowh = this->Height;
|
||
if (noww >= limitw && nowh >= limith)
|
||
tag = L"settings-splashlarge";
|
||
std::wstring path = g_scaleres [tag];
|
||
if (IsNormalizeStringEmpty (path))
|
||
path = g_scaleres [L"settings-splash"];
|
||
if (IsNormalizeStringEmpty (path))
|
||
path = g_vemani.splash_screen_image (g_idInVe);
|
||
return path;
|
||
}
|
||
void ResizeEvent ()
|
||
{
|
||
auto &ini = g_initfile;
|
||
auto setsect = ini ["Settings"];
|
||
auto lasts = setsect [L"Settings:LastWndState"];
|
||
auto savepos = setsect [L"Settings:SavePosAndSizeBeforeCancel"];
|
||
auto lastw = setsect [L"Settings:LastWidth"];
|
||
auto lasth = setsect [L"Settings:LastHeight"];
|
||
switch (this->WindowState)
|
||
{
|
||
case System::Windows::Forms::FormWindowState::Normal:
|
||
case System::Windows::Forms::FormWindowState::Maximized:
|
||
lasts = (int)this->WindowState;
|
||
}
|
||
if (this->WindowState == System::Windows::Forms::FormWindowState::Normal && savepos)
|
||
{
|
||
lastw = (int)(this->ClientSize.Width / DPI);
|
||
lasth = (int)(this->ClientSize.Height / DPI);
|
||
}
|
||
ResponseSplashChange ();
|
||
}
|
||
void InvokeClose ()
|
||
{
|
||
if (this->InvokeRequired) this->Invoke (gcnew Action (this, &MainHtmlWnd::Close));
|
||
else this->Close ();
|
||
}
|
||
IntPtr GetHWnd () { return this->Handle; }
|
||
delegate IntPtr GetHwndDelegate ();
|
||
HWND InvokeGetHWND ()
|
||
{
|
||
if (this->InvokeRequired)
|
||
{
|
||
GetHwndDelegate ^del = gcnew GetHwndDelegate (this, &MainHtmlWnd::GetHWnd);
|
||
IntPtr result = safe_cast <IntPtr> (this->Invoke (del));
|
||
return static_cast <HWND> (result.ToPointer ());
|
||
}
|
||
else return static_cast <HWND> (this->Handle.ToPointer ());
|
||
}
|
||
bool BackPage () { return this->webui->GoBack (); }
|
||
bool InvokeBackPage ()
|
||
{
|
||
if (this->InvokeRequired) return (bool)this->Invoke (gcnew Func <bool> (this, &MainHtmlWnd::BackPage));
|
||
else return BackPage (); // <20><>ǰ<EFBFBD>߳̾<DFB3><CCBE><EFBFBD> UI <20>߳<EFBFBD>
|
||
}
|
||
public:
|
||
MainHtmlWnd ()
|
||
{
|
||
InitSize ();
|
||
System::Windows::Forms::Application::DoEvents ();
|
||
splash = gcnew SplashForm (
|
||
CStringToMPString (GetSuitSplashImage ()),
|
||
StringToColor (CStringToMPString (g_vemani.splash_screen_backgroundcolor (g_idInVe))),
|
||
this
|
||
);
|
||
System::Windows::Forms::Application::DoEvents ();
|
||
Init ();
|
||
ITaskbarList3 *ptr = nullptr;
|
||
HRESULT hr = CoCreateInstance (CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (void **)&ptr);
|
||
if (SUCCEEDED (hr))
|
||
{
|
||
taskbar = ptr;
|
||
taskbar->HrInit ();
|
||
}
|
||
else
|
||
{
|
||
taskbar = nullptr;
|
||
if (ptr) ptr->Release ();
|
||
}
|
||
}
|
||
Object ^CallScriptFunction (String ^lpFuncName, ... array <Object ^> ^alpParams)
|
||
{
|
||
try { return this->webui->Document->InvokeScript (lpFuncName, alpParams); }
|
||
catch (Exception ^e)
|
||
{
|
||
try
|
||
{
|
||
this->webui->Document->InvokeScript ("messageBoxAsync", gcnew array <Object ^> {
|
||
e->Message,
|
||
e->Source,
|
||
0,
|
||
CStringToMPString (g_vemani.background_color (g_idInVe))
|
||
});
|
||
}
|
||
catch (Exception ^ex)
|
||
{
|
||
MessageBoxW (InvokeGetHWND (), MPStringToStdW (e->Message).c_str (), MPStringToStdW (e->Source).c_str (), 0);
|
||
}
|
||
}
|
||
return nullptr;
|
||
}
|
||
Object ^CallScriptFunction (String ^lpScriptName)
|
||
{
|
||
try { return this->webui->Document->InvokeScript (lpScriptName); }
|
||
catch (Exception ^ex) { System::Windows::Forms::MessageBox::Show ("Error calling JavaScript function: " + ex->Message); }
|
||
return nullptr;
|
||
}
|
||
Object ^InvokeCallScriptFunction (String ^lpFuncName, ... array <Object ^> ^alpParams)
|
||
{
|
||
try
|
||
{
|
||
if (this->InvokeRequired) return (Object ^)this->Invoke (gcnew Func <String ^, array <Object ^> ^, Object ^> (this, &MainHtmlWnd::CallScriptFunction), lpFuncName, alpParams);
|
||
else return CallScriptFunction (lpFuncName, alpParams);
|
||
}
|
||
catch (Exception ^e) {}
|
||
return nullptr;
|
||
}
|
||
Object ^InvokeCallScriptFunction (String ^lpScriptName)
|
||
{
|
||
try
|
||
{
|
||
if (this->InvokeRequired) return (Object ^)this->Invoke (gcnew Func <String ^, Object ^> (this, &MainHtmlWnd::CallScriptFunction), lpScriptName);
|
||
else return CallScriptFunction (lpScriptName);
|
||
}
|
||
catch (Exception ^e) {}
|
||
return nullptr;
|
||
}
|
||
Object ^ExecScript (... array <Object ^> ^alpScript) { return InvokeCallScriptFunction ("eval", alpScript); }
|
||
Object ^CallEvent (String ^funcName, Object ^e) override
|
||
{
|
||
std::wstring fname = MPStringToStdW (funcName);
|
||
if (fname == L"InvokeBackPage") InvokeBackPage ();
|
||
return nullptr;
|
||
}
|
||
property int PageScale
|
||
{
|
||
int get ()
|
||
{
|
||
CComPtr <IWebBrowser2> web2;
|
||
HRESULT hr = GetWebBrowser2Interface (webui, &web2);
|
||
if (FAILED (hr)) return 0;
|
||
VARIANT v;
|
||
VariantInit (&v);
|
||
hr = web2->ExecWB (OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DODEFAULT, nullptr, &v);
|
||
if (FAILED (hr) || v.vt != VT_I4) return 0;
|
||
int val = v.lVal;
|
||
VariantClear (&v);
|
||
return val;
|
||
}
|
||
void set (int value)
|
||
{
|
||
CComPtr <IWebBrowser2> web2;
|
||
HRESULT hr = GetWebBrowser2Interface (webui, &web2);
|
||
if (FAILED (hr)) return;
|
||
VARIANT v;
|
||
VariantInit (&v);
|
||
v.vt = VT_I4;
|
||
v.lVal = value;
|
||
web2->ExecWB (OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, &v, nullptr);
|
||
}
|
||
}
|
||
// ֻ<><D6BB><EFBFBD><EFBFBD><EFBFBD>á<EFBFBD>0 - 100
|
||
property double TProgressPercent { void set (double progressPercent) { if (taskbar) taskbar->SetProgressValue (InvokeGetHWND (), progressPercent * 100, 100 * 100); }}
|
||
property TBPFLAG TProgressState { void set (TBPFLAG state) { if (taskbar) taskbar->SetProgressState (InvokeGetHWND (), state); }}
|
||
~MainHtmlWnd ()
|
||
{
|
||
if (taskbar) taskbar->Release ();
|
||
taskbar = nullptr;
|
||
}
|
||
};
|
||
using MainWnd = MainHtmlWnd;
|
||
|
||
HRESULT SetCurrentAppUserModelID (PCWSTR appID)
|
||
{
|
||
typedef HRESULT (WINAPI *SetAppUserModelIDFunc)(PCWSTR);
|
||
HMODULE shell32 = LoadLibraryW (L"shell32.dll");
|
||
destruct freelib ([&] () {
|
||
if (shell32) FreeLibrary (shell32);
|
||
});
|
||
try
|
||
{
|
||
if (!shell32) return E_FAIL;
|
||
auto SetAppUserModelID = (SetAppUserModelIDFunc)GetProcAddress (shell32, "SetCurrentProcessExplicitAppUserModelID");
|
||
if (!SetAppUserModelID)
|
||
{
|
||
FreeLibrary (shell32);
|
||
return E_FAIL;
|
||
}
|
||
return SetAppUserModelID (appID);
|
||
}
|
||
catch (...) { return E_FAIL; }
|
||
return E_FAIL;
|
||
}
|
||
|
||
void SetProgramSingleInstance (
|
||
const std::wstring &mutexName,
|
||
std::function <void ()> repeatCallback = nullptr,
|
||
bool focusMain = true)
|
||
{
|
||
HANDLE hMutex = CreateMutexW (NULL, TRUE, mutexName.c_str ());
|
||
if (hMutex == NULL) return;
|
||
destruct _mutexFree ([&] () { CloseHandle (hMutex); });
|
||
if (GetLastError () != ERROR_ALREADY_EXISTS) return;
|
||
if (repeatCallback) repeatCallback ();
|
||
wchar_t pathBuf [MAX_PATH] = {0};
|
||
GetModuleFileNameW (NULL, pathBuf, MAX_PATH);
|
||
std::wstring exeName = pathBuf;
|
||
exeName = exeName.substr (exeName.find_last_of (L"\\/") + 1);
|
||
DWORD existingPid = 0;
|
||
HANDLE snap = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
|
||
if (snap != INVALID_HANDLE_VALUE)
|
||
{
|
||
PROCESSENTRY32W pe = {sizeof (pe)};
|
||
if (Process32FirstW (snap, &pe))
|
||
{
|
||
do {
|
||
if (_wcsicmp (pe.szExeFile, exeName.c_str ()) == 0 &&
|
||
pe.th32ProcessID != GetCurrentProcessId ())
|
||
{
|
||
existingPid = pe.th32ProcessID;
|
||
break;
|
||
}
|
||
} while (Process32NextW (snap, &pe));
|
||
}
|
||
CloseHandle (snap);
|
||
}
|
||
HWND targetHwnd = NULL;
|
||
if (existingPid)
|
||
{
|
||
EnumWindows ([] (HWND hwnd, LPARAM lParam) -> BOOL {
|
||
DWORD pid = 0;
|
||
GetWindowThreadProcessId (hwnd, &pid);
|
||
if (pid == (DWORD)lParam && IsWindowVisible (hwnd))
|
||
{
|
||
*((HWND *)(&lParam)) = hwnd;
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
}, (LPARAM)&targetHwnd);
|
||
}
|
||
if (focusMain && targetHwnd)
|
||
{
|
||
if (IsIconic (targetHwnd)) ShowWindow (targetHwnd, SW_RESTORE);
|
||
DWORD thisThread = GetCurrentThreadId ();
|
||
DWORD wndThread = GetWindowThreadProcessId (targetHwnd, NULL);
|
||
AttachThreadInput (thisThread, wndThread, TRUE);
|
||
SetActiveWindow (targetHwnd);
|
||
SetForegroundWindow (targetHwnd);
|
||
AttachThreadInput (thisThread, wndThread, FALSE);
|
||
BringWindowToTop (targetHwnd);
|
||
}
|
||
ExitProcess (0);
|
||
}
|
||
[STAThread]
|
||
int APIENTRY wWinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
|
||
{
|
||
SetCurrentProcessExplicitAppUserModelID (g_lpAppId);
|
||
SetProgramSingleInstance (g_lpAppId);
|
||
SetProcessDPIAware ();
|
||
{
|
||
// <20><><EFBFBD>õ<EFBFBD>ǰĿ¼Ϊ<C2BC><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ¼
|
||
std::wnstring currdir = GetCurrentDirectoryW ();
|
||
std::wnstring rootdir = GetProgramRootDirectoryW ();
|
||
if (!PathEquals (currdir, rootdir)) SetCurrentDirectoryW (rootdir.c_str ());
|
||
}
|
||
CoInitializeEx (NULL, COINIT_MULTITHREADED | COINIT_APARTMENTTHREADED);
|
||
SetupInstanceEnvironment ();
|
||
destruct relco ([] () {
|
||
CoUninitialize ();
|
||
});
|
||
{
|
||
auto cmdline = GetCommandLineW ();
|
||
int argc = 0;
|
||
auto argv = CommandLineToArgvW (cmdline, &argc);
|
||
destruct relt ([&argv] () {
|
||
if (argv) LocalFree (argv);
|
||
});
|
||
for (size_t i = 1; i < argc; i ++) g_cmdargs.push_back (argv [i]);
|
||
}
|
||
SetWebBrowserEmulation ();
|
||
System::Windows::Forms::Application::EnableVisualStyles ();
|
||
System::Windows::Forms::Application::SetCompatibleTextRenderingDefault (false);
|
||
auto mwnd = gcnew MainHtmlWnd ();
|
||
g_mainwnd = mwnd;
|
||
System::Windows::Forms::Application::Run (mwnd);
|
||
return 0;
|
||
}
|