Использование ctypes для загрузки определенной библиотеки времени выполнения (MSVCRT80) - PullRequest
0 голосов
/ 13 сентября 2011

Мы используем ctypes.windll для загрузки сторонней библиотеки. Эта библиотека использует MSVCRT80 и заявляет, что она несет ответственность за освобождение ресурсов. Поэтому мы попытались использовать windll.msvcrt.free(pointer) для освобождения ресурсов, возвращаемых внешней библиотекой. Это не удается, так как windll.msvcrt - это другая среда выполнения ('MSVCRT90.DLL', с которой связан Python)

Для этого нам явно нужно загрузить MSVCRT80.DLL, но я не могу найти способ загрузить эту библиотеку. Я пытался использовать ctypes.util.find_library('msvcrt80'), но это возвращает None. Я предполагаю, что это потому, что эта функция только просматривает путь, в то время как фактическая библиотека находится в c:\windows\winsxs\amd64_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.6195_none_88e41e092fab0294.

Можно ли как-нибудь загрузить правильное время выполнения, используя ctypes?

Ответы [ 2 ]

1 голос
/ 15 сентября 2011

Я наконец нашел способ обойти эту проблему.После загрузки внешней библиотеки я перечисляю загруженные модули, используя EnumProcessModules, определяю имена файлов, используя GetModuleFileName, ссылаюсь на правильный модуль и загружаю функцию free() из этой среды выполнения.

Код IЯ использую, чтобы сделать это следующим образом:

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
1 голос
/ 14 сентября 2011

Согласно комментарию Ганса в вашем другом вопросе , вы можете использовать GetModuleHandle, чтобы получить указатель на уже загруженный CRT.Например:

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

Что бы это ни стоило, windll.msvcrt фактически относится к среде выполнения C, поставляемой системой Windows, которая называется msvcrt.dll и находится в вашем каталоге system32.

...