CTYPES structure passing

Discussion in 'Python' started by Peter West, Jun 3, 2010.

  1. Peter West

    Peter West Guest

    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?
     
    Peter West, Jun 3, 2010
    #1
    1. Advertising

  2. Peter West

    Bryan Guest

    Peter West wrote:
    > 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.

    --
    --Bryan
     
    Bryan, Jun 4, 2010
    #2
    1. Advertising

  3. Peter West

    Bryan Guest

    Correction/addendum: I wrote:
    > 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'".


    --
    --Bryan Olson
     
    Bryan, Jun 4, 2010
    #3
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Henk Punt
    Replies:
    0
    Views:
    397
    Henk Punt
    Jul 23, 2004
  2. =?utf-8?B?5Lq66KiA6JC95pel5piv5aSp5rav77yM5pyb5p6B

    ctypes: how to make a structure pointer to point to a buffer

    =?utf-8?B?5Lq66KiA6JC95pel5piv5aSp5rav77yM5pyb5p6B, Apr 23, 2007, in forum: Python
    Replies:
    1
    Views:
    1,073
    Diez B. Roggisch
    Apr 23, 2007
  3. Replies:
    7
    Views:
    490
  4. Michael Schäfer
    Replies:
    3
    Views:
    880
    Gabriel Genellina
    Apr 8, 2008
  5. Replies:
    0
    Views:
    504
Loading...

Share This Page