Python ctypes:使用函数指针时的WindowsError

我正在尝试使用Python的ctypes来处理DLL,但是当我尝试调用一个作为另一个函数指针传递的函数时,偶尔会遇到问题。

一个小背景…我试图build立一个使用Dokan (版本0.6.0)的用户空间文件系统。 有点宽松地说,Dokan基本上是Windows的FUSE 。 我用ctypes(类似于pydokan )包裹了dokan头文件。 该头文件包含一个函数指针的定义,如下所示

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

它还包含另一个function的原型

 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) 

后一个函数(FindFilesWithPattern)的实现必须调用它传递的FillFindData函数。 一个基本的实现看起来像这样

 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 

当这个函数被调用时,我偶尔会得到下面的错误:

 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 

我很烦。 乍一看,这看起来像我试图访问超出范围的内存。 但是这个错误偶尔会发生。 有时一切正常,结果如预期回来。 (为了澄清,当我偶尔说,我的意思是错误发生在程序的某些运行上,而不是在其他程序上发生,错误似乎在一次运行中一直发生或不发生。

我想知道如果也许我得到一个错误代码,而不是一个内存地址。 我在这里发现, 如果这是一个错误代码,那么它可能表示“没有足够的内存”。 当我看着系统监视器,这似乎并不是一个问题,虽然。 我已经尝试过运行像Heapy和Meliae这样的各种内存分析器,但是他们都没有使用Windows 64位上的Python 2.7。

我的下一个最好的猜测是,这是一个使用64位操作系统的问题。 也许用于函数指针的types不足以正确解决它。 在做一些Googlesearch之后,似乎其他人在使用Win64中的ctypes时遇到了问题。 我已经build立了我的Dokan库为64位架构。 那么我的Python代码有问题吗?

任何帮助将非常感激。 我已经为此奋斗了一段时间了。

类似的post可以在这里find。 这似乎并不相似,但。

注意:在python代码中,你会看到一些在这里没有定义的types(例如PDOKAN_FILE_INFO)。 那些结构或指向结构的指针,为了简洁起见,我没有包含它们。

你如何实例化和使用你的回调? 回调必须保持在可能被调用的生命周期的范围内。 看到这个答案 。 这些


编辑

澄清我认为的问题是…

我看到你必须实现一个DOKAN_OPERATIONS结构来实现像FindFilesWithPattern这样的回调,然后用这个结构调用DokanMain来挂载文件系统。 当你填写结构时,你应该为回调创建一个类型,然后用Python函数实例化回调。 像(伪代码):

 #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() 

一旦mount()返回dokan_op将被破坏。 这是我原来的答案所描述的情况,并会导致你所看到的错误。 因为我不知道代码的其余部分是什么样的,所以我推理你的问题,但是我认为你用Python实现FindFilesWithPattern的方式是正确的,尤其是, 因为你说它间歇性的工作。 我遇到了你以前看到的失败,上面的情况或类似的东西导致你看到的错误。

希望这可以帮助…