如何使用 ctypes 从缓冲区中读回?

How can I read back from a buffer using ctypes?

我有一个第三方库,我需要使用它的 python 脚本中的一个函数。这是:

ReadFromBlob(PVOID blob, INT blob_size, PCSTR section, PCSTR key, const void **buffer, UINT * size)

文档给出了如何使用它的示例:

UINT size = 0;
PVOID buffer = NULL;
ReadFromBlob(<blob>, <blob_size>, "MainImage", "Image", &buffer, &size);

我不熟悉 C,所以参数类型让我很困惑。我需要能够从 python 中的缓冲区中读取值。 这是我目前所拥有的:

from ctypes import *
lib = cdll.LoadLibrary(path_to_lib)
with open(filepath, 'rb') as file:
    data = file.read()
blob_size = c_int(len(data))
blob = cast(c_char_p(data), POINTER(c_char * blob_size.value))
b = bytes()
size = c_uint(len(b))
buffer = cast(cast(b, c_void_p), POINTER(c_char * size.value))
lib.ReadFromBlob(blob, blob_size, b"MainImage", b"Image", buffer, pointer(size))

但我最后还是得到了一个空缓冲区。请帮助我。

看起来该函数根据部分和键以及 returns 指向 blob 数据和大小的指针在 blob 中搜索数据,所以我创建了一个测试函数,它只回显 blob 和大小作为输出参数:

#include <windows.h>
#include <stdio.h>

__declspec(dllexport)
void ReadFromBlob(PVOID blob, INT blob_size, PCSTR section, PCSTR key, const void **buffer, UINT * size) {
    printf("section=\"%s\" key=\"%s\"\n",section,key);
    *buffer = blob;            // just echo back input data for example
    *size = (UINT)blob_size;
}

类型看起来像 Windows 类型,并且 ctypes 有一个子模块 wintypes,其中包含 Windows 定义,有助于正确设置类型。确保使用 Windows 类型的并行 ctypes 类型正确设置 .argtypes.restype。这有助于 ctypes 检查参数是否正确传递。

import ctypes as ct
from ctypes import wintypes as w

dll = ct.CDLL('./test')

# Note the parallels between C types and ctypes types.
# PVOID is just "pointer to void" and LPVOID mean the same thing, etc.
dll.ReadFromBlob.argtypes = w.LPVOID,w.INT,w.LPCSTR,w.LPCSTR,ct.POINTER(w.LPCVOID),w.LPUINT
dll.ReadFromBlob.restype = None

# storage for returned values, passed by reference as output parameters
buffer = w.LPCVOID()
size = w.UINT()
dll.ReadFromBlob(b'filedata',8,b'Section',b'Key',ct.byref(buffer),ct.byref(size))
print(ct.cast(buffer,ct.c_char_p).value,size.value)

输出显示接收到的部分和密钥,并打印返回的 blob 数据和大小:

section="Section" key="Key"
b'filedata' 8