pythonctypes

ctypes: Passing string by reference


With regard to Python 2.5, I wish to implement the following C code in python:

C code:

#include <wtypes.h>

__declspec(dllexport) X_ERROR __stdcall GetAdmSize(INT* piAdmSize, CHAR** chBuf, INT iBufSize);

int iProgSize = 0;
char szProgSize[50];
char* pszProgSize = szProgSize;
error = GetAdmSize(&iProgSize, &pszProgSize, 49);

Python code:

from ctypes import *
c_bool = c_int

x = windll.LoadLibrary("x.dll")
iProgSize = c_int()
szProgSize = create_string_buffer(50)
getAdmSize = x.AdkGetAdmSize
getAdmSize.argtypes = [POINTER(c_int), POINTER(c_char_p), c_int]
status = getAdmSize(byref(iProgSize), byref(szProgSize), 49)

But I'm getting the following exception:

Traceback (most recent call last):
    status = getAdmSize(byref(iProgSize), (szProgSize), 49)
ArgumentError: argument 2: <type 'exceptions.TypeError'>: expected LP_c_char_p instance instead of c_char_Array_50

What am I doing wrong?

UPDATE:

I tried:

pointerToStringBuffer = cast(szProgSize, c_char_p)
status = getAdmSize(byref(iProgSize), byref(pointerToStringBuffer), 49)

But this gives me:

Traceback (most recent call last):
    status = getAdmSize(byref(iProgSize), byref(pointerToStringBuffer), 49)
WindowsError: exception: access violation reading 0x00000031

As a matter of interest, I get the same error in C if I call this:

error = AdkGetAdmSize((int*)0, (char**)49, 0);

Seems like my arguments are not aligned correctly perhaps

Any suggestions?


Solution

  • A direct translation of your C code would be more like:

    import ctypes as ct
    
    dll = ct.WinDLL('./test.dll')
    iProgSize = ct.c_int(0)
    szProgSize = ct.create_string_buffer(50)
    pszProgSize = ct.c_char_p(ct.addressof(szProgSize))
    getAdmSize = dll.GetAdmSize
    getAdmSize.argtypes = ct.POINTER(ct.c_int), ct.POINTER(ct.c_char_p), ct.c_int
    getAdmSize.restype = ct.c_int
    status = getAdmSize(ct.byref(iProgSize), ct.byref(pszProgSize), 49)
    

    Mockup DLL I tested with:

    typedef int X_ERROR;
    typedef int INT;
    typedef char CHAR;
    
    #include <string.h>
    
    __declspec(dllexport)
    X_ERROR __stdcall GetAdmSize(INT* piAdmSize, CHAR** chBuf, INT iBufSize)
    {
        *piAdmSize = 5;
        strcpy_s(*chBuf, iBufSize, "abcd");
        return 1;
    }
    

    Results:

    >>> x.iProgSize
    c_long(5)
    >>> x.pszProgSize
    c_char_p('abcd')
    >>> x.szProgSize.value
    'abcd'