LoadLibraryEx 忽略并排清单
LoadLibraryEx ignores side-by-side manifest
LoadLibraryEx
函数是否使用并排清单?我有带有嵌入式 SxS 清单的 bar.dll,该清单描述了此 bar.dll 的版本,其他 dll 文件 foo.dll 具有将 bar.dll 列为依赖项并具有指定版本的清单。但是当我尝试使用 LoadLibraryEx("bar.dll", NULL, 0)
从 foo.dll 加载 bar.dll 时,我看到(启用了带有 gflags 的 sls)它忽略了这些清单,并加载了 bar.dll 的第一个版本在搜索路径中看到,如果我定义 ISOLATION_AWARE_ENABLED
并使用 LoadLibrary
它会找到正确的版本,但是这个 ISOLATION_AWARE_ENABLED
不会影响 LoadLibraryEx
的行为,我需要加载正确的版本LoadLibraryEx
因为 LoadLibraryEx
隐含地用于延迟加载 dll。 LoadLibraryEx
是不是应该这样工作,还是我的项目配置有问题?
foo dll
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity name="foo" version="0.1.2.3" type="win32"/>
<dependency>
<dependentAssembly>
<assemblyIdentity name="bar" version="0.1.2.3" type="win32" />
</dependentAssembly>
</dependency>
<file name="foo.dll">
</file>
</assembly>
bar.dll
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity name="bar" version="0.1.2.3" type="win32"/>
<file name="bar.dll">
</file>
</assembly>
LoadLibrary
使用了调用线程的活动激活上下文。但是这个上下文是什么?为什么它必须来自您的 foo.dll
?为什么不来自 xyz.dll
或来自 exe ?实际上大多数时间活动激活上下文正是来自 exe。
如果 dll 有自己的清单 - 系统为此 dll 创建激活上下文并保存它(直到 dll 被卸载)但不激活它。这显然是 - 我们有多个 dll 正在处理,但活动上下文只有一个 - 来自哪个 dll select 它?来自exe。但是系统在调用它的入口点之前激活(使其成为当前活动的)dll 激活上下文。并在入口点 return 后停用它。但是在另一个 dll 函数中说 - (谁调用它?)上下文已经不是来自你的 dll。
所以解决方案必须是下一个:
在dll中定义2个全局变量:
BOOL gActCtx;
HANDLE ghActCtx
在 DLL_PROCESS_ATTACH
上保存当前激活上下文(它来自您的 dll 清单)
gActCtx = GetCurrentActCtx(&ghActCtx);
在 DLL_PROCESS_DETACH
上释放它
if (gActCtx) ReleaseActCtx(ghActCtx);
当您需要加载时 bar.dll
下一步:
if (gActCtx)
{
ULONG_PTR Cookie;
if (ActivateActCtx(ghActCtx, &Cookie))
{
LoadLibraryExW(L"bar.dll", NULL, 0);
DeactivateActCtx(0, Cookie);
}
}
LoadLibraryEx
函数是否使用并排清单?我有带有嵌入式 SxS 清单的 bar.dll,该清单描述了此 bar.dll 的版本,其他 dll 文件 foo.dll 具有将 bar.dll 列为依赖项并具有指定版本的清单。但是当我尝试使用 LoadLibraryEx("bar.dll", NULL, 0)
从 foo.dll 加载 bar.dll 时,我看到(启用了带有 gflags 的 sls)它忽略了这些清单,并加载了 bar.dll 的第一个版本在搜索路径中看到,如果我定义 ISOLATION_AWARE_ENABLED
并使用 LoadLibrary
它会找到正确的版本,但是这个 ISOLATION_AWARE_ENABLED
不会影响 LoadLibraryEx
的行为,我需要加载正确的版本LoadLibraryEx
因为 LoadLibraryEx
隐含地用于延迟加载 dll。 LoadLibraryEx
是不是应该这样工作,还是我的项目配置有问题?
foo dll
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity name="foo" version="0.1.2.3" type="win32"/>
<dependency>
<dependentAssembly>
<assemblyIdentity name="bar" version="0.1.2.3" type="win32" />
</dependentAssembly>
</dependency>
<file name="foo.dll">
</file>
</assembly>
bar.dll
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity name="bar" version="0.1.2.3" type="win32"/>
<file name="bar.dll">
</file>
</assembly>
LoadLibrary
使用了调用线程的活动激活上下文。但是这个上下文是什么?为什么它必须来自您的 foo.dll
?为什么不来自 xyz.dll
或来自 exe ?实际上大多数时间活动激活上下文正是来自 exe。
如果 dll 有自己的清单 - 系统为此 dll 创建激活上下文并保存它(直到 dll 被卸载)但不激活它。这显然是 - 我们有多个 dll 正在处理,但活动上下文只有一个 - 来自哪个 dll select 它?来自exe。但是系统在调用它的入口点之前激活(使其成为当前活动的)dll 激活上下文。并在入口点 return 后停用它。但是在另一个 dll 函数中说 - (谁调用它?)上下文已经不是来自你的 dll。
所以解决方案必须是下一个:
在dll中定义2个全局变量:
BOOL gActCtx;
HANDLE ghActCtx
在 DLL_PROCESS_ATTACH
上保存当前激活上下文(它来自您的 dll 清单)
gActCtx = GetCurrentActCtx(&ghActCtx);
在 DLL_PROCESS_DETACH
if (gActCtx) ReleaseActCtx(ghActCtx);
当您需要加载时 bar.dll
下一步:
if (gActCtx)
{
ULONG_PTR Cookie;
if (ActivateActCtx(ghActCtx, &Cookie))
{
LoadLibraryExW(L"bar.dll", NULL, 0);
DeactivateActCtx(0, Cookie);
}
}