2011-09-13 10 views
0

ctypes.windll을 사용하여 타사 라이브러리를로드합니다. 이 라이브러리는 'MSVCRT80'을 사용하여 리소스를 확보하는 호출자의 책임임을 명시합니다. 따라서 우리는 windll.msvcrt.free(pointer)을 사용하여 외부 라이브러리가 반환 한 리소스를 해제하려고 시도했습니다. 이것은 windll.msvcrt이 다른 런타임 ('Python이 연결된'MSVCRT90.DLL ')이므로 실패합니다.ctypes를 사용하여 특정 런타임 라이브러리 (MSVCRT80)로드

따라서'MSVCRT80.DLL '을 명시 적으로로드해야하지만이 라이브러리를로드 할 방법을 찾을 수 없습니다. ctypes.util.find_library('msvcrt80')을 사용해 보았지만이 경우 None을 반환합니다. 실제 라이브러리는 c:\windows\winsxs\amd64_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.6195_none_88e41e092fab0294에있는 반면,이 함수는 경로를 통해서만 보았 기 때문에 이것이라고 생각합니다.

ctypes을 사용하여 올바른 런타임을로드 할 수있는 방법이 있습니까?

+0

열심히 그것을 찾기 DLL이 당신이 DLL을 사용하는 특정 런타임에서'free'를 호출하여 해방해야하는 리소스를 여러분에게 넘겨 줄 수 있다고 믿으십시오. 그것은 옳다는 것은 매우 어렵습니다. 무료 리소스를 호출하기 위해 DLL이 루틴을 내 보내지 않았습니까? 만약 당신이 말한다면, 당신은 벤더가 그들의 디자인을 고치거나 다른 라이브러리를 찾거나 리소스를 누출시킬 필요가 있다고 생각합니다! –

+0

@ David : 유감스럽게도 API에 의해 노출 된 무료 루틴은 없습니다. 끔찍한 일이지만 벤더가이 문제를 해결하는 데 어려움을 겪을 것입니다. 왜 그렇게 생각하는지에 대한 주된 이유는이 라이브러리가 대개 .NET 래퍼를 통해서만 노출된다는 것입니다. C++ 라이브러리는 대개 고객에게 직접 배포되지 않습니다. – larsmoa

+0

예치! 올바르게하기위한 한 가지 방법은 활성화 컨텍스트 API를 사용하는 것입니다. 그것은 ctypes에 의해'msvcrt80'이 올바르게로드되었는지 확인하는 좋은 방법입니다. 지저분한 방법은 프로세스에서 모듈을 열거하고 올바른 것을 선택하는 것입니다! –

답변

1

마침내이 문제의 해결 방법을 찾았습니다. 외부 라이브러리를로드 한 후 EnumProcessModules을 사용하여로드 된 모듈을 열거하고 GetModuleFileName을 사용하여 파일 이름을 확인한 다음 올바른 모듈을 참조하고이 런타임에서 free() -function을로드하십시오.

다음과 같이 내가이 일을 사용하고 코드는 다음과 같습니다

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

Hans' comment in your other question에 따르면 GetModuleHandle을 사용하여 이미로드 된 CRT의 핸들을 가져올 수 있습니다. 이처럼 : 그것은 가치가 무엇인지에 대한

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

windll.msvcrt 실제로 msvcrt.dll 이름과 system32 디렉토리에있는 Windows 시스템 공급 C 런타임을 말한다.

+0

사실 GetModuleHandleA ('msvcr80')는 모듈이로드 되었더라도 (다른 모듈과 함께 작동하지만, 어떤 이유로 든 런타임이 아니라) 0을 반환하므로 작동하지 않습니다. 그러나 이것은 나를 올바른 방향으로 밀었습니다. 솔루션에 대한 내 대답을 참조하십시오. – larsmoa

+0

재밌 네요, 저를 위해서 절대적으로 효과가있었습니다. 그러나 Python.exe가 링크되어 있기 때문에'msvcr90'으로 테스트했습니다. –

관련 문제