Mathieu Gauquelin
Mathieu Gauquelin

Reputation: 625

Python Ctypes read char* returned from C++ dll

I am discovering the world of ctypes because I am writing a DLL in C++ on Windows with a C wrapper to be able to use it on Python for example. I don't understand how it works with pointer on Python when I return for example a char * from my C++ function, how to get the data at the adress of the pointer ?

myClass.h file:

#include "myClassInc.h"
class __declspec(dllexport) myClass// __declspec to generate .lib file
{
public:
    // Attributes
    char * name;

    // Methods
    myClass();
    ~myClass();

    bool myMethod(string);
};

myClassInc.h (C wrapper) :

#ifdef MYCLASS
#  define EXPORT __declspec(dllexport)
#else
#  define EXPORT __declspec(dllimport)
#endif

// Wrapper in C for others languages (LabVIEW, Python, C#, ...)
extern "C"
{
    EXPORT typedef struct myClass myClass; // make the class opaque to the wrapper
    EXPORT myClass* cCreateObject(void);
    EXPORT char* cMyMethod(myClass* pMyClass);
}

and myClass.cpp :

#include "myClass.h"

myClass::myClass() {}
myClass::~myClass() {}

bool myClass::myMethod(string filename_video)
{
    int iLength = filename_video.length();
    name = new char[iLength+1];
    strcpy(name, filename_video.c_str());
    return true;
}

myClass* cCreateObject(void)
{
    return new myClass();
}

char * cMyMethod(myClass* pMyClass)
{
    if (pMyClass->myMethod("hello world"))
        return pMyClass->name;
}

Finally pythonScript.py :

from ctypes import *

mydll = cdll.LoadLibrary("mydll.dll")
class mydllClass(object):
    def __init__(self):
        mydll.cCreateObject.argtypes = [c_void_p]
        mydll.cCreateObject.restype = c_void_p

        mydll.cMyMethod.argtypes = [c_void_p]
        mydll.cMyMethod.restype = POINTER(c_char_p)

        self.obj = mydll.cCreateObject("")

    def myMethod(self):
        return mydll.cMyMethod(self.obj)

f = mydllClass() # Create object
a = f.myMethod() # WANT HERE TO READ "HELLO WORLD"

The result in a is <__main__.LP_c_char_p object at 0x0000000002A4A4C8>.

I don't find on the ctypes documentation how to read the data of a pointer like this. Can you help me please?

The same question will follow if I want to pass from Python a char * to myDll, how to do this (typically to give at the dll the path of a file to read from Python).

Upvotes: 1

Views: 2274

Answers (1)

Mark Tolonen
Mark Tolonen

Reputation: 177471

c_char_p is a char*. POINTER(c_char_p) is a char**. Fix your .restype and you should be good. ctypes has a default behavior of converting a c_char_p to a Python byte string.

Also, mydll.cCreateObject.argtypes = None is correct for no arguments. The existing definition states a void* is a required parameter.

Upvotes: 3

Related Questions