2011-06-13 3 views
3

파이썬의 ctypes를 사용하여 DLL을 작업하려하지만 다른 함수의 포인터로 전달 된 함수를 호출하려고 할 때 때때로 문제가 발생합니다.파이썬 ctypes : 함수 포인터를 사용할 때의 WindowsError

작은 배경 ... Dokan (버전 0.6.0)을 사용하여 사용자 공간 파일 시스템을 구축하려고합니다. 어느 정도 느슨하게 말하면 Dokan은 기본적으로 Windows 용 FUSE입니다. 나는 ctypes (pydokan과 유사)를 사용하여 dokan 헤더 파일을 싸서 만들었다. 그 헤더 파일은 또한

int (DOKAN_CALLBACK *FindFilesWithPattern) (
    LPCWSTR, 
    LPCWSTR, 
    PFillFindData, 
    PDOKAN_FILE_INFO); 

대응하는 ctypes 정의는이

PFillFindData = ctypes.WINFUNCTYPE(ctypes.c_int, 
            PWIN32_FIND_DATAW, 
            PDOKAN_FILE_INFO) 

FindFilesWithPattern = ctypes.WINFUNCTYPE(ctypes.c_int, 
              ctypes.c_wchar_p, 
              ctypes.c_wchar_p, 
              PFillFindData, 
              PDOKAN_FILE_INFO) 

같이 다른 함수의 프로토 타입을 포함이

typedef int (WINAPI *PFillFindData) (PWIN32_FIND_DATAW, PDOKAN_FILE_INFO); 

과 같은 함수 포인터에 대한 정의를 포함 후자 함수 (FindFilesWithPattern)의 구현은 전달 된 FillFindData 함수를 호출해야합니다. 나는 화가입니다

Traceback (most recent call last): 
    File "_ctypes/callbacks.c", line 313, in 'calling callback function' 
    File "src/test.py", line 385, in FindFilesWithPattern 
     FillFindData(pFile, DokanFileInfo) 
WindowsError: exception: access violation reading 0x0000000000000008 

:이 함수가 호출 될 때 기본 된 구현이

def FindFilesWithPattern(self, 
         FileName, 
         SearchPattern, 
         FillFindData, 
         DokanFileInfo): 
    if FileName == '\\': 
     File = WIN32_FIND_DATAW(FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_READONLY, 
           FILETIME(1, 1), 
           FILETIME(1, 1), 
           FILETIME(1, 1), 
           0, 
           len(self.HelloWorldText), 
           0, 
           0, 
           'Hello_World.txt', 
           'Hello_~1.txt') 
     pFile = PWIN32_FIND_DATAW(File) 
     FillFindData(pFile, DokanFileInfo) 
     return 0 
    else: 
     return -ERROR_FILE_NOT_FOUND 

처럼 보인다, 나는 가끔 다음과 같은 오류가 . 언뜻보기에 내가 범위를 벗어난 메모리에 액세스하려는 것처럼 보입니다. 그러나이 오류는 가끔 발생합니다. 때로는 모든 것이 잘 작동하고 결과가 예상대로 돌아옵니다. (명확히 말하자면, 가끔씩 말하면, 프로그램의 일부 실행에서 오류가 발생하고 단일 실행 내에서 오류가 발생하거나 일관되게 발생하지 않는 것입니다.)

나는 아마도 메모리 주소가 아닌 오류 코드가 다시 나타납니다. 나는 here 인 것을 발견했다. 이것은이 오류 코드이고 "not enough memory"라고 표시 될 수있다. 내가 시스템 모니터를 볼 때 이것은 문제가되지 않는다. HeapyMeliae과 같은 다양한 메모리 프로파일 러를 실행 해 보았습니다.하지만 어느 것도 Windows 64 비트에서 Python 2.7에서 작동하지 않습니다.

내 생각에 다음은 64 비트 OS를 사용하는 문제입니다. 함수 포인터에 대해 사용되는 유형이 적절하게 처리하기에 충분하지 않을 수 있습니다. 인터넷 검색을 한 후에 다른 사람들이 Win64에서 ctypes를 사용하는 데 문제가있는 것처럼 보입니다. 64 비트 아키텍처 용 Dokan 라이브러리를 구축했습니다. 내 파이썬 코드에 문제가 있습니까?

도움이 될 것입니다. 나는 이것과 함께 얼마 동안 고투했다.

비슷한 게시물은 here입니다. 그것은 끔찍하게 비슷하게 보이지 않습니다.

참고 : 여기서는 정의되지 않은 일부 유형 (예 : PDOKAN_FILE_INFO)이 파이썬 코드에 표시됩니다. 그것들은 간결성을 위해 포함시키지 않은 구조체 나 구조체에 대한 포인터입니다.

+0

"오류가 발생하거나 실행이 일관되게 발생하지 않는 것 같습니다." 이것은 나에게 오류가 입력에 의존한다는 것을 암시합니다. 따라서 메모리 문제 일 가능성은 거의 없습니다. 알고리즘이 처리 할 수없는 원치 않는/예상치 못한 입력이있을 가능성이 높습니다. – Santa

+0

함수의 첫 번째 줄에 FindFilesWithPattern 함수 (print "function pointer : {}". format (PFillFindData))에 print 문을 추가하면 오류가 사라집니다. print 문을 주석 처리 할 때 오류가 다시 발생합니다. 누구나 그 감각을 만들 수 있습니까? – Ryan

+0

위의 내 주석의 print 문을 .format (PFillFindData)을 포함하지 않는 다른 것으로 변경하면 오류가 발생합니다. – Ryan

답변

2

어떻게 콜백을 인스턴스화하고 사용합니까? 콜백은 호출 될 수있는 수명 동안 범위 내에 있어야합니다. this answer을 참조하십시오.내가 문제가 무슨 생각을 명확히이


편집

...

난 당신이 FindFilesWithPattern처럼 콜백을 구현하는 DOKAN_OPERATIONS 구조를 구현해야 참조, 그 구조 DokanMain 전화 파일 시스템을 마운트합니다. 구조체를 채울 때 콜백 유형을 작성한 다음 콜백을 파이썬 함수로 인스턴스화해야합니다. (의사)와 같은 뭔가 :

#Create the callback pointer type 
PFINDFILESWITHPATTERN = ctypes.WINFUNCTYPE(ctypes.c_int, 
              ctypes.c_wchar_p, 
              ctypes.c_wchar_p, 
              PFillFindData, 
              PDOKAN_FILE_INFO) 

# Implement in Python 
def FindFilesWithPatternImpl(...): 
    # implementation 

# Create a callback pointer object 
FindFilesWithPattern = PFINDFILESIWTHPATTERN(FindFilesWithPatternImpl) 

# Create the required structure listing the callback 
dokan_op = DOKAN_OPERATIONS(...,FindFilesWithPattern,...) 

# Register the callbacks 
DokanMain(byref(dokan_op)) 

당신은 콜백을 사용할 수있는 평생 dokan_op을 개체에 대한 참조를 유지해야합니다. 아래에 Dokan 비슷한 장착 구현하는 경우 :

def mount(): 
    # Create structure locally 
    dokan_op = DOKAN_OPERATIONS(...) 
    # Spin off thread to mount Dokan 
    threading.Thread(DokanMain,args=(byref(dokan_op),)) 

mount() 

dokan_op 반환 mount() 일단은 파괴 될 것이다. 이 시나리오는 저의 원래 대답으로 설명한 시나리오이므로보고있는 오류가 발생할 수 있습니다. 나는 나머지 코드가 어떻게 생겼는지 모르겠으므로 문제를 이론화하고있다.하지만 나는 파이썬에서 FindFilesWithPattern을 구현 한 방법이 정확하다고 생각한다. 당신이 간헐적으로 작동한다고 했거든요. 위와 같은 시나리오 또는 이와 유사한 오류가 발생했습니다. 으로 표시됩니다. 오류가 표시됩니다.

호프가 도움이 되었기를 바랍니다 ...

+0

아마 콜백을 어떤 의미에서 호출해서는 안됩니다. PFillFindData는 실제로는 typedef입니다. FindFilesWithPattern은 운영 체제에 의해 DLL에서 호출됩니다 (예 : "dir"명령 이후). 호출 될 때 함수 (FillFindData)에 대한 포인터를 전달합니다. FillFindData에 대한 구현은 실제로 내 파이썬 코드가 아닌 DLL에 있습니다. 조금 혼란 스럽다면 사과드립니다. – Ryan

+0

PFillFindData는 특정 함수 포인터에 대한 typedef이므로 c_void_p를 사용하는 것이 더 낫지 않습니까? – Ryan

+0

업데이트 : PFillFindData 대신 c_void_p를 사용하여 시도했지만 오류가 발생했습니다 (TypeError : 'long'개체는 호출 할 수 없음). – Ryan

관련 문제