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

时间:2011-06-13 16:32:14

标签: python windows ctypes dokan

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

一点背景......我正在尝试使用Dokan(版本0.6.0)构建用户空间文件系统。有些松散地说,Dokan基本上是FUSE用于Windows。我使用ctypes包装了dokan头文件(类似于pydokan)。该头文件包含一个看起来像这个

的函数指针的定义
typedef int (WINAPI *PFillFindData) (PWIN32_FIND_DATAW, PDOKAN_FILE_INFO);

它还包含另一个函数的原型

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

我很烦恼。乍一看,这看起来像是在尝试访问超出范围的内存。但这种错误只是偶尔发生。有时一切都运行正常,结果按预期返回。 (澄清一下,当我偶尔说,我的意思是错误发生在程序的某些运行而不是其他运行。错误似乎在一次运行中发生或不一致。)

我想知道我是否得到了错误代码而不是内存地址。我发现here 如果这是一个错误代码,那么它可能表示“内存不足”。当我查看系统监视器时,这似乎不是一个问题。我已尝试运行各种内存分析器,如HeapyMeliae,但它们似乎都不适用于Windows 64位上的Python 2.7。

我的下一个最好的猜测是这是使用64位操作系统的问题。也许用于函数指针的类型不足以正确地解决它。在做了一些谷歌搜索后,似乎其他人在Win64中使用ctypes时遇到了问题。我为64位架构构建了我的Dokan库。我的python代码有问题吗?

非常感谢任何帮助。我已经挣扎了一段时间了。

可以找到类似的帖子here。但它似乎并不十分相似。

注意:在python代码中,您将看到一些未在此处定义的类型(例如PDOKAN_FILE_INFO)。这些是结构或指向结构的指针,为了简洁起见,我没有包含它们。

1 个答案:

答案 0 :(得分:2)

如何实例化和使用回调?回调必须保留在可以调用它的生命周期的范围内。见this answer。这些


修改

澄清我认为问题是什么......

我认为你必须实现一个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的方式是正确的,尤其是。因为你说它间歇性地工作。我已经遇到过您之前看到的失败,而上述情况或类似会导致您看到的错误。

希望这会有所帮助......