Updates for WebUI:

· [Important] Fixed the destruction issue with PriReader (caused by incorrect pointer types leading to unexecuted object destruction tasks).
· [Important] Added a program execution selection interface for packages containing multiple applications (still using WebUI).
 Issue: Since the selection window is set to close when losing focus, checking the "Launch when ready" option after successful installation causes the pop-up window to disappear when a Toast notification appears (due to focus loss). Currently, the selection window can only be displayed by clicking a button.
· [Optimization] Reduced the creation of PriReader objects to lower memory and storage consumption.
(Translated by DeepSeek)
This commit is contained in:
Bruce
2025-03-02 00:33:09 +08:00
parent ff0cebc7cc
commit 949759ffe9
14 changed files with 2445 additions and 60 deletions

View File

@@ -1,6 +1,5 @@
// Microsoft Visual C++ generated resource script.
//
#include <Windows.h>
#include "resource.h"
/////////////////////////////////////////////////////////////////////////////
// 中文(简体,中国) resources
@@ -115,8 +114,8 @@ IDR_MANIFEST1 RT_MANIFEST "res/manifest.xml"
//
IDR_VERSION_ZH_CN VERSIONINFO
FILEVERSION 1,0,1,7
PRODUCTVERSION 1,0,1,7
FILEVERSION 1,0,1,9
PRODUCTVERSION 1,0,1,9
FILEFLAGSMASK 0x0L
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -133,9 +132,9 @@ BEGIN
BEGIN
VALUE "CompanyName", "Bruce Winter"
VALUE "FileDescription", "应用安装程序"
VALUE "FileVersion", "1.0.1.7"
VALUE "FileVersion", "1.0.1.9"
VALUE "LegalCopyright", "\\xA9Bruce Winter. All rights reserved."
VALUE "ProductVersion", "1.0.1.7"
VALUE "ProductVersion", "1.0.1.9"
END
END
BLOCK "VarFileInfo"
@@ -145,8 +144,8 @@ BEGIN
END
IDR_VERSION_EN_US VERSIONINFO
FILEVERSION 1,0,1,7
PRODUCTVERSION 1,0,1,7
FILEVERSION 1,0,1,9
PRODUCTVERSION 1,0,1,9
FILEFLAGSMASK 0x0L
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -163,9 +162,9 @@ BEGIN
BEGIN
VALUE "CompanyName", "Bruce Winter"
VALUE "FileDescription", "App Installer"
VALUE "FileVersion", "1.0.1.7"
VALUE "FileVersion", "1.0.1.9"
VALUE "LegalCopyright", "\\xA9Bruce Winter. All rights reserved."
VALUE "ProductVersion", "1.0.1.7"
VALUE "ProductVersion", "1.0.1.9"
END
END
BLOCK "VarFileInfo"
@@ -239,6 +238,9 @@ BEGIN
PAGE_1_APP "Microsoft Store 应用"
PAGE_2_LOADING "请稍候..."
PAGE_2_INSTALLING "正在安装 %d%%"
APPLIST_WINTITLE "应用选择列表"
APPLIST_TITLE "你要从哪个应用开始?"
APPLIST_BUTTON_CANCEL "取消"
CLHELP_1 "命令行参数说明:\n\n"
CLHELP_2 "\t/?, /Help\n\t显示帮助窗口 (命令行参数说明)\n\n"
CLHELP_3 "\t/DisableFrame\n\t禁止使用自绘的窗口边框\n\n"
@@ -404,6 +406,9 @@ BEGIN
PAGE_1_APP "Microsoft Store App"
PAGE_2_LOADING "Please wait..."
PAGE_2_INSTALLING "Installing %d%%"
APPLIST_WINTITLE "App Select List"
APPLIST_TITLE "Which app do you want to start with?"
APPLIST_BUTTON_CANCEL "Cancel"
CLHELP_1 "Usage:\n\n"
CLHELP_2 "\t/?, /Help\n\tDisplay help window (command line parameter description).\n\n"
CLHELP_3 "\t/DisableFrame\n\tDisable the use of self-drawn window borders.\n\n"

View File

@@ -138,6 +138,11 @@
<AdditionalDependencies>shlwapi.lib;dwmapi.lib;crypt32.lib;$(OutDir)PackageManager.lib;$(OutDir)AppLauncher.lib;$(OutDir)Base64Img.lib;$(OutDir)ToastNotification.lib;$(OutDir)PriReader2.lib;$(OutDir)CertificateManager.lib</AdditionalDependencies>
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
</Link>
<Manifest>
<AdditionalManifestFiles>app.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles>
<InputResourceManifests>
</InputResourceManifests>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<ClCompile>
@@ -191,6 +196,9 @@
</Link>
<Manifest>
<EnableDpiAwareness>false</EnableDpiAwareness>
<AdditionalManifestFiles>app.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles>
<InputResourceManifests>
</InputResourceManifests>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
@@ -252,6 +260,7 @@
<ResourceCompile Include="AppInstaller.rc" />
</ItemGroup>
<ItemGroup>
<Reference Include="CustomMarshalers" />
<Reference Include="System" />
<Reference Include="System.Drawing">
<HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Drawing.dll</HintPath>

17
AppInstaller/app.manifest Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
</application>
</compatibility>
</assembly>

View File

@@ -31,18 +31,20 @@ std::wstring GetFileNameWithoutExtension (const std::wstring &filePath)
return GetFileNameWithoutExtension (filePath.c_str ());
}
std::string GetLogoBase64FromReader (PackageReader &reader, IStream **getOutput = NULL)
std::string GetLogoBase64FromReader (PackageReader &reader, IStream **getOutput = NULL, PriReader *priread = NULL)
{
if (!&reader) return std::string ("");
if (!reader.isAvailable ()) return std::string ("");
std::wstring logoPath = reader.getPropertyLogo ();
if (logoPath.empty () || logoPath.length () == 0) return std::string ("");
PriReader pri (reader.getPriFileStream ());
if (pri.isAvailable ())
PriReader *pri = ((priread != NULL) ? priread : new PriReader (reader.getPriFileStream ()));
if (pri->isAvailable ())
{
std::wstring logoPathFromPri = pri.findFilePathValue (logoPath);
std::wstring logoPathFromPri = pri->findFilePathValue (logoPath);
if (!logoPathFromPri.empty () && logoPath.length () > 0) logoPath = logoPathFromPri;
}
if (priread == NULL) delete pri;
pri = NULL;
IStream *imgfile = reader.extractFileToStream (logoPath);
if (getOutput) *getOutput = imgfile;
if (!imgfile)
@@ -288,4 +290,528 @@ std::string GetLogoBase64FromReader (PackageReader &reader, IStream **getOutput
b64res = "data:image/png;base64," + b64res;
}
return b64res;
}
std::string GetBase64FromPath (PackageReader &reader, LPCWSTR lpswImgPath, IStream **getOutput = NULL, PriReader *priread = NULL)
{
if (!&reader) return std::string ("");
if (!reader.isAvailable ()) return std::string ("");
if (!lpswImgPath) return std::string ("");
std::wstring logoPath = std::wstring (lpswImgPath);
if (logoPath.empty () || logoPath.length () == 0) return std::string ("");
PriReader *pri = ((priread != NULL) ? priread : new PriReader (reader.getPriFileStream ()));
if (pri->isAvailable ())
{
std::wstring logoPathFromPri = pri->findFilePathValue (logoPath);
if (!logoPathFromPri.empty () && logoPath.length () > 0) logoPath = logoPathFromPri;
}
if (priread == NULL) delete pri;
pri = NULL;
IStream *imgfile = reader.extractFileToStream (logoPath);
if (getOutput) *getOutput = imgfile;
if (!imgfile)
{
std::wstring fileName = GetFileNameWithoutExtension (logoPath);
IAppxPackageReader *appxreader = reader.getAppxPackageReader ();
CComPtr <IAppxFilesEnumerator> fe = NULL;
HRESULT hr = appxreader->GetPayloadFiles (&fe);
if (SUCCEEDED (hr) && fe)
{
std::vector <std::wstring> files;
BOOL hasCurrent = FALSE;
hr = fe->GetHasCurrent (FALSE);
while (SUCCEEDED (hr) && hasCurrent)
{
CComPtr <IAppxFile> ifile = NULL;
hr = fe->GetCurrent (&ifile);
if (SUCCEEDED (hr) && ifile)
{
LPWSTR lpstr = NULL;
if (SUCCEEDED (ifile->GetName (&lpstr)) && lpstr)
{
std::wstring strWillSearch = StringToUpper (StringTrim (lpstr));
std::wstring strWillToSearch = StringToUpper (StringTrim (fileName));
if (StrStrW (strWillSearch.c_str (), strWillToSearch.c_str ()))
{
bool isFind = LabelEqual (PathFindExtensionW (lpstr), L".png");
if (!isFind) isFind = LabelEqual (PathFindExtensionW (lpstr), L".jpg");
if (!isFind) isFind = LabelEqual (PathFindExtensionW (lpstr), L".jpeg");
if (!isFind) isFind = LabelEqual (PathFindExtensionW (lpstr), L".bmp");
if (isFind)
{
std::wstring temp (L"");
if (lpstr) temp += lpstr;
if (temp.length () > 0) push_no_repeat (files, temp);
}
}
}
}
}
bool isFindSuit = false;
{
std::map <int, std::wstring> scaleFiles;
std::wregex pattern (L"(scale-(\\d+))");
for (auto it : files)
{
if (StrStrW (it.c_str (), L"contrast-")) continue;
std::wsmatch match;
if (std::regex_search (it, match, pattern))
{
int temp = StrToIntW (match [1].str ().c_str ());
if (!temp)
{
scaleFiles [temp] = it;
}
}
}
if (scaleFiles.find (GetDPI ()) != scaleFiles.end ())
{
isFindSuit = true;
logoPath = scaleFiles [GetDPI ()];
}
else
{
bool isFindScale = false;
for (auto it : scaleFiles)
{
if (it.first >= GetDPI ())
{
isFindScale = true;
logoPath = scaleFiles [GetDPI ()];
break;
}
}
if (!isFindScale)
{
for (auto it : scaleFiles)
{
if (it.first >= 100)
{
isFindScale = true;
logoPath = scaleFiles [GetDPI ()];
break;
}
}
}
if (!isFindScale)
{
for (auto it : scaleFiles)
{
isFindScale = true;
logoPath = scaleFiles [GetDPI ()];
break;
}
}
isFindSuit = isFindScale;
}
}
if (!isFindSuit)
{
std::map <int, std::wstring> scaleFiles;
std::wregex pattern (L"(scale-(\\d+))");
for (auto it : files)
{
if (StrStrW (it.c_str (), L"contrast-white")) continue;
std::wsmatch match;
if (std::regex_search (it, match, pattern))
{
int temp = StrToIntW (match [1].str ().c_str ());
if (!temp)
{
scaleFiles [temp] = it;
}
}
}
if (scaleFiles.find (GetDPI ()) != scaleFiles.end ())
{
isFindSuit = true;
logoPath = scaleFiles [GetDPI ()];
}
else
{
bool isFindScale = false;
for (auto it : scaleFiles)
{
if (it.first >= GetDPI ())
{
isFindScale = true;
logoPath = scaleFiles [GetDPI ()];
break;
}
}
if (!isFindScale)
{
for (auto it : scaleFiles)
{
if (it.first >= 100)
{
isFindScale = true;
logoPath = scaleFiles [GetDPI ()];
break;
}
}
}
if (!isFindScale)
{
for (auto it : scaleFiles)
{
isFindScale = true;
logoPath = scaleFiles [GetDPI ()];
break;
}
}
isFindSuit = isFindScale;
}
}
if (!isFindSuit)
{
std::map <int, std::wstring> scaleFiles;
std::wregex pattern (L"(scale-(\\d+))");
for (auto it : files)
{
if (StrStrW (it.c_str (), L"contrast-black")) continue;
std::wsmatch match;
if (std::regex_search (it, match, pattern))
{
int temp = StrToIntW (match [1].str ().c_str ());
if (!temp)
{
scaleFiles [temp] = it;
}
}
}
if (scaleFiles.find (GetDPI ()) != scaleFiles.end ())
{
isFindSuit = true;
logoPath = scaleFiles [GetDPI ()];
}
else
{
bool isFindScale = false;
for (auto it : scaleFiles)
{
if (it.first >= GetDPI ())
{
isFindScale = true;
logoPath = scaleFiles [GetDPI ()];
break;
}
}
if (!isFindScale)
{
for (auto it : scaleFiles)
{
if (it.first >= 100)
{
isFindScale = true;
logoPath = scaleFiles [GetDPI ()];
break;
}
}
}
if (!isFindScale)
{
for (auto it : scaleFiles)
{
isFindScale = true;
logoPath = scaleFiles [GetDPI ()];
break;
}
}
isFindSuit = isFindScale;
}
}
if (!isFindSuit)
{
for (auto it : files)
{
logoPath = std::wstring (L"") + it;
break;
}
}
}
imgfile = reader.extractFileToStream (logoPath);
}
if (getOutput) *getOutput = imgfile;
if (!imgfile) return std::string ("");
std::string b64res ("");
LPSTR szRes = StreamToBase64 (imgfile);
if (!getOutput)
{
if (imgfile)
{
imgfile->Release ();
imgfile = NULL;
}
}
if (!szRes) return b64res;
if (szRes) b64res += szRes;
free (szRes);
if (b64res.length () > 0)
{
b64res = "data:image/png;base64," + b64res;
}
return b64res;
}
std::wstring GetBase64FromPathW (PackageReader &reader, LPCWSTR lpswImgPath, IStream **getOutput = NULL, PriReader *priread = NULL)
{
if (!&reader) return std::wstring (L"");
if (!reader.isAvailable ()) return std::wstring (L"");
if (!lpswImgPath) return std::wstring (L"");
std::wstring logoPath = std::wstring (lpswImgPath);
if (logoPath.empty () || logoPath.length () == 0) return std::wstring (L"");
PriReader *pri = ((priread != NULL) ? priread : new PriReader (reader.getPriFileStream ()));
if (pri->isAvailable ())
{
std::wstring logoPathFromPri = pri->findFilePathValue (logoPath);
if (!logoPathFromPri.empty () && logoPath.length () > 0) logoPath = logoPathFromPri;
}
if (priread == NULL) delete pri;
pri = NULL;
IStream *imgfile = reader.extractFileToStream (logoPath);
if (getOutput) *getOutput = imgfile;
if (!imgfile)
{
std::wstring fileName = GetFileNameWithoutExtension (logoPath);
IAppxPackageReader *appxreader = reader.getAppxPackageReader ();
CComPtr <IAppxFilesEnumerator> fe = NULL;
HRESULT hr = appxreader->GetPayloadFiles (&fe);
if (SUCCEEDED (hr) && fe)
{
std::vector <std::wstring> files;
BOOL hasCurrent = FALSE;
hr = fe->GetHasCurrent (FALSE);
while (SUCCEEDED (hr) && hasCurrent)
{
CComPtr <IAppxFile> ifile = NULL;
hr = fe->GetCurrent (&ifile);
if (SUCCEEDED (hr) && ifile)
{
LPWSTR lpstr = NULL;
if (SUCCEEDED (ifile->GetName (&lpstr)) && lpstr)
{
std::wstring strWillSearch = StringToUpper (StringTrim (lpstr));
std::wstring strWillToSearch = StringToUpper (StringTrim (fileName));
if (StrStrW (strWillSearch.c_str (), strWillToSearch.c_str ()))
{
bool isFind = LabelEqual (PathFindExtensionW (lpstr), L".png");
if (!isFind) isFind = LabelEqual (PathFindExtensionW (lpstr), L".jpg");
if (!isFind) isFind = LabelEqual (PathFindExtensionW (lpstr), L".jpeg");
if (!isFind) isFind = LabelEqual (PathFindExtensionW (lpstr), L".bmp");
if (isFind)
{
std::wstring temp (L"");
if (lpstr) temp += lpstr;
if (temp.length () > 0) push_no_repeat (files, temp);
}
}
}
}
}
bool isFindSuit = false;
{
std::map <int, std::wstring> scaleFiles;
std::wregex pattern (L"(scale-(\\d+))");
for (auto it : files)
{
if (StrStrW (it.c_str (), L"contrast-")) continue;
std::wsmatch match;
if (std::regex_search (it, match, pattern))
{
int temp = StrToIntW (match [1].str ().c_str ());
if (!temp)
{
scaleFiles [temp] = it;
}
}
}
if (scaleFiles.find (GetDPI ()) != scaleFiles.end ())
{
isFindSuit = true;
logoPath = scaleFiles [GetDPI ()];
}
else
{
bool isFindScale = false;
for (auto it : scaleFiles)
{
if (it.first >= GetDPI ())
{
isFindScale = true;
logoPath = scaleFiles [GetDPI ()];
break;
}
}
if (!isFindScale)
{
for (auto it : scaleFiles)
{
if (it.first >= 100)
{
isFindScale = true;
logoPath = scaleFiles [GetDPI ()];
break;
}
}
}
if (!isFindScale)
{
for (auto it : scaleFiles)
{
isFindScale = true;
logoPath = scaleFiles [GetDPI ()];
break;
}
}
isFindSuit = isFindScale;
}
}
if (!isFindSuit)
{
std::map <int, std::wstring> scaleFiles;
std::wregex pattern (L"(scale-(\\d+))");
for (auto it : files)
{
if (StrStrW (it.c_str (), L"contrast-white")) continue;
std::wsmatch match;
if (std::regex_search (it, match, pattern))
{
int temp = StrToIntW (match [1].str ().c_str ());
if (!temp)
{
scaleFiles [temp] = it;
}
}
}
if (scaleFiles.find (GetDPI ()) != scaleFiles.end ())
{
isFindSuit = true;
logoPath = scaleFiles [GetDPI ()];
}
else
{
bool isFindScale = false;
for (auto it : scaleFiles)
{
if (it.first >= GetDPI ())
{
isFindScale = true;
logoPath = scaleFiles [GetDPI ()];
break;
}
}
if (!isFindScale)
{
for (auto it : scaleFiles)
{
if (it.first >= 100)
{
isFindScale = true;
logoPath = scaleFiles [GetDPI ()];
break;
}
}
}
if (!isFindScale)
{
for (auto it : scaleFiles)
{
isFindScale = true;
logoPath = scaleFiles [GetDPI ()];
break;
}
}
isFindSuit = isFindScale;
}
}
if (!isFindSuit)
{
std::map <int, std::wstring> scaleFiles;
std::wregex pattern (L"(scale-(\\d+))");
for (auto it : files)
{
if (StrStrW (it.c_str (), L"contrast-black")) continue;
std::wsmatch match;
if (std::regex_search (it, match, pattern))
{
int temp = StrToIntW (match [1].str ().c_str ());
if (!temp)
{
scaleFiles [temp] = it;
}
}
}
if (scaleFiles.find (GetDPI ()) != scaleFiles.end ())
{
isFindSuit = true;
logoPath = scaleFiles [GetDPI ()];
}
else
{
bool isFindScale = false;
for (auto it : scaleFiles)
{
if (it.first >= GetDPI ())
{
isFindScale = true;
logoPath = scaleFiles [GetDPI ()];
break;
}
}
if (!isFindScale)
{
for (auto it : scaleFiles)
{
if (it.first >= 100)
{
isFindScale = true;
logoPath = scaleFiles [GetDPI ()];
break;
}
}
}
if (!isFindScale)
{
for (auto it : scaleFiles)
{
isFindScale = true;
logoPath = scaleFiles [GetDPI ()];
break;
}
}
isFindSuit = isFindScale;
}
}
if (!isFindSuit)
{
for (auto it : files)
{
logoPath = std::wstring (L"") + it;
break;
}
}
}
imgfile = reader.extractFileToStream (logoPath);
}
if (getOutput) *getOutput = imgfile;
if (!imgfile) return std::wstring (L"");
std::wstring b64res (L"");
LPWSTR szRes = StreamToBase64W (imgfile);
if (!getOutput)
{
if (imgfile)
{
imgfile->Release ();
imgfile = NULL;
}
}
if (!szRes) return b64res;
if (szRes) b64res += szRes;
free (szRes);
if (b64res.length () > 0)
{
b64res = L"data:image/png;base64," + b64res;
}
return b64res;
}

View File

@@ -28,6 +28,16 @@
using namespace System;
using namespace System::Windows::Forms;
using namespace System::Threading;
using namespace msclr::interop;
int GetScreenWidth ()
{
return GetSystemMetrics (SM_CXSCREEN);
}
int GetScreenHeight ()
{
return GetSystemMetrics (SM_CYSCREEN);
}
#define toInt(_String_Managed_Object_) Int32::Parse (_String_Managed_Object_)
#define toDouble(_String_Managed_Object_) Double::Parse (_String_Managed_Object_)
@@ -177,27 +187,23 @@ std::wstring StrPrintFormatW (LPCWSTR format, ...)
void SetWebBrowserEmulation ()
{
// 获取应用程序的可执行文件
String ^appName = System::IO::Path::GetFileNameWithoutExtension (System::Windows::Forms::Application::ExecutablePath);
const wchar_t *appNameWChar = (const wchar_t *)(void *)System::Runtime::InteropServices::Marshal::StringToHGlobalUni (appName);
BOOL is64Bit = FALSE;
IsWow64Process (GetCurrentProcess (), &is64Bit);
String^ appName = System::IO::Path::GetFileName (Application::ExecutablePath); // 包含扩展
IntPtr appNamePtr = System::Runtime::InteropServices::Marshal::StringToHGlobalUni (appName);
const wchar_t* appNameWChar = static_cast<const wchar_t*>(appNamePtr.ToPointer ());
BOOL isWow64 = FALSE;
IsWow64Process (GetCurrentProcess (), &isWow64);
HKEY hKey;
long regOpenResult = ERROR_SUCCESS;
if (is64Bit)
LPCWSTR keyPath = isWow64
? L"SOFTWARE\\WOW6432Node\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION"
: L"SOFTWARE\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION";
LONG result = RegOpenKeyExW (HKEY_CURRENT_USER, keyPath, 0, KEY_WRITE, &hKey);
if (result == ERROR_SUCCESS)
{
regOpenResult = RegOpenKeyExW (HKEY_CURRENT_USER, L"SOFTWARE\\WOW6432Node\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION", 0, KEY_WRITE, &hKey);
}
else
{
regOpenResult = RegOpenKeyExW (HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION", 0, KEY_WRITE, &hKey);
}
if (regOpenResult == ERROR_SUCCESS)
{
DWORD ie11Mode = 11001;
RegSetValueExW (hKey, appNameWChar, 0, REG_DWORD, (const BYTE *)&ie11Mode, sizeof (DWORD));
DWORD value = 11001;
RegSetValueExW (hKey, appNameWChar, 0, REG_DWORD, reinterpret_cast<const BYTE*>(&value), sizeof (value));
RegCloseKey (hKey);
}
System::Runtime::InteropServices::Marshal::FreeHGlobal (appNamePtr);
}
#include <windows.h>
@@ -237,6 +243,17 @@ bool IsIeVersion10 ()
RegCloseKey (hKey);
return isIe10;
}
bool IsWindows10AndLater ()
{
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;
}
size_t EnumerateFilesW (const std::wstring &directory, const std::wstring &filter,
std::vector <std::wstring> &outFiles, bool recursive = false)
@@ -313,6 +330,136 @@ HRESULT SetCurrentAppUserModelID (PCWSTR appID)
void ProgressCallback (unsigned progress);
void ToastPressCallback ();
void OutputDebugStringFormatted (const wchar_t* format, ...);
public ref class AppWindow: public Form
{
private:
WebBrowser ^webUI;
std::vector <appmap> *appItems = new std::vector <appmap> ();
System::Collections::Generic::Dictionary <String ^, Delegate ^> ^jsFunctionHandlers;
public:
AppWindow ()
{
this->Visible = false;
jsFunctionHandlers = gcnew System::Collections::Generic::Dictionary <String ^, Delegate ^> ();
this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::None;
this->ShowInTaskbar = false;
this->TopMost = true;
this->Size = System::Drawing::Size (392, 494);
if (IsWindows10AndLater ()) this->MinimumSize = System::Drawing::Size (392, 226);
else this->MinimumSize = System::Drawing::Size (392, 129);
if (IsWindows10AndLater ()) this->MaximumSize = System::Drawing::Size (392, 522);
else this->MaximumSize = System::Drawing::Size (368, 394);
this->Text = rcString (APPLIST_WINTITLE);
webUI = gcnew WebBrowser ();
webUI->Dock = DockStyle::Fill;
this->Controls->Add (webUI);
String ^rootDir = System::IO::Path::GetDirectoryName (System::Windows::Forms::Application::ExecutablePath);
String ^htmlFilePath = System::IO::Path::Combine (rootDir, "HTML\\Libs\\AppList.html");
if (IsIeVersion10 ()) htmlFilePath = System::IO::Path::Combine (rootDir, "HTML\\Libs\\AppListIE10.html"); // IE10 (Win8) 特供
if (IsWindows10AndLater ()) htmlFilePath = System::IO::Path::Combine (rootDir, "HTML\\Libs\\AppListWin10.html"); // Windows 10 及以上版本的风格
webUI->Navigate (htmlFilePath);
webUI->ObjectForScripting = this;
this->webUI->IsWebBrowserContextMenuEnabled = false;
webUI->DocumentCompleted += gcnew WebBrowserDocumentCompletedEventHandler (this, &AppWindow::OnDocumentCompleted);
this->StartPosition = FormStartPosition::CenterScreen;
this->Deactivate += gcnew EventHandler (this, &AppWindow::eventOnDeactivate);
}
void OnDocumentCompleted (Object ^sender, WebBrowserDocumentCompletedEventArgs ^e)
{
CallJSFunction ("SetText", gcnew array <Object ^> {
"span-title",
rcString (APPLIST_TITLE)
});
CallJSFunction ("SetText", gcnew array <Object ^> {
"button-cancel-window",
rcString (APPLIST_BUTTON_CANCEL)
});
this->Visible = true;
Thread ^thread = gcnew Thread (gcnew ThreadStart (this, &AppWindow::InvokeRefreshAppItems));
thread->Start ();
}
void SendAppData (std::vector<appmap> apps)
{
if (appItems) delete appItems;
appItems = nullptr;
appItems = new std::vector <appmap> ();
for (auto it : apps)
{
appItems->push_back (it);
}
this->InvokeRefreshAppItems ();
}
void eventLaunchApp (String ^appModelUserId)
{
DWORD dwPId = 0;
LaunchApp ((marshal_as <std::wstring> (appModelUserId)).c_str (), &dwPId);
this->Close ();
}
void eventCancelWindow ()
{
if (this->IsHandleCreated) this->Close ();
}
void eventOnDeactivate (Object ^sender, EventArgs ^e)
{
if (this->IsHandleCreated) this->Close ();
}
~AppWindow ()
{
if (appItems) delete appItems;
appItems = nullptr;
}
private:
Object ^CallJSFunction (String ^functionName, ... array<Object^> ^args)
{
if (webUI->Document != nullptr)
{
try
{
return webUI->Document->InvokeScript (functionName, args);
}
catch (Exception^ ex)
{
MessageBox::Show ("Error calling JavaScript function: " + ex->Message);
return nullptr;
}
}
return nullptr;
}
void InvokeRefreshAppItems ()
{
if (this->InvokeRequired)
{
this->Invoke (gcnew Action (this, &AppWindow::RefreshAppItems));
}
else
{
RefreshAppItems ();
}
}
void RefreshAppItems ()
{
CallJSFunction ("ClearListItems", gcnew array <Object ^> { });
bool isWin10 = IsWindows10AndLater ();
size_t height = ((appItems->size ()) * (isWin10 ? 50 : 60)) + (isWin10 ? 206 : 120);
if (height < (isWin10 ? 522 : 394)) this->Height = height;
else this->Height = 522;
this->Left = (GetScreenWidth () - this->Width) / 2;
this->Top = (GetScreenHeight () - this->Height) / 2;
for (auto it : *appItems)
{
String ^colorStr = gcnew String (it [L"BackgroundColor"].c_str ());
if (LabelEqual (it [L"BackgroundColor"], L"transparent")) colorStr = ColorToHtml (GetAeroColor ());
CallJSFunction ("AddListItems", gcnew array <Object ^> {
gcnew String (it [L"AppUserModelID"].c_str ()),
gcnew String (it [L"Square44x44LogoBase64"].c_str ()),
colorStr,
gcnew String (it [L"DisplayName"].c_str ())
});
}
}
};
public ref class MainWnd: public Form
{
@@ -432,7 +579,9 @@ public ref class MainWnd: public Form
{
this->Visible = true;
this->setLaunchWhenReadyJS (m_initConfig.readBoolValue (L"Settings", L"LaunchWhenReady", true));
#ifdef _DEBUG
if (IsIeVersion10 ()) hideFrameJS (false);
#endif
Thread ^thread = gcnew Thread (gcnew ThreadStart (this, &MainWnd::taskReadFile));
thread->Start ();
Thread ^thread2 = gcnew Thread (gcnew ThreadStart (this, &MainWnd::taskCountDarkMode));
@@ -468,6 +617,7 @@ public ref class MainWnd: public Form
thread->SetApartmentState (ApartmentState::STA);
thread->Start ();
} break;
case 3: break;
case 4:
{
// this->setButtonDisabledJS (true);
@@ -481,6 +631,17 @@ public ref class MainWnd: public Form
m_pkgInfo.getApplicationUserModelIDs (ids);
DWORD dwPId = 0;
if (ids.size () == 1) LaunchApp (ids [0].c_str (), &dwPId);
else if (ids.size () > 1)
{
AppWindow ^appWnd = gcnew AppWindow ();
std::vector <appmap> apps;
m_pkgInfo.getApplications (apps);
appWnd->SendAppData (apps);
appWnd->StartPosition = FormStartPosition::CenterScreen;
//appWnd->Owner = this;
appWnd->Show ();
//appWnd->ShowDialog ();
}
}
// this->setButtonDisabledJS (false);
} break;
@@ -490,6 +651,17 @@ public ref class MainWnd: public Form
} break;
}
}
void invokeEventOnPress_button1 ()
{
if (this->InvokeRequired)
{
this->Invoke (gcnew Action (this, &MainWnd::eventOnPress_button1));
}
else
{
eventOnPress_button1 ();
}
}
void eventOnPress_button2 ()
{
@@ -830,18 +1002,21 @@ public ref class MainWnd: public Form
setPicBoxVisibilityJS (false);
if (serial > 1)
{
std::string res = m_pkgInfo.getPropertyLogoBase64 ();
if (m_pkgInfo.getPropertyLogoIStream () && !res.empty () && res.length () > 10)
if (serial = 2)
{
std::string b64logo = res;
// MessageBox::Show (gcnew String ((std::string ("Base 64 String: ") + b64logo).c_str ()));
this->setStoreLogoJS (gcnew String (res.c_str ()));
setPicBoxVisibilityJS (true);
}
else
{
this->setStoreLogoJS ("./Libs/Images/StoreLogo.png");
setPicBoxVisibilityJS (false);
std::string res = m_pkgInfo.getPropertyLogoBase64 ();
if (m_pkgInfo.getPropertyLogoIStream () && !res.empty () && res.length () > 10)
{
std::string b64logo = res;
// MessageBox::Show (gcnew String ((std::string ("Base 64 String: ") + b64logo).c_str ()));
this->setStoreLogoJS (gcnew String (res.c_str ()));
setPicBoxVisibilityJS (true);
}
else
{
this->setStoreLogoJS ("./Libs/Images/StoreLogo.png");
setPicBoxVisibilityJS (false);
}
}
}
else
@@ -896,6 +1071,17 @@ public ref class MainWnd: public Form
pTaskbarList->Release ();
}
}
void invokeSetTaskbarProgress (int value)
{
if (this->InvokeRequired)
{
this->Invoke (gcnew Action <int> (this, &MainWnd::setTaskbarProgress), value);
}
else
{
setTaskbarProgress (value);
}
}
void clearTaskbarProgress ()
{
IntPtr hwnd = this->Handle;
@@ -911,6 +1097,17 @@ public ref class MainWnd: public Form
pTaskbarList->Release ();
}
}
void invokeClearTaskbarProgress ()
{
if (this->InvokeRequired)
{
this->Invoke (gcnew Action (this, &MainWnd::clearTaskbarProgress));
}
else
{
clearTaskbarProgress ();
}
}
bool invokeGetLaunchWhenReady ()
{
if (this->InvokeRequired)
@@ -985,10 +1182,7 @@ public ref class MainWnd: public Form
if (status == InstallStatus::Success)
{
invokeSetPage (4);
if (this->invokeGetLaunchWhenReady ())
{
if (reader.isPackageApplication ()) this->eventOnPress_button1 (); // 用于启用 APP
}
if (m_pkgInfo.applications.size () == 1 && !m_silentMode) this->eventOnPress_button1 (); // 用于启用 APP
Thread ^closeThread = gcnew Thread (gcnew ThreadStart (this, &MainWnd::taskCountCancel));
closeThread->IsBackground = true;
closeThread->Start ();
@@ -1003,7 +1197,7 @@ public ref class MainWnd: public Form
closeThread->Start ();
}
}
this->clearTaskbarProgress ();
this->invokeClearTaskbarProgress ();
std::wstring title = StrPrintFormatW (GetRCString_cpp (PAGE_4_TITLE).c_str (), m_pkgInfo.getPropertyName ().c_str ());
std::wstring text (L"");
if (GetLastErrorDetailTextLength ()) text += GetLastErrorDetailText ();
@@ -1015,7 +1209,12 @@ public ref class MainWnd: public Form
}
void taskCountCancel ()
{
for (char cnt = 0; cnt < 100; cnt ++)
int size = (int)m_pkgInfo.applications.size ();
if (size < 1) size = 1;
if (size > 5) size = 5;
if (m_silentMode) size = 1; // 不耽误时间
int tcnt = size * 100;
for (int cnt = 0; cnt < tcnt; cnt ++)
{
if (!this->IsHandleCreated) break;
Thread::Sleep (50);
@@ -1052,7 +1251,7 @@ public ref class MainWnd: public Form
}
public:
[STAThread]
void Button1_PressEvent () { eventOnPress_button1 (); }
void Button1_PressEvent () { invokeEventOnPress_button1 (); }
[STAThread]
void Button2_PressEvent () { eventOnPress_button2 (); }
[STAThread]
@@ -1075,7 +1274,7 @@ public ref class MainWnd: public Form
StrPrintFormatW (GetRCString_cpp (PAGE_2_INSTALLING).c_str (), (int)value).c_str ()
)
);
this->setTaskbarProgress ((unsigned)value);
this->invokeSetTaskbarProgress ((unsigned)value);
}
bool launchInstalledApp ()
{

View File

@@ -323,7 +323,8 @@ std::vector <std::wstring> applicationItems =
L"DisplayName",
L"BackgroundColor",
L"ForegroundText",
L"ShortName"
L"ShortName",
L"Square44x44Logo"
};
typedef std::wstring strlabel, StringLabel;
std::wstring StringTrim (const std::wstring &str)

View File

@@ -89,9 +89,40 @@ struct PackageInfomation
this->properties.description = reader.getPropertyDescription ();
this->properties.publisher = reader.getPropertyPublisher ();
}
this->properties.logoBase64 = GetLogoBase64FromReader (reader, &this->properties.logoStream);
this->properties.logoBase64 = GetLogoBase64FromReader (reader, &this->properties.logoStream, &pri);
this->prerequisites.osMinVersion = reader.getPrerequisiteOSMinVersion ();
reader.getApplications (this->applications);
for (auto &it : this->applications)
{
for (auto &sit : it)
{
if (LabelEqual (sit.first, L"AppUserModelID")) continue;
else if (LabelEqual (sit.first, L"Id")) continue;
else if (LabelEqual (sit.first, L"DisplayName"))
{
if (isMsResourceLabel (sit.second))
{
std::wstring temp (L"");
temp += pri.findStringValue (sit.second);
it [L"DisplayName"] = temp;
}
}
else if (LabelEqual (sit.first, L"ShortName"))
{
if (isMsResourceLabel (sit.second))
{
std::wstring temp (L"");
temp += pri.findStringValue (sit.second);
it [L"ShortName"] = temp;
}
}
else if (LabelEqual (sit.first, L"Square44x44Logo"))
{
sit.second = pri.findFilePathValue (sit.second);
it [strlabel (L"Square44x44LogoBase64")] = GetBase64FromPathW (reader, sit.second.c_str (), NULL, &pri);
}
}
}
reader.getCapabilities (capabilities);
reader.getDependencies (dependencies);
return reader.isAvailable ();

View File

@@ -316,7 +316,7 @@ class PriReader
PriReader (): priReader (NULL) {}
void destroy ()
{
if (!priReader) return;
if (priReader == NULL) return;
DestroyPriReader (priReader);
priReader = NULL;
}

View File

@@ -3,10 +3,12 @@
<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="Company.Product.Name" type="win32" />
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns=
"https://schemas.microsoft.com/SMI/2005/WindowsSettings">
True/PM
</dpiAware>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 10 / Windows 11 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</windowsSettings>
</application>
<description></description>

File diff suppressed because it is too large Load Diff

View File

@@ -316,7 +316,7 @@ class PriReader
PriReader (): priReader (NULL) {}
void destroy ()
{
if (!priReader) return;
if (priReader == NULL) return;
DestroyPriReader (priReader);
priReader = NULL;
}

View File

@@ -31,4 +31,33 @@ LPSTR StreamToBase64 (HISTREAM ifile)
if (!lpszStr) return NULL;
lstrcpyA (lpszStr, res.c_str ());
return lpszStr;
}
}
LPWSTR StreamToBase64W (HISTREAM ifile)
{
if (!ifile) return NULL;
IStream *pStream = (IStream *)ifile;
LARGE_INTEGER liZero = {};
pStream->Seek (liZero, STREAM_SEEK_SET, nullptr);
STATSTG statstg;
pStream->Stat (&statstg, STATFLAG_NONAME);
ULARGE_INTEGER uliSize = statstg.cbSize;
std::vector<BYTE> buffer (uliSize.QuadPart);
ULONG bytesRead;
pStream->Read (buffer.data (), static_cast<ULONG>(buffer.size ()), &bytesRead);
DWORD base64Size = 0;
if (!CryptBinaryToStringW (buffer.data (), bytesRead, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, nullptr, &base64Size))
{
return NULL;
}
std::vector <WCHAR> base64Buffer (base64Size);
if (!CryptBinaryToStringW (buffer.data (), bytesRead, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, base64Buffer.data (), &base64Size))
{
return NULL;
}
std::wstring res = std::wstring (base64Buffer.begin (), base64Buffer.end ());
LPWSTR lpszStr = (LPWSTR)calloc (res.capacity (), sizeof (WCHAR));
if (!lpszStr) return NULL;
lstrcpyW (lpszStr, res.c_str ());
return lpszStr;
}

View File

@@ -14,3 +14,5 @@ typedef HANDLE HISTREAM;
typedef char *LPSTR;
extern "C" BASE64IMG_API LPSTR StreamToBase64 (HISTREAM ifile);
extern "C" BASE64IMG_API LPWSTR StreamToBase64W (HISTREAM ifile);

View File

@@ -1652,6 +1652,10 @@ class PriReader
if (xmlreader) delete xmlreader;
xmlreader = nullptr;
if (IsFileExists (txmlpath)) DeleteFileW (txmlpath.c_str ());
if (IsFileExists (txmlpath.substr (0, txmlpath.length () - 4)))
{
DeleteFileW (txmlpath.substr (0, txmlpath.length () - 4).c_str ());
}
txmlpath = L"";
prifile = L"";
}
@@ -1760,6 +1764,10 @@ class PriReader
}
bool res = this->create (tempPriFile);
DeleteFileW (tempPriFile.c_str ());
if (IsFileExists (tempPriFile.substr (0, tempPriFile.length () - 4)))
{
DeleteFileW (tempPriFile.substr (0, tempPriFile.length () - 4).c_str ());
}
return res;
}
// 获取到的指针需要 free 手动释放。
@@ -1905,7 +1913,7 @@ void DestroyPriReader (HPRIREADER hpr)
{
if (!hpr) return;
PriReader *ptr = (PriReader *)hpr;
delete hpr;
delete ptr;
return;
}
// 返回的字符串只能肯定不是宽字符串,而不确定具体的编码方式(可能为 ANSI 也有可能为 UTF-8