ctypes, function pointers and a lot of trouble

M

Matt

Hi friends,

Okay so well, I have quite a problem right now with a file stream. What
I am doing is to use the Cannon SDK dlls to get control over my old
Cannon A60 Camera for some surveillance useage.

By using ctypes it all worked well until now. I am able to load the
dlls, use a lot of functions, am able to connect to the camera, read out
some params, send commands etc... but now I am stuck with reading the
picture data.

In C the code looks as follows (found in an supplemental *.h SDK file:

------------------------------CODE-----------------------------------------

#define cdSTDCALL __stdcall

typedef void cdSTDCALL cdSOpen(cdContext contextH, cdPermission,
cdError* err);
typedef void cdSTDCALL cdSClose(cdContext contextH, cdError* err);
typedef void cdSTDCALL cdSRead(cdContext contextH, void* buf,
cdUInt32* bufsize, cdError* err);
typedef void cdSTDCALL cdSWrite(cdContext contextH, const void *buf,
cdUInt32* bufsize, cdError *err);
typedef void cdSTDCALL cdSSeek(cdContext contextH, cdWhence, cdInt32
offset, cdError* err);
typedef cdInt32 cdSTDCALL cdSTell(cdContext contextH, cdError* err);
typedef void cdSTDCALL cdSProgress(cdContext contextH, cdUInt16
percentDone, cdError* err);

/* cdStream
*/
typedef struct {
cdContext contextH;
/* stream I/O function pointers */
cdSOpen* open;
cdSClose* close;
cdSRead* read;
cdSWrite* write;
cdSSeek* seek;
cdSTell* tell;
} cdStream;

/* cdStgMedium
*/
typedef struct {
cdMemType Type; /* Type of the medium (u). */
union {
cdChar* lpszFileName;
cdStream* pStream;
#ifdef macintosh
cdFSSpec* pFSSpec;
#endif
}u; /* Union of all transfer medium */
} cdStgMedium;

------------------------------\CODE----------------------------------------

and this is the function definition that should give me access to the
data stream (available via DLL):

------------------------------CODE-----------------------------------------

cdCAPI CDGetReleasedData(
cdHSource hSource,
cdProgressCallbackFunction * pCallbackFunc,
cdContext Context,
cdProgressOption ProgressOption,
cdReleaseImageInfo* pInfo,
cdStgMedium* pStgMedium
);

------------------------------\CODE----------------------------------------

So, since I'm no C-Professional, I can only guess what that code does.
With some previous commands I tell the camera to make a picture. This
picture is then automatically moved to the PCs RAM and with the function
above (CDGetReleasedData) I should be able to access this stream. Now I
havn't accessed any stream with ctypes yet so I have only a rough idea
how it could work.

The following are the relevant parts of my code that don't work:

------------------------------CODE-----------------------------------------

# Definitions:

class cdReleaseImageInfo(Structure):
_fields_ = [("SequenceID", c_uint),
("DataType", c_uint),
("Format", c_ubyte),
("DataSize", c_uint),
("Filename", c_char * 2)]


class cdStream(Structure):
_fields_ = [("contextH", c_uint),
("open", c_uint),
("close", c_uint),
("read", c_uint),
("write", c_uint),
("seek", c_uint),
("tell", c_uint)]

class memunion(Union):
_fields_ = [("lpszFileName", c_char),
("pStream", cdStream)]


class cdStgMedium(Structure):
_fields_ = [("Type", c_uint),
("u", memunion)]




# command:

datainfo = cdReleaseImageInfo()
data = cdStgMedium()
errorcode = cdsdk.CDGetReleasedData(devicehandle, byref(cbfunct),
c_uint(1), c_uint(1), byref(datainfo), byref(data))

------------------------------\CODE----------------------------------------


The function "cdsdk.CDGetReleasedData" itself gets executed correctly,
but returns an "Invalid Parameter" errorcode. there's also no useful
data whereas datainfo gets written correctly. I know that my cdStream
can't work, facing the C-code, but what'd be the right cdStream class?
What can I do? Any ideas?

Best regards and thanks,
Matt
 
M

Matt

Okay, thanks a lot for your reply Nick, I think you pushed me back on
the right way.

Now I started with trying to implement the callback functions and am
stuck at the following point:

I define my classes/structures/unions:

------------------------------CODE-----------------------------------------

class cdStream(Structure):
_fields_ = [("contextH", c_uint),
("open", c_void_p),
("close", c_void_p),
("read", c_void_p),
("write", c_void_p),
("seek", c_void_p),
("tell", c_void_p)]

class memunion(Union):
_fields_ = [("lpszFileName", c_char_p),
("pStream", cdStream)]


class cdStgMedium(Structure):
_fields_ = [("Type", c_uint),
("u", memunion)]

------------------------------\CODE----------------------------------------

then i define my functions (right now I do just nothing) and at the same
time I define the datatypes like they're listed in my C sample program:


------------------------------CODE-----------------------------------------

def pystreamopen (contextH, mode, pErr):
pass

cstreamopen = CFUNCTYPE(c_uint, c_ushort, c_uint)

def pystreamclose (contextH, pErr):
pass

cstreamclose = CFUNCTYPE(c_uint, c_uint)

def pystreamread (contextH, pBuf, pBufsize, pErr):
pass

cstreamread = CFUNCTYPE(c_uint, c_void_p, c_uint, c_uint)

def pystreamtell (contextH, pErr):
pass

cstreamtell = CFUNCTYPE(c_uint, c_uint)

def pystreamwrite (contextH, origin, offset, pErr):
print "writing..."
pass

cstreamwrite = CFUNCTYPE(c_uint, c_void_p, c_uint, c_uint)

------------------------------\CODE----------------------------------------

and now the problem starts: i want the pointers in the cdStream
Structure point at my functions and tried to do it the following way:


------------------------------CODE-----------------------------------------

data = cdStgMedium()
data.type = 0
data.u.pStream.contextH = c_uint(3) #must be some kind of identifier.
data.u.pStream.open = cstreamopen(pystreamopen)
data.u.pStream.close = cstreamclose(pystreamclose)
data.u.pStream.write = cstreamwrite(pystreamwrite)
data.u.pStream.tell = cstreamtell(pystreamtell)
data.u.pStream.read = cstreamread(pystreamread)

------------------------------\CODE----------------------------------------

unfortunately that doesn't work because Python returns a TypeError:
incompatible types, CFunctionType instance instead of c_void_p instance

Any ideas/help (please)?

Best regards,
Matt
 
M

Matt

Hi,

okay, thanks now my DLL function seems to accept the functions given,
but instead of running my program keeps crashing (with windows address
violation errors). I did some further investigations on that and figured
out that the contextH variable is not just an identifier as I thought,
but a quite complicated datastreamhandler.

Now to get it to work I additionally need to implement the following c
Structures:

------------------------------CODE-----------------------------------------

/* The internal data structure object of a stream */
typedef struct tagMemStreamData
{
cdChar mode;
cdInt32 lPos;
cdUInt32 dwVisibleSize;
cdUInt32 dwBufferSize;
cdChar *cpBuffer;
}MemStreamData;

typedef struct tagFilStreamData
{
cdChar szFileName[MAX_PATH];
HANDLE hFile;
}FilStreamData;

------------------------------\CODE----------------------------------------

This function just creates the pStream filestream (which is what I have
to do too)

------------------------------CODE-----------------------------------------

BOOL CreateMyFilStream( cdStream *pStream,
cdChar *szFileName )
{
FilStreamData *pFilStrm;

/* The domain for data is secured. */
pFilStrm = new FilStreamData;
if( pFilStrm == NULL )
{
return FALSE;
}

/* Data is changed the first stage. */
pFilStrm->hFile = INVALID_HANDLE_VALUE;
strcpy( pFilStrm->szFileName, szFileName );

pStream->contextH = (cdContext)pFilStrm;
pStream->close = _CloseMyFilStream;
pStream->open = _OpenMyFilStream;
pStream->read = _ReadMyFilStream;
pStream->seek = _SeekMyFilStream;
pStream->tell = _TellMyFilStream;
pStream->write = _WriteMyFilStream;

return TRUE;
}


------------------------------\CODE----------------------------------------



Now my solution is the following:


------------------------------CODE-----------------------------------------

class MemStreamData(Structure):
_fields_ = [("mode", c_byte),
("lPos", c_uint),
("dwVisibleSize", c_uint),
("dwBufferSize", c_uint),
("cpBuffer", POINTER(c_char))]

class FilStreamData (Structure):
_fields_ = [("szFileName", c_char * 30),
("hFile", c_uint)]


------------------------------\CODE----------------------------------------

and the code to fill all that with the right data is the following:

------------------------------CODE-----------------------------------------

datainfo = cdReleaseImageInfo()

databuf = c_char * 100000
cbuffer=MemStreamData()
cbuffer.mode = c_byte(0)
cbuffer.lPos = c_uint(0)
cbuffer.dwVisibleSize = c_uint(100000)
cbuffer.dwBufferSize = c_uint(100000)

#this line does not work, wrong datatype!?
cbuffer.cpBuffer = POINTER(databuf)

cpointer = cast(cbuffer, POINTER(c_uint))
stream = cdStream()
stream.contextH=cpointer
stream.open = cstreamopen(pystreamopen)
stream.close = cstreamclose(pystreamclose)
stream.write = cstreamwrite(pystreamwrite)
stream.tell = cstreamtell(pystreamtell)
stream.read = cstreamread(pystreamread)



data = cdStgMedium()
data.Type = c_uint(1)
data.u.pStream = POINTER(cdStream)(stream)

------------------------------\CODE----------------------------------------

Does anyone see where the errors are?

Best regards and thanks a lot,
Matt
 
M

Matt

Hello!

ouch, I should have seen that c_char... :S Well, I guess I just prove
that it's useless to go to work and do some programming while having a
headache like I had yesterday...

okay well, back to topic:

The DLL function seems to accept my parameters now, but unfortunately
Python terminates after the DLL gets the result from the "open" callback
function (at least its printouts are the last I get before it
terminates). So without any kind of error message it's getting more
difficult now.

Well, since I didn't invest much time into my callback functions I
suspect the error must be somewhere in there.

This is my code:

------------------------------CODE-----------------------------------------

class MemStreamData(Structure):
_fields_ = [("mode", c_byte),
("lPos", c_uint),
("dwVisibleSize", c_uint),
("dwBufferSize", c_uint),
("cpBuffer", POINTER(c_char))]

class FilStreamData (Structure):
_fields_ = [("szFileName", c_char * 30),
("hFile", c_uint)]






def pystreamopen (contextH, mode, pErr=0):
print "opening..."
print contextH
print mode
print pErr
return 0

cstreamopen = CFUNCTYPE(c_uint, c_ushort, c_uint)

def pystreamclose (contextH, pErr):
print "closing..."
return 0

cstreamclose = CFUNCTYPE(c_uint, c_uint)

def pystreamread (contextH, pBuf, pBufsize, pErr):
print "reading..."
return 0

cstreamread = CFUNCTYPE(c_uint, c_void_p, c_uint, c_uint)

def pystreamtell (contextH, pErr):
print "telling..."
return 0

cstreamtell = CFUNCTYPE(c_uint, c_uint)


def pystreamseek (contextH, origin, offset, pErr):
print "seeking..."
return 0

cstreamseek = CFUNCTYPE(c_uint, c_uint, c_uint, c_uint)


def pystreamwrite (contextH, origin, offset, pErr):
print "writing..."
return 0

cstreamwrite = CFUNCTYPE(c_uint, c_void_p, c_uint, c_uint)


class cdStream(Structure):
_fields_ = [("contextH", POINTER(MemStreamData)),
("open", cstreamopen),
("close", cstreamclose),
("read", cstreamread),
("write", cstreamwrite),
("seek", cstreamseek),
("tell", cstreamtell)]

-----------------------------/CODE-----------------------------------------



This is the way I create the vars:




------------------------------CODE-----------------------------------------


databuf = create_string_buffer(100000)
cbuffer=MemStreamData()
cbuffer.mode = c_byte(0)
cbuffer.lPos = c_uint(0)
cbuffer.dwVisibleSize = 100000
cbuffer.dwBufferSize = 100000
cbuffer.cpBuffer = databuf

stream = cdStream()
stream.contextH = POINTER(MemStreamData)(cbuffer)
stream.open = cstreamopen(pystreamopen)
stream.close = cstreamclose(pystreamclose)
stream.write = cstreamwrite(pystreamwrite)
stream.tell = cstreamtell(pystreamtell)
stream.read = cstreamread(pystreamread)


data = cdStgMedium()
data.Type = c_uint(1) # 0...FilStream 1...MemStream
data.u.pStream = POINTER(cdStream)(stream)

errorcode = cdsdk.CDGetReleasedData(devicehandle, byref(cbfunct),
c_uint(0), c_uint(0), byref(datainfo), POINTER(cdStgMedium)(data))

------------------------------/CODE-----------------------------------------



Now I have two problems:

1st: since contextH is not a c_uint (and pErr is a pointer) as I thought
earlier, I tried to change my definition of the open function to:

cstreamopen = CFUNCTYPE(POINTER(MemStreamData), c_ushort, POINTER(c_uint))

unfortunately that throws an error when I try to:

stream.open = cstreamopen(pystreamopen)


2nd: as may saw, I defined "def pystreamopen (contextH, mode, pErr=0)".
The pErr variable should be a pointer to a c_uint where my function can
tell the DLL that opening the stream went well (or give some errorcode).

When I do not define pErr=0 and simply say pErr, I get the following error:

Traceback (most recent call last):
File "\loewis\25\python\Modules\_ctypes\callbacks.c", line 206, in
'calling callback function'
TypeError: pystreamopen() takes exactly 3 arguments (2 given)

At first I thought okay, maybe there's no pErr and there's some error in
the C-Code, but when I do "def pystreamopen (contextH, mode)" I get the
same Error with:
TypeError: pystreamopen() takes exactly 3 arguments (2 given)


Any ideas?


And another question: my callback functions are all defined as void...
in C. That means that there shouldn't be anything returned. I tried this
by using the pass statement, but got an error that returntype int was
expected. Also "return" or "return None" don't work. Why?



Puh, long mail again... hope you're so kind again and take the time to
help me out.

Best regards from Austria,
Matt
 
M

MRAB

Hello!

ouch, I should have seen that c_char... :S Well, I guess I just prove
that it's useless to go to work and do some programming while having a
headache like I had yesterday...

okay well, back to topic:

The DLL function seems to accept my parameters now, but unfortunately
Python terminates after the DLL gets the result from the "open" callback
function (at least its printouts are the last I get before it
terminates). So without any kind of error message it's getting more
difficult now.

Well, since I didn't invest much time into my callback functions I
suspect the error must be somewhere in there.

This is my code:

------------------------------CODE-----------------------------------------

class MemStreamData(Structure):
_fields_ = [("mode", c_byte),
("lPos", c_uint),
("dwVisibleSize", c_uint),
("dwBufferSize", c_uint),
("cpBuffer", POINTER(c_char))]

class FilStreamData (Structure):
_fields_ = [("szFileName", c_char * 30),
("hFile", c_uint)]

def pystreamopen (contextH, mode, pErr=0):
print "opening..."
print contextH
print mode
print pErr
return 0

cstreamopen = CFUNCTYPE(c_uint, c_ushort, c_uint)

def pystreamclose (contextH, pErr):
print "closing..."
return 0

cstreamclose = CFUNCTYPE(c_uint, c_uint)

def pystreamread (contextH, pBuf, pBufsize, pErr):
print "reading..."
return 0

cstreamread = CFUNCTYPE(c_uint, c_void_p, c_uint, c_uint)

def pystreamtell (contextH, pErr):
print "telling..."
return 0

cstreamtell = CFUNCTYPE(c_uint, c_uint)

def pystreamseek (contextH, origin, offset, pErr):
print "seeking..."
return 0

cstreamseek = CFUNCTYPE(c_uint, c_uint, c_uint, c_uint)

def pystreamwrite (contextH, origin, offset, pErr):
print "writing..."
return 0

cstreamwrite = CFUNCTYPE(c_uint, c_void_p, c_uint, c_uint)

class cdStream(Structure):
_fields_ = [("contextH", POINTER(MemStreamData)),
("open", cstreamopen),
("close", cstreamclose),
("read", cstreamread),
("write", cstreamwrite),
("seek", cstreamseek),
("tell", cstreamtell)]

-----------------------------/CODE-----------------------------------------

This is the way I create the vars:

------------------------------CODE-----------------------------------------

databuf = create_string_buffer(100000)
cbuffer=MemStreamData()
cbuffer.mode = c_byte(0)
cbuffer.lPos = c_uint(0)
cbuffer.dwVisibleSize = 100000
cbuffer.dwBufferSize = 100000
cbuffer.cpBuffer = databuf

stream = cdStream()
stream.contextH = POINTER(MemStreamData)(cbuffer)
stream.open = cstreamopen(pystreamopen)
stream.close = cstreamclose(pystreamclose)
stream.write = cstreamwrite(pystreamwrite)
stream.tell = cstreamtell(pystreamtell)
stream.read = cstreamread(pystreamread)

data = cdStgMedium()
data.Type = c_uint(1) # 0...FilStream 1...MemStream
data.u.pStream = POINTER(cdStream)(stream)

errorcode = cdsdk.CDGetReleasedData(devicehandle, byref(cbfunct),
c_uint(0), c_uint(0), byref(datainfo), POINTER(cdStgMedium)(data))

------------------------------/CODE-----------------------------------------

Now I have two problems:

1st: since contextH is not a c_uint (and pErr is a pointer) as I thought
earlier, I tried to change my definition of the open function to:

cstreamopen = CFUNCTYPE(POINTER(MemStreamData), c_ushort, POINTER(c_uint))

unfortunately that throws an error when I try to:

stream.open = cstreamopen(pystreamopen)

2nd: as may saw, I defined "def pystreamopen (contextH, mode, pErr=0)".
The pErr variable should be a pointer to a c_uint where my function can
tell the DLL that opening the stream went well (or give some errorcode).

When I do not define pErr=0 and simply say pErr, I get the following error:

Traceback (most recent call last):
File "\loewis\25\python\Modules\_ctypes\callbacks.c", line 206, in
'calling callback function'
TypeError: pystreamopen() takes exactly 3 arguments (2 given)

At first I thought okay, maybe there's no pErr and there's some error in
the C-Code, but when I do "def pystreamopen (contextH, mode)" I get the
same Error with:
TypeError: pystreamopen() takes exactly 3 arguments (2 given)

Any ideas?

And another question: my callback functions are all defined as void...
in C. That means that there shouldn't be anything returned. I tried this
by using the pass statement, but got an error that returntype int was
expected. Also "return" or "return None" don't work. Why?

Puh, long mail again... hope you're so kind again and take the time to
help me out.
The docs say CFUNCTYPE(restype, *argtypes), so:

cstreamopen = CFUNCTYPE(c_uint, c_ushort, c_uint)

is saying that the result type is c_uint, not void. I think you need:

cstreamopen = CFUNCTYPE(None, c_uint, c_ushort, c_uint)

instead.
 
M

Matt

The docs say CFUNCTYPE(restype, *argtypes), so:

cstreamopen = CFUNCTYPE(c_uint, c_ushort, c_uint)

is saying that the result type is c_uint, not void. I think you need:

cstreamopen = CFUNCTYPE(None, c_uint, c_ushort, c_uint)

instead.

Hm, thanks, now I can access my data in the functions and also write
them but the program keeps terminating right at the point when the
"open" function finishes. Unfortunately everything closes and I get no
error messages.

I did some additional work in the meantime and changed my code so it has
the correct datatypes now:

--------------------------CODE--------------------------------------------

def pystreamopen (contextH, mode, pErr):
print "opening..."
print contextH.contents.dwBufferSize #just to check the structure
print mode #tells about what the DLL wants to do with this stream
contextH.contents.mode = c_byte(5) #5=Permission to read and write
contextH.contents.lPos = c_uint(0) #start position

print pErr.contents
pErr.contents = c_uint(0)


cstreamopen = CFUNCTYPE(None, POINTER(MemStreamData), c_ushort,
POINTER(c_uint))

def pystreamclose (contextH, pErr):
print "closing..."
pass

cstreamclose = CFUNCTYPE(None, POINTER(MemStreamData), POINTER(c_uint))

def pystreamread (contextH, pBuf, pBufsize, pErr):
print "reading..."
pass

cstreamread = CFUNCTYPE(None, POINTER(MemStreamData), c_uint, c_uint,
POINTER(c_uint))

def pystreamtell (contextH, pErr):
print "telling...

..
..
..etc...

--------------------------/CODE--------------------------------------------

and the function call:

--------------------------CODE--------------------------------------------

errorcode = cdsdk.CDGetReleasedData(devicehandle, byref(cbfunct),
c_uint(0), c_uint(0), byref(datainfo), POINTER(cdStgMedium)(data))

--------------------------/CODE--------------------------------------------


while it's running my program prints the following and then
exits/terminates:

I also tried different editors, but get the same result...



Anyway, meanwhile decided to try a different approach. Maybe I have
more luck by having the function write the data directly into a file on
the HDD.
Doe anyone know how to translate the following into Python/ctypes?

I googled quite a lot before but all topic-related I found was my own
posting here in this NG :S

--------------------------CODE--------------------------------------------

pFilStrm->hFile = CreateFile( pFilStrm->szFileName,
dwDesiredAccess, dwShareMode, NULL,
dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL );


--------------------------/CODE--------------------------------------------

This function is obviously a default C-function that generates a file
and returns a c-handle to that file. In my case I'd need exactly such a
handle to get things working...

Furthermore there's a writefile function I'd need to translate too:

--------------------------CODE--------------------------------------------

WriteFile( pFilStrm->hFile, pBuf, dwNumberOfBytesToWrite, pBufsize, NULL );

--------------------------/CODE--------------------------------------------


Ideas?

Thanks and best wishes,
Matt
 

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

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top