Python calls C and C++ dynamic link library methods

  • 2020-04-02 13:53:00
  • OfStack

This article explains the method of calling C/C++ DLL dynamic link library in Python with an example. The specific example is as follows:

Example 1:

First, before creating a DLL project (this example creates the environment as VS 2005), the header file:


//hello.h
#ifdef EXPORT_HELLO_DLL
#define HELLO_API __declspec(dllexport)
#else
#define HELLO_API __declspec(dllimport)
#endif
extern "C"
{
 HELLO_API int IntAdd(int , int);
}

The CPP file:


//hello.cpp
#define EXPORT_HELLO_DLL
#include "hello.h"
HELLO_API int IntAdd(int a, int b)
{
 return a + b;
}

Here are two points to note:

(1) clear of compile time function calling conventions used in __cdecl or __stdcall, because according to the DLL function calling conventions, Python will use the corresponding function to load the DLL.

(2) if you use a C++ project, the exported interface needs extern "C" so that the exported function can be recognized in python.

In my project, I use the convention method of function call of s/s to compile and link to produce hello.dll, and then I use the ctypes library to load and call the hello.dll in Python:


from ctypes import *
dll = cdll.LoadLibrary('hello.dll');
ret = dll.IntAdd(2, 4);
print ret;

At this point, the first small example is complete, and you can try it yourself.

Example 2:

Example 1 is a "hello world" level program, in practice, more need to pass data structures, strings, etc., to meet our needs. This example will then show you how to pass data structure parameters and how to get the return value through the data structure.

First, write the DLL project in the header file:


//hello.h
#ifdef EXPORT_HELLO_DLL
#define HELLO_API __declspec(dllexport)
#else
#define HELLO_API __declspec(dllimport)
#endif

#define ARRAY_NUMBER 20
#define STR_LEN 20

struct StructTest
{
 int number;
 char* pChar;
 char str[STR_LEN];
 int iArray[ARRAY_NUMBER];
};

extern "C"
{
 //HELLO_API int IntAdd(int , int);
 HELLO_API char* GetStructInfo(struct StructTest* pStruct);
}

The CPP file is as follows:


//hello.cpp
#include <string.h>
#define EXPORT_HELLO_DLL
#include "hello.h"

HELLO_API char* GetStructInfo(struct StructTest* pStruct)
{
 for (int i = 0; i < ARRAY_NUMBER; i++)
 pStruct->iArray[i] = i;
 pStruct->pChar = "hello python!";
 strcpy (pStruct->str, "hello world!");
 pStruct->number = 100;
 return "just OK";
}

This function GetStructInfo returns "just OK" by passing a pointer to the StructTest type, then assigning values to properties in the object.

Writing Python calling code is as follows, first of all in Python inherit Structure to construct a and C DLL StructTest consistent data Structure, and then set function GetStructInfo parameter types and return type, and finally create a StructTest object, and transformed into a pointer as an argument, GetStrcutInfo call function, and finally the value of the output data Structure to check whether the call is successful:


from ctypes import *
ARRAY_NUMBER = 20;
STR_LEN = 20;
#define type
INTARRAY20 = c_int * ARRAY_NUMBER;
CHARARRAY20 = c_char * STR_LEN;
#define struct
class StructTest(Structure):
  _fields_ = [
    ("number", c_int),
    ("pChar", c_char_p),
    ("str", CHARARRAY20),
    ("iArray", INTARRAY20)
        ]
#load dll and get the function object
dll = cdll.LoadLibrary('hello.dll');
GetStructInfo = dll.GetStructInfo;
#set the return type
GetStructInfo.restype = c_char_p;
#set the argtypes
GetStructInfo.argtypes = [POINTER(StructTest)];
objectStruct = StructTest();
#invoke api GetStructInfo
retStr = GetStructInfo(byref(objectStruct));
#check result
print "number: ", objectStruct.number;
print "pChar: ", objectStruct.pChar;
print "str: ", objectStruct.str;
for i,val in enumerate(objectStruct.iArray):
  print 'Array[i]: ', val;
print retStr;

Conclusion:

1. Using 64-bit Python to load a 32-bit DLL will cause an error
2. The above are just some test programs. When writing Python, use "try Except" to handle exceptions whenever possible
3. Pay attention to byte alignment when Python interacts with C DLLS
4. The functionality of the ctypes library remains to be explored


Related articles: