mirror of
https://github.com/modernw/App-Installer-For-Windows-8.x-Reset.git
synced 2026-04-11 17:57:19 +10:00
Added new features and the setup scripts for ARM users.
This commit is contained in:
7
.gitignore
vendored
7
.gitignore
vendored
@@ -245,4 +245,9 @@ ModelManifest.xml
|
||||
[Gg]enerated/
|
||||
|
||||
# Setup Build Files
|
||||
[Oo]thers/
|
||||
[Oo]thers/
|
||||
|
||||
# Arm Build Files
|
||||
arm_build.bat
|
||||
ArmBuild.ps1
|
||||
package.zip
|
||||
@@ -168,6 +168,46 @@ namespace AppxPackage
|
||||
|
||||
return result;
|
||||
}
|
||||
[StructLayout (LayoutKind.Sequential)]
|
||||
internal struct WSTRWSTRPAIR
|
||||
{
|
||||
public IntPtr lpKey; // LPWSTR
|
||||
public IntPtr lpValue; // LPWSTR
|
||||
}
|
||||
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr GetPriLocaleResourceAllValuesList (
|
||||
PCSPRIFILE pFilePri,
|
||||
[MarshalAs (UnmanagedType.LPWStr)] string lpResName);
|
||||
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void DestroyLocaleResourceAllValuesList (IntPtr list);
|
||||
[DllImport (DLL, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr GetPriFileResourceAllValuesList (
|
||||
PCSPRIFILE pFilePri,
|
||||
[MarshalAs (UnmanagedType.LPWStr)] string lpResName);
|
||||
/// <summary>
|
||||
/// 将 HWSWSPAIRLIST 解析为 Dictionary<string, string>(语言代码 → 字符串值)
|
||||
/// </summary>
|
||||
public static Dictionary<string, string> ParseWSWSPAIRLIST (IntPtr ptr)
|
||||
{
|
||||
if (ptr == IntPtr.Zero) return null;
|
||||
|
||||
uint count = (uint)Marshal.ReadInt32 (ptr); // dwLength
|
||||
IntPtr pFirst = IntPtr.Add (ptr, sizeof (uint)); // 跳过 dwLength
|
||||
int elementSize = Marshal.SizeOf (typeof (WSTRWSTRPAIR));
|
||||
|
||||
var dict = new Dictionary<string, string> ((int)count);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
IntPtr pItem = IntPtr.Add (pFirst, i * elementSize);
|
||||
var item = (WSTRWSTRPAIR)Marshal.PtrToStructure (pItem, typeof (WSTRWSTRPAIR));
|
||||
|
||||
string key = item.lpKey != IntPtr.Zero ? Marshal.PtrToStringUni (item.lpKey) : null;
|
||||
string value = item.lpValue != IntPtr.Zero ? Marshal.PtrToStringUni (item.lpValue) : null;
|
||||
if (key != null)
|
||||
dict [key] = value;
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
}
|
||||
public static class LpcwstrListHelper
|
||||
{
|
||||
|
||||
@@ -239,6 +239,69 @@ namespace AppxPackage
|
||||
|
||||
return task.Result;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取指定字符串资源的所有语言变体(语言代码 → 字符串值)
|
||||
/// </summary>
|
||||
public Dictionary<string, string> LocaleResourceAllValue (string resName)
|
||||
{
|
||||
var task = Task.Factory.StartNew (() =>
|
||||
{
|
||||
IntPtr ptr = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
// 修正:第一个参数应为 m_hPriFile,而不是 ptr
|
||||
ptr = PriFileHelper.GetPriLocaleResourceAllValuesList (m_hPriFile, resName);
|
||||
if (ptr == IntPtr.Zero)
|
||||
return new Dictionary<string, string> ();
|
||||
|
||||
// 解析 HWSWSPAIRLIST 为 Dictionary<string, string>
|
||||
var raw = PriFileHelper.ParseWSWSPAIRLIST (ptr);
|
||||
return raw ?? new Dictionary<string, string> ();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (ptr != IntPtr.Zero)
|
||||
PriFileHelper.DestroyLocaleResourceAllValuesList (ptr);
|
||||
}
|
||||
});
|
||||
return task.Result;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取指定文件资源的所有缩放/对比度/目标大小变体(PriResourceKey → 文件路径)
|
||||
/// </summary>
|
||||
public Dictionary<PriResourceKey, string> PathResourceAllValue (string resName)
|
||||
{
|
||||
var task = Task.Factory.StartNew (() =>
|
||||
{
|
||||
IntPtr ptr = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
ptr = PriFileHelper.GetPriFileResourceAllValuesList (m_hPriFile, resName);
|
||||
if (ptr == IntPtr.Zero)
|
||||
return new Dictionary<PriResourceKey, string> ();
|
||||
|
||||
// 解析 HDWSPAIRLIST 为 Dictionary<uint, string>
|
||||
var raw = PriFileHelper.ParseDWSPAIRLIST (ptr);
|
||||
if (raw == null)
|
||||
return new Dictionary<PriResourceKey, string> ();
|
||||
|
||||
// 将 uint 键转换为 PriResourceKey
|
||||
var result = new Dictionary<PriResourceKey, string> ();
|
||||
foreach (var kv in raw)
|
||||
{
|
||||
var key = new PriResourceKey (kv.Key);
|
||||
result [key] = kv.Value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (ptr != IntPtr.Zero)
|
||||
PriFileHelper.DestroyPriResourceAllValueList (ptr); // 注意:使用对应的释放函数
|
||||
}
|
||||
});
|
||||
return task.Result;
|
||||
}
|
||||
}
|
||||
public class PriReaderBundle: IDisposable
|
||||
{
|
||||
|
||||
@@ -1217,7 +1217,6 @@ HWSDSPAIRLIST GetPriResourcesAllValuesList (PCSPRIFILE pPriFile, const LPCWSTR *
|
||||
return CreateWSDSPAIRLISTFromMap (rnout);
|
||||
}
|
||||
|
||||
#ifndef ELDER_FUNC
|
||||
size_t GetPriLocaleStringResources (
|
||||
PCSPRIFILE pPriFile,
|
||||
const std::vector <std::wstring> &resnames,
|
||||
@@ -1332,6 +1331,8 @@ size_t GetPriLocaleStringResources (
|
||||
resourceMapSection = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef ELDER_FUNC
|
||||
std::wstring GetConfirmLocaleResources (const std::map <std::wnstring, std::wstring> &strvalue, const std::wnstring &lang)
|
||||
{
|
||||
for (auto &it : strvalue)
|
||||
@@ -1464,4 +1465,113 @@ LPWSTR GetPriResource (PCSPRIFILE pFilePri, LPCWSTR lpswResId)
|
||||
}
|
||||
LPWSTR GetPriStringResource (PCSPRIFILE pFilePri, LPCWSTR lpswUri) { return GetPriResource (pFilePri, lpswUri); }
|
||||
LPWSTR GetPriPathResource (PCSPRIFILE pFilePri, LPCWSTR lpswFilePath) { return GetPriResource (pFilePri, lpswFilePath); }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
HWSWSPAIRLIST CreateWSWSPAIRLISTFromMap (const std::map<std::wnstring, std::wstring>& input)
|
||||
{
|
||||
DWORD count = (DWORD)input.size ();
|
||||
if (count == 0) return nullptr;
|
||||
|
||||
size_t totalSize = sizeof (WSWSPAIRLIST) + sizeof (WSTRWSTRPAIR) * (count - 1);
|
||||
HWSWSPAIRLIST list = (HWSWSPAIRLIST)malloc (totalSize);
|
||||
if (!list) return nullptr;
|
||||
|
||||
list->dwLength = count;
|
||||
DWORD index = 0;
|
||||
for (const auto& pair : input)
|
||||
{
|
||||
list->lpArray [index].lpKey = _wcsdup (pair.first.c_str ());
|
||||
list->lpArray [index].lpValue = _wcsdup (pair.second.c_str ());
|
||||
++index;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
HWSWSPAIRLIST GetPriLocaleResourceAllValuesList (PCSPRIFILE pPriFile, LPCWSTR lpResName)
|
||||
{
|
||||
if (!pPriFile || !lpResName || !*lpResName)
|
||||
{
|
||||
SetPriLastError (L"Invalid parameters");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<std::wstring> resnames = { lpResName };
|
||||
std::map<std::wnstring, std::map<std::wnstring, std::wstring>> output;
|
||||
|
||||
try
|
||||
{
|
||||
GetPriLocaleStringResources (pPriFile, resnames, output);
|
||||
}
|
||||
catch (System::Exception^ e)
|
||||
{
|
||||
SetPriLastError (MPStringToStdW (e->Message));
|
||||
return nullptr;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
SetPriLastError (StringToWString (e.what ()));
|
||||
return nullptr;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
SetPriLastError (L"Unknown exception in GetPriLocaleStringResources");
|
||||
return nullptr;
|
||||
}
|
||||
auto it = output.find (std::wnstring (lpResName));
|
||||
if (it == output.end () || it->second.empty ())
|
||||
{
|
||||
SetPriLastError (L"Resource not found or has no language variants");
|
||||
return nullptr;
|
||||
}
|
||||
return CreateWSWSPAIRLISTFromMap (it->second);
|
||||
}
|
||||
void DestroyLocaleResourceAllValuesList (HWSWSPAIRLIST list)
|
||||
{
|
||||
if (!list) return;
|
||||
for (DWORD i = 0; i < list->dwLength; ++i)
|
||||
{
|
||||
if (list->lpArray [i].lpKey)
|
||||
free (list->lpArray [i].lpKey);
|
||||
if (list->lpArray [i].lpValue)
|
||||
free (list->lpArray [i].lpValue);
|
||||
}
|
||||
free (list);
|
||||
}
|
||||
HDWSPAIRLIST GetPriFileResourceAllValuesList (PCSPRIFILE pPriFile, LPCWSTR lpResName)
|
||||
{
|
||||
if (!pPriFile || !lpResName || !*lpResName)
|
||||
{
|
||||
SetPriLastError (L"Invalid parameters");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<std::wstring> resnames = { lpResName };
|
||||
std::map<std::wnstring, std::map<DWORD, std::wnstring>> output;
|
||||
|
||||
try
|
||||
{
|
||||
GetPriScaleAndTargetSizeFileList (pPriFile, resnames, output);
|
||||
}
|
||||
catch (System::Exception^ e)
|
||||
{
|
||||
SetPriLastError (MPStringToStdW (e->Message));
|
||||
return nullptr;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
SetPriLastError (StringToWString (e.what ()));
|
||||
return nullptr;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
SetPriLastError (L"Unknown exception in GetPriScaleAndTargetSizeFileList");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto it = output.find (std::wnstring (lpResName));
|
||||
if (it == output.end () || it->second.empty ())
|
||||
{
|
||||
SetPriLastError (L"Resource not found or has no variants");
|
||||
return nullptr;
|
||||
}
|
||||
return CreateDWSPAIRLISTFromMap (it->second);
|
||||
}
|
||||
@@ -113,6 +113,19 @@ extern "C" {
|
||||
// 低 16 位:
|
||||
// Scale 或 TargetSize 或 LCID
|
||||
PRIFORMATCLI_API HWSDSPAIRLIST GetPriResourcesAllValuesList (PCSPRIFILE pPriFile, const LPCWSTR *lpResNames, DWORD dwCount);
|
||||
typedef struct WSTRWSTRPAIR__
|
||||
{
|
||||
LPWSTR lpKey _DEFAULT_VALUE_SET (NULL);
|
||||
LPWSTR lpValue _DEFAULT_VALUE_SET (NULL);
|
||||
} WSTRWSTRPAIR, *HWSTRWSTRPAIR;
|
||||
typedef struct WSWSPAIRLIST__
|
||||
{
|
||||
DWORD dwLength _DEFAULT_VALUE_SET (0);
|
||||
WSTRWSTRPAIR lpArray [1];
|
||||
} WSWSPAIRLIST, *HWSWSPAIRLIST;
|
||||
PRIFORMATCLI_API HWSWSPAIRLIST GetPriLocaleResourceAllValuesList (PCSPRIFILE pPriFile, LPCWSTR lpResName);
|
||||
PRIFORMATCLI_API void DestroyLocaleResourceAllValuesList (HWSWSPAIRLIST list);
|
||||
PRIFORMATCLI_API HDWSPAIRLIST GetPriFileResourceAllValuesList (PCSPRIFILE pPriFile, LPCWSTR lpResName);
|
||||
#ifdef _DEFAULT_VALUE_SET
|
||||
#undef _DEFAULT_VALUE_SET
|
||||
#endif
|
||||
|
||||
169
shared/ArmInstall.ps1
Normal file
169
shared/ArmInstall.ps1
Normal file
@@ -0,0 +1,169 @@
|
||||
#Requires -RunAsAdministrator
|
||||
|
||||
Push-Location $PSScriptRoot
|
||||
try {
|
||||
# 语言检测函数
|
||||
function Get-Language {
|
||||
$lang = [System.Globalization.CultureInfo]::CurrentUICulture.TwoLetterISOLanguageName
|
||||
if ($lang -eq "zh") { return "zh" }
|
||||
return "en"
|
||||
}
|
||||
|
||||
$lang = Get-Language
|
||||
|
||||
# 本地化消息
|
||||
$messages = @{
|
||||
en = @{
|
||||
title = "Desktop App Installer Setup"
|
||||
confirm = "Do you want to install Desktop App Installer? (y/n)"
|
||||
invalid = "Invalid input. Please enter y or n."
|
||||
cancelled = "Installation cancelled."
|
||||
arch_error = "Error: Cannot continue installation because the computer's processor architecture is not ARM."
|
||||
creating_shortcuts = "Creating shortcuts in Start Screen..."
|
||||
registering = "Registering..."
|
||||
complete = "Installation complete!"
|
||||
}
|
||||
zh = @{
|
||||
title = "Desktop App Installer 安装程序"
|
||||
confirm = "是否安装 Desktop App Installer?(y/n)"
|
||||
invalid = "无效输入,请输入 y 或 n。"
|
||||
cancelled = "安装已取消。"
|
||||
arch_error = "错误:无法继续安装,因为计算机的处理器架构不是 ARM。"
|
||||
creating_shortcuts = "正在创建开始屏幕快捷方式..."
|
||||
registering = "正在注册..."
|
||||
complete = "安装完成!"
|
||||
}
|
||||
}
|
||||
|
||||
$msg = $messages[$lang]
|
||||
|
||||
# 函数定义
|
||||
function Create-Shortcut {
|
||||
param(
|
||||
[string]$LnkPath,
|
||||
[string]$TargetPath,
|
||||
[string]$AppId
|
||||
)
|
||||
$toolShortcutPath = Join-Path $PSScriptRoot "shortcut.exe"
|
||||
if (-not (Test-Path $toolShortcutPath)) {
|
||||
throw "Error: cannot find file 'shortcut.exe' in folder '$PSScriptRoot'"
|
||||
}
|
||||
& $toolShortcutPath $LnkPath $TargetPath $AppId
|
||||
return $LASTEXITCODE
|
||||
}
|
||||
|
||||
function Set-DesktopInit {
|
||||
param(
|
||||
[string]$IniPath,
|
||||
[string]$Section,
|
||||
[string]$Key,
|
||||
[string]$Value
|
||||
)
|
||||
$toolDesktopIniPath = Join-Path $PSScriptRoot "desktopini.exe"
|
||||
if (-not (Test-Path $toolDesktopIniPath)) {
|
||||
throw "Error: cannot find file 'desktopini.exe' in folder '$PSScriptRoot'"
|
||||
}
|
||||
& $toolDesktopIniPath $IniPath $Section $Key $Value
|
||||
return $LASTEXITCODE
|
||||
}
|
||||
|
||||
# 检查处理器架构
|
||||
if ($env:PROCESSOR_ARCHITECTURE.Trim() -ne "ARM") {
|
||||
throw $msg.arch_error
|
||||
}
|
||||
|
||||
# 确认安装
|
||||
do {
|
||||
$response = Read-Host $msg.confirm
|
||||
$response = $response.ToLower()
|
||||
if ($response -eq 'y') {
|
||||
$confirmed = $true
|
||||
break
|
||||
} elseif ($response -eq 'n') {
|
||||
Write-Host $msg.cancelled
|
||||
exit 0
|
||||
} else {
|
||||
Write-Host $msg.invalid
|
||||
}
|
||||
} while ($true)
|
||||
|
||||
# 安装目录和快捷方式目录
|
||||
$appStartMenuFolder = "Desktop App Installer"
|
||||
$appPublicStartMenuFolder = [System.IO.Path]::Combine($env:ProgramData, "Microsoft\Windows\Start Menu\Programs")
|
||||
$startitemfolder = [System.IO.Path]::Combine($appPublicStartMenuFolder, $appStartMenuFolder)
|
||||
$AppFolder = $PSScriptRoot
|
||||
|
||||
Write-Output $msg.creating_shortcuts
|
||||
if (-not (Test-Path $startitemfolder)) {
|
||||
New-Item -ItemType Directory -Path $startitemfolder -Force | Out-Null
|
||||
}
|
||||
|
||||
$shortcuts = @(
|
||||
@{
|
||||
LnkPath = Join-Path $startitemfolder "App Installer.lnk"
|
||||
TargetPath = Join-Path $AppFolder "appinstaller.exe"
|
||||
AppId = "Microsoft.DesktopAppInstaller!App"
|
||||
},
|
||||
@{
|
||||
LnkPath = Join-Path $startitemfolder "Settings.lnk"
|
||||
TargetPath = Join-Path $AppFolder "settings.exe"
|
||||
AppId = "WindowsModern.PracticalToolsProject!Settings"
|
||||
},
|
||||
@{
|
||||
LnkPath = Join-Path $startitemfolder "Package Manager.lnk"
|
||||
TargetPath = Join-Path $AppFolder "Manager.exe"
|
||||
AppId = "WindowsModern.PracticalToolsProject!Manager"
|
||||
},
|
||||
@{
|
||||
LnkPath = Join-Path $startitemfolder "Update.lnk"
|
||||
TargetPath = Join-Path $AppFolder "Update.exe"
|
||||
AppId = "WindowsModern.PracticalToolsProject!Update"
|
||||
},
|
||||
@{
|
||||
LnkPath = Join-Path $startitemfolder "Package Reader.lnk"
|
||||
TargetPath = Join-Path $AppFolder "Reader.exe"
|
||||
AppId = "WindowsModern.PracticalToolsProject!Reader"
|
||||
}
|
||||
)
|
||||
|
||||
foreach ($item in $shortcuts) {
|
||||
$exitCode = Create-Shortcut -LnkPath $item.LnkPath -TargetPath $item.TargetPath -AppId $item.AppId
|
||||
}
|
||||
|
||||
# $desktopini = Join-Path $startitemfolder "desktop.ini"
|
||||
$desktopini = $startitemfolder
|
||||
Set-DesktopInit -IniPath $desktopini -Section ".ShellClassInfo" -Key "ConfirmFileOp" -Value 0
|
||||
Set-DesktopInit -IniPath $desktopini -Section "LocalizedFileNames" -Key "App Installer.lnk" -Value "@$AppFolder\appinstaller.exe,-300"
|
||||
Set-DesktopInit -IniPath $desktopini -Section "LocalizedFileNames" -Key "Settings.lnk" -Value "@$AppFolder\settings.exe,-200"
|
||||
Set-DesktopInit -IniPath $desktopini -Section "LocalizedFileNames" -Key "Update.lnk" -Value "@$AppFolder\reslib.dll,-103"
|
||||
Set-DesktopInit -IniPath $desktopini -Section "LocalizedFileNames" -Key "Package Manager.lnk" -Value "@$AppFolder\reslib.dll,-228"
|
||||
Set-DesktopInit -IniPath $desktopini -Section "LocalizedFileNames" -Key "Uninstall.lnk" -Value "@$AppFolder\reslib.dll,-131"
|
||||
Set-DesktopInit -IniPath $desktopini -Section ".ShellClassInfo" -Key "LocalizedResourceName" -Value "@$AppFolder\appinstaller.exe,-300"
|
||||
|
||||
Write-Output $msg.registering
|
||||
$reg = [Microsoft.Win32.Registry]::ClassesRoot
|
||||
$key = $reg.CreateSubKey("Microsoft.DesktopAppInstaller")
|
||||
$key.SetValue("", "Windows Store App Package")
|
||||
$key.Close()
|
||||
$subKey = $reg.CreateSubKey("Microsoft.DesktopAppInstaller\Shell\Open\Command")
|
||||
$subKey.SetValue("", "`"$AppFolder\appinstaller.exe`" `"%1`"")
|
||||
$subKey.Close()
|
||||
$subKey = $reg.CreateSubKey("Microsoft.DesktopAppInstaller\DefaultIcon")
|
||||
$subKey.SetValue("", "$AppFolder\appinstaller.exe,2")
|
||||
$subKey.Close()
|
||||
$subKey = $reg.CreateSubKey("Applications\AppInstaller.exe\DefaultIcon")
|
||||
$subKey.SetValue("", "$AppFolder\appinstaller.exe,-136")
|
||||
$subKey.Close()
|
||||
$subKey = $reg.CreateSubKey(".appx")
|
||||
$subKey.SetValue("", "Microsoft.DesktopAppInstaller")
|
||||
$subKey.Close()
|
||||
$subKey = $reg.CreateSubKey(".appxbundle")
|
||||
$subKey.SetValue("", "Microsoft.DesktopAppInstaller")
|
||||
$subKey.Close()
|
||||
|
||||
Write-Output ""
|
||||
Write-Output $msg.complete
|
||||
Start-Sleep -Seconds 5
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
153
shared/ArmUninstall.ps1
Normal file
153
shared/ArmUninstall.ps1
Normal file
@@ -0,0 +1,153 @@
|
||||
#Requires -RunAsAdministrator
|
||||
|
||||
Push-Location $PSScriptRoot
|
||||
try {
|
||||
# 语言检测函数
|
||||
function Get-Language {
|
||||
$lang = [System.Globalization.CultureInfo]::CurrentUICulture.TwoLetterISOLanguageName
|
||||
if ($lang -eq "zh") { return "zh" }
|
||||
return "en"
|
||||
}
|
||||
|
||||
$lang = Get-Language
|
||||
|
||||
# 本地化消息
|
||||
$messages = @{
|
||||
en = @{
|
||||
title = "Uninstall Desktop App Installer"
|
||||
confirm = "Are you sure you want to uninstall Desktop App Installer? (y/n)"
|
||||
invalid = "Invalid input. Please enter y or n."
|
||||
removing_start = "Removing Start Menu folder..."
|
||||
removing_reg = "Removing registry entries..."
|
||||
removing_dir = "Removing installation directory..."
|
||||
confirm_dir = "Do you also want to delete the installation directory? (y/n)"
|
||||
complete = "Uninstallation complete."
|
||||
error = "Error: "
|
||||
cancelled = "Uninstall cancelled."
|
||||
}
|
||||
zh = @{
|
||||
title = "卸载 Desktop App Installer"
|
||||
confirm = "确定要卸载 Desktop App Installer 吗?(y/n)"
|
||||
invalid = "无效输入,请输入 y 或 n。"
|
||||
removing_start = "正在删除开始菜单文件夹..."
|
||||
removing_reg = "正在删除注册表项..."
|
||||
removing_dir = "正在删除安装目录..."
|
||||
confirm_dir = "是否同时删除安装目录?(y/n)"
|
||||
complete = "卸载完成。"
|
||||
error = "错误:"
|
||||
cancelled = "卸载已取消。"
|
||||
}
|
||||
}
|
||||
|
||||
$msg = $messages[$lang]
|
||||
|
||||
if ($env:PROCESSOR_ARCHITECTURE.Trim() -ne "ARM") {
|
||||
throw "Error: Cannot continue installation because the computer's processor architecture is not ARM."
|
||||
}
|
||||
|
||||
# 确认卸载(控制台交互)
|
||||
do {
|
||||
$response = Read-Host $msg.confirm
|
||||
$response = $response.ToLower()
|
||||
if ($response -eq 'y') {
|
||||
$confirmed = $true
|
||||
break
|
||||
} elseif ($response -eq 'n') {
|
||||
Write-Host $msg.cancelled
|
||||
exit 0
|
||||
} else {
|
||||
Write-Host $msg.invalid
|
||||
}
|
||||
} while ($true)
|
||||
|
||||
# 定义路径
|
||||
$appStartMenuFolder = "Desktop App Installer"
|
||||
$appPublicStartMenuFolder = [System.IO.Path]::Combine($env:ProgramData, "Microsoft\Windows\Start Menu\Programs")
|
||||
$startitemfolder = [System.IO.Path]::Combine($appPublicStartMenuFolder, $appStartMenuFolder)
|
||||
$AppFolder = $PSScriptRoot
|
||||
|
||||
# 删除开始菜单文件夹
|
||||
Write-Host $msg.removing_start
|
||||
if (Test-Path $startitemfolder) {
|
||||
Remove-Item -Path $startitemfolder -Recurse -Force -ErrorAction SilentlyContinue
|
||||
if (Test-Path $startitemfolder) {
|
||||
Write-Warning "$msg.error Could not remove $startitemfolder"
|
||||
} else {
|
||||
Write-Output "Removed $startitemfolder"
|
||||
}
|
||||
} else {
|
||||
Write-Output "Start Menu folder not found, skipping."
|
||||
}
|
||||
|
||||
# 删除注册表项
|
||||
Write-Host $msg.removing_reg
|
||||
$reg = [Microsoft.Win32.Registry]::ClassesRoot
|
||||
|
||||
$keysToDelete = @(
|
||||
"Microsoft.DesktopAppInstaller",
|
||||
".appx",
|
||||
".appxbundle"
|
||||
)
|
||||
foreach ($keyName in $keysToDelete) {
|
||||
try {
|
||||
if ($reg.OpenSubKey($keyName) -ne $null) {
|
||||
$reg.DeleteSubKeyTree($keyName)
|
||||
Write-Output "Removed registry key: HKCR\$keyName"
|
||||
} else {
|
||||
Write-Output "Registry key not found: HKCR\$keyName"
|
||||
}
|
||||
} catch {
|
||||
Write-Warning "$msg.error Could not remove HKCR\$keyName : $_"
|
||||
}
|
||||
}
|
||||
|
||||
# 删除 Applications\AppInstaller.exe 下的 DefaultIcon
|
||||
$appPath = "Applications\AppInstaller.exe"
|
||||
try {
|
||||
$appKey = $reg.OpenSubKey($appPath, $true)
|
||||
if ($appKey) {
|
||||
$subKeyNames = $appKey.GetSubKeyNames()
|
||||
if ($subKeyNames -contains "DefaultIcon") {
|
||||
$appKey.DeleteSubKey("DefaultIcon")
|
||||
Write-Output "Removed registry key: HKCR\$appPath\DefaultIcon"
|
||||
}
|
||||
$appKey.Close()
|
||||
} else {
|
||||
Write-Output "Registry key not found: HKCR\$appPath"
|
||||
}
|
||||
} catch {
|
||||
Write-Warning "$msg.error Could not process HKCR\$appPath : $_"
|
||||
}
|
||||
|
||||
# 删除安装目录
|
||||
Write-Host $msg.removing_dir
|
||||
do {
|
||||
$respDir = Read-Host $msg.confirm_dir
|
||||
$respDir = $respDir.ToLower()
|
||||
if ($respDir -eq 'y') {
|
||||
if (Test-Path $AppFolder) {
|
||||
Remove-Item -Path $AppFolder -Recurse -Force -ErrorAction SilentlyContinue
|
||||
if (Test-Path $AppFolder) {
|
||||
Write-Warning "$msg.error Could not delete $AppFolder"
|
||||
} else {
|
||||
Write-Output "Deleted installation directory."
|
||||
}
|
||||
} else {
|
||||
Write-Output "Installation directory not found."
|
||||
}
|
||||
break
|
||||
} elseif ($respDir -eq 'n') {
|
||||
Write-Output "Skipped deleting installation directory."
|
||||
break
|
||||
} else {
|
||||
Write-Host $msg.invalid
|
||||
}
|
||||
} while ($true)
|
||||
|
||||
Write-Host $msg.complete
|
||||
Start-Sleep -Seconds 3
|
||||
} catch {
|
||||
Write-Error "Uninstall failed: $_"
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
13
shared/arm_install.bat
Normal file
13
shared/arm_install.bat
Normal file
@@ -0,0 +1,13 @@
|
||||
@echo off
|
||||
if exist "%SystemRoot%\SysWOW64" path %path%;%windir%\SysNative;%SystemRoot%\SysWOW64;%~dp0
|
||||
bcdedit >nul
|
||||
if '%errorlevel%' NEQ '0' (goto UACPrompt) else (goto UACAdmin)
|
||||
:UACPrompt
|
||||
%1 start "" mshta vbscript:createobject("shell.application").shellexecute("""%~0""","::",,"runas",1)(window.close)&exit
|
||||
exit /B
|
||||
:UACAdmin
|
||||
cd /d "%~dp0"
|
||||
|
||||
set SCRIPT_DIR=%~dp0
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File "%SCRIPT_DIR%ArmInstall.ps1"
|
||||
pause
|
||||
6
shared/arm_readme.txt
Normal file
6
shared/arm_readme.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
对于 Windows RT 用户,请以管理员身份运行 arm_install.bat 或 arm_uninstall.bat 进行安装或卸载。安装前请务必将压缩包中的所有文件放置在一个独立的文件夹中,该文件夹请勿随意移动或删除,不建议放置在桌面上。若需更新或移动程序,请先执行原卸载脚本,然后再进行安装操作。x86、x64 以及支持 x86 兼容层的 ARM64 系统请使用标准安装程序,本方案仅适用于 ARM 设备。
|
||||
感谢“冰糖XH”(主页:https://github.com/bingtangxh)帮助我完成了针对 ARM 架构的程序编译。
|
||||
|
||||
(Translated by DeepSeek)
|
||||
For Windows RT users, please run arm_install.bat or arm_uninstall.bat as an administrator to install or uninstall. Before installation, extract all files from the compressed package into a dedicated folder; do not move or delete this folder arbitrarily, and it is not recommended to place it on the desktop. If you need to update or relocate the program, first run the original uninstall script, then proceed with the installation. For x86, x64, and ARM64 systems that support the x86 compatibility layer, please use the standard installer; this solution is specifically for ARM devices.
|
||||
Thanks to "BingTangXH" (Homepage: https://github.com/bingtangxh) for helping me complete the program compilation for the ARM architecture.
|
||||
13
shared/arm_uninstall.bat
Normal file
13
shared/arm_uninstall.bat
Normal file
@@ -0,0 +1,13 @@
|
||||
@echo off
|
||||
if exist "%SystemRoot%\SysWOW64" path %path%;%windir%\SysNative;%SystemRoot%\SysWOW64;%~dp0
|
||||
bcdedit >nul
|
||||
if '%errorlevel%' NEQ '0' (goto UACPrompt) else (goto UACAdmin)
|
||||
:UACPrompt
|
||||
%1 start "" mshta vbscript:createobject("shell.application").shellexecute("""%~0""","::",,"runas",1)(window.close)&exit
|
||||
exit /B
|
||||
:UACAdmin
|
||||
cd /d "%~dp0"
|
||||
|
||||
set SCRIPT_DIR=%~dp0
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File "%SCRIPT_DIR%ArmUninstall.ps1"
|
||||
pause
|
||||
@@ -24,9 +24,6 @@
|
||||
return Bridge.String.tolower(Bridge.String.trim(item.Identity.FullName));
|
||||
});
|
||||
var themeColor = Bridge.UI.themeColor;
|
||||
var appbar = document.getElementById("appBar");
|
||||
var appbarControl = new AppBar.AppBar(appbar);
|
||||
appbarControl.enabled = false;
|
||||
pagemgr.register("reader", document.getElementById("tag-reader"), document.getElementById("page-reader"));
|
||||
pagemgr.go("reader");
|
||||
});
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
<link rel="stylesheet" href="fonts/fonts.css">
|
||||
<link rel="stylesheet" href="fonts/segx.css">
|
||||
<link rel="stylesheet" href="manager/page.css">
|
||||
<link rel="stylesheet" href="manager/appitem.css">
|
||||
<link rel="stylesheet" href="manager/appbar.css">
|
||||
<link rel="stylesheet" href="reader/page.css">
|
||||
<script type="text/javascript" src="js/handler.js"></script>
|
||||
<script type="text/javascript" src="js/event.js"></script>
|
||||
<script type="text/javascript" src="js/tileback.js"></script>
|
||||
@@ -47,21 +46,37 @@
|
||||
<div id="page-reader" style="display: none;" class="ispage">
|
||||
<h2>读取</h2>
|
||||
<p>请选择一个包,获取其信息。</p>
|
||||
<label for="read-pkgpath">文件路径</label>
|
||||
<input type="file" id="read-pkgpath">
|
||||
<input type="checkbox" id="read-usepri">
|
||||
<label for="read-usepri">需要解析 PRI 资源文件</label>
|
||||
<div>
|
||||
<label for="read-pkgpath">文件路径</label>
|
||||
<input type="file" id="read-pkgpath">
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" id="read-usepri">
|
||||
<label for="read-usepri">需要解析 PRI 资源文件</label>
|
||||
</div>
|
||||
<button id="read-btn">读取</button>
|
||||
<p>读取结果:</p>
|
||||
<div id="read-result"></div>
|
||||
<script>
|
||||
(function() {
|
||||
function generateHtmlReport(pi) {
|
||||
var pkg = pi.json;
|
||||
if (!pi.valid) {
|
||||
var ret = document.createElement("p");
|
||||
ret.textContent = "错误:无效的包文件";
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
var readBtn = document.getElementById("read-btn");
|
||||
var readResult = document.getElementById("read-result");
|
||||
var readPkgpath = document.getElementById("read-pkgpath");
|
||||
var readUsepri = document.getElementById("read-usepri");
|
||||
readBtn.onclick = function() {
|
||||
var self = this;
|
||||
if (!readPkgpath.value) {
|
||||
readResult.textContent = "错误:请选择一个有效文件";
|
||||
return;
|
||||
}
|
||||
var pr = Package.reader;
|
||||
pr.readFromPackage(readPkgpath.value, readUsepri.checked).then(function(pi) {
|
||||
readResult.textContent = JSON.stringify(pi);
|
||||
@@ -138,33 +153,6 @@
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
<div class="win-overlay win-commandlayout win-appbar win-bottom appbar win-ui-dark" id="appBar" role="menubar">
|
||||
</div>
|
||||
<div data-win-control="WinJS.UI.Flyout" id="app-uninstall-flyout" style="position: absolute; width: 336px; padding: 0; max-height: 284px;">
|
||||
<div class="top" style="padding: 20px 20px 0 20px;">
|
||||
<span data-res-resxml="MANAGER_APP_UNINSTALL_DESC"></span>
|
||||
</div>
|
||||
<div class="sapplist applist"></div>
|
||||
<style>
|
||||
#app-uninstall-flyout {
|
||||
/*min-height: 88px;
|
||||
transition: all 0.3s cubic-bezier(0.1, 0.9, 0.2, 1);*/
|
||||
}
|
||||
|
||||
#app-uninstall-flyout .sapplist {
|
||||
padding: 0 20px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
-ms-overflow-style: -ms-autohiding-scrollbar;
|
||||
max-height: 160px;
|
||||
}
|
||||
</style>
|
||||
<div class="bottom" style="padding: 20px 20px 20px 20px; height: 32px;">
|
||||
<button class="confirm" data-res-resxml="MANAGER_APP_UNINSTALL" style="float: right;"></button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
11
shared/html/reader/page.css
Normal file
11
shared/html/reader/page.css
Normal file
@@ -0,0 +1,11 @@
|
||||
.page>aside>nav ul li.selected {
|
||||
background-color: #0059ff;
|
||||
}
|
||||
|
||||
.page>aside>nav ul li.selected:hover {
|
||||
background-color: #1a52e0;
|
||||
}
|
||||
|
||||
.page>aside>nav ul li.selected:active {
|
||||
background-color: #1a52e0;
|
||||
}
|
||||
BIN
shared/license/license_cn.rtf
Normal file
BIN
shared/license/license_cn.rtf
Normal file
Binary file not shown.
BIN
shared/license/license_en.rtf
Normal file
BIN
shared/license/license_en.rtf
Normal file
Binary file not shown.
Reference in New Issue
Block a user