2014-12-09 8 views
2

이것은 일반적으로 실행 파일과 함께있는 매니페스트 파일에 DLL 종속성을 지정하여 수행됩니다. 그러나, 나는 파이썬에서 이것을 달성하는 방법을 모른다. DLL을로드하는 것은 문제가 아니지만 SXS에서로드 할 적절한 DLL을 찾는 것이 문제입니다.SXS에서 Python으로 C DLL을 어떻게로드합니까?

DLL을 찾을 위치를 지정하는 표준 절차가 있습니까?

c:\windows\winsxs\amd64_my_handy_lib_<public_key_token>_1.0.0.0_none_<some_ID> 

정말 수동으로 이름을 내 DLL을 찾는 c:\windows\winsxs 디렉토리를 검색해야합니까, 그것은 올바른 버전이 포함되어 있는지 확인하기 위해 상위 디렉토리를 확인 :이 예제의이 여기에 살고있는 가정하자?

필자는 파이썬 프로젝트를 수행하기에 적절한 방법을 알기에 충분하지 않습니다.

+0

매니페스트를 확장 모듈 인 경우 .pyd에 포함하거나 전용 어셈블리 만 사용할 수 있습니다. ctype 인 경우 매니페스트를 포함시켜 활성화 컨텍스트를 만들 수 있습니다. 나는 그것이 당신이 필요로하는 것이면 후자에 대한 모범을 줄 수 있습니다. – eryksun

+0

확장 모듈이 아니지만 확실히 탐색 할 수있는 경로입니다. .pyd에 매니페스트를 삽입하는 방법에 대한 아이디어가 있습니까? 현재 다음과 같이 ctypes를 사용하여 DLL을 가져옵니다. 'self._lib = ctypes.CDLL (경로)' 여기서 ** 경로 **는 DLL 경로입니다. 당신이 언급 한 예를보고 싶습니다. – skiloup

답변

5

다음은 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 

,

이것은 VS 2010으로 작성된 Python 3.4.2에서 테스트되었으며 대신 msvcr100.dll과 연결됩니다. 따라서 최소한이 경우에는 활성화 컨텍스트를 설정하는 것이 실제로 필요합니다. 그렇지 않으면 msvcr90.dll로드가 ERROR_MOD_NOT_FOUND과 함께 실패합니다.