I’m working on a small project that requires interfacing Python to a C .dll. I’ve never had to pass an array of structures by reference before with ctypes, so here’s a quick sanity check I did to make sure I was doing it right before diving into something heavier.
The .dll source:
// structtest.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#ifdef STRUCTTEST_EXPORTS
#define STRUCTTEST_API __declspec(dllexport)
#else
#define STRUCTTEST_API __declspec(dllimport)
#endif
extern "C" {
struct structtest {
char x;
int y;
long z;
};
STRUCTTEST_API void fillonestruct(struct structtest *t)
{
t->x = 'A';
t->y = 1234;
t->z = 5678;
}
STRUCTTEST_API void fillmultiplestruct(struct structtest *t, int n)
{
for (int i = 0; i < n; i++)
{
t->x = (char)((int)'A' + i);
t->y = i;
t->z = i;
t++;
}
}
}
Here’s the Python program that uses the .dll:
from ctypes import *
class structtest(Structure):
_fields_ = [("x", c_char),
("y", c_int),
("z", c_long)]
if __name__ == "__main__":
n_struct2 = 5
lib = CDLL("structtest.dll")
struct1 = structtest()
struct2 = (structtest * n_struct2)()
print("Before passing to .dll")
print("Struct1 x:{} y:{} z:{}".format(struct1.x, struct1.y, struct1.z))
for i in range(n_struct2):
print("Struct2[{}] x:{} y:{} z:{}".format(i, struct2[i].x, struct2[i].y, struct2[i].z))
lib.fillonestruct(byref(struct1))
lib.fillmultiplestruct(byref(struct2), c_int(n_struct2))
print("\nAfter passing to .dll")
print("Struct1 x:{} y:{} z:{}".format(struct1.x, struct1.y, struct1.z))
for i in range(n_struct2):
print("Struct2[{}] x:{} y:{} z:{}".format(i, struct2[i].x, struct2[i].y, struct2[i].z))
The output:
Before passing to .dll
Struct1 x: y:0 z:0
Struct2[0] x: y:0 z:0
Struct2[1] x: y:0 z:0
Struct2[2] x: y:0 z:0
Struct2[3] x: y:0 z:0
Struct2[4] x: y:0 z:0
After passing to .dll
Struct1 x:A y:1234 z:5678
Struct2[0] x:A y:0 z:0
Struct2[1] x:B y:1 z:1
Struct2[2] x:C y:2 z:2
Struct2[3] x:D y:3 z:3
Struct2[4] x:E y:4 z:4
So hooray – everything works as expected.