更新在C DLL中创建的LP_c_ubyte缓冲区

时间:2018-04-26 17:53:05

标签: python dll ctypes

我正在使用Python ctypes为C DLL创建一个Python包装器。

在下面的Python代码中,我创建了一个connectionString的数组c_ubyte,我需要填充个人。例如1,2,3,4,5,6 ...此连接字符串将传递给DLL的DoCallBack函数并打印。为回调函数创建一个缓冲区以填充,并将所有内容传递给python回调函数。

  1. 我正在寻找一种方法来更新connectionString字节,然后再将它们传递给DLL的DoCallBack
  2. 然后如何从python connectionString函数中的callbackFnk中提取字节。
  3. 我正在寻找一种方法来更新outBuffer python函数中的callbackFnk中的字节
  4. 这个问题的延续 In python how do I set the value of a LP_c_ubyte

    C DLL代码

    typedef void(*FPCallback)(unsigned char * outBuffer, unsigned short MaxOutBufferLength, unsigned char * connectionString);
    FPCallback g_Callback;
    
    extern "C" __declspec( dllexport ) void RegisterCallback(void(*p_Callback)( unsigned char * outBuffer, unsigned short MaxOutBufferLength, unsigned char * connectionString)) {
        g_Callback = p_Callback ; 
    }
    
    extern "C" __declspec( dllexport ) void DoCallBack( unsigned char connectionString) {
        printf( "connectionString=[%02x %02x %02x %02x %02x %02x...]\n", connectionString[0], connectionString[1], connectionString[2], connectionString[3], connectionString[4], connectionString[5] ); 
        const unsigned short MAX_BUFFER_SIZE = 6 ; 
        unsigned char outBuffer[MAX_BUFFER_SIZE];     
    
        g_Callback( outBuffer, MAX_BUFFER_SIZE, connectionString, 6 ); 
    
        // Print the results. 
        printf( "buffer=[%02x %02x %02x %02x %02x %02x...]\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5] ); 
    }
    

    Python代码

    def callbackFnk( outBuffer, outBufferMaxSize, connectionString )
        # (Q2) How do I extract individual bytes of the connectionString? 
        # (Q3) How do I update individual bytes of the out buffer?     
    
    customDLL = cdll.LoadLibrary ("customeDLL.dll")
    
    # RegisterCallback
    CustomDLLCallbackFUNC = CFUNCTYPE(None, POINTER( c_ubyte), c_ushort, POINTER( c_ubyte) )
    CustomDLLCallback_func = CustomDLLCallbackFUNC( callbackFnk )
    RegisterCallback = customDLL.RegisterCallback
    RegisterCallback.argtypes = [ CustomDLLCallbackFUNC ]
    RegisterCallback( CustomDLLCallback_func ) 
    
    # DoCallBack
    DoCallBack = customDLL.DoCallBack
    DoCallBack.argtypes = [ POINTER( c_ubyte) ]
    
    connectionString = c_ubyte(6) 
    # (Q1) How do I update this array of bytes? 
    
    # Call the callback 
    DoCallBack(connectionString) 
    

1 个答案:

答案 0 :(得分:1)

OP的例子有很多错误而且没有编译,所以我把它放在一起。我假设connectionString只是一个以空终止的输入字符串,并演示更新回调中的输出字符串。

注意 input 字符串,c_char_p可以是类型,并且可以传递Python字节字符串。 c_wchar_p用于Python Unicode字符串。不得在C代码中修改字符串。回调函数也会将它作为Python字符串接收,使其易于阅读。

输出缓冲区只能被索引,小心不要索引超过缓冲区的长度。调用者分配的输出缓冲区应始终作为指针和长度传递。

C ++ DLL

#include <stdio.h>

typedef void (*CALLBACK)(const char* string, unsigned char* buffer, size_t size);

CALLBACK g_pCallback;

extern "C" __declspec(dllexport) void RegisterCallback(CALLBACK pCallback) {
    g_pCallback = pCallback;
}

extern "C" __declspec(dllexport) void DoCallBack(char* string) {
    unsigned char buf[6];
    printf("string = %s\n", string);
    g_pCallback(string, buf, sizeof(buf));
    printf("buf = [%02x %02x %02x %02x %02x %02x]\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
}

<强>的Python

from ctypes import *

CALLBACK = CFUNCTYPE(None,c_char_p,POINTER(c_ubyte),c_size_t)

@CALLBACK
def callback(string,buf,length):
    print(string)
    for i in range(length):
        buf[i] = i * 2

dll = CDLL('test')

# RegisterCallback
RegisterCallback = dll.RegisterCallback
RegisterCallback.argtypes = [CALLBACK]
RegisterCallback.restype = None
RegisterCallback(callback) 

# DoCallBack
DoCallBack = dll.DoCallBack
DoCallBack.argtypes = [c_char_p]
DoCallBack.restype = None
DoCallBack(b'test string')

<强>输出

string = test string
b'test string'
buf = [00 02 04 06 08 0a]