CTYPES structure passing

P

Peter West

Hi

I'm hoping someone here can tell me what I'm doing wrong as I've spent
the best part of three days reading docs and trying code.

I want to port a windows DLL that controls a USB camera to Python
using C types. I've happily converted a lot of the functions but am
stuck with one vital function that requires a structure to be passed
to the DLL for filling with data.

I have the C declarations

CAM_API BOOL LUCAM_EXPORT LucamGetFormat(HANDLE hCamera,
LUCAM_FRAME_FORMAT *pFormat, FLOAT *pFrameRate);

where the LUCAM_FRAME_FORMAT is defined as

typedef struct {
ULONG xOffset; // x coordinate on imager of top left corner of
subwindow in pixels
ULONG yOffset; // y coordinate on imager of top left corner of
subwindow in pixels
ULONG width; // width in pixels of subwindow
ULONG height; // height in pixels of subwindow
ULONG pixelFormat; // pixel format for data
union
{
USHORT subSampleX; // sub-sample ratio in x direction in pixels
(x:1)
USHORT binningX; // binning ratio in x direction in pixels (x:1)
};
USHORT flagsX; // LUCAM_FRAME_FORMAT_FLAGS_*
union
{
USHORT subSampleY; // sub-sample ratio in y direction in pixels
(y:1)
USHORT binningY; // binning ratio in y direction in pixels (y:1)
};
USHORT flagsY; // LUCAM_FRAME_FORMAT_FLAGS_*
} LUCAM_FRAME_FORMAT;

In my Python code I have

#------------- Frame format --------------------
class FRAME_FORMAT_UNION(Union):
__fields__ = [("subSample", c_ushort), # sub-sample ratio in x
direction in pixels (x:1)
("binning", c_ushort )] # binning ratio in x
direction in pixels (x:1)


class LUCAM_FRAME_FORMAT(Structure):
__fields__ = [( "xOffset", c_ulong), # x coordinate on imager of
top left corner of subwindow in pixels
( "yOffset", c_ulong), # y coordinate on imager of
top left corner of subwindow in pixels
( "width", c_ulong), # width in pixels of
subwindow
( "height", c_ulong), # height in pixels of
subwindow
( "pixelFormat", c_ulong), #pixel format for data
( "XUnion", FRAME_FORMAT_UNION),
( "flagsX", c_ushort), # LUCAM_FRAME_FORMAT_FLAGS_*
( "YUnion", FRAME_FORMAT_UNION),
( "flagsY", c_ushort)]

LP_FRAME_FORMAT = POINTER(LUCAM_FRAME_FORMAT)

and make the call like this

FrameRate = c_float(0)
FrameFormat = LUCAM_FRAME_FORMAT()

FrameFormat.xOffset = 0
FrameFormat.yOffset = 0
FrameFormat.width = 0
FrameFormat.height = 0
FrameFormat.pixelFormat = 0
FrameFormat.XUnion = 0
FrameFormat.flagsX = 0
FrameFormat.YUnion = 0
FrameFormat.flagsY = 0

lucam = windll.lucamapi
error = bool()
GetFormat = lucam.LucamGetFormat
GetFormat.argtypes = ( HANDLE, LP_FRAME_FORMAT, POINTER(c_float) )
GetFormat.restype = BOOL
error = GetFormat (hCamera, FrameFormat, FrameRate )

On return the FrameRate parameter is correct but the FrameFormat
structure no longer has the any field attributes. Further more it
often generates an access violation, apparently in python26.dll. I
guess the call is writing to unallocated memory but I have no idea
why.

Can anyone help?
 
B

Bryan

Peter said:
I'm hoping someone here can tell me what I'm doing wrong as I've spent
the best part of three days reading docs and trying code.

Yeah, I imagine a person could re-read them over and over and not see
the gotcha. Sit down, maybe prepare some comfort food, and try to to
be to upset when you find out how your three days were wasted...

[...]
In my Python code I have

#------------- Frame format --------------------
class FRAME_FORMAT_UNION(Union):
    __fields__ = [("subSample", c_ushort),  #  sub-sample ratio in x
direction in pixels (x:1)
                 ("binning", c_ushort )]    #  binning ratio in x
direction in pixels (x:1)

class LUCAM_FRAME_FORMAT(Structure):
   __fields__ = [( "xOffset", c_ulong),  # x coordinate on imager of
top left corner of subwindow in pixels

There's your problem: The all-important _fields_ attribute is spelled
with *single* underscores. You're probably familiar with the Python
convention of special member names with double-underscores at each
end? Well, ctypes doesn't follow it.

[...]
and make the call like this

FrameRate = c_float(0)
FrameFormat = LUCAM_FRAME_FORMAT()

FrameFormat.xOffset = 0
FrameFormat.yOffset = 0
FrameFormat.width = 0
FrameFormat.width = 0
FrameFormat.height = 0
FrameFormat.pixelFormat = 0
FrameFormat.XUnion = 0
FrameFormat.flagsX = 0
FrameFormat.YUnion = 0
FrameFormat.flagsY = 0


Which gives your FrameRate object some new attributes, completely
unrelated to the _fields_ that ctypes uses to lay out a struct.

Rhodri James pointed out that you want:

FrameFormat.XUnion.subSample = 0
or
FrameFormat.XUnion.binning = 0

And same for FrameFormat.YUnion. If you spell _fields_ as ctypes
requires, it will complain about your assignments, in that you are
trying to assign an in to a union. As your code is, those assignments
just make a new attribute to which you can assign anything.
 
B

Bryan

Correction/addendum: I said:
try to to
be to upset when you find out how your three days were wasted...

Of course that's, "try not to be too upset..."

[...]
You're probably familiar with the Python
convention of special member names with double-underscores at each
end? Well, ctypes doesn't follow it.

The double-ended-double-underscore convention is for names defined by
the Python language. As a library module, ctypes is technically right
not to use it. It's still a diabolical gotcha.

[...]
If you spell _fields_ as ctypes
requires, it will complain about your assignments, in that you are
trying to assign an in to a union.

Obviously a typo, for "trying to assign an int to a union." Come to
think of it, I bet initially Peter West had that bit right. Because of
the _fields_ issue, the correct assignment failed:

FrameFormat.XUnion.subSample = 0

Without _fields_, ctypes did not create a FrameFormat.XUnion member,
so the assignment fails with "AttributeError: 'LUCAM_FRAME_FORMAT'
object has no attribute 'XUnion'".
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,736
Latest member
AdolphBig6

Latest Threads

Top