如何取消对嵌套ctypes结构中的值的引用?

2024-07-03 06:59:10 发布

您现在位置:Python中文网/ 问答频道 /正文

我想用ctypes将一些C代码SIGMAFP_SDK包装成Python, 但是下面的语法让我很困惑

操作系统:Windows10Pro Python版本:3.8.5

这是我的C头文件

typedef struct  _SDK_INFO
{
    void    *lpInterface;
    HANDLE  hMultipleOpenSync;
    void    *lpDataIn;
    void    *lpDataOut;
    void    *lpDataInBig;
    void    *lpDataOutBig;
    DWORD   dwDataInSize;
    DWORD   dwDataOutSize;

    DWORD   dwLastSendSize;
    DWORD   dwLastRecvSize;
    BOOL    bLastUseBugBuffer;
    BOOL    bUseBuffer;

    DWORD   dwDataInSizeBig;
    DWORD   dwDataOutSizeBig;
} SDK_INFO, *LPSDK_INFO;

typedef struct  tag_RATIONAL {
    ULONG   ulNumerator;
    ULONG   ulDenominator;
}   RATIONAL;

typedef struct  tag_SRATIONAL {
    LONG    lNumerator;
    LONG    lDenominator;
}   SRATIONAL;


typedef struct  tag_ImageFileDirectory {
    WORD    wTagId;
    WORD    wType;
    DWORD   dwCount;
    union
    {
        DWORD_PTR   ulData;
        VOID*       lpData;
        CHAR*       lpAscii;
        BYTE*       lpByte;
        USHORT*     lpShort;
        ULONG*      lpLong;
        RATIONAL*   lpRational;
        CHAR*       lpSbyte;
        BYTE*       lpUndefined;
        SHORT*      lpSshort;
        LONG*       lpSlong;
        SRATIONAL*  lpSrational;
        FLOAT*      lpFloat;
        DOUBLE*     lpDouble;
    }   Value;
}   ImageFileDirectory;

typedef struct  tag_IFDArray {
    DWORD               dwDirectoryCount;
    ImageFileDirectory* imageFileDirectory;
}   IFDArray;

typedef IFDArray    APIConfigTag;

HRESULT WINAPI sgm_ConfigAPI(LPSDK_INFO lpInfo, APIConfigTag *apiConfigTag);

我将上面的代码包装成python代码,如下所示

class _LPSDK_INFO(ctypes.Structure):
    _fields_ = [('lpInterface', ctypes.c_char_p),
                ('hMultipleOpenSync', wintypes.HANDLE),
                ('lpDataIn', ctypes.c_char_p),
                ('lpDataOut', ctypes.c_char_p),
                ('lpDataInBig', ctypes.c_char_p),
                ('lpDataOutBig', ctypes.c_char_p),
                ('dwDataInSize', wintypes.DWORD),
                ('dwDataOutSize', wintypes.DWORD),
                ('dwLastSendSize', wintypes.DWORD),
                ('dwLastRecvSize', wintypes.DWORD),
                ('bLastUseBugBuffer', wintypes.BOOL),
                ('bUseBuffer', ctypes.c_bool),
                ('dwDataInSizeBig', wintypes.DWORD),
                ('dwDataOutSizeBig', wintypes.DWORD)]


class _RATIONAL(ctypes.Structure):
    _fields_ = [('ulNumerator', wintypes.ULONG),
                ('ulDenominator', wintypes.ULONG)]


class _SRATIONAL(ctypes.Structure):
    _fields_ = [('lNumerator', wintypes.LONG),
                ('lDenominator', wintypes.LONG)]


class _Value(ctypes.Union):
    _fields_ = [('ulData',      ctypes.c_longlong),
                ('lpData',      wintypes.LPVOID),
                ('lpAscii',     wintypes.PCHAR),
                ('lpByte',      wintypes.PBYTE),
                ('lpShort',     wintypes.PUSHORT),
                ('lpLong',      wintypes.PULONG),
                ('lpRational',  ctypes.POINTER(_RATIONAL)),
                ('lpSbyte',     wintypes.PCHAR),
                ('lpUndefined', wintypes.PBYTE),
                ('lpSshort',    wintypes.PSHORT),
                ('lpSlong',     wintypes.PLONG),
                ('lpSrational', ctypes.POINTER(_SRATIONAL)),
                ('lpFloat',     wintypes.PFLOAT),
                ('lpDouble',    ctypes.POINTER(ctypes.c_double))]


class _ImageFileDirectory(ctypes.Structure):
    _fields_ = [('wTagId', wintypes.WORD),
                ('wType', wintypes.WORD),
                ('dwCount', wintypes.DWORD),
                ('Value', ctypes.POINTER(_Value))]


class _APIConfigTag(ctypes.Structure):
    _fields_ = [('dwDirectoryCount', wintypes.DWORD),
                ('imageFileDirectory', ctypes.POINTER(_ImageFileDirectory))]


if __name__ == '__main__':
    lpInfo = _LPSDK_INFO()
    apiConfigTag = _APIConfigTag()

    source_dir = os.path.dirname(__file__)
    SGM_CONFIGAPI = ctypes.CDLL(source_dir + '/dll/SIGMA_ConfigAPI.dll')
    c_sgm_ConfigAPI = SGM_CONFIGAPI.sgm_ConfigAPI
    c_sgm_ConfigAPI.restype = ctypes.c_long
    c_sgm_ConfigAPI.argtypes = [ctypes.POINTER(_LPSDK_INFO), ctypes.POINTER(_APIConfigTag)]
    result = c_sgm_ConfigAPI(ctypes.byref(lpInfo), ctypes.byref(apiConfigTag))
    print(f'c_sgm_ConfigAPI.result = {hex(result)}')
    print(f'apiConfigTag.dwDirectoryCount: {apiConfigTag.dwDirectoryCount}')
    print(f'apiConfigTag.imageFileDirectory.wTagId: {apiConfigTag.imageFileDirectory.wTagId}') # How can i reference wTagId's value?
    print(f'apiConfigTag.imageFileDirectory.wTagId.Value.ulData: {apiConfigTag.imageFileDirectory.wTagId.Value.ulData}') # And how about this value of wTagId.Value.ulData?

如果我删除代码上面的最后两行并执行它。 它工作正常

但我添加了最后两行并执行它 面对以下错误:

AttributeError: 'LP__ImageFileDirectory' object has no attribute 'wTagId'

如何取消对值的引用


Tags: infofieldsvaluectypesclasspointertypedefdword
1条回答
网友
1楼 · 发布于 2024-07-03 06:59:10

要取消对指针的引用,需要使用contents。然后可以访问它所指向的结构或联合的成员。例如:

print(apiConfigTag.imageFileDirectory.contents.wTagId)

print(apiConfigTag.imageFileDirectory.contents.Value.contents.ulData)

相关问题 更多 >