我们正在使用ctypes.windll
加载第三方库。该库使用“MSVCRT80”并声明呼叫者有责任释放资源。因此,我们尝试使用windll.msvcrt.free(pointer)
释放外部库返回的资源。这失败,因为windll.msvcrt
是另一个运行时(Python与之链接的'MSVCRT90.DLL')
因此我们明确需要加载'MSVCRT80.DLL',但我找不到加载这个库的方法。我尝试过使用ctypes.util.find_library('msvcrt80')
,但这会返回None
。我想这是因为这个函数只查看路径,而实际的库位于c:\windows\winsxs\amd64_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.6195_none_88e41e092fab0294
。
有没有办法可以使用ctypes
加载正确的运行时?
答案 0 :(得分:1)
根据Hans' comment in your other question,您可以使用GetModuleHandle来获取已加载的CRT的句柄。像这样:
handle = windll.kernel32.GetModuleHandleA('msvcr80')
msvcr80 = WinDLL('', handle=handle)
msvcr80.free(...)
对于它的价值,windll.msvcrt
实际上是指Windows系统提供的C运行时,它名为msvcrt.dll
并位于system32
目录中。
答案 1 :(得分:1)
我终于想出了解决这个问题的方法。加载外部库后,我使用EnumProcessModules
枚举已加载的模块,使用GetModuleFileName
确定文件名并引用正确的模块并从此运行时加载free()
- 函数。
我用来执行此操作的代码如下:
from ctypes import *
def enumProcessModules():
# Get handle of current process
kernel32 = windll.kernel32
kernel32.GetCurrentProcess.restype = c_void_p
hProcess = kernel32.GetCurrentProcess()
# Load EnumProcessModules either from kernel32.dll or psapi.dll
try:
EnumProcessModulesProc = windll.psapi.EnumProcessModules
except AttributeError:
EnumProcessModulesProc = windll.kernel32.EnumProcessModules
EnumProcessModulesProc.restype = c_bool
EnumProcessModulesProc.argtypes = [c_void_p, POINTER(c_void_p), c_ulong, POINTER(c_ulong)]
hProcess = kernel32.GetCurrentProcess()
hMods = (c_void_p * 1024)()
cbNeeded = c_ulong()
if EnumProcessModulesProc(hProcess, hMods, sizeof(hMods), byref(cbNeeded)):
return hMods
return None
def getLoadedModule(moduleName):
kernel32 = windll.kernel32
kernel32.GetModuleFileNameA.restype = c_ulong
kernel32.GetModuleFileNameA.argtypes = [c_void_p, c_char_p, c_ulong]
modules = enumProcessModules()
if modules is None:
return None
for module in modules:
cPath = c_char_p(' ' * 1024)
kernel32.GetModuleFileNameA(module, cPath, c_ulong(1024))
path = cPath.value
if path.lower().endswith(moduleName):
return module
return None
要加载正确的运行时并找到free()
函数,我使用上面的代码:
runtimeModuleHandle = getLoadedModule("msvcr80.dll")
runtimeModule = ctypes.CDLL('', handle = runtimeModuleHandle) # cdecl calling convention
runtimeModule.free.restype = None
runtimeModule.free.argtypes = [ctypes.c_void_p]
myFreeProc = runtimeModule.free