mirror of
https://github.com/modernw/App-Installer-For-Windows-8.x-Reset.git
synced 2026-04-11 17:57:19 +10:00
The encapsulation of the package manager API has been completed (only a portion of the API has been encapsulated).
This commit is contained in:
@@ -4,16 +4,25 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "appinstaller", "AppInstallerReset\AppInstallerReset.vcxproj", "{C96219BE-8AFF-4914-8933-B6B7047A94D8}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{33D91B58-1981-4A3C-B4D1-86EE406CDE12} = {33D91B58-1981-4A3C-B4D1-86EE406CDE12}
|
||||
{A7753282-AA16-43D9-8ACA-7065239DD702} = {A7753282-AA16-43D9-8ACA-7065239DD702}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pkgread", "pkgread\pkgread.vcxproj", "{A7753282-AA16-43D9-8ACA-7065239DD702}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dlltest", "dlltest\dlltest.vcxproj", "{F5CCB3AB-AC43-432A-862D-4F264760B09B}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{8EAC0230-4990-4E41-8E0F-D641D1561396} = {8EAC0230-4990-4E41-8E0F-D641D1561396}
|
||||
{33D91B58-1981-4A3C-B4D1-86EE406CDE12} = {33D91B58-1981-4A3C-B4D1-86EE406CDE12}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dlltest", "dlltest\dlltest.vcxproj", "{F5CCB3AB-AC43-432A-862D-4F264760B09B}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "priformatcli", "..\priformatcli\priformatcli\priformatcli.vcxproj", "{33D91B58-1981-4A3C-B4D1-86EE406CDE12}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pkgmgr", "pkgmgr\pkgmgr.vcxproj", "{8EAC0230-4990-4E41-8E0F-D641D1561396}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "notice", "notice\notice.vcxproj", "{798ED492-EECE-457D-8FD8-129DA93CE126}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
@@ -54,6 +63,18 @@ Global
|
||||
{33D91B58-1981-4A3C-B4D1-86EE406CDE12}.Release|x64.Build.0 = Release|x64
|
||||
{33D91B58-1981-4A3C-B4D1-86EE406CDE12}.Release|x86.ActiveCfg = Release|Win32
|
||||
{33D91B58-1981-4A3C-B4D1-86EE406CDE12}.Release|x86.Build.0 = Release|Win32
|
||||
{8EAC0230-4990-4E41-8E0F-D641D1561396}.Debug|x64.ActiveCfg = Debug|Win32
|
||||
{8EAC0230-4990-4E41-8E0F-D641D1561396}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{8EAC0230-4990-4E41-8E0F-D641D1561396}.Debug|x86.Build.0 = Debug|Win32
|
||||
{8EAC0230-4990-4E41-8E0F-D641D1561396}.Release|x64.ActiveCfg = Release|Win32
|
||||
{8EAC0230-4990-4E41-8E0F-D641D1561396}.Release|x86.ActiveCfg = Release|Win32
|
||||
{8EAC0230-4990-4E41-8E0F-D641D1561396}.Release|x86.Build.0 = Release|Win32
|
||||
{798ED492-EECE-457D-8FD8-129DA93CE126}.Debug|x64.ActiveCfg = Debug|Win32
|
||||
{798ED492-EECE-457D-8FD8-129DA93CE126}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{798ED492-EECE-457D-8FD8-129DA93CE126}.Debug|x86.Build.0 = Debug|Win32
|
||||
{798ED492-EECE-457D-8FD8-129DA93CE126}.Release|x64.ActiveCfg = Release|Win32
|
||||
{798ED492-EECE-457D-8FD8-129DA93CE126}.Release|x86.ActiveCfg = Release|Win32
|
||||
{798ED492-EECE-457D-8FD8-129DA93CE126}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>$(OutDir)pkgread.lib;$(OutDir)priformatcli.lib;$(OutDir)pkgmgr.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@@ -125,7 +126,7 @@
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>$(OutDir)pkgread.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>$(OutDir)pkgread.lib;$(OutDir)priformatcli.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
#include <Windows.h>
|
||||
#include "..\pkgread\pkgread.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
#include <iomanip>
|
||||
#include "..\priformatcli\priformatcli.h"
|
||||
#include "..\pkgread\pkgread.h"
|
||||
#include "..\pkgmgr\pkgmgr.h"
|
||||
|
||||
void read_package (const std::wstring &filepath)
|
||||
{
|
||||
package_reader pr (filepath);
|
||||
pr.enable_pri_convert (true);
|
||||
pr.use_pri (true);
|
||||
std::wcout << L"Is Valid: " << (pr.valid () ? L"true" : L"false") << std::endl;
|
||||
std::wcout << L"Package Type: ";
|
||||
switch (pr.package_type ())
|
||||
@@ -61,6 +66,7 @@ void read_package (const std::wstring &filepath)
|
||||
std::wcout << L"\tDescription: " << prop.description () << std::endl;
|
||||
std::wcout << L"\tPublisher Display Name: " << prop.publisher_display_name () << std::endl;
|
||||
std::wcout << L"\tLogo: " << prop.logo () << std::endl;
|
||||
std::wcout << L"\tLogo Base64: " << prop.logo_base64 () << std::endl;
|
||||
std::wcout << L"\tFramework: " << (prop.framework () ? L"true" : L"false") << std::endl;
|
||||
std::wcout << L"\tResource Package: " << (prop.resource_package () ? L"true" : L"false") << std::endl;
|
||||
auto preq = pr.get_prerequisites ();
|
||||
@@ -134,7 +140,9 @@ void read_package (const std::wstring &filepath)
|
||||
std::wcout << L"\tApplication" << cnt ++ << std::endl;
|
||||
for (auto &it_s : it)
|
||||
{
|
||||
std::wcout << L"\t\t" << it_s.first << L": " << it_s.second << std::endl;
|
||||
std::wcout << L"\t\t" << it_s.first << L": " << it.newat (it_s.first) << std::endl;
|
||||
std::wstring base64 = it.newat_base64 (it_s.first);
|
||||
if (!base64.empty ()) std::wcout << L"\t\t" << it_s.first << L" (Base64): " << base64 << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,20 +162,57 @@ void read_package (const std::wstring &filepath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using cbfunc = std::function <void (int progress)>;
|
||||
void ProgressCallback (DWORD dwProgress, void *pCustom)
|
||||
{
|
||||
if (auto func = reinterpret_cast <cbfunc *> (pCustom)) (*func)(dwProgress);
|
||||
}
|
||||
HRESULT AddAppxPackage (const std::wstring path, cbfunc callback, std::wstring &errorcode, std::wstring &detailmsg)
|
||||
{
|
||||
LPWSTR ec = nullptr, dm = nullptr;
|
||||
struct reltask
|
||||
{
|
||||
using endfunc = std::function <void ()>;
|
||||
endfunc endtask = nullptr;
|
||||
reltask (endfunc et): endtask (et) {}
|
||||
~reltask () { if (endtask) endtask (); }
|
||||
} relt ([=] () {
|
||||
if (ec) free (ec);
|
||||
if (dm) free (dm);
|
||||
});
|
||||
HRESULT hr = AddAppxPackageFromPath (path.c_str (), nullptr, DEPOLYOPTION_NONE, ProgressCallback, &callback, &ec, &dm);
|
||||
errorcode.clear ();
|
||||
detailmsg.clear ();
|
||||
if (ec) errorcode = ec;
|
||||
if (dm) detailmsg = dm;
|
||||
return hr;
|
||||
}
|
||||
int main (int argc, char *argv [])
|
||||
{
|
||||
setlocale (LC_ALL, "");
|
||||
std::wcout.imbue (std::locale ("", LC_CTYPE));
|
||||
std::wcout << L"Please enter the file path: " << std::endl;
|
||||
std::wcout << L"\\> ";
|
||||
std::wstring pkgPathStr = L"E:\\Profiles\\Bruce\\Desktop\\resources.pri";
|
||||
//std::getline (std::wcin, pkgPathStr);
|
||||
std::wstring pkgPathStr = L"E:\\Profiles\\Bruce\\Desktop\\Discourse.appx";
|
||||
pkgPathStr = L"F:\\BaiduNetdiskDownload\\Collection4\\Microsoft.BingFinance_2015.709.2014.2069_neutral_~_8wekyb3d8bbwe\\FinanceApp_3.0.4.336_x86.appx";
|
||||
pkgPathStr = L"F:\\BaiduNetdiskDownload\\Collection4\\Microsoft.BingFinance_2015.709.2014.2069_neutral_~_8wekyb3d8bbwe.appxbundle";
|
||||
pkgPathStr = L"";
|
||||
if (pkgPathStr.empty ()) std::getline (std::wcin, pkgPathStr);
|
||||
pkgPathStr.erase (
|
||||
std::remove (pkgPathStr.begin (), pkgPathStr.end (), L'\"'),
|
||||
pkgPathStr.end ()
|
||||
);
|
||||
|
||||
std::wcout << L"Installing ..." << std::endl;
|
||||
std::wstring ec, dm;
|
||||
HRESULT hr = AddAppxPackage (pkgPathStr, [] (int progress) {
|
||||
std::wcout << L"\r " << progress << L"%";
|
||||
}, ec, dm);
|
||||
if (SUCCEEDED (hr)) std::wcout << std::endl << L"Installed Successfully." << std::endl;
|
||||
else
|
||||
{
|
||||
std::wcout << std::endl << L"Exception: " << ec << L"(0x" << std::hex << std::setw (8) << std::setfill (L'0') << hr << L")" << std::endl;
|
||||
std::wcout << L"Detail Message: " << dm << std::endl;
|
||||
}
|
||||
system ("pause");
|
||||
return 0;
|
||||
}
|
||||
30
notice/ReadMe.txt
Normal file
30
notice/ReadMe.txt
Normal file
@@ -0,0 +1,30 @@
|
||||
========================================================================
|
||||
动态链接库:pkgmgr 项目概述
|
||||
========================================================================
|
||||
|
||||
应用程序向导已为您创建了此 pkgmgr DLL。
|
||||
|
||||
本文件概要介绍组成 pkgmgr 应用程序的每个文件的内容。
|
||||
|
||||
|
||||
pkgmgr.vcxproj
|
||||
这是使用应用程序向导生成的 VC++ 项目的主项目文件,其中包含生成该文件的 Visual C++ 的版本信息,以及有关使用应用程序向导选择的平台、配置和项目功能的信息。
|
||||
|
||||
pkgmgr.vcxproj.filters
|
||||
这是使用“应用程序向导”生成的 VC++ 项目筛选器文件。它包含有关项目文件与筛选器之间的关联信息。在 IDE 中,通过这种关联,在特定节点下以分组形式显示具有相似扩展名的文件。例如,“.cpp”文件与“源文件”筛选器关联。
|
||||
|
||||
pkgmgr.cpp
|
||||
这是主 DLL 源文件。
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
其他标准文件:
|
||||
|
||||
StdAfx.h, StdAfx.cpp
|
||||
这些文件用于生成名为 pkgmgr.pch 的预编译头 (PCH) 文件和名为 StdAfx.obj 的预编译类型文件。
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
其他注释:
|
||||
|
||||
应用程序向导使用“TODO:”注释来指示应添加或自定义的源代码部分。
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
19
notice/dllmain.cpp
Normal file
19
notice/dllmain.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
// dllmain.cpp : 定义 DLL 应用程序的入口点。
|
||||
#include "stdafx.h"
|
||||
|
||||
BOOL APIENTRY DllMain( HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
39
notice/notice.cpp
Normal file
39
notice/notice.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// pkgmgr.cpp : 定义 DLL 应用程序的导出函数。
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "notice.h"
|
||||
#include "raii.h"
|
||||
#include "version.h"
|
||||
|
||||
#undef GetFullPathName
|
||||
std::wstring GetFullPathName (const std::wstring &lpFileName)
|
||||
{
|
||||
if (lpFileName.empty ()) return L"";
|
||||
DWORD length = GetFullPathNameW (lpFileName.c_str (), 0, nullptr, nullptr);
|
||||
if (length == 0) return L"";
|
||||
std::vector <WCHAR> buffer (length + 1, L'\0');
|
||||
DWORD result = GetFullPathNameW (lpFileName.c_str (), length, buffer.data (), nullptr);
|
||||
if (result == 0) return L"";
|
||||
return std::wstring (buffer.data (), result);
|
||||
}
|
||||
|
||||
std::wstring g_swExceptionCode = L"";
|
||||
std::wstring g_swExceptionDetail = L"";
|
||||
|
||||
struct destruct
|
||||
{
|
||||
std::function <void ()> endtask = nullptr;
|
||||
destruct (std::function <void ()> pfunc): endtask (pfunc) {}
|
||||
~destruct () { if (endtask) endtask (); }
|
||||
};
|
||||
static std::wstring StringToWString (const std::string &str, UINT codePage = CP_ACP)
|
||||
{
|
||||
if (str.empty ()) return std::wstring ();
|
||||
int len = MultiByteToWideChar (codePage, 0, str.c_str (), -1, nullptr, 0);
|
||||
if (len == 0) return std::wstring ();
|
||||
std::wstring wstr (len - 1, L'\0');
|
||||
MultiByteToWideChar (codePage, 0, str.c_str (), -1, &wstr [0], len);
|
||||
return wstr;
|
||||
}
|
||||
|
||||
39
notice/notice.h
Normal file
39
notice/notice.h
Normal file
@@ -0,0 +1,39 @@
|
||||
// 下列 ifdef 块是创建使从 DLL 导出更简单的
|
||||
// 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 PKGMGR_EXPORTS
|
||||
// 符号编译的。在使用此 DLL 的
|
||||
// 任何其他项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将
|
||||
// PKGMGR_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的
|
||||
// 符号视为是被导出的。
|
||||
#ifdef NOTICE_EXPORTS
|
||||
#define NOTICE_API __declspec(dllexport)
|
||||
#else
|
||||
#define NOTICE_API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
// 这里的 API 常用“Appx”在函数名中,此举是为了防止与其他类似的函数名混淆。
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
#define _DEFAULT_INIT_VALUE_(_init_value_) = _init_value_
|
||||
#ifndef PKGMGR_EXPORTS
|
||||
#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_) = _init_value_
|
||||
#else
|
||||
#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_)
|
||||
#endif
|
||||
#else
|
||||
#define _DEFAULT_INIT_VALUE_(_init_value_)
|
||||
#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_)
|
||||
#endif
|
||||
|
||||
#ifdef _DEFAULT_INIT_VALUE_
|
||||
#undef _DEFAULT_INIT_VALUE_
|
||||
#endif
|
||||
#ifdef _DEFAULT_INIT_VALUE_FORFUNC_
|
||||
#undef _DEFAULT_INIT_VALUE_FORFUNC_
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
107
notice/notice.vcxproj
Normal file
107
notice/notice.vcxproj
Normal file
@@ -0,0 +1,107 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{798ED492-EECE-457D-8FD8-129DA93CE126}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>notice</RootNamespace>
|
||||
<ProjectName>notice</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CLRSupport>false</CLRSupport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CLRSupport>false</CLRSupport>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
<Import Project="..\packages\pugixml.1.15.0\build\native\pugixml.targets" Condition="Exists('..\packages\pugixml.1.15.0\build\native\pugixml.targets')" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ReferencePath>$(VCINSTALLDIR)\vcpackages;$(VCInstallDir)atlmfc\lib;$(VCInstallDir)lib;$(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(ReferencePath)</ReferencePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ReferencePath>$(VCINSTALLDIR)\vcpackages;$(VCInstallDir)atlmfc\lib;$(VCInstallDir)lib;$(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(ReferencePath)</ReferencePath>
|
||||
</PropertyGroup>
|
||||
<!-- 关键:启用 WinRT 扩展 -->
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalOptions>/ZW:nostdlib /FUplatform.winmd /FUwindows.winmd %(AdditionalOptions)</AdditionalOptions>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;NOTICE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<CompileAsWinRT>true</CompileAsWinRT>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalOptions>/ZW:nostdlib /FUplatform.winmd /FUWindows.winmd %(AdditionalOptions)</AdditionalOptions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;NOTICE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<CompileAsWinRT>true</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="notice.cpp" />
|
||||
<ClCompile Include="stdafx.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="notice.h" />
|
||||
<ClInclude Include="raii.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
<ClInclude Include="version.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\pugixml.1.15.0\build\native\pugixml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\pugixml.1.15.0\build\native\pugixml.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
45
notice/notice.vcxproj.filters
Normal file
45
notice/notice.vcxproj.filters
Normal file
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="notice.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="targetver.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="raii.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="version.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="notice.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
4
notice/packages.config
Normal file
4
notice/packages.config
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="pugixml" version="1.15.0" targetFramework="native" />
|
||||
</packages>
|
||||
8
notice/raii.h
Normal file
8
notice/raii.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
struct raii
|
||||
{
|
||||
std::function <void ()> endtask = nullptr;
|
||||
raii (std::function <void ()> pFunc = nullptr): endtask (pFunc) {}
|
||||
~raii () { if (endtask) endtask (); }
|
||||
};
|
||||
8
notice/stdafx.cpp
Normal file
8
notice/stdafx.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
// stdafx.cpp : 只包括标准包含文件的源文件
|
||||
// pkgmgr.pch 将作为预编译头
|
||||
// stdafx.obj 将包含预编译类型信息
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: 在 STDAFX.H 中引用任何所需的附加头文件,
|
||||
//而不是在此文件中引用
|
||||
38
notice/stdafx.h
Normal file
38
notice/stdafx.h
Normal file
@@ -0,0 +1,38 @@
|
||||
// stdafx.h : 标准系统包含文件的包含文件,
|
||||
// 或是经常使用但不常更改的
|
||||
// 特定于项目的包含文件
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "targetver.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // 从 Windows 头中排除极少使用的资料
|
||||
// Windows 头文件:
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
|
||||
// TODO: 在此处引用程序需要的其他头文件
|
||||
#include <wrl.h>
|
||||
#include <windows.ui.notifications.h>
|
||||
#include <windows.data.xml.dom.h>
|
||||
#include <stdio.h>
|
||||
#include <shobjidl.h>
|
||||
#include <wrl/client.h>
|
||||
#include <fstream>
|
||||
#include <propvarutil.h>
|
||||
#include <propkey.h>
|
||||
#include <wrl.h>
|
||||
#include <string>
|
||||
#include <shlobj.h>
|
||||
#include <propkey.h>
|
||||
#include <comdef.h>
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace ABI::Windows::UI::Notifications;
|
||||
using namespace ABI::Windows::Data::Xml::Dom;
|
||||
using namespace Microsoft::WRL::Wrappers;
|
||||
|
||||
#include <pugiconfig.hpp>
|
||||
#include <pugixml.hpp>
|
||||
8
notice/targetver.h
Normal file
8
notice/targetver.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
// 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。
|
||||
|
||||
// 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将
|
||||
// 将 _WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。
|
||||
|
||||
#include <SDKDDKVer.h>
|
||||
125
notice/version.h
Normal file
125
notice/version.h
Normal file
@@ -0,0 +1,125 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
typedef uint64_t UINT64;
|
||||
typedef int64_t INT64;
|
||||
typedef uint16_t UINT16;
|
||||
typedef struct version
|
||||
{
|
||||
UINT16 major = 0, minor = 0, build = 0, revision = 0;
|
||||
version (UINT64 value):
|
||||
major ((value >> 0x30) & 0xFFFF), minor ((value >> 0x20) & 0xFFFF),
|
||||
build ((value >> 0x10) & 0xFFFF), revision ((value) & 0xFFFF) {}
|
||||
version (UINT16 major, UINT16 minor, UINT16 build, UINT16 revision):
|
||||
major (major), minor (minor), build (build), revision (revision) {}
|
||||
version (const std::wstring &verstr) { this->interpret (verstr); }
|
||||
version (const std::string &verstr) { this->interpret (verstr); }
|
||||
version () {}
|
||||
version (const version &other): major (other.major), minor (other.minor), build (other.build), revision (other.revision) {}
|
||||
version (version &&other): major (other.major), minor (other.minor), build (other.build), revision (other.revision) {}
|
||||
version &operator = (const version &other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
major = other.major;
|
||||
minor = other.minor;
|
||||
build = other.build;
|
||||
revision = other.revision;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
version &operator = (version &&other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
major = other.major;
|
||||
minor = other.minor;
|
||||
build = other.build;
|
||||
revision = other.revision;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
version &operator = (UINT64 value) { this->data (value); return *this; }
|
||||
UINT64 data () const { return (((UINT64)major) << 48) | (((UINT64)minor) << 32) | (((UINT64)build) << 16) | ((UINT64)revision); }
|
||||
UINT64 data (UINT64 value)
|
||||
{
|
||||
major = (value >> 48) & 0xFFFF;
|
||||
minor = (value >> 32) & 0xFFFF;
|
||||
build = (value >> 16) & 0xFFFF;
|
||||
revision = value & 0xFFFF;
|
||||
return value;
|
||||
}
|
||||
std::wstring stringifyw () const
|
||||
{
|
||||
std::wstringstream ss;
|
||||
ss << major << L'.' << minor << L'.' << build << L'.' << revision;
|
||||
return ss.str ();
|
||||
}
|
||||
std::string stringify () const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << major << '.' << minor << '.' << build << '.' << revision;
|
||||
return ss.str ();
|
||||
}
|
||||
version &interpret (const std::wstring &verstr)
|
||||
{
|
||||
auto result = split (verstr);
|
||||
if (result.size () > 0) this->major = _wtoi (result [0].c_str ());
|
||||
if (result.size () > 1) this->minor = _wtoi (result [1].c_str ());
|
||||
if (result.size () > 2) this->build = _wtoi (result [2].c_str ());
|
||||
if (result.size () > 3) this->revision = _wtoi (result [3].c_str ());
|
||||
return *this;
|
||||
}
|
||||
version &interpret (const std::string &verstr)
|
||||
{
|
||||
auto result = split (verstr);
|
||||
if (result.size () > 0) this->major = atoi (result [0].c_str ());
|
||||
if (result.size () > 1) this->minor = atoi (result [1].c_str ());
|
||||
if (result.size () > 2) this->build = atoi (result [2].c_str ());
|
||||
if (result.size () > 3) this->revision = atoi (result [3].c_str ());
|
||||
return *this;
|
||||
}
|
||||
bool empty () const { return *(UINT64 *)this == 0; }
|
||||
friend bool operator == (const version &l, const version &r) { return *(UINT64 *)&l == *(UINT64 *)&r; }
|
||||
friend bool operator == (const version &l, const UINT64 &r) { return l.data () == r; }
|
||||
friend bool operator == (const UINT64 &r, const version &l) { return l.data () == r; }
|
||||
friend bool operator < (const version &l, const version &r) { return l.data () < r.data (); }
|
||||
friend bool operator > (const version &l, const version &r) { return l.data () > r.data (); }
|
||||
friend bool operator <= (const version &l, const version &r) { return l.data () <= r.data (); }
|
||||
friend bool operator >= (const version &l, const version &r) { return l.data () >= r.data (); }
|
||||
friend bool operator != (const version &l, const version &r) { return *(UINT64 *)&l != *(UINT64 *)&r; }
|
||||
explicit operator bool () const { return !this->empty (); }
|
||||
bool operator ! () { return this->empty (); }
|
||||
friend std::ostream &operator << (std::ostream &o, const version &v) { return o << v.major << '.' << v.minor << '.' << v.build << '.' << v.revision; }
|
||||
friend std::wostream &operator << (std::wostream &o, const version &v) { return o << v.major << '.' << v.minor << '.' << v.build << '.' << v.revision; }
|
||||
bool equals (const version &r) const { return *this == r; }
|
||||
INT64 compare (const version &r) const { return this->data () - r.data (); }
|
||||
static version parse (const std::wstring &value) { return version (value); }
|
||||
static version parse (const std::string &value) { return version (value); }
|
||||
static std::wstring stringifyw (const version &v) { return v.stringifyw (); }
|
||||
static std::string stringify (const version &v) { return v.stringify (); }
|
||||
static bool equals (const version &l, const version &r) { return l == r; }
|
||||
static INT64 compare (const version &l, const version &r) { return l.data () - r.data (); }
|
||||
static version decode (UINT64 value) { return version (value); }
|
||||
static UINT64 encode (const version &v) { return v.data (); }
|
||||
protected:
|
||||
template <typename StringType> std::vector <StringType> split (const StringType &str, typename StringType::value_type delimiter1 = '.', typename StringType::value_type delimiter2 = ',')
|
||||
{
|
||||
std::vector <StringType> result;
|
||||
std::basic_stringstream<typename StringType::value_type> ss (str);
|
||||
StringType segment;
|
||||
while (std::getline (ss, segment, delimiter1))
|
||||
{
|
||||
size_t pos = 0;
|
||||
while ((pos = segment.find (delimiter2)) != StringType::npos)
|
||||
{
|
||||
result.push_back (segment.substr (0, pos));
|
||||
segment.erase (0, pos + 1);
|
||||
}
|
||||
if (!segment.empty ()) result.push_back (segment);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} Version;
|
||||
30
pkgmgr/ReadMe.txt
Normal file
30
pkgmgr/ReadMe.txt
Normal file
@@ -0,0 +1,30 @@
|
||||
========================================================================
|
||||
动态链接库:pkgmgr 项目概述
|
||||
========================================================================
|
||||
|
||||
应用程序向导已为您创建了此 pkgmgr DLL。
|
||||
|
||||
本文件概要介绍组成 pkgmgr 应用程序的每个文件的内容。
|
||||
|
||||
|
||||
pkgmgr.vcxproj
|
||||
这是使用应用程序向导生成的 VC++ 项目的主项目文件,其中包含生成该文件的 Visual C++ 的版本信息,以及有关使用应用程序向导选择的平台、配置和项目功能的信息。
|
||||
|
||||
pkgmgr.vcxproj.filters
|
||||
这是使用“应用程序向导”生成的 VC++ 项目筛选器文件。它包含有关项目文件与筛选器之间的关联信息。在 IDE 中,通过这种关联,在特定节点下以分组形式显示具有相似扩展名的文件。例如,“.cpp”文件与“源文件”筛选器关联。
|
||||
|
||||
pkgmgr.cpp
|
||||
这是主 DLL 源文件。
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
其他标准文件:
|
||||
|
||||
StdAfx.h, StdAfx.cpp
|
||||
这些文件用于生成名为 pkgmgr.pch 的预编译头 (PCH) 文件和名为 StdAfx.obj 的预编译类型文件。
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
其他注释:
|
||||
|
||||
应用程序向导使用“TODO:”注释来指示应添加或自定义的源代码部分。
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
19
pkgmgr/dllmain.cpp
Normal file
19
pkgmgr/dllmain.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
// dllmain.cpp : 定义 DLL 应用程序的入口点。
|
||||
#include "stdafx.h"
|
||||
|
||||
BOOL APIENTRY DllMain( HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
629
pkgmgr/pkgmgr.cpp
Normal file
629
pkgmgr/pkgmgr.cpp
Normal file
@@ -0,0 +1,629 @@
|
||||
// pkgmgr.cpp : 定义 DLL 应用程序的导出函数。
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "pkgmgr.h"
|
||||
#include "raii.h"
|
||||
#include "version.h"
|
||||
|
||||
#undef GetFullPathName
|
||||
std::wstring GetFullPathName (const std::wstring &lpFileName)
|
||||
{
|
||||
if (lpFileName.empty ()) return L"";
|
||||
DWORD length = GetFullPathNameW (lpFileName.c_str (), 0, nullptr, nullptr);
|
||||
if (length == 0) return L"";
|
||||
std::vector <WCHAR> buffer (length + 1, L'\0');
|
||||
DWORD result = GetFullPathNameW (lpFileName.c_str (), length, buffer.data (), nullptr);
|
||||
if (result == 0) return L"";
|
||||
return std::wstring (buffer.data (), result);
|
||||
}
|
||||
|
||||
std::wstring g_swExceptionCode = L"";
|
||||
std::wstring g_swExceptionDetail = L"";
|
||||
|
||||
struct destruct
|
||||
{
|
||||
std::function <void ()> endtask = nullptr;
|
||||
destruct (std::function <void ()> pfunc): endtask (pfunc) {}
|
||||
~destruct () { if (endtask) endtask (); }
|
||||
};
|
||||
static std::wstring StringToWString (const std::string &str, UINT codePage = CP_ACP)
|
||||
{
|
||||
if (str.empty ()) return std::wstring ();
|
||||
int len = MultiByteToWideChar (codePage, 0, str.c_str (), -1, nullptr, 0);
|
||||
if (len == 0) return std::wstring ();
|
||||
std::wstring wstr (len - 1, L'\0');
|
||||
MultiByteToWideChar (codePage, 0, str.c_str (), -1, &wstr [0], len);
|
||||
return wstr;
|
||||
}
|
||||
using onprogress = AsyncOperationProgressHandler <DeploymentResult ^, DeploymentProgress>;
|
||||
using onprogresscomp = AsyncOperationWithProgressCompletedHandler <DeploymentResult ^, DeploymentProgress>;
|
||||
using progressopt = IAsyncOperationWithProgress <DeploymentResult ^, DeploymentProgress> ^;
|
||||
template <typename TAsyncOpCreator> HRESULT RunPackageManagerOperation (TAsyncOpCreator asyncCreator, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg)
|
||||
{
|
||||
g_swExceptionCode = L"";
|
||||
g_swExceptionDetail = L"";
|
||||
if (pErrorCode) *pErrorCode = nullptr;
|
||||
if (pDetailMsg) *pDetailMsg = nullptr;
|
||||
try
|
||||
{
|
||||
HANDLE hCompEvt = nullptr;
|
||||
destruct closeevt ([&hCompEvt] () {
|
||||
if (hCompEvt) { CloseHandle (hCompEvt); hCompEvt = nullptr; }
|
||||
});
|
||||
hCompEvt = CreateEventExW (nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
|
||||
if (!hCompEvt) return E_FAIL;
|
||||
auto depopt = asyncCreator ();
|
||||
depopt->Progress = ref new onprogress ([pfCallback, pCustom] (progressopt operation, DeploymentProgress progress) {
|
||||
if (pfCallback) pfCallback ((DWORD)progress.percentage, pCustom);
|
||||
});
|
||||
depopt->Completed = ref new onprogresscomp ([&hCompEvt] (progressopt, AsyncStatus) {
|
||||
SetEvent (hCompEvt);
|
||||
});
|
||||
WaitForSingleObject (hCompEvt, INFINITE);
|
||||
switch (depopt->Status)
|
||||
{
|
||||
case AsyncStatus::Completed:
|
||||
return S_OK;
|
||||
case AsyncStatus::Error:
|
||||
{
|
||||
auto depresult = depopt->GetResults ();
|
||||
auto errorcode = depopt->ErrorCode;
|
||||
HResult hr = errorcode;
|
||||
String ^errstr = Exception::CreateException (errorcode.Value)->ToString ();
|
||||
g_swExceptionCode += errstr && errstr->Data () ? errstr->Data () : L"";
|
||||
g_swExceptionDetail += depresult->ErrorText->Data ();
|
||||
if (pErrorCode) *pErrorCode = _wcsdup (g_swExceptionCode.c_str ());
|
||||
if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ());
|
||||
return (HRESULT)errorcode.Value;
|
||||
}
|
||||
case AsyncStatus::Canceled:
|
||||
g_swExceptionDetail = L"Installation Canceled";
|
||||
if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ());
|
||||
return E_ABORT;
|
||||
case AsyncStatus::Started:
|
||||
g_swExceptionDetail = L"Installation is Running";
|
||||
if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ());
|
||||
return E_PENDING;
|
||||
}
|
||||
}
|
||||
catch (Exception ^e)
|
||||
{
|
||||
g_swExceptionDetail = e->ToString ()->Data ();
|
||||
if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ());
|
||||
return (SUCCEEDED ((HRESULT)e->HResult) ? E_FAIL : (HRESULT)e->HResult);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
g_swExceptionDetail = StringToWString (e.what () ? e.what () : "Unknown exception.");
|
||||
if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ());
|
||||
return E_FAIL;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
g_swExceptionDetail = L"Unknown exception";
|
||||
if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ());
|
||||
return E_FAIL;
|
||||
}
|
||||
return E_FAIL;
|
||||
}
|
||||
[MTAThread]
|
||||
HRESULT AddAppxPackageFromURI (LPCWSTR lpPkgFileUri, PCREGISTER_PACKAGE_DEFENDENCIES alpDepUrlList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg)
|
||||
{
|
||||
return RunPackageManagerOperation ([=] () {
|
||||
auto pkgmgr = ref new PackageManager ();
|
||||
auto depuris = ref new Platform::Collections::Vector <Uri ^> ();
|
||||
if (alpDepUrlList)
|
||||
{
|
||||
for (size_t i = 0; i < alpDepUrlList->dwSize; i ++)
|
||||
{
|
||||
auto &pstr = alpDepUrlList->alpDepUris [i];
|
||||
try
|
||||
{
|
||||
if (pstr && *pstr)
|
||||
{
|
||||
auto depuristr = ref new String (pstr);
|
||||
Uri ^duri = nullptr;
|
||||
try { duri = ref new Uri (depuristr); }
|
||||
catch (Exception ^e)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::wstring fullpath = GetFullPathName (pstr ? pstr : L"");
|
||||
if (fullpath.empty ()) fullpath = pstr ? pstr : L"";
|
||||
duri = ref new Uri (ref new String (fullpath.c_str ()));
|
||||
}
|
||||
catch (Exception ^e) { continue; }
|
||||
}
|
||||
depuris->Append (duri);
|
||||
}
|
||||
}
|
||||
catch (Exception ^e) { continue; }
|
||||
}
|
||||
}
|
||||
if (depuris->Size > 0) depuris = nullptr;
|
||||
auto ope = pkgmgr->AddPackageAsync (ref new Uri (ref new String (lpPkgFileUri)), depuris, (DeploymentOptions)dwDeployOption);
|
||||
return ope;
|
||||
}, pfCallback, pCustom, pErrorCode, pDetailMsg);
|
||||
}
|
||||
[MTAThread]
|
||||
HRESULT AddAppxPackageFromPath (LPCWSTR lpPkgPath, PCREGISTER_PACKAGE_DEFENDENCIES alpDepUrlList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg)
|
||||
{
|
||||
std::wstring fullpath = GetFullPathName (lpPkgPath ? lpPkgPath : L"");
|
||||
if (fullpath.empty ()) fullpath = lpPkgPath ? lpPkgPath : L"";
|
||||
return AddAppxPackageFromURI (fullpath.c_str (), alpDepUrlList, dwDeployOption, pfCallback, pCustom, pErrorCode, pDetailMsg);
|
||||
}
|
||||
std::wstring WinRTStringToStdString (String ^pstr)
|
||||
{
|
||||
try { if (!pstr) return L""; return (pstr->Data () ? pstr->Data () : L""); }
|
||||
catch (...) {} return L"";
|
||||
}
|
||||
#define PlatformGetStringValue(mpObj, _prop_) \
|
||||
([&] () -> std::wstring { \
|
||||
auto strptr = (mpObj)->_prop_; \
|
||||
return WinRTStringToStdString (strptr); \
|
||||
}) ()
|
||||
void SidToAccountName (const std::wstring &sidString, std::wstring &stringSid)
|
||||
{
|
||||
PSID sid = nullptr;
|
||||
raii lrel ([&sid] () {
|
||||
if (sid) LocalFree (sid);
|
||||
sid = nullptr;
|
||||
});
|
||||
if (ConvertStringSidToSidW (sidString.c_str (), &sid))
|
||||
{
|
||||
DWORD nameCharCount = 0;
|
||||
DWORD domainNameCharCount = 0;
|
||||
SID_NAME_USE sidType;
|
||||
LookupAccountSidW (nullptr, sid, nullptr, &nameCharCount, nullptr, &domainNameCharCount, &sidType);
|
||||
std::vector <WCHAR> namebuf (nameCharCount + 1);
|
||||
std::vector <WCHAR> domainNameBuf (domainNameCharCount + 1);
|
||||
ZeroMemory (namebuf.data (), (nameCharCount + 1) * sizeof (WCHAR));
|
||||
ZeroMemory (domainNameBuf.data (), (domainNameCharCount + 1) * sizeof (WCHAR));
|
||||
if (LookupAccountSidW (nullptr, sid, namebuf.data (), &nameCharCount, domainNameBuf.data (), &domainNameCharCount, &sidType))
|
||||
{
|
||||
stringSid = domainNameBuf.data ();
|
||||
stringSid += stringSid + L"\\" + namebuf.data ();
|
||||
}
|
||||
}
|
||||
if (stringSid.length () == 0) stringSid = sidString;
|
||||
}
|
||||
struct pkg_info
|
||||
{
|
||||
struct identity
|
||||
{
|
||||
std::wstring name = L"";
|
||||
std::wstring publisher = L"";
|
||||
std::wstring fullname = L"";
|
||||
std::wstring familyname = L"";
|
||||
std::wstring resourceid = L"";
|
||||
std::wstring publisherid = L"";
|
||||
uint16_t architecture = -1;
|
||||
Version version;
|
||||
} id;
|
||||
struct properities
|
||||
{
|
||||
std::wstring displayname = L"";
|
||||
std::wstring description = L"";
|
||||
std::wstring publisher = L"";
|
||||
std::wstring logo = L"";
|
||||
bool framework = false;
|
||||
bool resource_package = false;
|
||||
} prop;
|
||||
bool bundle = false;
|
||||
bool development_mode = false;
|
||||
std::wstring installlocation = L"";
|
||||
std::wstring users = L"";
|
||||
std::wstring sids = L"";
|
||||
std::vector <pkg_info> dependencies;
|
||||
static pkg_info parse (Windows::ApplicationModel::Package ^pkg, Windows::Management::Deployment::PackageManager ^mgr)
|
||||
{
|
||||
pkg_info pi;
|
||||
if (!pkg) throw ref new InvalidArgumentException ("No package found.");
|
||||
#define WAPParseSetValue(_left_part_, _right_part_, _default_value_) \
|
||||
do { try { _left_part_ = _right_part_; } catch (...) { _left_part_ = _default_value_; } } while (false)
|
||||
#define WAPParseSetStringValue(_left_part_, _right_part_) \
|
||||
WAPParseSetValue (_left_part_, WinRTStringToStdString (_right_part_), L"")
|
||||
WAPParseSetStringValue (pi.id.name, pkg->Id->Name);
|
||||
WAPParseSetStringValue (pi.id.publisher, pkg->Id->Publisher);
|
||||
WAPParseSetStringValue (pi.id.fullname, pkg->Id->FullName);
|
||||
WAPParseSetStringValue (pi.id.familyname, pkg->Id->FamilyName);
|
||||
WAPParseSetStringValue (pi.id.publisherid, pkg->Id->PublisherId);
|
||||
WAPParseSetStringValue (pi.id.resourceid, pkg->Id->ResourceId);
|
||||
try { pi.id.version = version (pkg->Id->Version.Major, pkg->Id->Version.Minor, pkg->Id->Version.Build, pkg->Id->Version.Revision); } catch (...) {}
|
||||
WAPParseSetValue (pi.id.architecture, (WORD)pkg->Id->Architecture, (WORD)-1);
|
||||
WAPParseSetStringValue (pi.prop.displayname, pkg->DisplayName);
|
||||
WAPParseSetStringValue (pi.prop.description, pkg->Description);
|
||||
WAPParseSetStringValue (pi.prop.publisher, pkg->PublisherDisplayName);
|
||||
WAPParseSetStringValue (pi.prop.logo, pkg->Logo->ToString ());
|
||||
WAPParseSetValue (pi.prop.framework, pkg->IsFramework, false);
|
||||
WAPParseSetValue (pi.prop.resource_package, pkg->IsResourcePackage, false);
|
||||
WAPParseSetValue (pi.bundle, pkg->IsBundle, false);
|
||||
WAPParseSetValue (pi.development_mode, pkg->IsDevelopmentMode, false);
|
||||
WAPParseSetStringValue (pi.installlocation, pkg->InstalledLocation->Path);
|
||||
try
|
||||
{
|
||||
size_t i = 0;
|
||||
auto users = mgr->FindUsers (pkg->Id->FullName);
|
||||
for (auto it : users)
|
||||
{
|
||||
{
|
||||
std::wstring sid = L"";
|
||||
SidToAccountName (it->UserSecurityId->Data (), sid);
|
||||
if (i) pi.users += L';';
|
||||
pi.users += sid;
|
||||
}
|
||||
{
|
||||
std::wstring sid;
|
||||
WAPParseSetStringValue (sid, it->UserSecurityId);
|
||||
if (i) pi.sids += L';';
|
||||
pi.users += sid;
|
||||
}
|
||||
i ++;
|
||||
}
|
||||
}
|
||||
catch (...) {}
|
||||
try
|
||||
{
|
||||
auto deps = pkg->Dependencies;
|
||||
for (auto it : deps)
|
||||
{
|
||||
auto deppkg = pkg_info::parse (it, mgr);
|
||||
deppkg.dependencies.clear ();
|
||||
pi.dependencies.push_back (deppkg);
|
||||
}
|
||||
}
|
||||
catch (...) {}
|
||||
return pi;
|
||||
#ifdef WAPParseSetStringValue
|
||||
#undef WAPParseSetStringValue
|
||||
#endif
|
||||
#ifdef WAPParseSetValue
|
||||
#undef WAPParseSetValue
|
||||
#endif
|
||||
}
|
||||
// 返回的反而是缓冲区,因为是柔性结构体要动态申请。这个方法很常用
|
||||
void to_c_struct (std::vector <BYTE> &bytesret) const
|
||||
{
|
||||
bytesret.clear ();
|
||||
bytesret.resize (sizeof (FIND_PACKAGE_INFO) * (this->dependencies.size () + 1));
|
||||
FIND_PACKAGE_INFO &fpi = *(FIND_PACKAGE_INFO *)bytesret.data ();
|
||||
fpi.piIdentity.lpFamilyName = this->id.familyname.c_str ();
|
||||
fpi.piIdentity.lpFullName = this->id.fullname.c_str ();
|
||||
fpi.piIdentity.lpName = this->id.name.c_str ();
|
||||
fpi.piIdentity.lpPublisher = this->id.publisher.c_str ();
|
||||
fpi.piIdentity.lpPublisherId = this->id.publisherid.c_str ();
|
||||
fpi.piIdentity.lpResourceId = this->id.resourceid.c_str ();
|
||||
fpi.piIdentity.qwVersion = this->id.version.data ();
|
||||
fpi.piIdentity.wProcessArchitecture = this->id.architecture;
|
||||
fpi.piProperties.bIsBundle = this->bundle;
|
||||
fpi.piProperties.bIsDevelopmentMode = this->development_mode;
|
||||
fpi.piProperties.bIsFramework = this->prop.framework;
|
||||
fpi.piProperties.bIsResourcePackage = this->prop.resource_package;
|
||||
fpi.piProperties.lpDescription = this->prop.description.c_str ();
|
||||
fpi.piProperties.lpDisplayName = this->prop.displayname.c_str ();
|
||||
fpi.piProperties.lpLogoUri = this->prop.logo.c_str ();
|
||||
fpi.piProperties.lpPublisher = this->prop.publisher.c_str ();
|
||||
fpi.dwDependencesSize = this->dependencies.size ();
|
||||
fpi.lpInstallLocation = this->installlocation.c_str ();
|
||||
fpi.lpUsers = this->users.c_str ();
|
||||
FIND_PACKAGE_INFO *deps = (FIND_PACKAGE_INFO *)&fpi.ullBuffer;
|
||||
for (size_t i = 0; i < this->dependencies.size (); i ++)
|
||||
{
|
||||
std::vector <BYTE> depbytes;
|
||||
this->dependencies [i].to_c_struct (depbytes);
|
||||
deps [i] = *(FIND_PACKAGE_INFO *)depbytes.data ();
|
||||
}
|
||||
}
|
||||
};
|
||||
[STAThread]
|
||||
HRESULT FindAppxPackageByCallback (std::function <void (pkg_info &)> pfCallback, LPWSTR *pErrorCode, LPWSTR *pDetailMsg)
|
||||
{
|
||||
g_swExceptionCode = L"";
|
||||
g_swExceptionDetail = L"";
|
||||
try
|
||||
{
|
||||
auto pkgmgr = ref new PackageManager ();
|
||||
auto pkgarr = pkgmgr->FindPackages ();
|
||||
for (auto pkg : pkgarr)
|
||||
{
|
||||
auto pkginfo = pkg_info::parse (pkg, pkgmgr);
|
||||
if (pfCallback) pfCallback (pkginfo);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
catch (AccessDeniedException ^e)
|
||||
{
|
||||
g_swExceptionDetail = e->ToString ()->Data ();
|
||||
if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ());
|
||||
return (SUCCEEDED ((HRESULT)e->HResult) ? E_FAIL : (HRESULT)e->HResult);
|
||||
}
|
||||
catch (Exception ^e)
|
||||
{
|
||||
g_swExceptionDetail = e->ToString ()->Data ();
|
||||
if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ());
|
||||
return (SUCCEEDED ((HRESULT)e->HResult) ? E_FAIL : (HRESULT)e->HResult);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
g_swExceptionDetail = StringToWString (e.what () ? e.what () : "Unknown exception.");
|
||||
if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ());
|
||||
return E_FAIL;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
g_swExceptionDetail = L"Unknown exception";
|
||||
if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ());
|
||||
return E_FAIL;
|
||||
}
|
||||
return E_FAIL;
|
||||
}
|
||||
[STAThread]
|
||||
HRESULT GetAppxPackages (PKGMGR_FINDENUMCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg)
|
||||
{
|
||||
return FindAppxPackageByCallback ([&pCustom, &pfCallback] (pkg_info &pi) {
|
||||
std::vector <BYTE> bytes;
|
||||
pi.to_c_struct (bytes);
|
||||
if (pfCallback) pfCallback ((FIND_PACKAGE_INFO *)bytes.data (), pCustom);
|
||||
}, pErrorCode, pDetailMsg);
|
||||
}
|
||||
[MTAThread]
|
||||
HRESULT RemoveAppxPackage (LPCWSTR lpPkgFullName, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg)
|
||||
{
|
||||
return RunPackageManagerOperation ([=] () {
|
||||
auto pkgmgr = ref new PackageManager ();
|
||||
return pkgmgr->RemovePackageAsync (ref new String (lpPkgFullName));
|
||||
}, pfCallback, pCustom, pErrorCode, pDetailMsg);
|
||||
}
|
||||
[MTAThread]
|
||||
HRESULT CleanupAppxPackage (LPCWSTR lpPkgName, LPCWSTR lpUserSID, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg)
|
||||
{
|
||||
return RunPackageManagerOperation ([=] () {
|
||||
auto pkgmgr = ref new PackageManager ();
|
||||
return pkgmgr->CleanupPackageForUserAsync (ref new String (lpPkgName), ref new String (lpUserSID));
|
||||
}, pfCallback, pCustom, pErrorCode, pDetailMsg);
|
||||
}
|
||||
[MTAThread]
|
||||
HRESULT RegisterAppxPackageByUri (LPCWSTR lpManifestUri, PCREGISTER_PACKAGE_DEFENDENCIES alpDependencyUriList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg)
|
||||
{
|
||||
return RunPackageManagerOperation ([=] () {
|
||||
auto pkgmgr = ref new PackageManager ();
|
||||
auto depuris = ref new Platform::Collections::Vector <Uri ^> ();
|
||||
if (alpDependencyUriList)
|
||||
{
|
||||
for (size_t i = 0; i < alpDependencyUriList->dwSize; i ++)
|
||||
{
|
||||
auto &pstr = alpDependencyUriList->alpDepUris [i];
|
||||
try
|
||||
{
|
||||
if (pstr && *pstr)
|
||||
{
|
||||
auto depuristr = ref new String (pstr);
|
||||
Uri ^duri = nullptr;
|
||||
try { duri = ref new Uri (depuristr); }
|
||||
catch (Exception ^e)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::wstring fullpath = GetFullPathName (pstr ? pstr : L"");
|
||||
if (fullpath.empty ()) fullpath = pstr ? pstr : L"";
|
||||
duri = ref new Uri (ref new String (fullpath.c_str ()));
|
||||
}
|
||||
catch (Exception ^e) { continue; }
|
||||
}
|
||||
depuris->Append (duri);
|
||||
}
|
||||
}
|
||||
catch (Exception ^e) { continue; }
|
||||
}
|
||||
}
|
||||
if (depuris->Size > 0) depuris = nullptr;
|
||||
return pkgmgr->RegisterPackageAsync (ref new Uri (ref new String (lpManifestUri)), depuris, (DeploymentOptions)dwDeployOption);
|
||||
}, pfCallback, pCustom, pErrorCode, pDetailMsg);
|
||||
}
|
||||
[MTAThread]
|
||||
HRESULT RegisterAppxPackageByPath (LPCWSTR lpManifestPath, PCREGISTER_PACKAGE_DEFENDENCIES alpDependencyUriList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg)
|
||||
{
|
||||
std::wstring fullpath = GetFullPathName (lpManifestPath ? lpManifestPath : L"");
|
||||
if (fullpath.empty ()) fullpath = lpManifestPath ? lpManifestPath : L"";
|
||||
return RegisterAppxPackageByPath (fullpath.c_str (), alpDependencyUriList, dwDeployOption, pfCallback, pCustom, pErrorCode, pDetailMsg);
|
||||
}
|
||||
[MTAThread]
|
||||
HRESULT RegisterAppxPackageByFullName (LPCWSTR lpPackageFullName, PCREGISTER_PACKAGE_DEFENDENCIES alpDepFullNameList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg)
|
||||
{
|
||||
return RunPackageManagerOperation ([=] () {
|
||||
auto pkgmgr = ref new PackageManager ();
|
||||
auto depuris = ref new Platform::Collections::Vector <String ^> ();
|
||||
if (alpDepFullNameList)
|
||||
{
|
||||
for (size_t i = 0; i < alpDepFullNameList->dwSize; i ++)
|
||||
{
|
||||
auto &pstr = alpDepFullNameList->alpDepUris [i];
|
||||
try { if (pstr && *pstr) depuris->Append (ref new String (pstr)); }
|
||||
catch (Exception ^e) { continue; }
|
||||
}
|
||||
}
|
||||
if (depuris->Size > 0) depuris = nullptr;
|
||||
return pkgmgr->RegisterPackageByFullNameAsync (ref new String (lpPackageFullName), depuris, (DeploymentOptions)dwDeployOption);
|
||||
}, pfCallback, pCustom, pErrorCode, pDetailMsg);
|
||||
}
|
||||
template <typename TFunction> HRESULT ExecPackageManagerFunctionNoReturn (TFunction func, LPWSTR *pErrorCode, LPWSTR *pDetailMsg)
|
||||
{
|
||||
g_swExceptionCode = L"";
|
||||
g_swExceptionDetail = L"";
|
||||
try
|
||||
{
|
||||
func ();
|
||||
return S_OK;
|
||||
}
|
||||
catch (Exception ^e)
|
||||
{
|
||||
g_swExceptionDetail = e->ToString ()->Data ();
|
||||
if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ());
|
||||
return (SUCCEEDED ((HRESULT)e->HResult) ? E_FAIL : (HRESULT)e->HResult);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
g_swExceptionDetail = StringToWString (e.what () ? e.what () : "Unknown exception.");
|
||||
if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ());
|
||||
return E_FAIL;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
g_swExceptionDetail = L"Unknown exception";
|
||||
if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ());
|
||||
return E_FAIL;
|
||||
}
|
||||
return E_FAIL;
|
||||
}
|
||||
[STAThread]
|
||||
HRESULT SetAppxPackageStatus (LPCWSTR lpPackageFullName, DWORD dwStatus, LPWSTR *pErrorCode, LPWSTR *pDetailMsg)
|
||||
{
|
||||
return ExecPackageManagerFunctionNoReturn ([=] () {
|
||||
auto pkgmgr = ref new PackageManager ();
|
||||
pkgmgr->SetPackageState (ref new String (lpPackageFullName), (Windows::Management::Deployment::PackageState)dwStatus);
|
||||
}, pErrorCode, pDetailMsg);
|
||||
}
|
||||
[MTAThread]
|
||||
HRESULT StageAppxPackageFromURI (LPCWSTR lpFileUri, PCREGISTER_PACKAGE_DEFENDENCIES alpDepUriList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg)
|
||||
{
|
||||
return RunPackageManagerOperation ([=] () {
|
||||
auto pkgmgr = ref new PackageManager ();
|
||||
auto depuris = ref new Platform::Collections::Vector <Uri ^> ();
|
||||
if (alpDepUriList)
|
||||
{
|
||||
for (size_t i = 0; i < alpDepUriList->dwSize; i ++)
|
||||
{
|
||||
auto &pstr = alpDepUriList->alpDepUris [i];
|
||||
try
|
||||
{
|
||||
if (pstr && *pstr)
|
||||
{
|
||||
auto depuristr = ref new String (pstr);
|
||||
Uri ^duri = nullptr;
|
||||
try { duri = ref new Uri (depuristr); }
|
||||
catch (Exception ^e)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::wstring fullpath = GetFullPathName (pstr ? pstr : L"");
|
||||
if (fullpath.empty ()) fullpath = pstr ? pstr : L"";
|
||||
duri = ref new Uri (ref new String (fullpath.c_str ()));
|
||||
}
|
||||
catch (Exception ^e) { continue; }
|
||||
}
|
||||
depuris->Append (duri);
|
||||
}
|
||||
}
|
||||
catch (Exception ^e) { continue; }
|
||||
}
|
||||
}
|
||||
if (depuris->Size > 0) depuris = nullptr;
|
||||
return pkgmgr->StagePackageAsync (ref new Uri (ref new String (lpFileUri)), depuris, (DeploymentOptions)dwDeployOption);
|
||||
}, pfCallback, pCustom, pErrorCode, pDetailMsg);
|
||||
}
|
||||
[MTAThread]
|
||||
HRESULT StageAppxPackageFromPath (LPCWSTR lpPkgPath, PCREGISTER_PACKAGE_DEFENDENCIES alpDepUriList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg)
|
||||
{
|
||||
std::wstring fullpath = GetFullPathName (lpPkgPath ? lpPkgPath : L"");
|
||||
if (fullpath.empty ()) fullpath = lpPkgPath ? lpPkgPath : L"";
|
||||
return StageAppxPackageFromPath (fullpath.c_str (), alpDepUriList, dwDeployOption, pfCallback, pCustom, pErrorCode, pDetailMsg);
|
||||
}
|
||||
[MTAThread]
|
||||
HRESULT StageAppxUserData (LPCWSTR lpPackageFullName, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg)
|
||||
{
|
||||
return RunPackageManagerOperation ([=] () {
|
||||
auto pkgmgr = ref new PackageManager ();
|
||||
return pkgmgr->StageUserDataAsync (ref new String (lpPackageFullName));
|
||||
}, pfCallback, pCustom, pErrorCode, pDetailMsg);
|
||||
}
|
||||
[MTAThread]
|
||||
HRESULT UpdateAppxPackageFromURI (LPCWSTR lpPkgFileUri, PCREGISTER_PACKAGE_DEFENDENCIES alpDepUrlList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg)
|
||||
{
|
||||
return RunPackageManagerOperation ([=] () {
|
||||
auto pkgmgr = ref new PackageManager ();
|
||||
auto depuris = ref new Platform::Collections::Vector <Uri ^> ();
|
||||
if (alpDepUrlList)
|
||||
{
|
||||
for (size_t i = 0; i < alpDepUrlList->dwSize; i ++)
|
||||
{
|
||||
auto &pstr = alpDepUrlList->alpDepUris [i];
|
||||
try
|
||||
{
|
||||
if (pstr && *pstr)
|
||||
{
|
||||
auto depuristr = ref new String (pstr);
|
||||
Uri ^duri = nullptr;
|
||||
try { duri = ref new Uri (depuristr); }
|
||||
catch (Exception ^e)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::wstring fullpath = GetFullPathName (pstr ? pstr : L"");
|
||||
if (fullpath.empty ()) fullpath = pstr ? pstr : L"";
|
||||
duri = ref new Uri (ref new String (fullpath.c_str ()));
|
||||
}
|
||||
catch (Exception ^e) { continue; }
|
||||
}
|
||||
depuris->Append (duri);
|
||||
}
|
||||
}
|
||||
catch (Exception ^e) { continue; }
|
||||
}
|
||||
}
|
||||
if (depuris->Size > 0) depuris = nullptr;
|
||||
return pkgmgr->UpdatePackageAsync (ref new Uri (ref new String (lpPkgFileUri)), depuris, (DeploymentOptions)dwDeployOption);
|
||||
}, pfCallback, pCustom, pErrorCode, pDetailMsg);
|
||||
}
|
||||
[MTAThread]
|
||||
HRESULT UpdateAppxPackageFromPath (LPCWSTR lpPkgPath, PCREGISTER_PACKAGE_DEFENDENCIES alpDepUrlList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg)
|
||||
{
|
||||
std::wstring fullpath = GetFullPathName (lpPkgPath ? lpPkgPath : L"");
|
||||
if (fullpath.empty ()) fullpath = lpPkgPath ? lpPkgPath : L"";
|
||||
return UpdateAppxPackageFromURI (fullpath.c_str (), alpDepUrlList, dwDeployOption, pfCallback, pCustom, pErrorCode, pDetailMsg);
|
||||
}
|
||||
[STAThread]
|
||||
HRESULT FindAppxPackage (LPCWSTR lpPackageFullName, PKGMGR_FINDENUMCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg)
|
||||
{
|
||||
g_swExceptionCode = L"";
|
||||
g_swExceptionDetail = L"";
|
||||
try
|
||||
{
|
||||
auto pkgmgr = ref new PackageManager ();
|
||||
auto pkg = pkgmgr->FindPackage (ref new String (lpPackageFullName));
|
||||
auto pkginfo = pkg_info::parse (pkg, pkgmgr);
|
||||
std::vector <BYTE> bytes;
|
||||
pkginfo.to_c_struct (bytes);
|
||||
if (pfCallback) pfCallback ((FIND_PACKAGE_INFO *)bytes.data (), pCustom);
|
||||
return S_OK;
|
||||
}
|
||||
catch (AccessDeniedException ^e)
|
||||
{
|
||||
g_swExceptionDetail = e->ToString ()->Data ();
|
||||
if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ());
|
||||
return (SUCCEEDED ((HRESULT)e->HResult) ? E_FAIL : (HRESULT)e->HResult);
|
||||
}
|
||||
catch (Exception ^e)
|
||||
{
|
||||
g_swExceptionDetail = e->ToString ()->Data ();
|
||||
if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ());
|
||||
return (SUCCEEDED ((HRESULT)e->HResult) ? E_FAIL : (HRESULT)e->HResult);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
g_swExceptionDetail = StringToWString (e.what () ? e.what () : "Unknown exception.");
|
||||
if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ());
|
||||
return E_FAIL;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
g_swExceptionDetail = L"Unknown exception";
|
||||
if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ());
|
||||
return E_FAIL;
|
||||
}
|
||||
return E_FAIL;
|
||||
}
|
||||
[STAThread]
|
||||
LPCWSTR GetPackageManagerLastErrorCode () { return g_swExceptionCode.c_str (); }
|
||||
[STAThread]
|
||||
LPCWSTR GetPackageManagerLastErrorDetailMessage () { return g_swExceptionDetail.c_str (); }
|
||||
192
pkgmgr/pkgmgr.h
Normal file
192
pkgmgr/pkgmgr.h
Normal file
@@ -0,0 +1,192 @@
|
||||
// 下列 ifdef 块是创建使从 DLL 导出更简单的
|
||||
// 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 PKGMGR_EXPORTS
|
||||
// 符号编译的。在使用此 DLL 的
|
||||
// 任何其他项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将
|
||||
// PKGMGR_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的
|
||||
// 符号视为是被导出的。
|
||||
#ifdef PKGMGR_EXPORTS
|
||||
#define PKGMGR_API __declspec(dllexport)
|
||||
#else
|
||||
#define PKGMGR_API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
// 这里的 API 常用“Appx”在函数名中,此举是为了防止与其他类似的函数名混淆。
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
#define _DEFAULT_INIT_VALUE_(_init_value_) = _init_value_
|
||||
#ifndef PKGMGR_EXPORTS
|
||||
#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_) = _init_value_
|
||||
#else
|
||||
#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_)
|
||||
#endif
|
||||
#else
|
||||
#define _DEFAULT_INIT_VALUE_(_init_value_)
|
||||
#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_)
|
||||
#endif
|
||||
|
||||
// 进度回调。pCustom 可以传入自定义内容
|
||||
typedef void (*PKGMRR_PROGRESSCALLBACK) (DWORD dwProgress, void *pCustom);
|
||||
|
||||
#define PKGMGR_RESULT_OK S_OK
|
||||
#define PKGMGR_RESULT_ERROR E_FAIL
|
||||
#define PKGMGR_RESULT_CANCEL E_ABORT
|
||||
#define PKGMGR_RESULT_STARTED E_PENDING
|
||||
|
||||
typedef struct _REGISTER_PACKAGE_DEFENDENCIES
|
||||
{
|
||||
DWORD dwSize _DEFAULT_INIT_VALUE_ (0);
|
||||
LPWSTR alpDepUris [1];
|
||||
} REGISTER_PACKAGE_DEFENDENCIES, *PREGISTER_PACKAGE_DEFENDENCIES;
|
||||
typedef const REGISTER_PACKAGE_DEFENDENCIES CREGISTER_PACKAGE_DEFENDENCIES, *PCREGISTER_PACKAGE_DEFENDENCIES;
|
||||
|
||||
// 下面值与 Windows::Management::Deployment::DeploymentOptions 一一对应。由于需要写成 API,所以
|
||||
// 只能如此。
|
||||
// 可查阅文档 https://learn.microsoft.com/zh-cn/uwp/api/windows.management.deployment.deploymentoptions?view=winrt-26100
|
||||
|
||||
// 设置此选项时,应用将在开发模式下安装。 有关开发模式的信息,请参阅 备注。
|
||||
// 使用此选项可启用关键应用开发方案。不能将此选项与捆绑包结合使用。
|
||||
// 如果将此选项与捆绑包一起使用,调用将返回ERROR_INSTALL_FAILED。
|
||||
#define DEPOLYOPTION_FORCE_APP_SHUTDOWN 0x00000001
|
||||
// 如果当前正在使用此包或依赖于此包的任何包,则会强制关闭与该包关联的进程,以便可以继续注册。
|
||||
#define DEPOLYOPTION_DEVELOPMENT_MODE 0x00000002
|
||||
// 设置此选项时,将指示应用跳过资源适用性检查。 这会有效地暂存或注册用户传递给 命令的所有资源包,
|
||||
// 这会强制对捆绑包中包含的所有包具有适用性。 如果用户传入捆绑包,则将注册所有包含的资源包。
|
||||
// 仅限 Windows。
|
||||
#define DEPOLYOPTION_INSTALL_ALL_RESOURCES 0x00000020
|
||||
// 使用默认行为。
|
||||
#define DEPOLYOPTION_NONE 0x00000000
|
||||
// 安装一个 Appx/AppxBundle/Msix/MsixBundle 包
|
||||
// 注意:传入的文件路径为 DOS/NT 风格。如:C:\Windows\...
|
||||
// 该函数类似于 PowerShell 的 Add-AppxPackage
|
||||
// dwDeployOption 接受 DEPOLYOPTION_* 常量
|
||||
// 输出的错误信息别忘了用 free 释放
|
||||
PKGMGR_API HRESULT AddAppxPackageFromPath (LPCWSTR lpPkgPath, PCREGISTER_PACKAGE_DEFENDENCIES alpDepUrlList _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), DWORD dwDeployOption _DEFAULT_INIT_VALUE_FORFUNC_ (DEPOLYOPTION_NONE), PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL));
|
||||
// 安装一个 Appx/AppxBundle/Msix/MsixBundle 包
|
||||
// 注意:传入的文件路径为 URI。
|
||||
// 该函数类似于 PowerShell 的 Add-AppxPackage
|
||||
// dwDeployOption 接受 DEPOLYOPTION_* 常量
|
||||
// 输出的错误信息别忘了用 free 释放
|
||||
PKGMGR_API HRESULT AddAppxPackageFromURI (LPCWSTR lpFileUri, PCREGISTER_PACKAGE_DEFENDENCIES alpDepFullNameList _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), DWORD dwDeployOption _DEFAULT_INIT_VALUE_FORFUNC_ (DEPOLYOPTION_NONE), PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL));
|
||||
|
||||
typedef struct _FIND_PACKAGE_ID
|
||||
{
|
||||
UINT64 qwVersion _DEFAULT_INIT_VALUE_ (0);
|
||||
// x86: 0
|
||||
// x64: 9
|
||||
// Arm: 5
|
||||
// Neutral: 11
|
||||
// Arm64: 12
|
||||
// Unknown: 65535(-1)
|
||||
WORD wProcessArchitecture _DEFAULT_INIT_VALUE_ ((WORD)-1);
|
||||
WORD wPadding [3];
|
||||
LPCWSTR lpName _DEFAULT_INIT_VALUE_ (NULL);
|
||||
LPCWSTR lpFullName _DEFAULT_INIT_VALUE_ (NULL);
|
||||
LPCWSTR lpFamilyName _DEFAULT_INIT_VALUE_ (NULL);
|
||||
LPCWSTR lpPublisher _DEFAULT_INIT_VALUE_ (NULL);
|
||||
LPCWSTR lpPublisherId _DEFAULT_INIT_VALUE_ (NULL);
|
||||
LPCWSTR lpResourceId _DEFAULT_INIT_VALUE_ (NULL);
|
||||
} FIND_PACKAGE_ID, *PFIND_PACKAGE_ID;
|
||||
typedef struct _FIND_PACKAGE_PROPERTIES
|
||||
{
|
||||
LPCWSTR lpDisplayName _DEFAULT_INIT_VALUE_ (NULL);
|
||||
LPCWSTR lpDescription _DEFAULT_INIT_VALUE_ (NULL);
|
||||
LPCWSTR lpPublisher _DEFAULT_INIT_VALUE_ (NULL);
|
||||
LPCWSTR lpLogoUri _DEFAULT_INIT_VALUE_ (NULL);
|
||||
BOOL bIsFramework _DEFAULT_INIT_VALUE_ (FALSE);
|
||||
BOOL bIsResourcePackage _DEFAULT_INIT_VALUE_ (FALSE);
|
||||
BOOL bIsBundle _DEFAULT_INIT_VALUE_ (FALSE);
|
||||
BOOL bIsDevelopmentMode _DEFAULT_INIT_VALUE_ (FALSE);
|
||||
} FIND_PACKAGE_PROPERTIES, *PFIND_PACKAGE_PROPERTIES;
|
||||
typedef struct _FIND_PACKAGE_INFO
|
||||
{
|
||||
FIND_PACKAGE_ID piIdentity;
|
||||
FIND_PACKAGE_PROPERTIES piProperties;
|
||||
LPCWSTR lpInstallLocation _DEFAULT_INIT_VALUE_ (NULL);
|
||||
// 多个用户由 ";" 分隔
|
||||
LPCWSTR lpUsers _DEFAULT_INIT_VALUE_ (NULL);
|
||||
// 多个用户由 ";" 分隔
|
||||
LPCWSTR lpSIDs _DEFAULT_INIT_VALUE_ (NULL);
|
||||
DWORD dwDependencesSize _DEFAULT_INIT_VALUE_ (0);
|
||||
// 这个项无意义,仅用于内存对齐
|
||||
DWORD dwPadding _DEFAULT_INIT_VALUE_ (0);
|
||||
// 这个项无意义,除非之后我想通过动态内存方式写依赖项的数组。
|
||||
UINT64 ullBuffer _DEFAULT_INIT_VALUE_ (0);
|
||||
} FIND_PACKAGE_INFO, *PFIND_PACKAGE_INFO;
|
||||
typedef const FIND_PACKAGE_INFO CFIND_PACKAGE_INFO, *LPCFIND_PACKAGE_INFO;
|
||||
// 注:回调时的指针不要手动释放
|
||||
typedef void (*PKGMGR_FINDENUMCALLBACK) (LPCFIND_PACKAGE_INFO pNowItem, void *pCustom);
|
||||
// 通过回调来获取所有包的信息。回调函数允许传自定义内容。返回的值可以判断是否成功。
|
||||
// 该函数类似于 PowerShell 的 Get-AppxPackage
|
||||
// 注意:回调函数中包的信息无法修改,也不能擅自释放。且随着函数的执行完毕自动释放。这就要求在回调中自行拷贝一份。
|
||||
// 输出的错误信息别忘了用 free 释放
|
||||
PKGMGR_API HRESULT GetAppxPackages (PKGMGR_FINDENUMCALLBACK pfCallback, void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL));
|
||||
// 移除一个已经安装到电脑上的应用。注意:传入的是包完整名。
|
||||
// 输出的错误信息别忘了用 free 释放
|
||||
PKGMGR_API HRESULT RemoveAppxPackage (LPCWSTR lpPkgFullName, PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL));
|
||||
// 清理指定用户的指定 包 。 用于清除删除用户用户配置文件后为用户安装的包。
|
||||
// 输出的错误信息别忘了用 free 释放
|
||||
PKGMGR_API HRESULT CleanupAppxPackage (LPCWSTR lpPkgName, LPCWSTR lpUserSID, PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL));
|
||||
|
||||
// 注册应用包
|
||||
// dwDeployOption 接受 DEPOLYOPTION_* 常量
|
||||
PKGMGR_API HRESULT RegisterAppxPackageByPath (LPCWSTR lpManifestPath, PCREGISTER_PACKAGE_DEFENDENCIES alpDependencyUriList _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), DWORD dwDeployOption _DEFAULT_INIT_VALUE_FORFUNC_ (DEPOLYOPTION_NONE), PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL));
|
||||
// 注册应用包
|
||||
// dwDeployOption 接受 DEPOLYOPTION_* 常量
|
||||
PKGMGR_API HRESULT RegisterAppxPackageByUri (LPCWSTR lpManifestUri, PCREGISTER_PACKAGE_DEFENDENCIES alpDependencyUriList _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), DWORD dwDeployOption _DEFAULT_INIT_VALUE_FORFUNC_ (DEPOLYOPTION_NONE), PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL));
|
||||
// 注册应用包
|
||||
// dwDeployOption 接受 DEPOLYOPTION_* 常量
|
||||
PKGMGR_API HRESULT RegisterAppxPackageByFullName (LPCWSTR lpPackageFullName, PCREGISTER_PACKAGE_DEFENDENCIES alpDepFullNameList _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), DWORD dwDeployOption _DEFAULT_INIT_VALUE_FORFUNC_ (DEPOLYOPTION_NONE), PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL));
|
||||
|
||||
// 请查阅 https://learn.microsoft.com/zh-cn/uwp/api/windows.management.deployment.packagestate?view=winrt-26100
|
||||
|
||||
// 包可用。
|
||||
#define PACKAGESTATUS_NORMAL 0
|
||||
// 包的许可证无效。
|
||||
#define PACKAGESTATUS_LICENSE_INVALID 1
|
||||
// 包有效负载由未知源修改。
|
||||
#define PACKAGESTATUS_MODIFIED 2
|
||||
// 包有效负载被故意篡改。
|
||||
#define PACKAGESTATUS_TAMPERED 3
|
||||
// 例如,将 包的状态设置为“可用”、“已篡改”等。
|
||||
// dwStatus 请使用 PACKAGESTATUS_* 常量
|
||||
PKGMGR_API HRESULT SetAppxPackageStatus (LPCWSTR lpPackageFullName, DWORD dwStatus, LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL));
|
||||
// 在不注册包的情况下将 包 暂存到系统。
|
||||
// dwDeployOption 接受 DEPOLYOPTION_* 常量
|
||||
PKGMGR_API HRESULT StageAppxPackageFromURI (LPCWSTR lpFileUri, PCREGISTER_PACKAGE_DEFENDENCIES alpDepUriList _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), DWORD dwDeployOption _DEFAULT_INIT_VALUE_FORFUNC_ (DEPOLYOPTION_NONE), PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL));
|
||||
// 在不注册包的情况下将 包 暂存到系统。
|
||||
// dwDeployOption 接受 DEPOLYOPTION_* 常量
|
||||
PKGMGR_API HRESULT StageAppxPackageFromPath (LPCWSTR lpFileUri, PCREGISTER_PACKAGE_DEFENDENCIES alpDepUriList _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), DWORD dwDeployOption _DEFAULT_INIT_VALUE_FORFUNC_ (DEPOLYOPTION_NONE), PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL));
|
||||
// 在不注册包的情况下将 包的 漫游数据暂存到系统。 在暂存包之后、为特定用户注册包之前调用此方法。
|
||||
// dwDeployOption 接受 DEPOLYOPTION_* 常量
|
||||
PKGMGR_API HRESULT StageAppxUserData (LPCWSTR lpPackageFullName, PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL));
|
||||
// 为当前用户汇报已安装的包或其依赖项包。
|
||||
// 仅当更新包的版本高于已安装包的版本时,才能更新已安装的包。 如果不存在以前版本的包,则操作将失败。
|
||||
// 注意:传入的文件路径为 DOS/NT 风格。如:C:\Windows\...
|
||||
// dwDeployOption 接受 DEPOLYOPTION_* 常量
|
||||
// 输出的错误信息别忘了用 free 释放
|
||||
PKGMGR_API HRESULT UpdateAppxPackageFromPath (LPCWSTR lpPkgPath, PCREGISTER_PACKAGE_DEFENDENCIES alpDepUrlList _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), DWORD dwDeployOption _DEFAULT_INIT_VALUE_FORFUNC_ (DEPOLYOPTION_NONE), PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL));
|
||||
// 为当前用户汇报已安装的包或其依赖项包。
|
||||
// 仅当更新包的版本高于已安装包的版本时,才能更新已安装的包。 如果不存在以前版本的包,则操作将失败。
|
||||
// 注意:传入的文件路径为 URI。
|
||||
// dwDeployOption 接受 DEPOLYOPTION_* 常量
|
||||
// 输出的错误信息别忘了用 free 释放
|
||||
PKGMGR_API HRESULT UpdateAppxPackageFromURI (LPCWSTR lpFileUri, PCREGISTER_PACKAGE_DEFENDENCIES alpDepFullNameList _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), DWORD dwDeployOption _DEFAULT_INIT_VALUE_FORFUNC_ (DEPOLYOPTION_NONE), PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL));
|
||||
// 检索有关为任何用户安装的指定 包 的信息。
|
||||
PKGMGR_API HRESULT FindAppxPackage (LPCWSTR lpPackageFullName, PKGMGR_FINDENUMCALLBACK pfCallback, void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL));
|
||||
// 获取错误代码。错误代码不一定有,且更多有效信息来自错误详细信息。
|
||||
PKGMGR_API LPCWSTR GetPackageManagerLastErrorCode ();
|
||||
// 获取错误详细信息。这个是常用的
|
||||
PKGMGR_API LPCWSTR GetPackageManagerLastErrorDetailMessage ();
|
||||
#ifdef _DEFAULT_INIT_VALUE_
|
||||
#undef _DEFAULT_INIT_VALUE_
|
||||
#endif
|
||||
#ifdef _DEFAULT_INIT_VALUE_FORFUNC_
|
||||
#undef _DEFAULT_INIT_VALUE_FORFUNC_
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
96
pkgmgr/pkgmgr.vcxproj
Normal file
96
pkgmgr/pkgmgr.vcxproj
Normal file
@@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{8EAC0230-4990-4E41-8E0F-D641D1561396}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>pkgmgr</RootNamespace>
|
||||
<ProjectName>pkgmgr</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CLRSupport>false</CLRSupport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CLRSupport>false</CLRSupport>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings" />
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ReferencePath>$(VCINSTALLDIR)\vcpackages;$(VCInstallDir)atlmfc\lib;$(VCInstallDir)lib;$(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(ReferencePath)</ReferencePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ReferencePath>$(VCINSTALLDIR)\vcpackages;$(VCInstallDir)atlmfc\lib;$(VCInstallDir)lib;$(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(ReferencePath)</ReferencePath>
|
||||
</PropertyGroup>
|
||||
<!-- 关键:启用 WinRT 扩展 -->
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalOptions>/ZW:nostdlib /FUplatform.winmd /FUwindows.winmd %(AdditionalOptions)</AdditionalOptions>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;PKGMGR_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<CompileAsWinRT>true</CompileAsWinRT>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalOptions>/ZW:nostdlib /FUplatform.winmd /FUWindows.winmd %(AdditionalOptions)</AdditionalOptions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;PKGMGR_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<CompileAsWinRT>true</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pkgmgr.cpp" />
|
||||
<ClCompile Include="stdafx.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pkgmgr.h" />
|
||||
<ClInclude Include="raii.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
<ClInclude Include="version.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
||||
42
pkgmgr/pkgmgr.vcxproj.filters
Normal file
42
pkgmgr/pkgmgr.vcxproj.filters
Normal file
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pkgmgr.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pkgmgr.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="stdafx.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="targetver.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="raii.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="version.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
8
pkgmgr/raii.h
Normal file
8
pkgmgr/raii.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
struct raii
|
||||
{
|
||||
std::function <void ()> endtask = nullptr;
|
||||
raii (std::function <void ()> pFunc = nullptr): endtask (pFunc) {}
|
||||
~raii () { if (endtask) endtask (); }
|
||||
};
|
||||
8
pkgmgr/stdafx.cpp
Normal file
8
pkgmgr/stdafx.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
// stdafx.cpp : 只包括标准包含文件的源文件
|
||||
// pkgmgr.pch 将作为预编译头
|
||||
// stdafx.obj 将包含预编译类型信息
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: 在 STDAFX.H 中引用任何所需的附加头文件,
|
||||
//而不是在此文件中引用
|
||||
30
pkgmgr/stdafx.h
Normal file
30
pkgmgr/stdafx.h
Normal file
@@ -0,0 +1,30 @@
|
||||
// stdafx.h : 标准系统包含文件的包含文件,
|
||||
// 或是经常使用但不常更改的
|
||||
// 特定于项目的包含文件
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "targetver.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // 从 Windows 头中排除极少使用的资料
|
||||
// Windows 头文件:
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
|
||||
// TODO: 在此处引用程序需要的其他头文件
|
||||
#using <Windows.winmd>
|
||||
using namespace Platform;
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::Management::Deployment;
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <objbase.h>
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
#include <sddl.h>
|
||||
#include <algorithm>
|
||||
#include <collection.h>
|
||||
#include <string>
|
||||
#include <sddl.h>
|
||||
8
pkgmgr/targetver.h
Normal file
8
pkgmgr/targetver.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
// 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。
|
||||
|
||||
// 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将
|
||||
// 将 _WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。
|
||||
|
||||
#include <SDKDDKVer.h>
|
||||
125
pkgmgr/version.h
Normal file
125
pkgmgr/version.h
Normal file
@@ -0,0 +1,125 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
typedef uint64_t UINT64;
|
||||
typedef int64_t INT64;
|
||||
typedef uint16_t UINT16;
|
||||
typedef struct version
|
||||
{
|
||||
UINT16 major = 0, minor = 0, build = 0, revision = 0;
|
||||
version (UINT64 value):
|
||||
major ((value >> 0x30) & 0xFFFF), minor ((value >> 0x20) & 0xFFFF),
|
||||
build ((value >> 0x10) & 0xFFFF), revision ((value) & 0xFFFF) {}
|
||||
version (UINT16 major, UINT16 minor, UINT16 build, UINT16 revision):
|
||||
major (major), minor (minor), build (build), revision (revision) {}
|
||||
version (const std::wstring &verstr) { this->interpret (verstr); }
|
||||
version (const std::string &verstr) { this->interpret (verstr); }
|
||||
version () {}
|
||||
version (const version &other): major (other.major), minor (other.minor), build (other.build), revision (other.revision) {}
|
||||
version (version &&other): major (other.major), minor (other.minor), build (other.build), revision (other.revision) {}
|
||||
version &operator = (const version &other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
major = other.major;
|
||||
minor = other.minor;
|
||||
build = other.build;
|
||||
revision = other.revision;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
version &operator = (version &&other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
major = other.major;
|
||||
minor = other.minor;
|
||||
build = other.build;
|
||||
revision = other.revision;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
version &operator = (UINT64 value) { this->data (value); return *this; }
|
||||
UINT64 data () const { return (((UINT64)major) << 48) | (((UINT64)minor) << 32) | (((UINT64)build) << 16) | ((UINT64)revision); }
|
||||
UINT64 data (UINT64 value)
|
||||
{
|
||||
major = (value >> 48) & 0xFFFF;
|
||||
minor = (value >> 32) & 0xFFFF;
|
||||
build = (value >> 16) & 0xFFFF;
|
||||
revision = value & 0xFFFF;
|
||||
return value;
|
||||
}
|
||||
std::wstring stringifyw () const
|
||||
{
|
||||
std::wstringstream ss;
|
||||
ss << major << L'.' << minor << L'.' << build << L'.' << revision;
|
||||
return ss.str ();
|
||||
}
|
||||
std::string stringify () const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << major << '.' << minor << '.' << build << '.' << revision;
|
||||
return ss.str ();
|
||||
}
|
||||
version &interpret (const std::wstring &verstr)
|
||||
{
|
||||
auto result = split (verstr);
|
||||
if (result.size () > 0) this->major = _wtoi (result [0].c_str ());
|
||||
if (result.size () > 1) this->minor = _wtoi (result [1].c_str ());
|
||||
if (result.size () > 2) this->build = _wtoi (result [2].c_str ());
|
||||
if (result.size () > 3) this->revision = _wtoi (result [3].c_str ());
|
||||
return *this;
|
||||
}
|
||||
version &interpret (const std::string &verstr)
|
||||
{
|
||||
auto result = split (verstr);
|
||||
if (result.size () > 0) this->major = atoi (result [0].c_str ());
|
||||
if (result.size () > 1) this->minor = atoi (result [1].c_str ());
|
||||
if (result.size () > 2) this->build = atoi (result [2].c_str ());
|
||||
if (result.size () > 3) this->revision = atoi (result [3].c_str ());
|
||||
return *this;
|
||||
}
|
||||
bool empty () const { return *(UINT64 *)this == 0; }
|
||||
friend bool operator == (const version &l, const version &r) { return *(UINT64 *)&l == *(UINT64 *)&r; }
|
||||
friend bool operator == (const version &l, const UINT64 &r) { return l.data () == r; }
|
||||
friend bool operator == (const UINT64 &r, const version &l) { return l.data () == r; }
|
||||
friend bool operator < (const version &l, const version &r) { return l.data () < r.data (); }
|
||||
friend bool operator > (const version &l, const version &r) { return l.data () > r.data (); }
|
||||
friend bool operator <= (const version &l, const version &r) { return l.data () <= r.data (); }
|
||||
friend bool operator >= (const version &l, const version &r) { return l.data () >= r.data (); }
|
||||
friend bool operator != (const version &l, const version &r) { return *(UINT64 *)&l != *(UINT64 *)&r; }
|
||||
explicit operator bool () const { return !this->empty (); }
|
||||
bool operator ! () { return this->empty (); }
|
||||
friend std::ostream &operator << (std::ostream &o, const version &v) { return o << v.major << '.' << v.minor << '.' << v.build << '.' << v.revision; }
|
||||
friend std::wostream &operator << (std::wostream &o, const version &v) { return o << v.major << '.' << v.minor << '.' << v.build << '.' << v.revision; }
|
||||
bool equals (const version &r) const { return *this == r; }
|
||||
INT64 compare (const version &r) const { return this->data () - r.data (); }
|
||||
static version parse (const std::wstring &value) { return version (value); }
|
||||
static version parse (const std::string &value) { return version (value); }
|
||||
static std::wstring stringifyw (const version &v) { return v.stringifyw (); }
|
||||
static std::string stringify (const version &v) { return v.stringify (); }
|
||||
static bool equals (const version &l, const version &r) { return l == r; }
|
||||
static INT64 compare (const version &l, const version &r) { return l.data () - r.data (); }
|
||||
static version decode (UINT64 value) { return version (value); }
|
||||
static UINT64 encode (const version &v) { return v.data (); }
|
||||
protected:
|
||||
template <typename StringType> std::vector <StringType> split (const StringType &str, typename StringType::value_type delimiter1 = '.', typename StringType::value_type delimiter2 = ',')
|
||||
{
|
||||
std::vector <StringType> result;
|
||||
std::basic_stringstream<typename StringType::value_type> ss (str);
|
||||
StringType segment;
|
||||
while (std::getline (ss, segment, delimiter1))
|
||||
{
|
||||
size_t pos = 0;
|
||||
while ((pos = segment.find (delimiter2)) != StringType::npos)
|
||||
{
|
||||
result.push_back (segment.substr (0, pos));
|
||||
segment.erase (0, pos + 1);
|
||||
}
|
||||
if (!segment.empty ()) result.push_back (segment);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} Version;
|
||||
@@ -92,14 +92,23 @@ void GetLocaleElaboratedCodeFromLcid (LCID lcid, std::string &ret)
|
||||
ret = GetLocaleElaboratedCodeFromLcidA (lcid);
|
||||
}
|
||||
|
||||
LCID LocaleCodeToLcidW (LPCWSTR localeCode)
|
||||
LCID LocaleCodeToLcidW (const std::wstring &localeCode)
|
||||
{
|
||||
BYTE buf [LOCALE_NAME_MAX_LENGTH * sizeof (WCHAR)] = {0};
|
||||
int res = GetLocaleInfoEx (localeCode, LOCALE_RETURN_NUMBER | LOCALE_ILANGUAGE, (LPWSTR)buf, LOCALE_NAME_MAX_LENGTH);
|
||||
LCID lcid = *((LCID *)buf);
|
||||
return lcid;
|
||||
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
|
||||
try
|
||||
{
|
||||
BYTE buf [LOCALE_NAME_MAX_LENGTH * sizeof (WCHAR)] = {0};
|
||||
int res = GetLocaleInfoEx (localeCode.c_str (), LOCALE_RETURN_NUMBER | LOCALE_ILANGUAGE, (LPWSTR)buf, LOCALE_NAME_MAX_LENGTH);
|
||||
LCID lcid = *((LCID *)buf);
|
||||
return lcid;
|
||||
}
|
||||
catch (const std::exception &e) {}
|
||||
return LocaleNameToLCID (localeCode.c_str (), 0);
|
||||
#else
|
||||
return LocaleNameToLCID (localeCode.c_str (), 0);
|
||||
#endif
|
||||
}
|
||||
LCID LocaleCodeToLcidA (LPCSTR localeCode)
|
||||
LCID LocaleCodeToLcidA (const std::string &localeCode)
|
||||
{
|
||||
std::wstring lcWide = StringToWString (std::string (localeCode));
|
||||
return LocaleCodeToLcidW (lcWide.c_str ());
|
||||
@@ -157,7 +166,91 @@ std::string LcidToLocaleCodeA (LCID lcid, char divide = '-')
|
||||
}
|
||||
std::wstring LcidToLocaleCodeW (LCID lcid, WCHAR divide = L'-')
|
||||
{
|
||||
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
|
||||
try
|
||||
{
|
||||
WCHAR buf [LOCALE_NAME_MAX_LENGTH] = {0};
|
||||
LCIDToLocaleName (lcid, buf, LOCALE_NAME_MAX_LENGTH, 0);
|
||||
return buf;
|
||||
}
|
||||
catch (const std::exception &e) {}
|
||||
return GetLocaleRestrictedCodeFromLcidW (lcid) + divide + GetLocaleElaboratedCodeFromLcidW (lcid);
|
||||
#else
|
||||
return GetLocaleRestrictedCodeFromLcidW (lcid) + divide + GetLocaleElaboratedCodeFromLcidW (lcid);
|
||||
#endif
|
||||
}
|
||||
std::wstring LcidToLocaleCode (LCID lcid, WCHAR divide = L'-') { return LcidToLocaleCodeW (lcid, divide); }
|
||||
std::string LcidToLocaleCode (LCID lcid, char divide = '-') { return LcidToLocaleCodeA (lcid, divide); }
|
||||
|
||||
std::wstring GetUserDefaultLocaleName ()
|
||||
{
|
||||
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
|
||||
try
|
||||
{
|
||||
WCHAR buf [LOCALE_NAME_MAX_LENGTH] = {0};
|
||||
GetUserDefaultLocaleName (buf, LOCALE_NAME_MAX_LENGTH);
|
||||
return buf;
|
||||
}
|
||||
catch (const std::exception &e) {}
|
||||
return LcidToLocaleCodeW (GetUserDefaultLCID ());
|
||||
#else
|
||||
return LcidToLocaleCodeW (GetUserDefaultLCID ());
|
||||
#endif
|
||||
}
|
||||
std::wstring GetSystemDefaultLocaleName ()
|
||||
{
|
||||
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
|
||||
try
|
||||
{
|
||||
WCHAR buf [LOCALE_NAME_MAX_LENGTH] = {0};
|
||||
GetSystemDefaultLocaleName (buf, LOCALE_NAME_MAX_LENGTH);
|
||||
return buf;
|
||||
}
|
||||
catch (const std::exception &e) {}
|
||||
return LcidToLocaleCodeW (GetSystemDefaultLCID ());
|
||||
#else
|
||||
return LcidToLocaleCodeW (GetSystemDefaultLCID ());
|
||||
#endif
|
||||
}
|
||||
|
||||
std::wstring GetComputerLocaleCodeW ()
|
||||
{
|
||||
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
LCID lcid = GetThreadLocale ();
|
||||
std::wstring tmp = LcidToLocaleCodeW (lcid);
|
||||
if (lcid && tmp.length () > 1) return tmp;
|
||||
}
|
||||
{
|
||||
WCHAR buf [LOCALE_NAME_MAX_LENGTH] = {0};
|
||||
GetUserDefaultLocaleName (buf, LOCALE_NAME_MAX_LENGTH);
|
||||
if (lstrlenW (buf)) return buf;
|
||||
}
|
||||
{
|
||||
WCHAR buf [LOCALE_NAME_MAX_LENGTH] = {0};
|
||||
GetSystemDefaultLocaleName (buf, LOCALE_NAME_MAX_LENGTH);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e) {}
|
||||
LCID lcid = GetThreadLocale ();
|
||||
if (!lcid) lcid = GetUserDefaultLCID ();
|
||||
if (!lcid) lcid = GetSystemDefaultLCID ();
|
||||
return LcidToLocaleCodeW (lcid);
|
||||
}
|
||||
#else
|
||||
{
|
||||
LCID lcid = GetThreadLocale ();
|
||||
if (!lcid) lcid = GetUserDefaultLCID ();
|
||||
if (!lcid) lcid = GetSystemDefaultLCID ();
|
||||
return LcidToLocaleCodeW (lcid);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
bool LocaleNameCompare (const std::wstring &left, const std::wstring &right)
|
||||
{
|
||||
return std::wnstring::equals (left, right) || LocaleCodeToLcidW (left) == LocaleCodeToLcidW (right);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "readobj.h"
|
||||
#include "pkgread.h"
|
||||
#include "localeex.h"
|
||||
#include "themeinfo.h"
|
||||
|
||||
#define ToHandleRead(_cpp_ptr_) reinterpret_cast <HPKGREAD> (_cpp_ptr_)
|
||||
#define ToPtrPackage(_cpp_ptr_) reinterpret_cast <package *> (_cpp_ptr_)
|
||||
@@ -860,3 +861,312 @@ BOOL GetPackagePrerequisite (_In_ HPKGREAD hReader, _In_ LPCWSTR lpName, _Outptr
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Selector
|
||||
std::wnstring SelectLanguageSuitPackageNameByLocaleCode (std::map <std::wnstring, appx_info::resource> &in, const std::wstring &langcode, std::wnstring &output)
|
||||
{
|
||||
output.clear ();
|
||||
for (auto &it : in)
|
||||
{
|
||||
if (it.second.restype != appx_info::ResourceType::language) continue;
|
||||
for (auto &it_s : it.second.resvalue.languages) if (LocaleNameCompare (it_s, langcode)) return output = it.first;
|
||||
}
|
||||
return output = L"";
|
||||
}
|
||||
std::wnstring SelectLanguageSuitPackageName (std::map <std::wnstring, appx_info::resource> &in, std::wnstring &output)
|
||||
{
|
||||
output.clear ();
|
||||
output = SelectLanguageSuitPackageNameByLocaleCode (in, GetComputerLocaleCodeW (), output);
|
||||
if (output.empty ()) output = SelectLanguageSuitPackageNameByLocaleCode (in, L"en-US", output);
|
||||
if (output.empty ())
|
||||
{
|
||||
for (auto &it : in)
|
||||
{
|
||||
if (it.second.pkgtype == APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_APPLICATION)
|
||||
{
|
||||
output = it.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (output.empty ())
|
||||
{
|
||||
try { output = in.begin ()->first; }
|
||||
catch (const std::exception &e) { output = L""; }
|
||||
}
|
||||
return output;
|
||||
}
|
||||
std::wnstring SelectScaleSuitPackageName (std::map <std::wnstring, appx_info::resource> &in, std::wnstring &output)
|
||||
{
|
||||
output.clear ();
|
||||
struct res_key_value
|
||||
{
|
||||
std::wnstring filename = L"";
|
||||
uint32_t scale = 0;
|
||||
res_key_value (const std::wstring &fpath = L"", uint32_t s = 0):
|
||||
filename (fpath), scale (s) {}
|
||||
};
|
||||
std::vector <res_key_value> rkv;
|
||||
for (auto &it : in) if ((WORD)it.second.restype & (WORD)appx_info::ResourceType::scale)
|
||||
{
|
||||
for (auto &it_s : it.second.resvalue.scales)
|
||||
{
|
||||
if (!it_s) continue;
|
||||
rkv.push_back (res_key_value (it.first, it_s));
|
||||
}
|
||||
}
|
||||
std::sort (rkv.begin (), rkv.end (), [] (const res_key_value &a, const res_key_value &b) {
|
||||
return a.scale < b.scale;
|
||||
});
|
||||
auto dpi = GetDPI ();
|
||||
for (auto &it : rkv) if (it.scale > dpi) return output = it.filename;
|
||||
if (output.empty ()) { for (auto it = rkv.rbegin (); it != rkv.rend (); ++ it) if (it->scale < dpi) return output = it->filename; }
|
||||
if (output.empty ()) { for (auto &it : in) if (it.second.pkgtype == APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_APPLICATION) return output = it.first; }
|
||||
try { output = in.begin ()->first; }
|
||||
catch (const std::exception &e) { output = L""; }
|
||||
return output;
|
||||
}
|
||||
|
||||
// File Stream
|
||||
HANDLE GetAppxFileFromAppxPackage (_In_ HPKGREAD hReader, _In_ LPCWSTR lpFileName)
|
||||
{
|
||||
auto ptr = ToPtrPackage (hReader);
|
||||
if (!ptr) return nullptr;
|
||||
if (!lpFileName) return nullptr;
|
||||
switch (ptr->type ())
|
||||
{
|
||||
case PackageType::single: {
|
||||
auto reader = ptr->appx_reader ();
|
||||
CComPtr <IAppxFile> afile;
|
||||
if (FAILED (reader.payload_stream (lpFileName, &afile))) return nullptr;
|
||||
IStream *istream = nullptr;
|
||||
if (FAILED (afile->GetStream (&istream))) return nullptr;
|
||||
else return istream;
|
||||
} break;
|
||||
case PackageType::bundle: {
|
||||
auto bread = ptr->bundle_reader ();
|
||||
CComPtr <IAppxPackageReader> appfile;
|
||||
if (FAILED (bread.random_application_package (&appfile))) return nullptr;
|
||||
appxreader reader (appfile.p);
|
||||
CComPtr <IAppxFile> afile;
|
||||
if (FAILED (reader.payload_stream (lpFileName, &afile))) return nullptr;
|
||||
IStream *istream = nullptr;
|
||||
if (FAILED (afile->GetStream (&istream))) return nullptr;
|
||||
else return istream;
|
||||
} break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
HANDLE GetAppxBundlePayloadPackageFile (_In_ HPKGREAD hReader, _In_ LPCWSTR lpFileName)
|
||||
{
|
||||
auto ptr = ToPtrPackage (hReader);
|
||||
if (!ptr) return nullptr;
|
||||
if (!lpFileName) return nullptr;
|
||||
if (ptr->type () == PackageType::bundle)
|
||||
{
|
||||
auto reader = ptr->bundle_reader ();
|
||||
CComPtr <IAppxFile> iafile;
|
||||
if (FAILED (reader.get_payload_package (lpFileName, &iafile))) return nullptr;
|
||||
IStream *istream = nullptr;
|
||||
if (FAILED (iafile->GetStream (&istream))) return nullptr;
|
||||
else return istream;
|
||||
}
|
||||
else return nullptr;
|
||||
}
|
||||
HANDLE GetAppxPriFileStream (_In_ HPKGREAD hReader) { return GetAppxFileFromAppxPackage (hReader, L"resources.pri"); }
|
||||
HANDLE GetFileFromPayloadPackage (_In_ HANDLE hPackageStream, _In_ LPCWSTR lpFileName)
|
||||
{
|
||||
if (!hPackageStream || !lpFileName) return nullptr;
|
||||
IStream *ifs = (IStream *)hPackageStream;
|
||||
CComPtr <IAppxPackageReader> iappx;
|
||||
if (FAILED (GetAppxPackageReader (ifs, &iappx))) return nullptr;
|
||||
appxreader reader (iappx.p);
|
||||
CComPtr <IAppxFile> iaf;
|
||||
if (FAILED (reader.payload_stream (lpFileName, &iaf))) return nullptr;
|
||||
IStream *istream = nullptr;
|
||||
if (FAILED (iaf->GetStream (&istream))) return nullptr;
|
||||
else return istream;
|
||||
}
|
||||
HANDLE GetPriFileFromPayloadPackage (_In_ HANDLE hPackageStream) { return GetFileFromPayloadPackage (hPackageStream, L"resources.pri"); }
|
||||
BOOL GetSuitablePackageFromBundle (_In_ HPKGREAD hReader, _Outptr_ HANDLE *pStreamForLang, _Outptr_ HANDLE *pStreamForScale)
|
||||
{
|
||||
auto ptr = ToPtrPackage (hReader);
|
||||
if (!ptr) return FALSE;
|
||||
if (ptr->type () != PackageType::bundle) return FALSE;
|
||||
if (pStreamForLang) *pStreamForLang = nullptr;
|
||||
if (pStreamForScale) *pStreamForScale = nullptr;
|
||||
auto bread = ptr->bundle_reader ();
|
||||
auto pkgsinfo = bread.package_id_items ();
|
||||
std::map <std::wnstring, appx_info::resource> mapfr;
|
||||
pkgsinfo.resource_info (mapfr);
|
||||
std::wnstring lf = L"", sf = L"";
|
||||
SelectLanguageSuitPackageName (mapfr, lf);
|
||||
SelectScaleSuitPackageName (mapfr, sf);
|
||||
if (lf == sf)
|
||||
{
|
||||
WORD flag = (bool)pStreamForLang << 1 | (bool)pStreamForScale;
|
||||
switch (flag)
|
||||
{
|
||||
case 0b01:
|
||||
case 0b10:
|
||||
case 0b11: {
|
||||
IStream *file = nullptr;
|
||||
CComPtr <IAppxFile> pread;
|
||||
if (FAILED (bread.get_payload_package (lf, &pread))) return false;
|
||||
if (FAILED (pread->GetStream (&file))) return false;
|
||||
if (pStreamForLang) *pStreamForLang = file;
|
||||
if (pStreamForScale) *pStreamForScale = file;
|
||||
return true;
|
||||
} break;
|
||||
default:
|
||||
case 0b00: {
|
||||
CComPtr <IAppxFile> pread;
|
||||
if (FAILED (bread.get_payload_package (lf, &pread))) return false;
|
||||
CComPtr <IStream> file = nullptr;
|
||||
if (FAILED (pread->GetStream (&file))) return false;
|
||||
else return true;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
CComPtr <IAppxFile> reslangpkg;
|
||||
if (FAILED (bread.get_payload_package (lf, &reslangpkg))) return false;
|
||||
if (pStreamForLang)
|
||||
{
|
||||
IStream *file = nullptr;
|
||||
if (FAILED (reslangpkg->GetStream (&file))) return false;
|
||||
*pStreamForLang = file;
|
||||
}
|
||||
else
|
||||
{
|
||||
CComPtr <IStream> file;
|
||||
if (FAILED (reslangpkg->GetStream (&file))) return false;
|
||||
}
|
||||
}
|
||||
{
|
||||
CComPtr <IAppxFile> resscalepkg;
|
||||
if (FAILED (bread.get_payload_package (sf, &resscalepkg))) return false;
|
||||
if (pStreamForScale)
|
||||
{
|
||||
IStream *file = nullptr;
|
||||
if (FAILED (resscalepkg->GetStream (&file))) return false;
|
||||
*pStreamForScale = file;
|
||||
}
|
||||
else
|
||||
{
|
||||
CComPtr <IStream> file;
|
||||
if (FAILED (resscalepkg->GetStream (&file))) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
ULONG DestroyAppxFileStream (_In_ HANDLE hFileStream)
|
||||
{
|
||||
if (!hFileStream) return 0;
|
||||
IStream *ptr = reinterpret_cast <IStream *> (hFileStream);
|
||||
if (!ptr) return 0;
|
||||
return ptr->Release ();
|
||||
}
|
||||
HANDLE GetAppxBundleApplicationPackageFile (_In_ HPKGREAD hReader)
|
||||
{
|
||||
if (!hReader) return nullptr;
|
||||
auto ptr = ToPtrPackage (hReader);
|
||||
if (!ptr) return nullptr;
|
||||
switch (ptr->type ())
|
||||
{
|
||||
case PackageType::single: {
|
||||
return nullptr;
|
||||
} break;
|
||||
case PackageType::bundle: {
|
||||
auto bread = ptr->bundle_reader ();
|
||||
IStream *ipf = nullptr;
|
||||
if (FAILED (bread.random_application_package (&ipf))) return nullptr;
|
||||
else return ipf;
|
||||
} break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::wstring GetMimeTypeFromStream (IStream *filestream)
|
||||
{
|
||||
if (!filestream) return L"";
|
||||
LARGE_INTEGER liZero = {0};
|
||||
filestream->Seek (liZero, STREAM_SEEK_SET, nullptr);
|
||||
BYTE buffer [256] = {0};
|
||||
ULONG bytesRead = 0;
|
||||
HRESULT hr = filestream->Read (buffer, sizeof (buffer), &bytesRead);
|
||||
filestream->Seek (liZero, STREAM_SEEK_SET, nullptr);
|
||||
if (FAILED (hr) || bytesRead == 0) return L"";
|
||||
LPWSTR lpMime = nullptr;
|
||||
raii relt ([&lpMime] () {
|
||||
if (lpMime) CoTaskMemFree (lpMime);
|
||||
lpMime = nullptr;
|
||||
});
|
||||
std::wstring mime;
|
||||
hr = FindMimeFromData (
|
||||
nullptr, // pBC
|
||||
nullptr, // URL (unknown)
|
||||
buffer, // data buffer
|
||||
bytesRead, // data size
|
||||
nullptr, // proposed MIME
|
||||
FMFD_RETURNUPDATEDIMGMIMES |
|
||||
FMFD_IGNOREMIMETEXTPLAIN |
|
||||
FMFD_URLASFILENAME,
|
||||
&lpMime, // result
|
||||
0 // reserved
|
||||
);
|
||||
if (SUCCEEDED (hr) && lpMime) mime = lpMime;
|
||||
if (mime.empty ())
|
||||
{
|
||||
if (bytesRead >= 8 && memcmp (buffer, "\x89PNG\r\n\x1A\n", 8) == 0) mime = L"image/png";
|
||||
else if (bytesRead >= 3 && buffer [0] == 0xFF && buffer [1] == 0xD8) mime = L"image/jpeg";
|
||||
else if (bytesRead >= 6 && memcmp (buffer, "GIF89a", 6) == 0) mime = L"image/gif";
|
||||
else if (bytesRead >= 2 && buffer [0] == 'B' && buffer [1] == 'M') mime = L"image/bmp";
|
||||
else if (bytesRead >= 12 && memcmp (buffer, "RIFF", 4) == 0 && memcmp (buffer + 8, "WEBP", 4) == 0) mime = L"image/webp";
|
||||
else if (bytesRead >= 4 && memcmp (buffer, "\x00\x00\x01\x00", 4) == 0) mime = L"image/x-icon";
|
||||
else mime = L"application/octet-stream";
|
||||
}
|
||||
return mime;
|
||||
}
|
||||
std::wstring GetBase64StringFromStreamW (IStream *ifile)
|
||||
{
|
||||
if (!ifile) return L"";
|
||||
IStream *&pStream = 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 nullptr;
|
||||
std::vector <WCHAR> base64Buffer (base64Size + 1);
|
||||
if (!CryptBinaryToStringW (buffer.data (), bytesRead, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, base64Buffer.data (), &base64Size)) return nullptr;
|
||||
pStream->Seek (liZero, STREAM_SEEK_SET, nullptr);
|
||||
return std::wstring (base64Buffer.data ());
|
||||
}
|
||||
LPWSTR StreamToBase64W (_In_ HANDLE hFileStream, _Out_writes_ (dwCharCount) LPWSTR lpMimeBuf, _In_ DWORD dwCharCount, _Outptr_ LPWSTR *lpBase64Head)
|
||||
{
|
||||
IStream *ifs = (IStream *)hFileStream;
|
||||
if (!ifs) return nullptr;
|
||||
LPWSTR retptr = nullptr;
|
||||
std::wstring ret = L"";
|
||||
std::wstring mime = GetMimeTypeFromStream (ifs);
|
||||
auto &dwBufSize = dwCharCount;
|
||||
if (lpMimeBuf)
|
||||
{
|
||||
ZeroMemory (lpMimeBuf, sizeof (WCHAR) * dwBufSize);
|
||||
wcsncpy_s (lpMimeBuf, dwBufSize, mime.c_str (), _TRUNCATE);
|
||||
}
|
||||
ret += L"data:" + mime + L";base64,";
|
||||
size_t head = ret.length ();
|
||||
ret += GetBase64StringFromStreamW (ifs);
|
||||
retptr = _wcsdup (ret.c_str ());
|
||||
if (lpBase64Head) *lpBase64Head = retptr + head;
|
||||
return retptr;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define _DEFAULT_INIT_VALUE_(_init_value_) = _init_value_
|
||||
#ifdef PKGREAD_EXPORTS
|
||||
#ifndef PKGREAD_EXPORTS
|
||||
#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_) = _init_value_
|
||||
#else
|
||||
#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_)
|
||||
@@ -252,6 +252,36 @@ extern "C"
|
||||
#define GetPackagePrerequisiteOsMinVersion(_In_hReader_, _Outptr_pVerRet_) GetPackagePrerequisite (_In_hReader_, PKG_PREREQUISITE_OS_MIN_VERSION, _Outptr_pVerRet_)
|
||||
#define GetPackagePrerequisiteOsMaxVersionTested(_In_hReader_, _Outptr_pVerRet_) GetPackagePrerequisite (_In_hReader_, PKG_PREREQUISITE_OS_MAX_VERSION_TESTED, _Outptr_pVerRet_)
|
||||
|
||||
// File Stream
|
||||
// 从 Appx 包中获取 Appx 中的文件的文件流。
|
||||
// 注:只提取 Payloads 文件。不可提供 Footprint 文件。
|
||||
// 对于 AppxBundle 包,则随机从一个应用包中提取文件。
|
||||
PKGREAD_API HANDLE GetAppxFileFromAppxPackage (_In_ HPKGREAD hReader, _In_ LPCWSTR lpFileName);
|
||||
// 从 AppxBundle 包中获取 Appx 子包的文件流。
|
||||
PKGREAD_API HANDLE GetAppxBundlePayloadPackageFile (_In_ HPKGREAD hReader, _In_ LPCWSTR lpFileName);
|
||||
// 从 Appx 包中获取 Appx 的 Pri 文件流
|
||||
// 对于 AppxBundle 包,则随机从一个应用包中提取 Pri 文件。
|
||||
PKGREAD_API HANDLE GetAppxPriFileStream (_In_ HPKGREAD hReader);
|
||||
// 从 AppxBundle 包中获取的子包的文件流中提取包中的文件
|
||||
// 注:只提取 Payloads 文件。不可提供 Footprint 文件。
|
||||
PKGREAD_API HANDLE GetFileFromPayloadPackage (_In_ HANDLE hPackageStream, _In_ LPCWSTR lpFileName);
|
||||
// 从 AppxBundle 包中获取的子包的文件流中提取 Pri 文件流
|
||||
PKGREAD_API HANDLE GetPriFileFromPayloadPackage (_In_ HANDLE hPackageStream);
|
||||
// 从 AppxBundle 包中获取合适的包,合适指的是资源合适。
|
||||
// 第一个用于返回的参数指的是返回的语言合适的选项,第二个用于返回的参数是返回的缩放资源。
|
||||
// 如果指向的都是同一个包,那么两个参数返回的都是同一个指针。
|
||||
// 对于 Appx 文件直接返回假。
|
||||
PKGREAD_API BOOL GetSuitablePackageFromBundle (_In_ HPKGREAD hReader, _Outptr_ HANDLE *pStreamForLang, _Outptr_ HANDLE *pStreamForScale);
|
||||
// 文件流必须通过此来释放。
|
||||
PKGREAD_API ULONG DestroyAppxFileStream (_In_ HANDLE hFileStream);
|
||||
// 转换:文件流转换到 Data URL。这样转换后浏览器可以使用图片。
|
||||
// 注意:dwCharCount 指的是 lpMimeBuf 的可容纳字符数,如 WCHAR lpMimeBuf [dwCharCount],不是实际可容纳字节数。
|
||||
// 返回的非空指针需要通过 free 释放。lpBase64Head 返回的是 Base64 编码后的数据,为返回指针指向的部分。
|
||||
// 如字符串为 data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D
|
||||
// 那么: ↑ lpBase64Head 指向于“base64,”后的第一个字符。
|
||||
PKGREAD_API LPWSTR StreamToBase64W (_In_ HANDLE hFileStream, _Out_writes_ (dwCharCount) LPWSTR lpMimeBuf, _In_ DWORD dwCharCount, _Outptr_ LPWSTR *lpBase64Head);
|
||||
// 获取 AppxBundle 包中的应用包文件流。最后通过 DestroyAppxFileStream 销毁。
|
||||
PKGREAD_API HANDLE GetAppxBundleApplicationPackageFile (_In_ HPKGREAD hReader);
|
||||
#ifdef _DEFAULT_INIT_VALUE_
|
||||
#undef _DEFAULT_INIT_VALUE_
|
||||
#endif
|
||||
@@ -262,24 +292,142 @@ extern "C"
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (__cplusplus) && !defined (PKGREAD_EXPORTS)
|
||||
#if defined (__cplusplus)
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <cstring>
|
||||
#include <Shlwapi.h>
|
||||
#include <algorithm>
|
||||
//#include "..\priformatcli\priformatcli.h"
|
||||
const std::vector <std::wstring> g_filepathitems =
|
||||
{
|
||||
L"LockScreenLogo",
|
||||
L"Logo",
|
||||
L"SmallLogo",
|
||||
L"Square150x150Logo",
|
||||
L"Square30x30Logo",
|
||||
L"Square310x310Logo",
|
||||
L"Square44x44Logo",
|
||||
L"Square70x70Logo",
|
||||
L"Square71x71Logo",
|
||||
L"StartPage",
|
||||
L"Tall150x310Logo",
|
||||
L"VisualGroup",
|
||||
L"WideLogo",
|
||||
L"Wide310x150Logo",
|
||||
L"Executable"
|
||||
};
|
||||
class package_reader
|
||||
{
|
||||
private:
|
||||
HPKGREAD hReader = nullptr;
|
||||
std::wstring filepath = L"";
|
||||
struct deconstr
|
||||
bool usepri = false;
|
||||
bool resswitch = false;
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
prifilebundle pribundlereader;
|
||||
std::vector <IStream *> prifilestreams;
|
||||
#endif
|
||||
void initpri ()
|
||||
{
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
pribundlereader.destroy ();
|
||||
for (auto &it : prifilestreams) if (it != nullptr) DestroyAppxFileStream (it);
|
||||
prifilestreams.clear ();
|
||||
switch (this->package_type ())
|
||||
{
|
||||
case PKGTYPE_APPX: {
|
||||
IStream *pristream = (IStream *)GetAppxPriFileStream (hReader);
|
||||
if (pristream)
|
||||
{
|
||||
prifilestreams.push_back (pristream);
|
||||
pribundlereader.set (3, pristream);
|
||||
}
|
||||
} break;
|
||||
case PKGTYPE_BUNDLE: {
|
||||
HANDLE hls = nullptr, hss = nullptr;
|
||||
destruct rel1 ([&hls, &hss] () {
|
||||
if (hls) DestroyAppxFileStream (hls);
|
||||
if (hss) DestroyAppxFileStream (hss);
|
||||
});
|
||||
GetSuitablePackageFromBundle (hReader, &hls, &hss);
|
||||
HANDLE hlpri = GetPriFileFromPayloadPackage (hls),
|
||||
hspri = GetPriFileFromPayloadPackage (hss);
|
||||
IStream *ls = (IStream *)hls, *ss = (IStream *)hss;
|
||||
switch ((bool)ls << 1 | (bool)ss)
|
||||
{
|
||||
case 0b01:
|
||||
case 0b10: {
|
||||
if (hlpri) pribundlereader.set (1, (IStream *)hlpri);
|
||||
if (hspri) pribundlereader.set (2, (IStream *)hspri);
|
||||
HANDLE hd = GetAppxBundleApplicationPackageFile (hReader);
|
||||
destruct relthd ([&hd] () {
|
||||
if (hd) DestroyAppxFileStream (hd);
|
||||
});
|
||||
HANDLE hdpri = GetPriFileFromPayloadPackage (hd);
|
||||
if (hd) pribundlereader.set (3, (IStream *)hd);
|
||||
} break;
|
||||
case 0b11: {
|
||||
if (ls) pribundlereader.set (1, (IStream *)hlpri);
|
||||
if (ss) pribundlereader.set (2, (IStream *)hspri);
|
||||
} break;
|
||||
default:
|
||||
case 0b00: {
|
||||
IStream *pkgstream = (IStream *)GetAppxBundleApplicationPackageFile (hReader);
|
||||
destruct relthd ([&pkgstream] () {
|
||||
if (pkgstream) DestroyAppxFileStream (pkgstream);
|
||||
});
|
||||
IStream *pristream = (IStream *)GetPriFileFromPayloadPackage (pkgstream);
|
||||
if (pristream)
|
||||
{
|
||||
prifilestreams.push_back (pristream);
|
||||
pribundlereader.set (3, pristream);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
try
|
||||
{
|
||||
std::vector <std::wstring> resnames;
|
||||
{
|
||||
auto prop = get_properties ();
|
||||
std::wstring temp = prop.description ();
|
||||
if (IsMsResourcePrefix (temp.c_str ())) resnames.push_back (temp);
|
||||
temp = prop.display_name ();
|
||||
if (IsMsResourcePrefix (temp.c_str ())) resnames.push_back (temp);
|
||||
temp = prop.publisher_display_name ();
|
||||
if (IsMsResourcePrefix (temp.c_str ())) resnames.push_back (temp);
|
||||
resnames.push_back (prop.logo ());
|
||||
}
|
||||
{
|
||||
auto app = get_applications ();
|
||||
std::vector <application> apps;
|
||||
app.get (apps);
|
||||
for (auto &it_map : apps)
|
||||
{
|
||||
for (auto &it_item : it_map)
|
||||
{
|
||||
if (std::find (g_filepathitems.begin (), g_filepathitems.end (), it_item.first) != g_filepathitems.end () && !it_item.second.empty ())
|
||||
resnames.push_back (it_item.second);
|
||||
else if (IsMsResourcePrefix (it_item.second.c_str ())) resnames.push_back (it_item.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
pribundlereader.add_search (resnames);
|
||||
}
|
||||
catch (const std::exception &e) {}
|
||||
#endif
|
||||
}
|
||||
typedef struct deconstr
|
||||
{
|
||||
std::function <void ()> endtask = nullptr;
|
||||
deconstr (std::function <void ()> pf): endtask (pf) {}
|
||||
~deconstr () { if (endtask) endtask (); }
|
||||
};
|
||||
} destruct;
|
||||
public:
|
||||
class base_subitems
|
||||
{
|
||||
@@ -333,22 +481,151 @@ class package_reader
|
||||
if (FAILED (hr)) return bRetWhenFailed;
|
||||
else return ret != FALSE;
|
||||
}
|
||||
std::wstring display_name () const { return string_value (PKG_PROPERTIES_DISPLAYNAME); }
|
||||
std::wstring publisher_display_name () const { return string_value (PKG_PROPERTIES_PUBLISHER); }
|
||||
std::wstring description () const { return string_value (PKG_PROPERTIES_DESCRIPTION); }
|
||||
std::wstring logo () const { return string_value (PKG_PROPERTIES_LOGO); }
|
||||
std::wstring display_name (bool toprires = true)
|
||||
{
|
||||
std::wstring ret = string_value (PKG_PROPERTIES_DISPLAYNAME);
|
||||
if (!toprires) return ret;
|
||||
if (!enable_pri ()) return ret;
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
else
|
||||
{
|
||||
if (!IsMsResourcePrefix (ret.c_str ())) return ret;
|
||||
std::wstring privalue = pri_get_res (ret);
|
||||
if (privalue.empty ()) return ret;
|
||||
return privalue;
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
std::wstring publisher_display_name (bool toprires = true)
|
||||
{
|
||||
std::wstring ret = string_value (PKG_PROPERTIES_PUBLISHER);
|
||||
if (!toprires) return ret;
|
||||
if (!enable_pri ()) return ret;
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
else
|
||||
{
|
||||
if (!IsMsResourcePrefix (ret.c_str ())) return ret;
|
||||
std::wstring privalue = pri_get_res (ret);
|
||||
if (privalue.empty ()) return ret;
|
||||
return privalue;
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
std::wstring description (bool toprires = true)
|
||||
{
|
||||
std::wstring ret = string_value (PKG_PROPERTIES_DESCRIPTION);
|
||||
if (!toprires) return ret;
|
||||
if (!enable_pri ()) return ret;
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
else
|
||||
{
|
||||
if (!IsMsResourcePrefix (ret.c_str ())) return ret;
|
||||
std::wstring privalue = pri_get_res (ret);
|
||||
if (privalue.empty ()) return ret;
|
||||
return privalue;
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
std::wstring logo (bool toprires = true)
|
||||
{
|
||||
std::wstring ret = string_value (PKG_PROPERTIES_LOGO);
|
||||
if (!toprires) return ret;
|
||||
if (!enable_pri ()) return ret;
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
else
|
||||
{
|
||||
std::wstring privalue = pri_get_res (ret);
|
||||
if (privalue.empty ()) return ret;
|
||||
return privalue;
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
std::wstring logo_base64 ()
|
||||
{
|
||||
switch (GetPackageType (hReader))
|
||||
{
|
||||
case PKGTYPE_APPX: {
|
||||
HANDLE pic = GetAppxFileFromAppxPackage (hReader, logo ().c_str ());
|
||||
destruct relp ([&pic] () {
|
||||
if (pic) DestroyAppxFileStream (pic);
|
||||
pic = nullptr;
|
||||
});
|
||||
LPWSTR lpstr = nullptr;
|
||||
destruct rel ([&lpstr] () {
|
||||
if (lpstr) free (lpstr);
|
||||
lpstr = nullptr;
|
||||
});
|
||||
lpstr = StreamToBase64W (pic, nullptr, 0, nullptr);
|
||||
return lpstr ? lpstr : L"";
|
||||
} break;
|
||||
case PKGTYPE_BUNDLE: {
|
||||
HANDLE pkg = nullptr, pic = nullptr;
|
||||
destruct relp ([&pic, &pkg] () {
|
||||
if (pic) DestroyAppxFileStream (pic);
|
||||
if (pkg) DestroyAppxFileStream (pkg);
|
||||
pkg = nullptr;
|
||||
pic = nullptr;
|
||||
});
|
||||
GetSuitablePackageFromBundle (hReader, nullptr, &pkg);
|
||||
pic = GetFileFromPayloadPackage (pkg, logo ().c_str ());
|
||||
LPWSTR lpstr = nullptr;
|
||||
destruct rel ([&lpstr] () {
|
||||
if (lpstr) free (lpstr);
|
||||
lpstr = nullptr;
|
||||
});
|
||||
lpstr = StreamToBase64W (pic, nullptr, 0, nullptr);
|
||||
return lpstr ? lpstr : L"";
|
||||
} break;
|
||||
}
|
||||
return L"";
|
||||
}
|
||||
bool framework () const { return bool_value (PKG_PROPERTIES_FRAMEWORD); }
|
||||
bool resource_package () const { return bool_value (PKG_PROPERTIES_IS_RESOURCE); }
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
prifilebundle *pbreader = nullptr;
|
||||
bool *usepri = nullptr;
|
||||
bool *resconvert = nullptr;
|
||||
#endif
|
||||
bool enable_pri () const
|
||||
{
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
if (!pbreader) return false;
|
||||
if (!usepri || !*usepri) return false;
|
||||
if (!resconvert) return false;
|
||||
return *resconvert;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
std::wstring pri_get_res (const std::wstring &resname)
|
||||
{
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
if (resname.empty ()) return L"";
|
||||
if (!pbreader) return L"";
|
||||
return pbreader->resource (resname);
|
||||
#else
|
||||
return L"";
|
||||
#endif
|
||||
}
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
properties (HPKGREAD &hReader, prifilebundle *pri, bool *up, bool *resc):
|
||||
base (hReader), pbreader (pri), usepri (up), resconvert (resc) {}
|
||||
#endif
|
||||
};
|
||||
class application: public std::map <std::wstring, std::wstring>
|
||||
{
|
||||
using base = std::map <std::wstring, std::wstring>;
|
||||
public:
|
||||
using base::base;
|
||||
std::wstring user_model_id () const { return this->find (L"AppUserModelID")->second; }
|
||||
friend bool operator == (const application &a1, const application &a2) { return !_wcsicmp (a1.user_model_id ().c_str (), a2.user_model_id ().c_str ()); }
|
||||
friend bool operator != (const application &a1, const application &a2) { return _wcsicmp (a1.user_model_id ().c_str (), a2.user_model_id ().c_str ()); }
|
||||
explicit operator bool () const { return this->user_model_id ().empty (); }
|
||||
application () = default;
|
||||
std::wstring user_model_id () { return this->at (L"AppUserModelID"); }
|
||||
friend bool operator == (application &a1, application &a2) { return !_wcsicmp (a1.user_model_id ().c_str (), a2.user_model_id ().c_str ()); }
|
||||
friend bool operator != (application &a1, application &a2) { return _wcsicmp (a1.user_model_id ().c_str (), a2.user_model_id ().c_str ()); }
|
||||
explicit operator bool () { return this->user_model_id ().empty (); }
|
||||
std::wstring &operator [] (const std::wstring &key)
|
||||
{
|
||||
auto it = this->find (key);
|
||||
@@ -356,6 +633,21 @@ class package_reader
|
||||
{
|
||||
it = this->insert (std::make_pair (key, L"")).first;
|
||||
}
|
||||
if (!enable_pri ()) return it->second;
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
if (IsMsResourcePrefix (it->second.c_str ()))
|
||||
{
|
||||
std::wstring privalue = pri_get_res (it->second);
|
||||
if (!privalue.empty ()) return privalue;
|
||||
return it->second;
|
||||
}
|
||||
else if (std::find (g_filepathitems.begin (), g_filepathitems.end (), it->first) != g_filepathitems.end () && !it->second.empty ())
|
||||
{
|
||||
std::wstring privalue = pri_get_res (it->second);
|
||||
if (!privalue.empty ()) return privalue;
|
||||
return it->second;
|
||||
}
|
||||
#endif
|
||||
return it->second;
|
||||
}
|
||||
typename base::iterator find_case_insensitive (const std::wstring &key)
|
||||
@@ -376,6 +668,124 @@ class package_reader
|
||||
}
|
||||
return this->end ();
|
||||
}
|
||||
std::wstring at (const std::wstring &key)
|
||||
{
|
||||
auto it = this->find_case_insensitive (key);
|
||||
if (it == this->end ()) throw std::out_of_range ("application::at: key not found");
|
||||
if (!enable_pri ()) return it->second;
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
if (IsMsResourcePrefix (it->second.c_str ()))
|
||||
{
|
||||
std::wstring privalue = pri_get_res (it->second);
|
||||
if (!privalue.empty ()) return privalue;
|
||||
}
|
||||
#endif
|
||||
return it->second;
|
||||
}
|
||||
std::wstring newat (const std::wstring &key, bool to_pri_string = true)
|
||||
{
|
||||
auto it = this->find (key);
|
||||
if (it == this->end ())
|
||||
{
|
||||
it = this->insert (std::make_pair (key, L"")).first;
|
||||
}
|
||||
if (!enable_pri () && to_pri_string) return it->second;
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
if (IsMsResourcePrefix (it->second.c_str ()))
|
||||
{
|
||||
std::wstring privalue = pri_get_res (it->second);
|
||||
if (!privalue.empty ()) return privalue;
|
||||
return it->second;
|
||||
}
|
||||
else if (std::find (g_filepathitems.begin (), g_filepathitems.end (), it->first) != g_filepathitems.end () && !it->second.empty ())
|
||||
{
|
||||
std::wstring privalue = pri_get_res (it->second);
|
||||
if (!privalue.empty ()) return privalue;
|
||||
return it->second;
|
||||
}
|
||||
#endif
|
||||
return it->second;
|
||||
}
|
||||
// 仅支持文件
|
||||
std::wstring newat_base64 (const std::wstring &key)
|
||||
{
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
std::wstring value = newat (key);
|
||||
if (std::find (g_filepathitems.begin (), g_filepathitems.end (), key) != g_filepathitems.end () && !value.empty ())
|
||||
{
|
||||
switch (GetPackageType (hReader))
|
||||
{
|
||||
case PKGTYPE_APPX: {
|
||||
HANDLE pic = GetAppxFileFromAppxPackage (hReader, value.c_str ());
|
||||
destruct relp ([&pic] () {
|
||||
if (pic) DestroyAppxFileStream (pic);
|
||||
pic = nullptr;
|
||||
});
|
||||
LPWSTR lpstr = nullptr;
|
||||
destruct rel ([&lpstr] () {
|
||||
if (lpstr) free (lpstr);
|
||||
lpstr = nullptr;
|
||||
});
|
||||
lpstr = StreamToBase64W (pic, nullptr, 0, nullptr);
|
||||
return lpstr ? lpstr : L"";
|
||||
} break;
|
||||
case PKGTYPE_BUNDLE: {
|
||||
HANDLE pkg = nullptr, pic = nullptr;
|
||||
destruct relp ([&pic, &pkg] () {
|
||||
if (pic) DestroyAppxFileStream (pic);
|
||||
if (pkg) DestroyAppxFileStream (pkg);
|
||||
pkg = nullptr;
|
||||
pic = nullptr;
|
||||
});
|
||||
GetSuitablePackageFromBundle (hReader, nullptr, &pkg);
|
||||
pic = GetFileFromPayloadPackage (pkg, value.c_str ());
|
||||
LPWSTR lpstr = nullptr;
|
||||
destruct rel ([&lpstr] () {
|
||||
if (lpstr) free (lpstr);
|
||||
lpstr = nullptr;
|
||||
});
|
||||
lpstr = StreamToBase64W (pic, nullptr, 0, nullptr);
|
||||
return lpstr ? lpstr : L"";
|
||||
} break;
|
||||
}
|
||||
return L"";
|
||||
}
|
||||
else return L"";
|
||||
#else
|
||||
return L"";
|
||||
#endif
|
||||
}
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
HPKGREAD hReader = nullptr;
|
||||
prifilebundle *pbreader = nullptr;
|
||||
bool *usepri = nullptr;
|
||||
bool *resconvert = nullptr;
|
||||
#endif
|
||||
bool enable_pri () const
|
||||
{
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
if (!pbreader) return false;
|
||||
if (!usepri || !*usepri) return false;
|
||||
if (!resconvert) return false;
|
||||
return *resconvert;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
std::wstring pri_get_res (const std::wstring &resname)
|
||||
{
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
if (resname.empty ()) return L"";
|
||||
if (!pbreader) return L"";
|
||||
return pbreader->resource (resname);
|
||||
#else
|
||||
return L"";
|
||||
#endif
|
||||
}
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
application (HPKGREAD hReader, prifilebundle *pri, bool *up, bool *resc):
|
||||
hReader (hReader), pbreader (pri), usepri (up), resconvert (resc) {}
|
||||
#endif
|
||||
};
|
||||
class applications
|
||||
{
|
||||
@@ -405,7 +815,11 @@ class package_reader
|
||||
for (size_t i = 0; i < hMapList->dwSize; i ++)
|
||||
{
|
||||
HLIST_PVOID &hKeyValues = ((HLIST_PVOID *)hMapList->alpVoid) [i];
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
application app (hReader, pbreader, usepri, resconvert);
|
||||
#else
|
||||
application app;
|
||||
#endif
|
||||
for (size_t j = 0; j < hKeyValues->dwSize; j ++)
|
||||
{
|
||||
HPAIR_PVOID &hPair = ((HPAIR_PVOID *)hKeyValues->alpVoid) [j];
|
||||
@@ -418,6 +832,13 @@ class package_reader
|
||||
}
|
||||
return apps.size ();
|
||||
}
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
prifilebundle *pbreader = nullptr;
|
||||
bool *usepri = nullptr;
|
||||
bool *resconvert = nullptr;
|
||||
applications (HPKGREAD &hReader, prifilebundle *pri, bool *up, bool *resc):
|
||||
hReader (hReader), pbreader (pri), usepri (up), resconvert (resc) { hList = GetPackageApplications (hReader); }
|
||||
#endif
|
||||
};
|
||||
class capabilities: public base_subitems
|
||||
{
|
||||
@@ -569,7 +990,16 @@ class package_reader
|
||||
{
|
||||
file (fpath);
|
||||
}
|
||||
~package_reader () { DestroyPackageReader (hReader); hReader = nullptr; }
|
||||
~package_reader ()
|
||||
{
|
||||
DestroyPackageReader (hReader);
|
||||
hReader = nullptr;
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
pribundlereader.destroy ();
|
||||
for (auto &it : prifilestreams) if (it != nullptr) DestroyAppxFileStream (it);
|
||||
prifilestreams.clear ();
|
||||
#endif
|
||||
}
|
||||
std::wstring file () const { return filepath; }
|
||||
bool file (const std::wstring &path)
|
||||
{
|
||||
@@ -581,12 +1011,64 @@ class package_reader
|
||||
// PKGROLE_* 前缀常量
|
||||
WORD package_role () const { return GetPackageRole (hReader); }
|
||||
identity get_identity () { return identity (hReader); }
|
||||
properties get_properties () { return properties (hReader); }
|
||||
applications get_applications () { return applications (hReader); }
|
||||
properties get_properties ()
|
||||
{
|
||||
return properties (hReader
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
,
|
||||
&pribundlereader,
|
||||
&usepri,
|
||||
&resswitch
|
||||
#endif
|
||||
);
|
||||
}
|
||||
applications get_applications ()
|
||||
{
|
||||
return applications (hReader
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
,
|
||||
&pribundlereader,
|
||||
&usepri,
|
||||
&resswitch
|
||||
#endif
|
||||
);
|
||||
}
|
||||
capabilities get_capabilities () { return capabilities (hReader); }
|
||||
dependencies get_dependencies () { return dependencies (hReader); }
|
||||
resources get_resources () { return resources (hReader); }
|
||||
prerequisites get_prerequisites () { return prerequisites (hReader); }
|
||||
// 是否允许使用 PRI
|
||||
bool use_pri () const
|
||||
{
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
return usepri;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
// 是否允许使用 PRI
|
||||
bool use_pri (bool value)
|
||||
{
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
bool laststatus = usepri;
|
||||
usepri = value;
|
||||
if (laststatus ^ usepri) initpri ();
|
||||
return usepri;
|
||||
#else
|
||||
return usepri = false;
|
||||
#endif
|
||||
}
|
||||
// 是否自动从 PRI 中提取资源
|
||||
bool enable_pri_convert () const { return resswitch; }
|
||||
// 是否自动从 PRI 中提取资源
|
||||
bool enable_pri_convert (bool value)
|
||||
{
|
||||
#ifdef _PRI_READER_CLI_HEADER_
|
||||
return resswitch = value;
|
||||
#else
|
||||
return resswitch = false;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
BIN
pkgread/pkgread.rc
Normal file
BIN
pkgread/pkgread.rc
Normal file
Binary file not shown.
@@ -92,6 +92,7 @@
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>urlmon.lib;crypt32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@@ -122,6 +123,7 @@
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>urlmon.lib;crypt32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@@ -145,18 +147,18 @@
|
||||
<Text Include="ReadMe.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\priformatcli\priformatcli\priformatcli.h" />
|
||||
<ClInclude Include="dynarr.h" />
|
||||
<ClInclude Include="localeex.h" />
|
||||
<ClInclude Include="norstr.h" />
|
||||
<ClInclude Include="pkgread.h" />
|
||||
<ClInclude Include="raii.h" />
|
||||
<ClInclude Include="readobj.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="resource1.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="stringres.h" />
|
||||
<ClInclude Include="syncutil.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
<ClInclude Include="themeinfo.h" />
|
||||
<ClInclude Include="version.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -185,6 +187,9 @@
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="pkgread.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
||||
@@ -33,9 +33,6 @@
|
||||
<ClInclude Include="version.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="stringres.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
@@ -54,7 +51,10 @@
|
||||
<ClInclude Include="localeex.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\priformatcli\priformatcli\priformatcli.h">
|
||||
<ClInclude Include="resource1.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="themeinfo.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
@@ -72,4 +72,9 @@
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="pkgread.rc">
|
||||
<Filter>资源文件</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -209,7 +209,6 @@ template <typename ComInterface> class com_info_quote
|
||||
private:
|
||||
IComInterface &icom = nullptr;
|
||||
protected:
|
||||
ComInterface *pointer () const noexcept { return icom; }
|
||||
template <typename Fn> std::wstring get (_In_ Fn func) const
|
||||
{
|
||||
if (!icom) return L"";
|
||||
@@ -254,6 +253,7 @@ template <typename ComInterface> class com_info_quote
|
||||
com_info_quote (com_info_quote &&) noexcept = default;
|
||||
com_info_quote &operator = (com_info_quote &&) noexcept = default;
|
||||
bool valid () const { return !!icom; }
|
||||
ComInterface *pointer () const noexcept { return icom; }
|
||||
};
|
||||
namespace appx_info
|
||||
{
|
||||
@@ -703,6 +703,34 @@ namespace appx_info
|
||||
}
|
||||
UINT64 size () const { return get <UINT64> (&Interface::GetSize); }
|
||||
};
|
||||
enum class ResourceType
|
||||
{
|
||||
unknown = 0b00,
|
||||
language = 0b01,
|
||||
scale = 0b10,
|
||||
both = 0b11
|
||||
};
|
||||
struct resource
|
||||
{
|
||||
ResourceType restype = ResourceType::unknown;
|
||||
APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE pkgtype = APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_APPLICATION;
|
||||
struct resource_content
|
||||
{
|
||||
std::vector <std::wnstring> languages;
|
||||
std::vector <uint32_t> scales;
|
||||
resource_content (const std::vector <std::wnstring> &langs): languages (langs) {}
|
||||
resource_content (const std::vector <uint32_t> &ss): scales (ss) {}
|
||||
resource_content (const std::vector <std::wnstring> &langs, const std::vector <uint32_t> &ss): languages (langs), scales (ss) {}
|
||||
resource_content () = default;
|
||||
} resvalue;
|
||||
resource (const std::vector <std::wnstring> &languages):
|
||||
restype (ResourceType::language), resvalue (languages) {}
|
||||
resource (const std::vector <uint32_t> &ss):
|
||||
restype (ResourceType::scale), resvalue (ss) {}
|
||||
resource (const std::vector <std::wnstring> &langs, const std::vector <uint32_t> &ss):
|
||||
restype (ResourceType::both), resvalue (langs, ss) {}
|
||||
resource (): restype (ResourceType::unknown), resvalue () {}
|
||||
};
|
||||
class appx_iditems: virtual public com_info <IAppxBundleManifestPackageInfoEnumerator>
|
||||
{
|
||||
using Base = com_info <IAppxBundleManifestPackageInfoEnumerator>;
|
||||
@@ -777,6 +805,33 @@ namespace appx_info
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
size_t resource_info (std::map <std::wnstring, resource> &output) const
|
||||
{
|
||||
output.clear ();
|
||||
std::vector <appx_iditem> items;
|
||||
enumerate (items);
|
||||
for (auto &it : items)
|
||||
{
|
||||
std::wnstring fpath = it.file_name ();
|
||||
auto qres = it.qualified_resources ();
|
||||
std::vector <std::wstring> langs;
|
||||
std::vector <uint32_t> scales;
|
||||
qres.qualified_resources (&langs, &scales);
|
||||
std::vector <std::wnstring> langs_n;
|
||||
for (auto &it_l : langs) langs_n.push_back (it_l);
|
||||
BYTE status = (bool)langs_n.size () << 1 | (bool)scales.size ();
|
||||
switch (status)
|
||||
{
|
||||
case 0b01: output [fpath] = resource (scales); break;
|
||||
case 0b10: output [fpath] = resource (langs_n); break;
|
||||
case 0b11: output [fpath] = resource (langs_n, scales); break;
|
||||
default:
|
||||
case 0b00: output [fpath] = resource (); break;
|
||||
}
|
||||
output [fpath].pkgtype = it.type ();
|
||||
}
|
||||
return output.size ();
|
||||
}
|
||||
};
|
||||
}
|
||||
class appxreader: virtual public com_info_quote <IAppxPackageReader>
|
||||
@@ -1029,6 +1084,98 @@ class bundlereader: virtual public com_info_quote <IAppxBundleReader>
|
||||
if (FAILED (hr)) return hr;
|
||||
return GetAppxPackageReader (ist, output);
|
||||
}
|
||||
HRESULT random_application_package (_Outptr_ IAppxFile **output) const
|
||||
{
|
||||
CComPtr <IAppxBundleManifestPackageInfoEnumerator> iditems;
|
||||
HRESULT hr = get_package_id_items (&iditems);
|
||||
if (FAILED (hr)) return hr;
|
||||
BOOL hc = FALSE;
|
||||
hr = iditems->GetHasCurrent (&hc);
|
||||
bool find = false;
|
||||
std::wstring fname = L"";
|
||||
while (SUCCEEDED (hr) && hc)
|
||||
{
|
||||
CComPtr <IAppxBundleManifestPackageInfo> iditem;
|
||||
hr = iditems->GetCurrent (&iditem);
|
||||
if (SUCCEEDED (hr))
|
||||
{
|
||||
APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE ptype;
|
||||
if (!(SUCCEEDED (iditem->GetPackageType (&ptype)) && ptype == APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE::APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_APPLICATION))
|
||||
{
|
||||
hr = iditems->MoveNext (&hc);
|
||||
continue;
|
||||
}
|
||||
LPWSTR lpfname = nullptr;
|
||||
raii endt ([&lpfname] () {
|
||||
if (lpfname) CoTaskMemFree (lpfname);
|
||||
lpfname = nullptr;
|
||||
});
|
||||
if (SUCCEEDED (iditem->GetFileName (&lpfname)) && lpfname)
|
||||
{
|
||||
fname += lpfname;
|
||||
find = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
hr = iditems->MoveNext (&hc);
|
||||
}
|
||||
if (!find) return FAILED (hr) ? hr : E_FAIL;
|
||||
CComPtr <IAppxFile> afile;
|
||||
return get_payload_package (fname, output);
|
||||
}
|
||||
HRESULT random_resource_package (_Outptr_ IAppxFile **output) const
|
||||
{
|
||||
CComPtr <IAppxBundleManifestPackageInfoEnumerator> iditems;
|
||||
HRESULT hr = get_package_id_items (&iditems);
|
||||
if (FAILED (hr)) return hr;
|
||||
BOOL hc = FALSE;
|
||||
hr = iditems->GetHasCurrent (&hc);
|
||||
bool find = false;
|
||||
std::wstring fname = L"";
|
||||
while (SUCCEEDED (hr) && hc)
|
||||
{
|
||||
CComPtr <IAppxBundleManifestPackageInfo> iditem;
|
||||
hr = iditems->GetCurrent (&iditem);
|
||||
if (SUCCEEDED (hr))
|
||||
{
|
||||
APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE ptype;
|
||||
if (!(SUCCEEDED (iditem->GetPackageType (&ptype)) && ptype == APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE::APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_RESOURCE))
|
||||
{
|
||||
hr = iditems->MoveNext (&hc);
|
||||
continue;
|
||||
}
|
||||
LPWSTR lpfname = nullptr;
|
||||
raii endt ([&lpfname] () {
|
||||
if (lpfname) CoTaskMemFree (lpfname);
|
||||
lpfname = nullptr;
|
||||
});
|
||||
if (SUCCEEDED (iditem->GetFileName (&lpfname)) && lpfname)
|
||||
{
|
||||
fname += lpfname;
|
||||
find = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
hr = iditems->MoveNext (&hc);
|
||||
}
|
||||
if (!find) return FAILED (hr) ? hr : E_FAIL;
|
||||
CComPtr <IAppxFile> afile;
|
||||
return hr = get_payload_package (fname, output);
|
||||
}
|
||||
HRESULT random_application_package (_Outptr_ IStream **output) const
|
||||
{
|
||||
CComPtr <IAppxFile> iaf;
|
||||
HRESULT hr = S_OK;
|
||||
if (FAILED (hr = random_application_package (&iaf))) return hr;
|
||||
return iaf->GetStream (output);
|
||||
}
|
||||
HRESULT random_resource_package (_Outptr_ IStream **output) const
|
||||
{
|
||||
CComPtr <IAppxFile> iaf;
|
||||
HRESULT hr = S_OK;
|
||||
if (FAILED (hr = random_resource_package (&iaf))) return hr;
|
||||
return iaf->GetStream (output);
|
||||
}
|
||||
size_t application_packages (std::function <void (IAppxPackageReader *)> callback) const
|
||||
{
|
||||
CComPtr <IAppxBundleManifestPackageInfoEnumerator> iditems;
|
||||
|
||||
@@ -24,3 +24,12 @@
|
||||
#include <atlbase.h>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <urlmon.h>
|
||||
#include <wincrypt.h>
|
||||
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
40
pkgread/themeinfo.h
Normal file
40
pkgread/themeinfo.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
|
||||
bool IsHighContrastEnabled ()
|
||||
{
|
||||
HIGHCONTRAST hc = {sizeof (HIGHCONTRAST)};
|
||||
if (SystemParametersInfo (SPI_GETHIGHCONTRAST, sizeof (hc), &hc, 0)) return (hc.dwFlags & HCF_HIGHCONTRASTON) != 0;
|
||||
return false;
|
||||
}
|
||||
enum class HighContrastTheme
|
||||
{
|
||||
None,
|
||||
Black,
|
||||
White,
|
||||
Other
|
||||
};
|
||||
HighContrastTheme GetHighContrastTheme ()
|
||||
{
|
||||
HIGHCONTRAST hc = {sizeof (HIGHCONTRAST)};
|
||||
if (!SystemParametersInfo (SPI_GETHIGHCONTRAST, sizeof (hc), &hc, 0)) return HighContrastTheme::None;
|
||||
if (!(hc.dwFlags & HCF_HIGHCONTRASTON)) return HighContrastTheme::None;
|
||||
COLORREF bgColor = GetSysColor (COLOR_WINDOW);
|
||||
COLORREF textColor = GetSysColor (COLOR_WINDOWTEXT);
|
||||
int brightnessBg = (GetRValue (bgColor) + GetGValue (bgColor) + GetBValue (bgColor)) / 3;
|
||||
int brightnessText = (GetRValue (textColor) + GetGValue (textColor) + GetBValue (textColor)) / 3;
|
||||
if (brightnessBg < brightnessText) return HighContrastTheme::Black;
|
||||
else if (brightnessBg > brightnessText) return HighContrastTheme::White;
|
||||
else return HighContrastTheme::Other;
|
||||
}
|
||||
int GetDPI ()
|
||||
{
|
||||
HDC hDC = GetDC (NULL);
|
||||
int DPI_A = (int)(((double)GetDeviceCaps (hDC, 118) / (double)GetDeviceCaps (hDC, 8)) * 100);
|
||||
int DPI_B = (int)(((double)GetDeviceCaps (hDC, 88) / 96) * 100);
|
||||
ReleaseDC (NULL, hDC);
|
||||
if (DPI_A == 100) return DPI_B;
|
||||
else if (DPI_B == 100) return DPI_A;
|
||||
else if (DPI_A == DPI_B) return DPI_A;
|
||||
else return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user