views:

289

answers:

3

I've developped a DLL for a driver in C. I wrote a test program in C++ and the DLL works fine.

Now I'd like to interract with this DLL using Python. I've successfully hidden most of the user defined C structures but there is one point where I have to use C structures. I'm rather new to python so I may get things wrong.

My approach is to redefine a few structures in python using ctype then pass the variable to my DLL. However in these class I have a custom linked list which contains recursive types as follow

class EthercatDatagram(Structure):
    _fields_ = [("header", EthercatDatagramHeader),
       ("packet_data_length", c_int),
       ("packet_data", c_char_p),
       ("work_count", c_ushort),
       ("next_command", EthercatDatagram)]

This fails, because inside EthercatDatagram, EthercatDatagram is not already defined so the parser returns an error.

How should I represent this linked list in python so that my DLL understands it correctly?

A: 

You'll have to access _fields_ statically after you've created it.

class EthercatDatagram(Structure)
  _fields_ = [...]

EthercatDatagram._fields_.append(("next_command", EthercatDatagram))
Richard Levasseur
This doesn't work. It compiles and runs, but trying to actually use an instance of the class gives an error: AttributeError: 'EthercatDatagram' object has no attribute 'next_command'
user9876
+1  A: 

NOTE: This is wrong. I'm leaving it because there's a useful discussion, but beware. See comments.

Look carefully at what you're doing. You're creating a class, then you're trying to initialize a structure to contain links to the class, not an instance of the class. Is that what you intend?

If you did want to do that, and it may be perfectly reasonably when working with ctypes, remember python is a dynamic language. If you define the class before hand, you can always redefine it:

'''
Created on Aug 4, 2009

@author: lloyd
problem on stack overflow
'''
from ctypes import *

class Structure(object):
    pass

class EthercatDatagramHeader(object):
    pass

class EthercatDatagram(Structure):
    pass

class EthercatDatagram(Structure):
    _fields_ = [("header", EthercatDatagramHeader),
                        ("packet_data_length", c_int),
                        ("packet_data", c_char_p),
                        ("work_count", c_ushort),
                        ("next_command", EthercatDatagram)]
A. L. Flanagan
This creates two different classes called EthercatDatagram. The second class contains the first. So it won't work. (Think of "class Foo: ..." as a short form of "Foo = class(name="Foo", ...)".)
user9876
Blast, he's right (or she's right). It's kind of tricky to test, but if you do: fred = EthercatDatagram() print(dir(EthercatDatagram)) print(dir(fred._fields_[4][1]))then second object doesn't have the _fields_ structure. Sorry, I'm back to the drawing board...
A. L. Flanagan
A: 

You almost certainly want to declare next_command as a pointer. Having a structure that contains itself isn't possible (in any language).

I think this is what you want:

class EthercatDatagram(Structure):
    pass
EthercatDatagram._fields_ = [
    ("header", EthercatDatagramHeader),
    ("packet_data_length", c_int),
    ("packet_data", c_char_p),
    ("work_count", c_ushort),
    ("next_command", POINTER(EthercatDatagram))]
user9876