【问题标题】:Python CFFI + 7z.dll (COM) == access violations (sometimes)Python CFFI + 7z.dll (COM) == 访问冲突(有时)
【发布时间】:2013-09-04 22:58:19
【问题描述】:

我已将我的代码缩短为一个最小的用例。

脚本总是会完成,但大约 50% 的时间会出现内存访问冲突/崩溃。

这是在 Windows 7 上使用 64 位 Python 3

这段代码应该循环遍历 7zip 的所有处理程序并说明它们支持哪些扩展(以空格分隔的列表,可能为空...不是 VT_EMPTY,只是 bstrVal=L"")

#!/usr/bin/python
from cffi import FFI
ffi = FFI()
ffi.cdef("""

typedef struct PROPVARIANT {
    unsigned short    vt;
    unsigned short    wReserved1;
    unsigned short    wReserved2;
    unsigned short    wReserved3;
    union {
        int          intVal;
        wchar_t*      bstrVal;
        /* shortened for clarity */
    };
} PROPVARIANT;

typedef unsigned long long HRESULT;
typedef uint32_t PROPID;

HRESULT GetNumberOfFormats(uint32_t * numFormats);
HRESULT GetHandlerProperty2(uint32_t index, PROPID propID, PROPVARIANT * value);
""")

S_OK = 0x00000000  # Operation successful
VT_BSTR = 8
kExtension = 2

dll7z = ffi.dlopen('7z.dll')
num_formats = ffi.new('uint32_t*')
assert dll7z.GetNumberOfFormats(num_formats) == S_OK
print(num_formats[0])

tmp_pvar = ffi.new('PROPVARIANT*')
for i in range(num_formats[0]):
    assert dll7z.GetHandlerProperty2(i, kExtension, tmp_pvar) == S_OK
    assert tmp_pvar != ffi.NULL
    assert tmp_pvar[0].vt == VT_BSTR

    print(ffi.string(tmp_pvar[0].bstrVal))

令人烦恼的是,等效的 ctypes 代码似乎可以正常工作。

from ctypes import *

class PROPVARIANT(Structure):
    _fields_ = [
        ('vt', c_ushort),
        ('resrved1',  c_ushort),
        ('resrved2',  c_ushort),
        ('resrved3',  c_ushort),
        ('bstrVal', c_wchar_p),
    ]

dll7z = windll.LoadLibrary('7z.dll')

S_OK = 0x00000000  # Operation successful
VT_BSTR = 8
kExtension = 2

num_formats = c_uint()
assert dll7z.GetNumberOfFormats(byref(num_formats)) == S_OK
print(num_formats.value)

tmp_pvar = PROPVARIANT()
for i in range(num_formats.value):
    assert dll7z.GetHandlerProperty2(i, kExtension, tmp_pvar) == S_OK
    assert tmp_pvar.vt == VT_BSTR
    print(tmp_pvar.bstrVal)

【问题讨论】:

    标签: python python-3.x com 7zip python-cffi


    【解决方案1】:

    好的,这看起来像一个 CFFI 错误。

    如果我手动使用 malloc/free/memset,它可以正常工作。

    代码:

    from cffi import FFI
    ffi = FFI()
    ffi.cdef("""
    
    typedef struct PROPVARIANT {
        unsigned short    vt;
        unsigned short    wReserved1;
        unsigned short    wReserved2;
        unsigned short    wReserved3;
        union {
            int          intVal;
            wchar_t*      bstrVal;
            /* shortened for clarity */
        };
    } PROPVARIANT;
    
    typedef unsigned long long HRESULT;
    typedef uint32_t PROPID;
    
    HRESULT GetNumberOfFormats(uint32_t * numFormats);
    HRESULT GetHandlerProperty2(uint32_t index, PROPID propID, PROPVARIANT * value);
    
    void * malloc(size_t);
    void memset(void*, int, int);
    void free(void*);
    """)
    
    S_OK = 0x00000000  # Operation successful
    VT_BSTR = 8
    kExtension = 2
    
    dll7z = ffi.dlopen('7z.dll')
    C = ffi.dlopen(None)
    
    num_formats = ffi.new('uint32_t*')
    assert dll7z.GetNumberOfFormats(num_formats) == S_OK
    print(num_formats[0])
    
    tmp_pvar = ffi.cast("PROPVARIANT*", C.malloc(ffi.sizeof('PROPVARIANT')))
    C.memset(tmp_pvar, 0, ffi.sizeof('PROPVARIANT'))
    
    for i in range(num_formats[0]):
        assert dll7z.GetHandlerProperty2(i, kExtension, tmp_pvar) == S_OK
        assert tmp_pvar != ffi.NULL
        assert tmp_pvar[0].vt == VT_BSTR
    
        print(ffi.string(tmp_pvar[0].bstrVal))
    
    C.free(tmp_pvar)
    

    【讨论】:

      猜你喜欢
      • 2012-05-14
      • 1970-01-01
      • 2012-05-02
      • 1970-01-01
      • 2020-05-28
      • 1970-01-01
      • 1970-01-01
      • 2018-07-08
      • 1970-01-01
      相关资源
      最近更新 更多