views:

613

answers:

2

Howdy all - Here is the prototype for a C function that resides in a DLL:

extern "C" void__stdcall__declspec(dllexport) ReturnPulse(double*,double*,double*,double*,double*);

In another thread, I asked about how to properly create and send the necessary arguments to this function.

Here is the thread: http://stackoverflow.com/questions/1381016/how-do-i-wrap-this-c-function-with-multiple-arguments-with-ctypes

So I have used the good information in the thread above, but now I am getting this error: WindowsError: exception: access violation writing 0x00001001

I am unsure as to how to proceed. I'm on Windows XP - if I log into the administrator account, would that fix the problem? Or is this a problem with Python's memory objects being immutable?

Thanks all!

Edited with relevant Python:

FROGPCGPMonitorDLL = windll.LoadLibrary('C:\Program Files\MesaPhotonics\VideoFROG 7.0\PCGPMonitor.dll')

#Function argument:double* pulse
sizePULSE = 2 ##Manual is super unclear here
pulse = c_double * sizePULSE
ptrpulse = pulse()

#Function argument:double* tdl
sizeTRACE = FROGPCGPMonitorDLL.GetSize()
if sizeTRACE == 0 :
    sizeTRACE = 1 #Manually set size to 1 for testing purposes
    print "Size of FROG trace is zero. Probably not right."
tdl = c_double*sizeTRACE
ptrtdl = tdl()


#Function argument:double* tdP
sizeTRACE = FROGPCGPMonitorDLL.GetSize()
if sizeTRACE==0:
    sizeTRACE=1
    print "Size of FROG trace is zero. Probably not right."
tdP = c_double*sizeTRACE
ptrtdP = tdP()


#Function Argument:double* fdl
sizeTRACE = FROGPCGPMonitorDLL.GetSize()
if sizeTRACE==0:
    sizeTRACE=1
    print "Size of FROG trace is zero. Probably not right."
fdl = c_double*sizeTRACE
ptrfdl = fdl()

#Function Argument: double* fdP
sizeTRACE = FROGPCGPMonitorDLL.GetSize()
if sizeTRACE==0:
    sizeTRACE=1
    print "Size of FROG trace is zero. Probably not right."
fdP = c_double*sizeTRACE
ptrfdP = fdP()

FROGPCGPMonitorDLL.ReturnPulse(ptrpulse, ptrtdl, ptrtdP,ptrfdl,ptrfdP)

Edited to add some relevant code! I'm just writing a simple script to get each of the device's functions working first. The variable sizeTRACE can be reused, I know, but its just test code right now and the device isn't hooked up, so GetSize() is returning zero. Multiplying by zero would kill my buzz, so I'm forcing it to 1 for now. If this isn't clear, I apologize and will try to edit this post.

Second edit: It was suggested to plug in the device and see if that helped. I just plugged in the FROG, but I'm still getting the same error. Very strange, and I'm rather clueless. In any event, thanks again all!

A: 

The error you're getting is not related to Administrative rights. The problem is you're using C and inadvertently performing illegal operations (the kind of operations that if went unchecked would probably crash your system).

The error you get indicates that your program is trying to write to memory address 1001, but isn't supposed to be writing to that memory address.

This could happen for any number of reasons.

One possible reason is that the double* you're passing to ReturnPulse aren't as big as ReturnPulse expects them to be. You probably need to at least get GetSize to work properly... you might be able to work around it by just allocating a very large array instead of calling GetSize. i.e.

ptrfdP = (c_double*100000)()

That will allocate 100,000 doubles, which may be more appropriate for capturing a digital Pulse.

The other issue is that the type conversion may not be happening as expected.

You might have better luck if ctypes knows that ReturnPulse takes five double pointers. i.e.

# sometime before calling ReturnPulse
FROGPCGPMonitorDLL.ReturnPulse.argtypes = [POINTER(c_double), POINTER(c_double), POINTER(c_double), POINTER(c_double), POINTER(c_double)]

If neither of these techniques works, send the usage documentation on ReturnPulse, which should help us recognize the intended use.

Or better yet, send sample code that's supposed to work in C and I'll translate that to the equivalent implementation in ctypes.

Edit: adding example implementation of ReturnPulse and ctypes usage.

I have implemented something like what I expect ReturnPulse to be doing in a C DLL:

void ReturnPulse(double *a, double*b,double*c,double*d,double*e)
{
 // write some values to the memory pointed-to by a-e
 // a-e should have enough memory allocated for the loop
 for(int i = 0; i < 20; i++)
 {
  a[i] = 1.0*i;
  b[i] = 3.0*i;
  c[i] = 5.0*i;
  d[i] = 7.0*i;
  e[i] = 13.0*i;
 }
}

I compile this into a DLL (which I call examlib), and then call it using ctypes with the following code:

LP_c_double = ctypes.POINTER(ctypes.c_double)
examlib.ReturnPulse.argtypes = [LP_c_double, LP_c_double, LP_c_double, LP_c_double, LP_c_double, ]

a = (ctypes.c_double*20)()
b = (ctypes.c_double*20)()
c = (ctypes.c_double*20)()
d = (ctypes.c_double*20)()
e = (ctypes.c_double*20)()

examlib.ReturnPulse(a,b,c,d,e)

print 'values are'
for array in (a,b,c,d,e):
 print '\t'.join(map(str, array[:5]))

The resulting output is

values are
0.0     1.0     2.0     3.0     4.0
0.0     3.0     6.0     9.0     12.0
0.0     5.0     10.0    15.0    20.0
0.0     7.0     14.0    21.0    28.0
0.0     13.0    26.0    39.0    52.0

Indeed, even without setting ReturnPulse.argtypes, the code runs without errors.

Jason R. Coombs
Thanks so much! I'll try everything you said tomorrow or Friday, and let everyone know ASAP!
trayres
So I added the line you suggested, the ReturnPulse.argtypes...etcand I get:Traceback (most recent call last): File "C:\Foldershare\Programming\Python\Travis\FROGmoduleTESTv1\FROGmoduleTEST.py", line 231, in <module> FROGPCGPMonitorDLL.ReturnPulse(ptrpulse, ptrtdl, ptrtdP,ptrfdl,ptrfdP)ArgumentError: argument 1: <type 'exceptions.TypeError'>: expected LP_c_double instance instead of c_double_Array_0_Array_2I tried to put in an arbitrarily large double array as well,but it gave me the same WindowsError. So I think GetSize() works!Anyway, thanks for the help thus far. Its been great!
trayres
The fact that you're getting a type error indicates that the parameters you're passing don't match the spec required by ResultPulse.You're passing a c_double_Array_0_Array_2, which is a two-dimensional array of doubles with a width of 0 and a height of 2. This means that still no memory has been allocated suitable for ResultPulse to write. A c_double_Array_0_Array_2 is created by (c_double*0*2)(), so I expect the code you're testing against now isn't the same as the code included in the question.Remember that the * in ctypes doesn't follow mathematical conventions.
Jason R. Coombs
Also, you should double-check your call semantics. Since the ResultPulse is declared with the stdcall calling convention, you should be sure you're loading your library using WinDLL... i.e. FROGPCGPMonitorDLL = ctypes.WinDLL('frogpcgmonitor.dll')
Jason R. Coombs
Hum. I'm loading the function using windll, and I've set the argtypes. If I use arbitrarily large arrays, it returns the same access violation error. I am now getting "ArgumentError: argument 1: <type 'exceptions.TypeError'>: expected LP_c_double instance instead of c_double_Array_2_Array_64". I think I am declaring the array wrong...pulse = c_double * 2 * FROGPCGPMonitorDLL.GetSize()ptrpulse = pulse()Is what I am doing, then I'm passing that to the function. I used "from ctypes import *". This should be a pointer to a c double array...but it isn't operating correctly.
trayres
If I put 2*FROGPCGPMonitorDLL.GetSize() into one line, and say arraySize = 2*FROG...etc, the type I get is c_double_Array_128. But I'm still not getting an LP_c_double!It seems to be making too fine a distinction, or something. The function expects a pointer to an array of doubles - but whereas C only sees a continuous memory block, Python seems to be cutting things up funny, according to how I declare the rows/cols of the array.Hum...
trayres
PS sorry for formatting problems in above comments.
trayres
c_double_Array_128 (an array of 128 doubles) is probably what ReturnPulse is expecting. Does the FrogPCGP documentation give sample C code for utilizing ReturnPulse?
Jason R. Coombs
No - the documentation is sparse, at best. I'm going to email swamp optics and ask for some support. I really can't think of what might be the problem - this is very strange.So far, I've been trying variations on:size = 2*GetSize(); pulse = c_double*size; ptrpulse = pulse(); then I pass ptrpulse to the function. I have tried casting it too: so ptrpulse = cast(ptrpulse, POINTER(c_double)); - Its 2 am, so I forgot what error I was getting. But I'll try it once my head clears and I'm back in lab tomorrow morning.Thanks for your help. :D
trayres
Note:used semicolon in place of newlines for code (because comments don't show newlines, apparently).
trayres
Ok, this is where things start getting even more strange!If I say: size = 2 * FROGPCGPMonitorDLL.GetSize(), pulse = c_double * size, ptrpulse=pulse(), I get a write error. If I instead say pulse = c_double * 2 * FROGPCGPMonitorDLL.GetSize(), I get the other error! "expected LP_c_double instance instead of c_double_Array_2_Array_64"!This is...peculiar. I'll post an update once swampoptics gets back to me!
trayres
The reason you get the TypeError when you use "c_double * 2 * FDLL.GetSize()" is because (c_double * 2) produces a two-element array type. When you multiply that by GetSize(), you get a 64-element array of two-element arrays type (c_double_Array_2_Array_64 in ctypes terminology). The former implementation is the proper one, or you could use "pulse = c_double * ( 2 * FROGPCGPMonitorDLL.GetSize() );" Curious, why are you multiplying the result of GetSize by 2?
Jason R. Coombs
I see now in the other question the reason why you multiply GetSize() by 2 (because that's what their docs recommend). In that case, it sounds like you've done everything correctly.At this point, I would focus on contacting their support. I tried e-mailing them myself, but the e-mail bounced. I think you're doing everything correctly, at least according to their spec.
Jason R. Coombs
Thanks so much for your help. I can't seem to get ahold of the company, but now the lab isn't quite sure if the device is even working, so I have been reassigned to get the hardware to work before automating the testing (sounds reasonable).As soon as I get back to this, I'll post any updates. :)
trayres
A: 

ptrpulse and friends are python identifiers that point to various ctypes objects (I guess they are all c_double*2). They either need to be wrapped with a ctypes pointer object, or passed to the C function using ctypes.byref.

max