Skip to content

Commit

Permalink
UndockedRegFreeWinRT doesn't check Dynamic packages for WinRT Metadata (
Browse files Browse the repository at this point in the history
microsoft#1649)

* Added PACKAGE_FILTER_STATIC|DYNAMIC so metadata resolution also doesn't just search static package graph entries (and fail to find metadata in dynamic packages)

* Revise ResolveThirdPartyType() to be savvy to dynamic package graph

* Incorporated feedback

* Added PACKAGE_FILTER_STATIC|DYNAMIC so metadata resolution also doesn't just search static package graph entries (and fail to find metadata in dynamic packages)

* Revise ResolveThirdPartyType() to be savvy to dynamic package graph

* Incorporated feedback

* Add Dynamic+Static filters when retrieving the package graph as required to get the whole package graph

* Fix check for not-found-in-package-graph-let's-try-exe-dir

* Updated by VS

* Incorporated feedback
  • Loading branch information
DrusTheAxe authored May 19, 2022
1 parent f6dffda commit 2c23172
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 152 deletions.
1 change: 0 additions & 1 deletion WindowsAppRuntime.sln
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,6 @@ EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
test\inc\inc.vcxitems*{08bc78e0-63c6-49a7-81b3-6afc3deac4de}*SharedItemsImports = 4
test\inc\inc.vcxitems*{0a5fee93-48b7-40ec-bb9a-b27d11060da9}*SharedItemsImports = 4
dev\PushNotifications\PushNotifications.vcxitems*{103c0c23-7ba8-4d44-a63c-83488e2e3a81}*SharedItemsImports = 9
test\inc\inc.vcxitems*{2cd5cd9b-cf45-4fa7-9769-ee4e02426bf0}*SharedItemsImports = 4
dev\EnvironmentManager\API\Microsoft.Process.Environment.vcxitems*{2f3fad1b-d3df-4866-a3a3-c2c777d55638}*SharedItemsImports = 9
Expand Down
251 changes: 100 additions & 151 deletions dev/UndockedRegFreeWinRT/typeresolution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,61 +213,42 @@ namespace UndockedRegFreeWinRT
_COM_Outptr_opt_result_maybenull_ IMetaDataImport2** ppMetaDataImport,
_Out_opt_ mdTypeDef* pmdTypeDef)
{
HRESULT hr;

wchar_t szCandidateFilePath[MAX_PATH + 1] = { 0 };
wchar_t szCandidateFileName[MAX_PATH + 1] = { 0 };
PWSTR pszLastDot;

hr = StringCchCopy(szCandidateFileName, ARRAYSIZE(szCandidateFileName), pszFullName);

wchar_t szCandidateFileName[MAX_PATH + 1]{};
HRESULT hr{ StringCchCopy(szCandidateFileName, ARRAYSIZE(szCandidateFileName), pszFullName) };
if (SUCCEEDED(hr))
{
// To resolve type SomeNamespace.B.C, first check if SomeNamespace.B.C is a type or
// a namespace in the metadata files in the directory in this order:
// 1. SomeNamespace.B.C.WinMD
// 2. SomeNamespace.B.WinMD
// 3. SomeNamespace.WinMD
wchar_t szCandidateFilePath[MAX_PATH + 1]{};
PWSTR pszLastDot{};
do
{
pszLastDot = nullptr;

hr = StringCchPrintfEx(
szCandidateFilePath,
ARRAYSIZE(szCandidateFilePath),
nullptr,
nullptr,
0,
METADATA_FILE_PATH_FORMAT,
pszDirectoryPath,
szCandidateFileName);

hr = StringCchPrintfExW(szCandidateFilePath, ARRAYSIZE(szCandidateFilePath),
nullptr, nullptr, 0, METADATA_FILE_PATH_FORMAT,
pszDirectoryPath, szCandidateFileName);
if (SUCCEEDED(hr))
{
hr = FindTypeInMetaDataFile(
pMetaDataDispenser,
pszFullName,
szCandidateFilePath,
TRO_RESOLVE_TYPE_AND_NAMESPACE,
ppMetaDataImport,
pmdTypeDef);

hr = FindTypeInMetaDataFile(pMetaDataDispenser, pszFullName, szCandidateFilePath,
TRO_RESOLVE_TYPE_AND_NAMESPACE, ppMetaDataImport, pmdTypeDef);
if (SUCCEEDED(hr))
{
if (phstrMetaDataFilePath != nullptr)
{
hr = WindowsCreateString(
szCandidateFilePath,
static_cast<UINT32>(wcslen(szCandidateFilePath)),
phstrMetaDataFilePath);
hr = WindowsCreateString(szCandidateFilePath,
static_cast<UINT32>(wcslen(szCandidateFilePath)),
phstrMetaDataFilePath);
}
break;
}
}

hr = RO_E_METADATA_NAME_NOT_FOUND;
pszLastDot = wcsrchr(szCandidateFileName, '.');

if (pszLastDot != nullptr)
{
*pszLastDot = '\0';
Expand All @@ -278,78 +259,44 @@ namespace UndockedRegFreeWinRT
// the name might be a namespace name in a down-level file.
if (hr == RO_E_METADATA_NAME_NOT_FOUND)
{
wchar_t szFilePathSearchTemplate[MAX_PATH + 1] = { 0 };

hr = StringCchPrintfEx(
szFilePathSearchTemplate,
ARRAYSIZE(szFilePathSearchTemplate),
nullptr,
nullptr,
0,
METADATA_FILE_SEARCH_FORMAT,
pszDirectoryPath,
pszFullName);

wchar_t szFilePathSearchTemplate[MAX_PATH + 1]{};
hr = StringCchPrintfExW(szFilePathSearchTemplate, ARRAYSIZE(szFilePathSearchTemplate), nullptr,
nullptr, 0, METADATA_FILE_SEARCH_FORMAT, pszDirectoryPath, pszFullName);
if (SUCCEEDED(hr))
{
WIN32_FIND_DATA fd;
HANDLE hFindFile;

// Search in all files in the directory whose name begin with the input string.
hFindFile = FindFirstFile(szFilePathSearchTemplate, &fd);

WIN32_FIND_DATA fd{};
HANDLE hFindFile{ FindFirstFile(szFilePathSearchTemplate, &fd) };
if (hFindFile != INVALID_HANDLE_VALUE)
{
PWSTR pszFilePathPart;
size_t cchRemaining;

do
{
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
continue;
}

pszFilePathPart = szCandidateFilePath;
cchRemaining = ARRAYSIZE(szCandidateFilePath);
hr = StringCchCopyEx(
pszFilePathPart,
cchRemaining,
pszDirectoryPath,
&pszFilePathPart,
&cchRemaining,
0);

PWSTR pszFilePathPart{ szCandidateFilePath };
size_t cchRemaining{ ARRAYSIZE(szCandidateFilePath) };
hr = StringCchCopyExW(pszFilePathPart, cchRemaining, pszDirectoryPath,
&pszFilePathPart, &cchRemaining, 0);
if (SUCCEEDED(hr))
{
hr = StringCchCopyEx(
pszFilePathPart,
cchRemaining,
fd.cFileName,
&pszFilePathPart,
&cchRemaining,
0);
}

if (SUCCEEDED(hr))
{
hr = FindTypeInMetaDataFile(
pMetaDataDispenser,
pszFullName,
szCandidateFilePath,
TRO_RESOLVE_NAMESPACE,
ppMetaDataImport,
pmdTypeDef);

if (hr == S_OK)
hr = StringCchCopyExW(pszFilePathPart, cchRemaining, fd.cFileName,
&pszFilePathPart, &cchRemaining, 0);
if (SUCCEEDED(hr))
{
hr = E_UNEXPECTED;
break;
}

if (hr == RO_E_METADATA_NAME_IS_NAMESPACE)
{
break;
hr = FindTypeInMetaDataFile(pMetaDataDispenser, pszFullName, szCandidateFilePath,
TRO_RESOLVE_NAMESPACE, ppMetaDataImport, pmdTypeDef);
if (hr == S_OK)
{
hr = E_UNEXPECTED;
break;
}
else if (hr == RO_E_METADATA_NAME_IS_NAMESPACE)
{
break;
}
}
}
} while (FindNextFile(hFindFile, &fd));
Expand All @@ -366,10 +313,9 @@ namespace UndockedRegFreeWinRT

if (hr == STRSAFE_E_INSUFFICIENT_BUFFER)
{
hr = RO_E_METADATA_NAME_NOT_FOUND;
return RO_E_METADATA_NAME_NOT_FOUND;
}

return hr;
RETURN_HR(hr);
}

HRESULT FindTypeInDirectoryWithNormalization(
Expand All @@ -380,45 +326,23 @@ namespace UndockedRegFreeWinRT
_COM_Outptr_opt_result_maybenull_ IMetaDataImport2** ppMetaDataImport,
_Out_opt_ mdTypeDef* pmdTypeDef)
{
wchar_t pszPackagePath[MAX_PATH + 1];
PWSTR pszPackagePathWritePtr = pszPackagePath;
size_t cchPackagePathRemaining = ARRAYSIZE(pszPackagePath);

HRESULT hr = StringCchCopyEx(
pszPackagePath,
ARRAYSIZE(pszPackagePath),
pszDirectoryPath,
&pszPackagePathWritePtr,
&cchPackagePathRemaining,
0);

if (SUCCEEDED(hr))
wchar_t pszPackagePath[MAX_PATH + 1]{};
PWSTR pszPackagePathWritePtr{ pszPackagePath };
size_t cchPackagePathRemaining{ ARRAYSIZE(pszPackagePath) };
RETURN_IF_FAILED(StringCchCopyExW(pszPackagePath, ARRAYSIZE(pszPackagePath),
pszDirectoryPath, &pszPackagePathWritePtr, &cchPackagePathRemaining, 0));

// If the path is not terminated by a backslash, then append one.
if (pszPackagePath[ARRAYSIZE(pszPackagePath) - cchPackagePathRemaining - 1] != L'\\')
{
// If the path is not terminated by a backslash, then append one.
if (pszPackagePath[ARRAYSIZE(pszPackagePath) - cchPackagePathRemaining - 1] != L'\\')
{
hr = StringCchCopyEx(
pszPackagePathWritePtr,
cchPackagePathRemaining,
L"\\",
&pszPackagePathWritePtr,
&cchPackagePathRemaining,
0);
}
RETURN_IF_FAILED(StringCchCopyExW(pszPackagePathWritePtr, cchPackagePathRemaining,
L"\\", &pszPackagePathWritePtr, &cchPackagePathRemaining, 0));
}

if (SUCCEEDED(hr))
{
hr = FindTypeInDirectory(
pMetaDataDispenser,
pszFullName,
pszPackagePath,
phstrMetaDataFilePath,
ppMetaDataImport,
pmdTypeDef);
}
RETURN_IF_FAILED(FindTypeInDirectory(pMetaDataDispenser, pszFullName,
pszPackagePath, phstrMetaDataFilePath, ppMetaDataImport, pmdTypeDef));

return hr;
return S_OK;
}

HRESULT ResolveThirdPartyType(
Expand All @@ -428,40 +352,65 @@ namespace UndockedRegFreeWinRT
_COM_Outptr_opt_result_maybenull_ IMetaDataImport2** ppMetaDataImport,
_Out_opt_ mdTypeDef* pmdTypeDef)
{
HRESULT hr = S_OK;
UINT32 dwPackagesCount = 0;
UINT32 dwBufferLength = 0;

const UINT32 filter = PACKAGE_FILTER_HEAD | PACKAGE_FILTER_DIRECT | PACKAGE_FILTER_IS_IN_RELATED_SET;
hr = HRESULT_FROM_WIN32(GetCurrentPackageInfo(filter, &dwBufferLength, nullptr, &dwPackagesCount));
// Only find the type if the it is an unpackaged app. Packaged apps can have their exe on their package graph,
// which will allow type resolution against adjacent WinMDs.
if (hr == HRESULT_FROM_WIN32(APPMODEL_ERROR_NO_PACKAGE))
// Walk the package graph looking for the requested metadata
const uint32_t filter{ PACKAGE_FILTER_HEAD | PACKAGE_FILTER_DIRECT | PACKAGE_FILTER_IS_IN_RELATED_SET | PACKAGE_FILTER_DYNAMIC | PACKAGE_FILTER_STATIC };
uint32_t bufferLength{};
uint32_t packagesCount{};
bool processHasStaticPackageGraph{};
const HRESULT hr{ HRESULT_FROM_WIN32(GetCurrentPackageInfo(filter, &bufferLength, nullptr, &packagesCount)) };
if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
{
PCWSTR exeDir = nullptr; // Never freed; owned by process global.
RETURN_IF_FAILED(GetProcessExeDir(&exeDir));
// The process has a package graph. Walk it looking for the requested metadata
auto buffer{ wil::make_unique_nothrow<BYTE[]>(bufferLength) };
RETURN_IF_NULL_ALLOC(buffer);
RETURN_IF_WIN32_ERROR(GetCurrentPackageInfo(filter, &bufferLength, buffer.get(), &packagesCount));
const auto packageInfos{ reinterpret_cast<PACKAGE_INFO*>(buffer.get()) };
for (uint32_t index=0; index < packagesCount; ++index)
{
const auto& packageInfo{ packageInfos[index] };
HRESULT hrFindType{ FindTypeInDirectoryWithNormalization(pMetaDataDispenser, pszFullName,
packageInfo.path, phstrMetaDataFilePath, ppMetaDataImport, pmdTypeDef) };
if (SUCCEEDED(hrFindType))
{
return hrFindType;
}

hr = FindTypeInDirectoryWithNormalization(
pMetaDataDispenser,
pszFullName,
exeDir,
phstrMetaDataFilePath,
ppMetaDataImport,
pmdTypeDef);
// Keep track if we find any Static entries in the package graph
if (WI_IsFlagSet(packageInfo.flags, PACKAGE_PROPERTY_STATIC))
{
processHasStaticPackageGraph = true;
}
}
}

if (hr == RO_E_METADATA_NAME_NOT_FOUND)
// Not found in the package graph.

// Unpackaged apps may have metadata next to their executable.
//
// Packaged apps have metadata in their root directory which is
// in the package graph and thus already checked.
//
// NOTE: Only packaged apps have Static entries in their package graph.
// Unpackaged apps have no Static entries in their package graph.
if (!processHasStaticPackageGraph)
{
PCWSTR exeDir{}; // Never freed; owned by process global.
RETURN_IF_FAILED(GetProcessExeDir(&exeDir));
const HRESULT hrFindType{ FindTypeInDirectoryWithNormalization(
pMetaDataDispenser, pszFullName, exeDir,
phstrMetaDataFilePath, ppMetaDataImport, pmdTypeDef) };
if (hrFindType == RO_E_METADATA_NAME_NOT_FOUND)
{
// For compatibility purposes, if we fail to find the type in the unpackaged location, we should return
// HRESULT_FROM_WIN32(APPMODEL_ERROR_NO_PACKAGE) instead of a "not found" error. This preserves the
// behavior that existed before unpackaged type resolution was implemented.
hr = HRESULT_FROM_WIN32(APPMODEL_ERROR_NO_PACKAGE);
return HRESULT_FROM_WIN32(APPMODEL_ERROR_NO_PACKAGE);
}
return hr;
}
else
{
return RO_E_METADATA_NAME_NOT_FOUND;
RETURN_HR(hrFindType);
}

// Not found
return RO_E_METADATA_NAME_NOT_FOUND;
}

//
Expand Down

0 comments on commit 2c23172

Please sign in to comment.