如何在 Python 中从 SXS 加载 C DLL?
Posted
技术标签:
【中文标题】如何在 Python 中从 SXS 加载 C DLL?【英文标题】:How do I load a C DLL from the SXS in Python? 【发布时间】:2014-12-09 21:31:31 【问题描述】:这通常通过在与可执行文件一起驻留的清单文件中指定 DLL 依赖项来完成。但是,我不知道如何在 Python 中实现这一点。加载 DLL 不是问题,但要在 SXS 中找到合适的 DLL 来加载才是问题。
是否有指定在何处查找 DLL 的标准程序?对于此示例,我们假设它位于此处:
c:\windows\winsxs\amd64_my_handy_lib_<public_key_token>_1.0.0.0_none_<some_ID>
我真的需要手动搜索c:\windows\winsxs
目录按名称查找我的 DLL,然后检查父目录以查看它是否包含正确的版本?
我只是没有足够的 Python 项目知道完成此任务的适当方法。
【问题讨论】:
如果它是扩展模块,您可以将清单嵌入到 .pyd 中,或者只使用私有程序集。如果是 ctypes,您可以包含一个清单来创建激活上下文。如果您需要,我可以为后者举一个例子。 它不是一个扩展模块,但这肯定是一条可以探索的路径。知道如何将清单嵌入到 .pyd 中吗?我目前正在使用 ctypes 导入 DLL,如下所示:self._lib = ctypes.CDLL(path)
其中 path 是 dll 的路径。我想看看你提到的例子。
【参考方案1】:
这是一个从 WinSxS 目录加载 CRT 的示例。
actctx.manifest:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.VC90.CRT"
version="9.0.21022.8"
processorArchitecture="amd64"
publicKeyToken="1fc8b3b9a1e18e3b">
</assemblyIdentity>
</dependentAssembly>
</dependency>
</assembly>
actctx.py:
from ctypes import *
from ctypes.wintypes import *
kernel32 = WinDLL("kernel32", use_last_error=True)
ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID = 0x001
ACTCTX_FLAG_LANGID_VALID = 0x002
ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID = 0x004
ACTCTX_FLAG_RESOURCE_NAME_VALID = 0x008
ACTCTX_FLAG_SET_PROCESS_DEFAULT = 0x010
ACTCTX_FLAG_APPLICATION_NAME_VALID = 0x020
ACTCTX_FLAG_HMODULE_VALID = 0x080
DEACTIVATE_ACTCTX_FLAG_FORCE_EARLY_DEACTIVATION = 1
INVALID_HANDLE_VALUE = HANDLE(-1).value
ULONG_PTR = WPARAM # pointer-sized unsigned integer
class ACTCTX(Structure):
_fields_ = (("cbSize", ULONG),
("dwFlags", DWORD),
("lpSource", LPCWSTR),
("wProcessorArchitecture", USHORT),
("wLangId", LANGID),
("lpAssemblyDirectory", LPCWSTR),
("lpResourceName", LPCWSTR),
("lpApplicationName", LPCWSTR),
("hModule", HMODULE))
def __init__(self, *args, **kwds):
super(ACTCTX, self).__init__(sizeof(self), *args, **kwds)
CreateActCtxW = kernel32.CreateActCtxW
CreateActCtxW.restype = HANDLE
CreateActCtxW.argtypes = (POINTER(ACTCTX),)
ReleaseActCtx = kernel32.ReleaseActCtx
ReleaseActCtx.restype = None
ReleaseActCtx.argtypes = (HANDLE,)
ActivateActCtx = kernel32.ActivateActCtx
ActivateActCtx.argtypes = (HANDLE, POINTER(ULONG_PTR))
DeactivateActCtx = kernel32.DeactivateActCtx
DeactivateActCtx.argtypes = (DWORD, ULONG_PTR)
if __name__ == "__main__":
manifest_path = "actctx.manifest" # keep ref
ctx = ACTCTX(lpSource=manifest_path)
hActCtx = CreateActCtxW(byref(ctx))
if hActCtx == INVALID_HANDLE_VALUE:
raise WinError(get_last_error())
cookie = ULONG_PTR()
if not ActivateActCtx(hActCtx, byref(cookie)):
raise WinError()
msvcr90 = CDLL("msvcr90")
if not DeactivateActCtx(0, cookie):
raise WinError(get_last_error())
ReleaseActCtx(hActCtx)
# show DLL path
hModule = HANDLE(msvcr90._handle)
path = (c_wchar * 260)()
kernel32.GetModuleFileNameW(hModule, path, len(path))
print(path.value)
输出:
C:\Windows\WinSxS\amd64_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.6161_none_08e61857a83bc251\msvcr90.DLL
这是在 Python 3.4.2 下测试的,它是用 VS 2010 构建的,并改为与 msvcr100.dll 链接。所以至少在这种情况下确实需要设置激活上下文,否则加载 msvcr90.dll 将失败并显示ERROR_MOD_NOT_FOUND
。
【讨论】:
以上是关于如何在 Python 中从 SXS 加载 C DLL?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 MicroPython 中从 C 调用 python 函数