开发者

Using ctypes to load a specific runtime library (MSVCRT80)

We're using ctypes.windll to load a third-party library. This library uses 'MSVCRT80' and states that it's callers responsibility to free resources. Therefor we've tried using windll.msvcrt.free(pointer) to free resources returned by the external library. This fails as windll.msvcrt is another runtime ('MSVCRT90.DLL' which Python is linked with)

Therefor we explicitly need to load 'MSVCRT80.DLL', but I can't find a way to load this library. I've tried using ctypes.util.find_library('msvcrt80') but this returns None. I guess this is because this function only looks through the path, while the actual library is located at c:\windows\winsxs\amd64_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.6195_none_88e41开发者_如何转开发e092fab0294.

Is there any way I can load the correct runtime using ctypes?


According to Hans' comment in your other question, you can use GetModuleHandle to get the handle to the already loaded CRT. Like this:

handle = windll.kernel32.GetModuleHandleA('msvcr80')
msvcr80 = WinDLL('', handle=handle)
msvcr80.free(...)

For what it's worth, windll.msvcrt actually refers to the Windows system supplied C runtime, which is named msvcrt.dll and resides in your system32 directory.


I finally figured out a workaround for this problem. After loading the external library, I enumerate over the loaded modules using EnumProcessModules, determine the filenames using GetModuleFileName and reference the correct module and load the free()-function from this runtime.

The code I'm using to do this is as follows:

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

To load the correct runtime and find the free() function I use the code above:

    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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜