diff --git a/dev/MRTCore/mrt/Core/src/MRM.cpp b/dev/MRTCore/mrt/Core/src/MRM.cpp index 14439fe39f..81999d7420 100644 --- a/dev/MRTCore/mrt/Core/src/MRM.cpp +++ b/dev/MRTCore/mrt/Core/src/MRM.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation and Contributors. +// Copyright (c) Microsoft Corporation and Contributors. // Licensed under the MIT License. #include @@ -989,6 +989,12 @@ STDAPI MrmGetFilePathFromName(_In_opt_ PCWSTR filename, _Outptr_ PWSTR* filePath PCWSTR filenameToUse = filename; if (filename == nullptr || *filename == L'\0') { + wil::unique_cotaskmem_string baseDir; + if(SUCCEEDED(wil::TryGetEnvironmentVariableW(L"MICROSOFT_WINDOWSAPPRUNTIME_BASE_DIRECTORY", baseDir))) + { + path.swap(baseDir); + RETURN_IF_FAILED(StringCchLengthW(path.get(), STRSAFE_MAX_CCH, &bufferCount)); + } filenameToUse = c_defaultPriFilename; } @@ -997,8 +1003,8 @@ STDAPI MrmGetFilePathFromName(_In_opt_ PCWSTR filename, _Outptr_ PWSTR* filePath // - search under exe path // - if not exist, search parent path // If filename is not provided: - // - search under exe path with default name (resources.pri) - // - if not exist, search under same path with [modulename].pri + // - search under exe path (or baseDir) with default name (resources.pri) + // - if not exist, search under exe path (or baseDir) with [modulename].pri for (int i = 0; i < 2; i++) { size_t lengthOfName; diff --git a/dev/UndockedRegFreeWinRT/UndockedRegFreeWinRT-AutoInitializer.cs b/dev/UndockedRegFreeWinRT/UndockedRegFreeWinRT-AutoInitializer.cs index d8b4c026b9..e9a29c56f1 100644 --- a/dev/UndockedRegFreeWinRT/UndockedRegFreeWinRT-AutoInitializer.cs +++ b/dev/UndockedRegFreeWinRT/UndockedRegFreeWinRT-AutoInitializer.cs @@ -6,6 +6,7 @@ // DO NOT MODIFY. Changes to this file may cause incorrect behavior and will be lost on updates. // +using System; using System.Reflection; using System.Runtime.InteropServices; @@ -22,6 +23,9 @@ class AutoInitialize [global::System.Runtime.CompilerServices.ModuleInitializer] internal static void AccessWindowsAppSDK() { + // Set base directory env var for PublishSingleFile support (referenced by SxS redirection) + Environment.SetEnvironmentVariable("MICROSOFT_WINDOWSAPPRUNTIME_BASE_DIRECTORY", AppContext.BaseDirectory); + // No error handling needed as the target function does nothing (just {return S_OK}). // It's the act of calling the function causing the DllImport to load the DLL that // matters. This provides the moral equivalent of a native DLL's Import Address diff --git a/dev/UndockedRegFreeWinRT/catalog.cpp b/dev/UndockedRegFreeWinRT/catalog.cpp index f420fbd794..50033ac972 100644 --- a/dev/UndockedRegFreeWinRT/catalog.cpp +++ b/dev/UndockedRegFreeWinRT/catalog.cpp @@ -1,9 +1,10 @@ -// Copyright (c) Microsoft Corporation and Contributors. +// Copyright (c) Microsoft Corporation and Contributors. // Licensed under the MIT License. #include #include "catalog.h" +#include "Microsoft.Utf8.h" #include "TypeResolution.h" #include @@ -125,11 +126,26 @@ HRESULT LoadFromEmbeddedManifest(PCWSTR path) HRESULT WinRTLoadComponentFromFilePath(PCWSTR manifestPath) { - ComPtr fileStream; - RETURN_IF_FAILED(SHCreateStreamOnFileEx(manifestPath, STGM_READ, FILE_ATTRIBUTE_NORMAL, FALSE, nullptr, &fileStream)); try { - return ParseRootManifestFromXmlReaderInput(fileStream.Get()); + wil::unique_hfile file{ ::CreateFileW(manifestPath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, nullptr) }; + RETURN_HR_IF(HRESULT_FROM_WIN32(GetLastError()), !file); + + LARGE_INTEGER fileSize{}; + RETURN_IF_WIN32_BOOL_FALSE(::GetFileSizeEx(file.get(), &fileSize)); + const auto dataSize{ fileSize.QuadPart }; + RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), dataSize > INT32_MAX); + RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_SXS_XML_E_UNEXPECTEDEOF), dataSize == 0); + + const auto bufferSize{ static_cast(dataSize) + 1 }; + std::unique_ptr buffer{ std::make_unique(bufferSize) }; + + DWORD bytesRead{}; + RETURN_IF_WIN32_BOOL_FALSE(::ReadFile(file.get(), buffer.get(), bufferSize, &bytesRead, nullptr)); + file.reset(); + buffer[bytesRead] = '\0'; + + return WinRTLoadComponentFromString(std::string_view(buffer.get(), bytesRead)); } catch(...) { @@ -140,16 +156,23 @@ HRESULT WinRTLoadComponentFromFilePath(PCWSTR manifestPath) HRESULT WinRTLoadComponentFromString(std::string_view xmlStringValue) { - ComPtr xmlStream; - auto xmlStringValueData{ xmlStringValue.data() }; - auto xmlStringValueDataLength{ strlen(xmlStringValueData) }; - auto xmlStringValueDataSize{ xmlStringValueDataLength * sizeof(*xmlStringValueData) }; - xmlStream.Attach(SHCreateMemStream(reinterpret_cast(xmlStringValue.data()), static_cast(xmlStringValueDataSize))); - RETURN_HR_IF_NULL(E_OUTOFMEMORY, xmlStream); - ComPtr xmlReaderInput; - RETURN_IF_FAILED(CreateXmlReaderInputWithEncodingName(xmlStream.Get(), nullptr, L"utf-8", FALSE, nullptr, &xmlReaderInput)); try { + auto wideXmlString = ::Microsoft::Utf8::ToUtf16(xmlStringValue.data()); + + // Expand any env vars, such as %MICROSOFT_WINDOWSAPPRUNTIME_BASE_DIRECTORY% in asmv3:file.loadFrom + auto expandedSize = ExpandEnvironmentStringsW(wideXmlString.data(), nullptr, 0); + RETURN_HR_IF(HRESULT_FROM_WIN32(GetLastError()), expandedSize == 0); + std::unique_ptr expanded{ std::make_unique(expandedSize) }; + expandedSize = ExpandEnvironmentStringsW(wideXmlString.data(), expanded.get(), expandedSize); + RETURN_HR_IF(HRESULT_FROM_WIN32(GetLastError()), expandedSize == 0); + + ComPtr xmlStream; + xmlStream.Attach(SHCreateMemStream(reinterpret_cast(expanded.get()), static_cast(expandedSize * sizeof(WCHAR)))); + RETURN_HR_IF_NULL(E_OUTOFMEMORY, xmlStream); + ComPtr xmlReaderInput; + RETURN_IF_FAILED(CreateXmlReaderInputWithEncodingName(xmlStream.Get(), nullptr, L"UCS-2", FALSE, nullptr, &xmlReaderInput)); + return ParseRootManifestFromXmlReaderInput(xmlReaderInput.Get()); } catch (...) @@ -185,16 +208,47 @@ HRESULT ParseRootManifestFromXmlReaderInput(IUnknown* input) HRESULT ParseFileTag(IXmlReader* xmlReader) { - HRESULT hr = S_OK; - XmlNodeType nodeType; PCWSTR localName = nullptr; PCWSTR value = nullptr; - hr = xmlReader->MoveToAttributeByName(L"name", nullptr); - RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_SXS_MANIFEST_PARSE_ERROR), hr != S_OK); - RETURN_IF_FAILED(xmlReader->GetValue(&value, nullptr)); - std::wstring fileName{ !value ? L"" : value }; - RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_SXS_MANIFEST_PARSE_ERROR), fileName.empty()); + std::wstring fileName; auto locale = _create_locale(LC_ALL, "C"); + HRESULT hr = xmlReader->MoveToFirstAttribute(); + if (S_FALSE == hr) + { + return HRESULT_FROM_WIN32(ERROR_SXS_MANIFEST_PARSE_ERROR); + } + else + { + while (TRUE) + { + if (FAILED_LOG(xmlReader->GetLocalName(&localName, NULL))) + { + return HRESULT_FROM_WIN32(ERROR_SXS_MANIFEST_PARSE_ERROR); + } + if (FAILED_LOG(xmlReader->GetValue(&value, NULL))) + { + return HRESULT_FROM_WIN32(ERROR_SXS_MANIFEST_PARSE_ERROR); + } + if (localName != nullptr) + { + if ((_wcsicmp_l(L"name", localName, locale) == 0) && fileName.empty()) + { + fileName = value; + } + else if (_wcsicmp_l(L"loadFrom", localName, locale) == 0) + { + // override bare filename with fully qualified loadFrom path if supplied + fileName = value; + } + } + if (xmlReader->MoveToNextAttribute() != S_OK) + { + break; + } + } + } + RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_SXS_MANIFEST_PARSE_ERROR), fileName.empty()); + XmlNodeType nodeType; while (S_OK == xmlReader->Read(&nodeType)) { if (nodeType == XmlNodeType_Element) @@ -220,10 +274,8 @@ HRESULT ParseActivatableClassTag(IXmlReader* xmlReader, PCWSTR fileName) auto this_component = make_shared(); this_component->module_name = fileName; HRESULT hr = xmlReader->MoveToFirstAttribute(); - // Using this pattern intead of calling multiple MoveToAttributeByName improves performance const WCHAR* activatableClass = nullptr; const WCHAR* threadingModel = nullptr; - const WCHAR* xmlns = nullptr; if (S_FALSE == hr) { return HRESULT_FROM_WIN32(ERROR_SXS_MANIFEST_PARSE_ERROR); @@ -252,10 +304,6 @@ HRESULT ParseActivatableClassTag(IXmlReader* xmlReader, PCWSTR fileName) { activatableClass = pwszValue; } - else if (_wcsicmp_l(L"xmlns", pwszLocalName, locale) == 0) - { - xmlns = pwszValue; - } } if (xmlReader->MoveToNextAttribute() != S_OK) { @@ -288,7 +336,6 @@ HRESULT ParseActivatableClassTag(IXmlReader* xmlReader, PCWSTR fileName) { return HRESULT_FROM_WIN32(ERROR_SXS_MANIFEST_PARSE_ERROR); } - this_component->xmlns = xmlns; // Should we care if this value is blank or missing? // Check for duplicate activatable classes auto component_iter = g_types.find(activatableClass); if (component_iter != g_types.end())