Add ability to unpack and apply acls to package folders in msixmgr.exe (#201)

* Add ability to unpack packages and apply ACLs to the resulting package folders to msixmgr.exe

* Add command to apply acls to already unpacked package. For Unpack command, add logging for invalid package path. Wrap hmodule in smart pointer. Gate ACL logic behind IsApplyACLs

* Reformated logging for invalid package path

* Bug fix for wrapping applyaclsdll module with unique_ptr

* Refactor: move unpack/acl logic out of msixmgr.cpp and into separate files/classes

* Remove classes from UnpackProvider and ApplyACLsProvider

* Bug Fix: ApplyACLs command could not accept package path parameter; Bug fix: use Text<WCHAR> instead of PWSTR

* Use the optional package's publisher, not its entire package family name, when no publisher specified for main package dependency

* Updated Api_AppxManifestReader_OptionalPackage test to reflect bug fix

* Removed logging from ApplyACLsProvider

* Test bug fix: missing command in expectedPublisherValues vector

* Test fix: wrong publisher specified in expectedPublisherValues

* Updated help text; Output info to user on failures

* Revert "Test fix: wrong publisher specified in expectedPublisherValues"

This reverts commit 8c4954c6c167e6c7446055dcbb395a1be80f83f8.

* Checking back in test changes

* Checking back in msixmgr.vcxproj* files

* Output errors in hex; Output error message specific to missing cert

* Added msixmgr.exe dependency ApplyACLs.dll
This commit is contained in:
stephenk-msft 2019-08-20 16:58:11 -07:00 коммит произвёл GitHub
Родитель e6f55f088e
Коммит 3c48599fc2
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
20 изменённых файлов: 447 добавлений и 65 удалений

Двоичные данные
preview/MsixCore/Dependencies/x64/ApplyACLs.dll Normal file

Двоичный файл не отображается.

Двоичные данные
preview/MsixCore/Dependencies/x64/ApplyACLs.pdb Normal file

Двоичный файл не отображается.

Двоичные данные
preview/MsixCore/Dependencies/x86/ApplyACLs.dll Normal file

Двоичный файл не отображается.

Двоичные данные
preview/MsixCore/Dependencies/x86/ApplyACLs.pdb Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,51 @@
#include "MSIXWindows.hpp"
#include "ApplyACLsProvider.hpp"
#include "msixmgrLogger.hpp"
#include "..\msixmgrLib\GeneralUtil.hpp"
#include <string>
#include <iostream>
#include <vector>
#include <TraceLoggingProvider.h>
#include "InstallUI.hpp"
using namespace MsixCoreLib;
using namespace std;
namespace MsixCoreLib
{
HRESULT ApplyACLs(
_In_ std::vector<std::wstring> packageFolders)
{
auto autoFreeLibrary = [](HMODULE* module)
{
if (module != nullptr)
{
FreeLibrary(*module);
}
};
std::unique_ptr<HMODULE, decltype(autoFreeLibrary)>
applyACLsDll(nullptr, autoFreeLibrary);
HMODULE applyACLsLocal = LoadLibrary(L"applyacls.dll");
applyACLsDll.reset(&applyACLsLocal);
if (applyACLsDll == nullptr)
{
std::wcout << "Failed to load applyacls.dll. Please confirm the dll is next to this exe" << std::endl;
}
typedef HRESULT(STDMETHODCALLTYPE *APPLYACLSTOPACKAGEFOLDER)(PCWSTR folderPath);
APPLYACLSTOPACKAGEFOLDER ApplyACLsToPackageFolder =
reinterpret_cast<APPLYACLSTOPACKAGEFOLDER>
(GetProcAddress(*applyACLsDll, "ApplyACLsToPackageFolder"));
for (auto folder : packageFolders)
{
RETURN_IF_FAILED(ApplyACLsToPackageFolder(folder.c_str()));
}
return S_OK;
}
}

Просмотреть файл

@ -0,0 +1,12 @@
#pragma once
#include <string>
#include <vector>
namespace MsixCoreLib
{
HRESULT ApplyACLs(
_In_ std::vector<std::wstring> packageFolders);
}

Просмотреть файл

@ -78,7 +78,7 @@ std::map<std::wstring, Options, CaseInsensitiveLess> CommandLineInterface::s_opt
{
L"-Unpack",
Options(false, IDS_STRING_HELP_OPTION_UNPACK,
[&](CommandLineInterface* commandLineInterface, const std::string& packagePath)
[&](CommandLineInterface* commandLineInterface, const std::string&)
{
if (commandLineInterface->m_operationType != OperationType::Undefined)
{
@ -91,7 +91,7 @@ std::map<std::wstring, Options, CaseInsensitiveLess> CommandLineInterface::s_opt
{
{
L"-packagePath",
Option(true, IDS_STRING_HELP_OPTION_UNPACK_PATH,
Option(true, IDS_STRING_HELP_OPTION_UNPACK_PACKAGEPATH,
[&](CommandLineInterface* commandLineInterface, const std::string& packagePath)
{
if (commandLineInterface->m_operationType != OperationType::Unpack)
@ -130,6 +130,34 @@ std::map<std::wstring, Options, CaseInsensitiveLess> CommandLineInterface::s_opt
}
})
},
{
L"-ApplyACLs",
Options(false, IDS_STRING_HELP_OPTION_APPLYACLS,
[&](CommandLineInterface* commandLineInterface, const std::string&)
{
if (commandLineInterface->m_operationType != OperationType::Undefined)
{
return E_INVALIDARG;
}
commandLineInterface->m_operationType = OperationType::ApplyACLs;
return S_OK;
},
{
{
L"-packagePath",
Option(true, IDS_STRING_HELP_OPTION_APPLYACLS_PACKAGEPATH,
[&](CommandLineInterface* commandLineInterface, const std::string& packagePath)
{
if (commandLineInterface->m_operationType != OperationType::ApplyACLs)
{
return E_INVALIDARG;
}
commandLineInterface->m_packageFilePath = utf8_to_utf16(packagePath);
return S_OK;
}),
}
})
},
{
L"-?",
Options(false, IDS_STRING_HELP_OPTION_HELP,
@ -148,12 +176,23 @@ std::map<std::wstring, std::wstring> CommandLineInterface::s_optionAliases =
void CommandLineInterface::DisplayHelp()
{
std::wcout << GetStringResource(IDS_STRING_HELPTEXT) << std::endl;
std::wcout << GetStringResource(IDS_STRING_HELPTEXT_USAGE) << std::endl;
std::wcout << GetStringResource(IDS_STRING_HELPTEXT_DESCRIPTION) << std::endl;
std::wcout << GetStringResource(IDS_STRING_HELPTEXT_OPTIONS) << std::endl;
for (const auto& option : CommandLineInterface::s_options)
{
std::wcout << L"\t" << std::left << std::setfill(L' ') << std::setw(5) <<
option.first << L": " << GetStringResource(option.second.Help) << std::endl;
if (option.second.HasSuboptions)
{
for (const auto& suboption : option.second.Suboptions)
{
std::wcout << L"\t\t" << std::left << std::setfill(L' ') << std::setw(5) <<
suboption.first << L": " << GetStringResource(suboption.second.Help) << std::endl;
}
}
}
}
@ -209,8 +248,8 @@ HRESULT CommandLineInterface::Init()
auto suboptions = option->second.Suboptions;
while (index < m_argc)
{
std::wstring optionString = utf8_to_utf16(m_argv[index]);
auto suboption = suboptions.find(optionString);
std::wstring suboptionString = utf8_to_utf16(m_argv[index]);
auto suboption = suboptions.find(suboptionString);
if (suboption == suboptions.end())
{
TraceLoggingWrite(g_MsixUITraceLoggingProvider,
@ -226,9 +265,9 @@ HRESULT CommandLineInterface::Init()
{
return E_INVALIDARG;
}
parameter = m_argv[index];
suboptionParameter = m_argv[index];
}
RETURN_IF_FAILED(option->second.DefaultCallback(this, parameter));
RETURN_IF_FAILED(suboption->second.Callback(this, suboptionParameter));
++index;
}

Просмотреть файл

@ -30,24 +30,6 @@ struct Option
CallbackFunction Callback;
};
struct Options
{
using CallbackFunction = std::function<HRESULT(CommandLineInterface* commandLineInterface, const std::string& value)>;
Options(bool takesParam, const UINT help, CallbackFunction defaultCallback) : Help(help), DefaultCallback(defaultCallback), TakesParameter(takesParam), HasSuboptions(false) {}
Options(bool takesParam, const UINT help, CallbackFunction defaultCallback, std::map<std::wstring, Option> suboptions) : Help(help), DefaultCallback(defaultCallback), TakesParameter(takesParam), Suboptions(suboptions)
{
HasSuboptions = !Suboptions.empty();
}
bool HasSuboptions;
bool TakesParameter;
std::wstring Name;
UINT Help;
CallbackFunction DefaultCallback;
std::map<std::wstring, Option> Suboptions;
};
struct CaseInsensitiveLess
{
struct CaseInsensitiveCompare
@ -66,6 +48,24 @@ struct CaseInsensitiveLess
}
};
struct Options
{
using CallbackFunction = std::function<HRESULT(CommandLineInterface* commandLineInterface, const std::string& value)>;
Options(bool takesParam, const UINT help, CallbackFunction defaultCallback) : Help(help), DefaultCallback(defaultCallback), TakesParameter(takesParam), HasSuboptions(false) {}
Options(bool takesParam, const UINT help, CallbackFunction defaultCallback, std::map<std::wstring, Option, CaseInsensitiveLess> suboptions) : Help(help), DefaultCallback(defaultCallback), TakesParameter(takesParam), Suboptions(suboptions)
{
HasSuboptions = !Suboptions.empty();
}
bool HasSuboptions;
bool TakesParameter;
std::wstring Name;
UINT Help;
CallbackFunction DefaultCallback;
std::map<std::wstring, Option, CaseInsensitiveLess> Suboptions;
};
/// Parses the command line specified and creates a request.
class CommandLineInterface
{
@ -81,8 +81,10 @@ public:
void DisplayHelp();
HRESULT Init();
bool IsQuietMode() { return m_quietMode; }
bool IsApplyACLs() { return m_applyACLs; }
std::wstring GetPackageFilePathToInstall() { return m_packageFilePath; }
std::wstring GetPackageFullName() { return m_packageFullName; }
std::wstring GetUnpackDestination() { return m_unpackDestination; }
OperationType GetOperationType() { return m_operationType; }
private:
int m_argc = 0;

Просмотреть файл

@ -5,6 +5,7 @@
#include <CryptoProvider.hpp>
#include <TraceLoggingProvider.h>
#include "MsixTraceLoggingProvider.hpp"
#include <memory>
namespace MsixCoreLib
{

Просмотреть файл

@ -0,0 +1,170 @@
#include "MSIXWindows.hpp"
#include "UnpackProvider.hpp"
#include "ApplyACLsProvider.hpp"
#include <TraceLoggingProvider.h>
#include "msixmgrLogger.hpp"
#include "..\msixmgrLib\GeneralUtil.hpp"
#include "MSIXWindows.hpp"
#include <shlobj_core.h>
#include <CommCtrl.h>
#include <map>
#include <iostream>
using namespace MsixCoreLib;
using namespace std;
namespace MsixCoreLib
{
HRESULT UnpackPackage(
_In_ std::wstring packageFilePath,
_In_ std::wstring destination,
_In_ bool isApplyACLs)
{
MSIX_PACKUNPACK_OPTION unpackOption = MSIX_PACKUNPACK_OPTION_UNPACKWITHFLATSTRUCTURE;
MSIX_VALIDATION_OPTION validationOption = MSIX_VALIDATION_OPTION_FULL;
auto unpackDestinationUTF8 = utf16_to_utf8(destination);
std::vector<char> unpackDestination(unpackDestinationUTF8.c_str(), unpackDestinationUTF8.c_str() + unpackDestinationUTF8.size() + 1);
ComPtr<IAppxFactory> factory;
RETURN_IF_FAILED(CoCreateAppxFactoryWithHeap(MyAllocate, MyFree, validationOption, &factory));
ComPtr<IStream> stream;
RETURN_IF_FAILED(CreateStreamOnFileUTF16(packageFilePath.c_str(), true, &stream));
ComPtr<IAppxPackageReader> reader;
RETURN_IF_FAILED(factory->CreatePackageReader(stream.Get(), &reader));
RETURN_IF_FAILED(UnpackPackageFromPackageReader(
unpackOption,
reader.Get(),
&unpackDestination[0]));
if (isApplyACLs)
{
std::vector<std::wstring> packageFolders;
Text<WCHAR> packageFullName;
ComPtr<IAppxManifestReader> manifestReader;
RETURN_IF_FAILED(reader->GetManifest(&manifestReader));
ComPtr<IAppxManifestPackageId> packageId;
RETURN_IF_FAILED(manifestReader->GetPackageId(&packageId));
RETURN_IF_FAILED(packageId->GetPackageFullName(&packageFullName));
std::wstring packageFolderName = destination + L"\\" + packageFullName.Get();
packageFolders.push_back(packageFolderName);
RETURN_IF_FAILED(ApplyACLs(packageFolders));
}
return S_OK;
}
HRESULT UnpackBundle(
_In_ std::wstring packageFilePath,
_In_ std::wstring destination,
_In_ bool isApplyACLs)
{
MSIX_APPLICABILITY_OPTIONS applicabilityOption = static_cast<MSIX_APPLICABILITY_OPTIONS>(MSIX_APPLICABILITY_NONE);
MSIX_PACKUNPACK_OPTION unpackOption = MSIX_PACKUNPACK_OPTION_UNPACKWITHFLATSTRUCTURE;
MSIX_VALIDATION_OPTION validationOption = MSIX_VALIDATION_OPTION_FULL;
auto unpackDestinationUTF8 = utf16_to_utf8(destination);
std::vector<char> unpackDestination(unpackDestinationUTF8.c_str(), unpackDestinationUTF8.c_str() + unpackDestinationUTF8.size() + 1);
ComPtr<IAppxBundleFactory> factory;
RETURN_IF_FAILED(CoCreateAppxBundleFactoryWithHeap(MyAllocate, MyFree, validationOption, applicabilityOption, &factory));
ComPtr<IStream> stream;
RETURN_IF_FAILED(CreateStreamOnFileUTF16(packageFilePath.c_str(), true, &stream));
ComPtr<IAppxBundleReader> reader;
RETURN_IF_FAILED(factory->CreateBundleReader(stream.Get(), &reader));
RETURN_IF_FAILED(UnpackBundleFromBundleReader(
unpackOption,
reader.Get(),
&unpackDestination[0]));
std::vector<std::wstring> packageFolders;
if (isApplyACLs)
{
ComPtr<IAppxBundleManifestReader> bundleManifestReader;
RETURN_IF_FAILED(reader->GetManifest(&bundleManifestReader));
// Determine the name of the folder created for the unpacked bundle, and add this name to our list of package folders
Text<WCHAR> bundleFullName;
ComPtr<IAppxManifestPackageId> bundleId;
RETURN_IF_FAILED(bundleManifestReader->GetPackageId(&bundleId));
RETURN_IF_FAILED(bundleId->GetPackageFullName(&bundleFullName));
std::wstring bundleFolderName = destination + L"\\" + bundleFullName.Get();
packageFolders.push_back(bundleFolderName);
// Now we must determine the names of the folders created for each package in the bundle
// To do so, we can use the bundle reader's GetPayloadPackages API, which will tell us the names of all the package FILES
// that were unpacked. While we could then create a stream for each of these files to determine their package full names, this could
// be potentially costly. Instead, we will use the bundle manifest reader's GetPackageInfoItems API, which will give us easy access
// to <package file name, package full name> pairs for ALL packages in the bundle (not necessarily the ones that were unpacked). Once
// we have built up a map of these file name -> full name pairs, we can quickly determine the package full name for each file name
// returned by GetPayloadPackages. Append the package full name to the destination to get the folder name for the unpacked package, then
// add this folder name to our list of package folder names.
std::map <std::wstring, std::wstring> packagesMap;
ComPtr<IAppxBundleManifestPackageInfoEnumerator> packages;
ComPtr<IAppxBundleManifestPackageInfo> currentPackage;
RETURN_IF_FAILED(bundleManifestReader->GetPackageInfoItems(&packages));
BOOL hasCurrent = FALSE;
// Populate the packagesMap with package file name, package full name pairs
for (packages->GetHasCurrent(&hasCurrent); hasCurrent; packages->MoveNext(&hasCurrent))
{
RETURN_IF_FAILED(packages->GetCurrent(&currentPackage));
ComPtr<IAppxManifestPackageId> manifestPackageID;
RETURN_IF_FAILED(currentPackage->GetPackageId(&manifestPackageID));
Text<WCHAR> packageFullName;
RETURN_IF_FAILED(manifestPackageID->GetPackageFullName(&packageFullName));
Text<WCHAR> packageFileName;
RETURN_IF_FAILED(currentPackage->GetFileName(&packageFileName));
std::wstring stdPackageFileName = packageFileName.Get();
std::wstring stdPackageFullName = packageFullName.Get();
packagesMap[stdPackageFileName] = stdPackageFullName;
}
// Use GetPayloadPackages to enumerate over the package files that actually got unpacked
// after applicability logic was applied.
hasCurrent = false;
ComPtr<IAppxFilesEnumerator> packageFilesEnumerator;
RETURN_IF_FAILED(reader->GetPayloadPackages(&packageFilesEnumerator));
RETURN_IF_FAILED(packageFilesEnumerator->GetHasCurrent(&hasCurrent));
while (hasCurrent)
{
ComPtr<IAppxFile> file;
RETURN_IF_FAILED(packageFilesEnumerator->GetCurrent(&file));
Text<WCHAR> packageFileName;
RETURN_IF_FAILED(file->GetName(&packageFileName));
std::wstring stdPackageFileName = packageFileName.Get();
auto packageFullName = packagesMap[packageFileName.Get()];
std::wstring packageFolderName = destination + L"\\" + packageFullName;
packageFolders.push_back(packageFolderName);
RETURN_IF_FAILED(packageFilesEnumerator->MoveNext(&hasCurrent));
}
RETURN_IF_FAILED(ApplyACLs(packageFolders));
}
return S_OK;
}
}

Просмотреть файл

@ -0,0 +1,16 @@
#pragma once
#include <string>
#include <vector>
namespace MsixCoreLib
{
HRESULT UnpackPackage(
_In_ std::wstring packageFilePath,
_In_ std::wstring destination,
_In_ bool isApplyACLs);
HRESULT UnpackBundle(
_In_ std::wstring packageFilePath,
_In_ std::wstring destination,
_In_ bool isApplyACLs);
}

Просмотреть файл

@ -16,6 +16,9 @@
#include "..\msixmgrLib\GeneralUtil.hpp"
#include "resource.h"
#include <VersionHelpers.h>
#include "UnpackProvider.hpp"
#include "ApplyACLsProvider.hpp"
#include "MsixErrors.hpp"
#include <msixmgrActions.hpp>
using namespace std;
@ -137,6 +140,49 @@ int main(int argc, char * argv[])
std::cout << numPackages << " Package(s) found" << std::endl;
return S_OK;
}
case OperationType::Unpack:
{
HRESULT hr = S_OK;
auto packageFilePath = cli.GetPackageFilePathToInstall();
auto unpackDestination = cli.GetUnpackDestination();
if (IsPackageFile(packageFilePath))
{
hr = MsixCoreLib::UnpackPackage(packageFilePath, unpackDestination, cli.IsApplyACLs());
}
else if (IsBundleFile(packageFilePath))
{
hr = MsixCoreLib::UnpackBundle(packageFilePath, unpackDestination, cli.IsApplyACLs());
}
else
{
std::wcout << std::endl;
std::wcout << "Invalid package path: " << packageFilePath << std::endl;
std::wcout << "Please confirm the given package path is an .appx, .appxbundle, .msix, or .msixbundle file" << std::endl;
std::wcout << std::endl;
return E_INVALIDARG;
}
if (FAILED(hr))
{
std::wcout << std::endl;
std::wcout << L"Failed with HRESULT 0x" << std::hex << hr << L" when trying to unpack " << packageFilePath << std::endl;
if (hr == static_cast<HRESULT>(MSIX::Error::CertNotTrusted))
{
std::wcout << L"Please confirm that the certificate has been installed for this package" << std::endl;
}
std::wcout << std::endl;
}
return hr;
}
case OperationType::ApplyACLs:
{
std::vector<std::wstring> packageFolders;
packageFolders.push_back(cli.GetPackageFilePathToInstall()); // we're not actually installing anything. The API just returns the file path name we need.
RETURN_IF_FAILED(MsixCoreLib::ApplyACLs(packageFolders));
return S_OK;
}
default:
return E_NOT_SET;
}

Просмотреть файл

@ -75,7 +75,7 @@ BEGIN
IDS_STRING_HELP_OPTION_FINDPACKAGE
"Find package with the specific package full name."
IDS_STRING_HELP_OPTION_HELP "Display this help text."
IDS_STRING_HELPTEXT " Usage:\n ------\n \tmsixmgr.exe [options]\n\n Description:\n-----------\n \tInstalls an msix package, removes an msix package or queries for msix packages\n\n Options:\n -------\n"
IDS_STRING_HELPTEXT_USAGE " Usage:\n ------\n \tmsixmgr.exe [options]\n \tmsixmgr.exe -Unpack -packagePath <path to package> -destination <output folder> [-applyacls]\n \tmsixmgr.exe -ApplyACLs -packagePath <package folder path>\n\n"
IDS_STRING_UI_CANCEL "Cancel"
END
@ -96,11 +96,16 @@ BEGIN
IDS_STRING_REINSTALLAPP "Reinstall"
IDS_RUNFULLTRUST_CAPABILITY "Uses all system resources"
IDS_STRING_ERROR_MSG "App installation failed with error message: An internal error occurred with error 0x"
IDS_STRING_HELP_OPTION_UNPACK "Unpack package - Extract package contents to folder"
IDS_STRING_HELP_OPTION_UNPACK_PATH "Path to package to unpack"
IDS_STRING_HELP_OPTION_UNPACK_DESTINATION "Path to location where package should be unpacked to"
IDS_STRING_HELP_OPTION_UNPACK_APPLYACLS "Apply ACLs - apply ACLs to the folder created by unpack"
END
IDS_STRING_HELPTEXT_DESCRIPTION " Description:\n -----------\n \tInstalls an msix package, removes an msix package or queries for msix packages.\n \tMay also unpack msix packages and apply ACLs to the resulting package folders\n\n"
IDS_STRING_HELPTEXT_OPTIONS " Options:\n -------\n"
IDS_STRING_HELP_OPTION_UNPACK "Unpack a package (.appx, .msix, .appxbundle, .msixbundle) and extract its contents to a folder."
IDS_STRING_HELP_OPTION_UNPACK_PACKAGEPATH "the path to the package to unpack"
IDS_STRING_HELP_OPTION_UNPACK_DESTINATION "the directory to place the resulting package folder(s) in"
IDS_STRING_HELP_OPTION_UNPACK_APPLYACLS "optional parameter that applies ACLs to the resulting package folder(s) and their parent folder"
IDS_STRING_HELP_OPTION_APPLYACLS "Applies ACLs to a package folder (an unpacked package)"
IDS_STRING_HELP_OPTION_APPLYACLS_PACKAGEPATH "the path to the folder to apply acls to"
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////

Просмотреть файл

@ -200,15 +200,19 @@
</Manifest>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="ApplyACLsProvider.hpp" />
<ClInclude Include="CommandLineInterface.hpp" />
<ClInclude Include="InstallUI.hpp" />
<ClInclude Include="resource.h" />
<ClInclude Include="UnpackProvider.hpp" />
<ClInclude Include="Util.hpp" />
<ClInclude Include="msixmgrLogger.hpp" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="ApplyACLsProvider.cpp" />
<ClCompile Include="InstallUI.cpp" />
<ClCompile Include="CommandLineInterface.cpp" />
<ClCompile Include="UnpackProvider.cpp" />
<ClCompile Include="Util.cpp" />
<ClCompile Include="msixmgr.cpp" />
<ClCompile Include="msixmgrLogger.cpp" />

Просмотреть файл

@ -30,6 +30,12 @@
<ClInclude Include="Util.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UnpackProvider.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ApplyACLsProvider.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="InstallUI.cpp">
@ -47,6 +53,12 @@
<ClCompile Include="Util.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ApplyACLsProvider.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UnpackProvider.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="msixmgr.rc">

Просмотреть файл

@ -13,7 +13,7 @@
#define IDS_STRING_HELP_OPTION_FINDALLPACKAGES 107
#define IDS_STRING_HELP_OPTION_FINDPACKAGE 108
#define IDS_STRING_HELP_OPTION_HELP 109
#define IDS_STRING_HELPTEXT 110
#define IDS_STRING_HELPTEXT_USAGE 110
#define IDS_STRING_UI_CANCEL 111
#define IDS_STRING_UI_CLOSE 112
#define IDS_STRING_UI_TITLE 113
@ -28,10 +28,14 @@
#define IDS_STRING_REINSTALLAPP 122
#define IDS_RUNFULLTRUST_CAPABILITY 123
#define IDS_STRING_ERROR_MSG 124
#define IDS_STRING_HELP_OPTION_UNPACK 125
#define IDS_STRING_HELP_OPTION_UNPACK_PATH 126
#define IDS_STRING_HELP_OPTION_UNPACK_DESTINATION 127
#define IDS_STRING_HELP_OPTION_UNPACK_APPLYACLS 128
#define IDS_STRING_HELPTEXT_DESCRIPTION 125
#define IDS_STRING_HELPTEXT_OPTIONS 126
#define IDS_STRING_HELP_OPTION_UNPACK 127
#define IDS_STRING_HELP_OPTION_UNPACK_PACKAGEPATH 128
#define IDS_STRING_HELP_OPTION_UNPACK_DESTINATION 129
#define IDS_STRING_HELP_OPTION_UNPACK_APPLYACLS 130
#define IDS_STRING_HELP_OPTION_APPLYACLS 131
#define IDS_STRING_HELP_OPTION_APPLYACLS_PACKAGEPATH 132
// Next default values for new objects
//

Просмотреть файл

@ -196,6 +196,24 @@ namespace MsixCoreLib
return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER, dwlConditionMask);
}
bool EndsWith(std::wstring const &fullString, std::wstring const &ending) {
if (fullString.length() >= ending.length()) {
return (0 == fullString.compare(fullString.length() - ending.length(), ending.length(), ending));
}
else {
return false;
}
}
bool IsPackageFile(std::wstring const& path)
{
return EndsWith(path, L".appx") || EndsWith(path, L".msix");
}
bool IsBundleFile(std::wstring const& path)
{
return EndsWith(path, L".appxbundle") || EndsWith(path, L".msixbundle");
}
/// Replaces all oldchars in input with newchar
///

Просмотреть файл

@ -55,7 +55,7 @@ namespace MsixCoreLib
/// Returns the current user sid as a string.
///
/// @param userSidString - current user sid stirng
/// @param userSidString - current user sid string
HRESULT GetCurrentUserSidString(std::wstring & userSidString);
/// Determines if the currently running OS is Windows 10 RS3 or later.
@ -63,6 +63,23 @@ namespace MsixCoreLib
/// https://docs.microsoft.com/en-us/windows/desktop/SysInfo/targeting-your-application-at-windows-8-1
BOOL IsWindows10RS3OrLater();
/// Determines whether a string ends with a given substring
///
/// @return true if "fullString" ends with the specified "ending"; otherwise false
bool EndsWith(std::wstring const &fullString, std::wstring const &ending);
/// Determines whether a given file path corresponds to a package file (.appx, .msix)
///
/// @path -path for some file
/// @return true if "path" is a package file path ending with ".appx" or "msix"; otherwise false
bool IsPackageFile(std::wstring const& path);
/// Determines whether a given file path corresponds to a bundle file (.appxbundle, .msixbundle)
///
/// @path -path for some file
/// @return true if "path" is a bundle file path ending with ".appxbundle" or "msixbundle"; otherwise false
bool IsBundleFile(std::wstring const& path);
/// Replaces all oldchars in input with newchar
///
/// @param input - The input string that contains the characters to be changed

Просмотреть файл

@ -425,20 +425,18 @@ namespace MSIX {
auto name = dependencyNode->GetAttributeValue(XmlAttributeName::Name);
auto publisher = dependencyNode->GetAttributeValue(XmlAttributeName::Publisher);
std::string packageFamilyName;
std::string publisherHash;
// if no publisher for the main package dependency is specified, we default to the publisher of the optional package itself
if (publisher.empty())
{
auto packageIdInternal = context->self->m_packageId.As<IAppxManifestPackageIdInternal>();
packageFamilyName = packageIdInternal->GetPackageFamilyName();
}
else
{
// Convert publisher to publisher hash so we can build package family name
std::string publisherHash = ComputePublisherId(publisher);
packageFamilyName = name + "_" + publisherHash;
publisher = packageIdInternal->GetPublisher();
}
publisherHash = ComputePublisherId(publisher);
packageFamilyName = name + "_" + publisherHash;
auto dependency = ComPtr<IAppxManifestMainPackageDependency>::Make<AppxManifestMainPackageDependency>(context->self->m_factory.Get(), name, publisher, packageFamilyName);
context->packageDependencies->push_back(std::move(dependency));
return true;

Просмотреть файл

@ -623,13 +623,13 @@ TEST_CASE("Api_AppxManifestReader_OptionalPackage", "[api]")
std::vector<std::string> expectedPublisherValues =
{
"", // We expect the value to be NULL. Handle this special case separately
"CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US",
"CN=Microsoft Corporation2, O=Microsoft Corporation2, L=Redmond2, S=Washington, C=US2",
};
std::vector<std::string> expectedPackageFamilyNameValues =
{
"SampleAppManifest_8wekyb3d8bbwe",
"Demo.MyMainApp_8wekyb3d8bbwe",
"Demo.MyMainApp_4395hyxtvknyy",
};
@ -653,26 +653,13 @@ TEST_CASE("Api_AppxManifestReader_OptionalPackage", "[api]")
REQUIRE_SUCCEEDED(dependencyUtf8->GetName(&nameUtf8));
REQUIRE(expectedName == nameUtf8.ToString());
if (numDep == 0)
{
MsixTest::Wrappers::Buffer<wchar_t> publisher;
REQUIRE_SUCCEEDED(dependency->GetPublisher(&publisher));
REQUIRE(publisher.Get() == NULL);
MsixTest::Wrappers::Buffer<wchar_t> publisher;
REQUIRE_SUCCEEDED(dependency->GetPublisher(&publisher));
REQUIRE(expectedPublisherValues[numDep] == publisher.ToString());
MsixTest::Wrappers::Buffer<char> publisherUtf8;
REQUIRE_SUCCEEDED(dependencyUtf8->GetPublisher(&publisherUtf8));
REQUIRE(publisherUtf8.Get() == NULL);
}
else
{
MsixTest::Wrappers::Buffer<wchar_t> publisher;
REQUIRE_SUCCEEDED(dependency->GetPublisher(&publisher));
REQUIRE(expectedPublisherValues[numDep] == publisher.ToString());
MsixTest::Wrappers::Buffer<char> publisherUtf8;
REQUIRE_SUCCEEDED(dependencyUtf8->GetPublisher(&publisherUtf8));
REQUIRE(expectedPublisherValues[numDep] == publisherUtf8.ToString());
}
MsixTest::Wrappers::Buffer<char> publisherUtf8;
REQUIRE_SUCCEEDED(dependencyUtf8->GetPublisher(&publisherUtf8));
REQUIRE(expectedPublisherValues[numDep] == publisherUtf8.ToString());
MsixTest::Wrappers::Buffer<wchar_t> packageFamilyName;
REQUIRE_SUCCEEDED(dependency->GetPackageFamilyName(&packageFamilyName));