Skip to content

Commit d380341

Browse files
authored
PublishSingleFile dll and resources.pri redirection support (#4067)
* PublishSingleFile dll and resources.pri redirection support * Add support for expanding env vars in manifests, and then for parsing file.loadFrom attributes using them * Add System ns * PR feedback
1 parent fb4af2c commit d380341

File tree

3 files changed

+86
-29
lines changed

3 files changed

+86
-29
lines changed

dev/MRTCore/mrt/Core/src/MRM.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) Microsoft Corporation and Contributors.
1+
// Copyright (c) Microsoft Corporation and Contributors.
22
// Licensed under the MIT License.
33

44
#include <Windows.h>
@@ -989,6 +989,12 @@ STDAPI MrmGetFilePathFromName(_In_opt_ PCWSTR filename, _Outptr_ PWSTR* filePath
989989
PCWSTR filenameToUse = filename;
990990
if (filename == nullptr || *filename == L'\0')
991991
{
992+
wil::unique_cotaskmem_string baseDir;
993+
if(SUCCEEDED(wil::TryGetEnvironmentVariableW(L"MICROSOFT_WINDOWSAPPRUNTIME_BASE_DIRECTORY", baseDir)))
994+
{
995+
path.swap(baseDir);
996+
RETURN_IF_FAILED(StringCchLengthW(path.get(), STRSAFE_MAX_CCH, &bufferCount));
997+
}
992998
filenameToUse = c_defaultPriFilename;
993999
}
9941000

@@ -997,8 +1003,8 @@ STDAPI MrmGetFilePathFromName(_In_opt_ PCWSTR filename, _Outptr_ PWSTR* filePath
9971003
// - search under exe path
9981004
// - if not exist, search parent path
9991005
// If filename is not provided:
1000-
// - search under exe path with default name (resources.pri)
1001-
// - if not exist, search under same path with [modulename].pri
1006+
// - search under exe path (or baseDir) with default name (resources.pri)
1007+
// - if not exist, search under exe path (or baseDir) with [modulename].pri
10021008
for (int i = 0; i < 2; i++)
10031009
{
10041010
size_t lengthOfName;

dev/UndockedRegFreeWinRT/UndockedRegFreeWinRT-AutoInitializer.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// DO NOT MODIFY. Changes to this file may cause incorrect behavior and will be lost on updates.
77
// </auto-generated>
88

9+
using System;
910
using System.Reflection;
1011
using System.Runtime.InteropServices;
1112

@@ -22,6 +23,9 @@ class AutoInitialize
2223
[global::System.Runtime.CompilerServices.ModuleInitializer]
2324
internal static void AccessWindowsAppSDK()
2425
{
26+
// Set base directory env var for PublishSingleFile support (referenced by SxS redirection)
27+
Environment.SetEnvironmentVariable("MICROSOFT_WINDOWSAPPRUNTIME_BASE_DIRECTORY", AppContext.BaseDirectory);
28+
2529
// No error handling needed as the target function does nothing (just {return S_OK}).
2630
// It's the act of calling the function causing the DllImport to load the DLL that
2731
// matters. This provides the moral equivalent of a native DLL's Import Address

dev/UndockedRegFreeWinRT/catalog.cpp

Lines changed: 73 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
// Copyright (c) Microsoft Corporation and Contributors.
1+
// Copyright (c) Microsoft Corporation and Contributors.
22
// Licensed under the MIT License.
33

44
#include <pch.h>
55

66
#include "catalog.h"
7+
#include "Microsoft.Utf8.h"
78
#include "TypeResolution.h"
89

910
#include <activation.h>
@@ -125,11 +126,26 @@ HRESULT LoadFromEmbeddedManifest(PCWSTR path)
125126

126127
HRESULT WinRTLoadComponentFromFilePath(PCWSTR manifestPath)
127128
{
128-
ComPtr<IStream> fileStream;
129-
RETURN_IF_FAILED(SHCreateStreamOnFileEx(manifestPath, STGM_READ, FILE_ATTRIBUTE_NORMAL, FALSE, nullptr, &fileStream));
130129
try
131130
{
132-
return ParseRootManifestFromXmlReaderInput(fileStream.Get());
131+
wil::unique_hfile file{ ::CreateFileW(manifestPath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, nullptr) };
132+
RETURN_HR_IF(HRESULT_FROM_WIN32(GetLastError()), !file);
133+
134+
LARGE_INTEGER fileSize{};
135+
RETURN_IF_WIN32_BOOL_FALSE(::GetFileSizeEx(file.get(), &fileSize));
136+
const auto dataSize{ fileSize.QuadPart };
137+
RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), dataSize > INT32_MAX);
138+
RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_SXS_XML_E_UNEXPECTEDEOF), dataSize == 0);
139+
140+
const auto bufferSize{ static_cast<DWORD>(dataSize) + 1 };
141+
std::unique_ptr<char[]> buffer{ std::make_unique<char[]>(bufferSize) };
142+
143+
DWORD bytesRead{};
144+
RETURN_IF_WIN32_BOOL_FALSE(::ReadFile(file.get(), buffer.get(), bufferSize, &bytesRead, nullptr));
145+
file.reset();
146+
buffer[bytesRead] = '\0';
147+
148+
return WinRTLoadComponentFromString(std::string_view(buffer.get(), bytesRead));
133149
}
134150
catch(...)
135151
{
@@ -140,16 +156,23 @@ HRESULT WinRTLoadComponentFromFilePath(PCWSTR manifestPath)
140156

141157
HRESULT WinRTLoadComponentFromString(std::string_view xmlStringValue)
142158
{
143-
ComPtr<IStream> xmlStream;
144-
auto xmlStringValueData{ xmlStringValue.data() };
145-
auto xmlStringValueDataLength{ strlen(xmlStringValueData) };
146-
auto xmlStringValueDataSize{ xmlStringValueDataLength * sizeof(*xmlStringValueData) };
147-
xmlStream.Attach(SHCreateMemStream(reinterpret_cast<const BYTE*>(xmlStringValue.data()), static_cast<UINT>(xmlStringValueDataSize)));
148-
RETURN_HR_IF_NULL(E_OUTOFMEMORY, xmlStream);
149-
ComPtr<IXmlReaderInput> xmlReaderInput;
150-
RETURN_IF_FAILED(CreateXmlReaderInputWithEncodingName(xmlStream.Get(), nullptr, L"utf-8", FALSE, nullptr, &xmlReaderInput));
151159
try
152160
{
161+
auto wideXmlString = ::Microsoft::Utf8::ToUtf16(xmlStringValue.data());
162+
163+
// Expand any env vars, such as %MICROSOFT_WINDOWSAPPRUNTIME_BASE_DIRECTORY% in asmv3:file.loadFrom
164+
auto expandedSize = ExpandEnvironmentStringsW(wideXmlString.data(), nullptr, 0);
165+
RETURN_HR_IF(HRESULT_FROM_WIN32(GetLastError()), expandedSize == 0);
166+
std::unique_ptr<WCHAR[]> expanded{ std::make_unique<WCHAR[]>(expandedSize) };
167+
expandedSize = ExpandEnvironmentStringsW(wideXmlString.data(), expanded.get(), expandedSize);
168+
RETURN_HR_IF(HRESULT_FROM_WIN32(GetLastError()), expandedSize == 0);
169+
170+
ComPtr<IStream> xmlStream;
171+
xmlStream.Attach(SHCreateMemStream(reinterpret_cast<const BYTE*>(expanded.get()), static_cast<UINT>(expandedSize * sizeof(WCHAR))));
172+
RETURN_HR_IF_NULL(E_OUTOFMEMORY, xmlStream);
173+
ComPtr<IXmlReaderInput> xmlReaderInput;
174+
RETURN_IF_FAILED(CreateXmlReaderInputWithEncodingName(xmlStream.Get(), nullptr, L"UCS-2", FALSE, nullptr, &xmlReaderInput));
175+
153176
return ParseRootManifestFromXmlReaderInput(xmlReaderInput.Get());
154177
}
155178
catch (...)
@@ -185,16 +208,47 @@ HRESULT ParseRootManifestFromXmlReaderInput(IUnknown* input)
185208

186209
HRESULT ParseFileTag(IXmlReader* xmlReader)
187210
{
188-
HRESULT hr = S_OK;
189-
XmlNodeType nodeType;
190211
PCWSTR localName = nullptr;
191212
PCWSTR value = nullptr;
192-
hr = xmlReader->MoveToAttributeByName(L"name", nullptr);
193-
RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_SXS_MANIFEST_PARSE_ERROR), hr != S_OK);
194-
RETURN_IF_FAILED(xmlReader->GetValue(&value, nullptr));
195-
std::wstring fileName{ !value ? L"" : value };
196-
RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_SXS_MANIFEST_PARSE_ERROR), fileName.empty());
213+
std::wstring fileName;
197214
auto locale = _create_locale(LC_ALL, "C");
215+
HRESULT hr = xmlReader->MoveToFirstAttribute();
216+
if (S_FALSE == hr)
217+
{
218+
return HRESULT_FROM_WIN32(ERROR_SXS_MANIFEST_PARSE_ERROR);
219+
}
220+
else
221+
{
222+
while (TRUE)
223+
{
224+
if (FAILED_LOG(xmlReader->GetLocalName(&localName, NULL)))
225+
{
226+
return HRESULT_FROM_WIN32(ERROR_SXS_MANIFEST_PARSE_ERROR);
227+
}
228+
if (FAILED_LOG(xmlReader->GetValue(&value, NULL)))
229+
{
230+
return HRESULT_FROM_WIN32(ERROR_SXS_MANIFEST_PARSE_ERROR);
231+
}
232+
if (localName != nullptr)
233+
{
234+
if ((_wcsicmp_l(L"name", localName, locale) == 0) && fileName.empty())
235+
{
236+
fileName = value;
237+
}
238+
else if (_wcsicmp_l(L"loadFrom", localName, locale) == 0)
239+
{
240+
// override bare filename with fully qualified loadFrom path if supplied
241+
fileName = value;
242+
}
243+
}
244+
if (xmlReader->MoveToNextAttribute() != S_OK)
245+
{
246+
break;
247+
}
248+
}
249+
}
250+
RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_SXS_MANIFEST_PARSE_ERROR), fileName.empty());
251+
XmlNodeType nodeType;
198252
while (S_OK == xmlReader->Read(&nodeType))
199253
{
200254
if (nodeType == XmlNodeType_Element)
@@ -220,10 +274,8 @@ HRESULT ParseActivatableClassTag(IXmlReader* xmlReader, PCWSTR fileName)
220274
auto this_component = make_shared<component>();
221275
this_component->module_name = fileName;
222276
HRESULT hr = xmlReader->MoveToFirstAttribute();
223-
// Using this pattern intead of calling multiple MoveToAttributeByName improves performance
224277
const WCHAR* activatableClass = nullptr;
225278
const WCHAR* threadingModel = nullptr;
226-
const WCHAR* xmlns = nullptr;
227279
if (S_FALSE == hr)
228280
{
229281
return HRESULT_FROM_WIN32(ERROR_SXS_MANIFEST_PARSE_ERROR);
@@ -252,10 +304,6 @@ HRESULT ParseActivatableClassTag(IXmlReader* xmlReader, PCWSTR fileName)
252304
{
253305
activatableClass = pwszValue;
254306
}
255-
else if (_wcsicmp_l(L"xmlns", pwszLocalName, locale) == 0)
256-
{
257-
xmlns = pwszValue;
258-
}
259307
}
260308
if (xmlReader->MoveToNextAttribute() != S_OK)
261309
{
@@ -288,7 +336,6 @@ HRESULT ParseActivatableClassTag(IXmlReader* xmlReader, PCWSTR fileName)
288336
{
289337
return HRESULT_FROM_WIN32(ERROR_SXS_MANIFEST_PARSE_ERROR);
290338
}
291-
this_component->xmlns = xmlns; // Should we care if this value is blank or missing?
292339
// Check for duplicate activatable classes
293340
auto component_iter = g_types.find(activatableClass);
294341
if (component_iter != g_types.end())

0 commit comments

Comments
 (0)