Python ctypes: How to modify an existing char* array

删除回忆录丶 提交于 2019-12-01 04:13:25

ctypes can allocate a buffer object that your C library should be able to write to:

import ctypes
init_size = 256
pBuf = ctypes.create_string_buffer(init_size)

See: http://docs.python.org/2/library/ctypes.html#ctypes.create_string_buffer

The callback is invoked with pBuf and nBufLength. pBuf is already allocated with writable memory, but if you ask for pBuf.value, this is converted to an immutable python string.

Instead convert pBuf to an object that can be modified directly:

## If pBuf is c_char_p, then convert to writable object
c = ctypes.cast(pBuf, ctypes.POINTER(ctypes.c_char))
## At this point, you can set individual bytes
## with c[i] = x, but this is dangerous and there's a safer way:

## get address of string
addr = ctypes.addressof(c.contents)

## convert to char[] for safe writing
c2 = (c_char*nBufLength).from_address(addr)

## see how many bytes to write
nb = min(len(msg), nBufLength-1)

c2[:nb] = msg[:nb]
c2[nb+1] = '\0'

Don't declare pBuf as c_char_p. ctypes converts that type to an immutable Python string. You'll want to declare it as POINTER(c_char) instead. A quick and dirty Windows example:

DLL code (compiled on MSVC as cl /LD test.c)

typedef int (*CALLBACK)(void *pFileHandle, char *pBuf, long nBufLength);
char g_buf[10] = "012345678";
CALLBACK g_callback;
__declspec(dllexport) void set_callback(CALLBACK callback) { g_callback = callback; }
__declspec(dllexport) void call_callback() { g_callback(0,g_buf,10); }
__declspec(dllexport) const char* get_buf() { return g_buf; }

Python 3.X code:

from ctypes import *

# Declare the callback type, argument types and return types
CALLBACK = CFUNCTYPE(c_int,c_void_p,POINTER(c_char),c_long)
dll = CDLL('x')
dll.set_callback.argtypes = [CALLBACK]
dll.set_callback.restype = None
dll.call_callback.argtypes = []
dll.call_callback.restype = None
dll.get_buf.argtypes = []
dll.get_buf.restype = c_char_p

@CALLBACK
def callback(handle,buf,length):
    for i in range(9):
        buf[i] = ord('A') + i
    buf[9] = 0
    return 0

dll.set_callback(callback)
dll.call_callback()
print(dll.get_buf())

Output:

b'ABCDEFGHI'
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!