Program works in IDLE, but fails at the command line
Asked Answered
D

3

6

I'm using Python's ctypes library to talk to a Windows DLL. When I run my code from IDLE, Ipython, or typed into the interactive python interpreter, it works fine. When I run the same code from the Windows command prompt, it crashes. Why does one way crash, and one way succeed?

Here's a simplified version of the code I'm running:

import ctypes, os, sys

print "Current directory:", os.getcwd()
print "sys.path:"
for i in sys.path:
    print i

PCO_api = ctypes.oledll.LoadLibrary("SC2_Cam")

camera_handle = ctypes.c_ulong()
print "Opening camera..."
PCO_api.PCO_OpenCamera(ctypes.byref(camera_handle), 0)
print " Camera handle:", camera_handle.value

wSensor = ctypes.c_uint16(0)
print "Setting sensor format..."
PCO_api.PCO_SetSensorFormat(camera_handle, wSensor)
PCO_api.PCO_GetSensorFormat(camera_handle, ctypes.byref(wSensor))
mode_names = {0: "standard", 1:"extended"}
print " Sensor format is", mode_names[wSensor.value]

When I run this code from IDLE or Ipython, I get the following result:

Current directory: C:\Users\Admin\Desktop\code
sys.path:
C:\Users\Admin\Desktop\code
C:\Python27\Lib\idlelib
C:\Windows\system32\python27.zip
C:\Python27\DLLs
C:\Python27\lib
C:\Python27\lib\plat-win
C:\Python27\lib\lib-tk
C:\Python27
C:\Python27\lib\site-packages
Opening camera...
 Camera handle: 39354336
Setting sensor format...
 Sensor format is standard
>>> 

When I run this code from the Windows command prompt, I get the following results:

Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:\Users\Admin>cd Desktop\code

C:\Users\Admin\Desktop\code>C:\Python27\python.exe test.py
Current directory: C:\Users\Admin\Desktop\code
sys.path:
C:\Users\Admin\Desktop\code
C:\Windows\system32\python27.zip
C:\Python27\DLLs
C:\Python27\lib
C:\Python27\lib\plat-win
C:\Python27\lib\lib-tk
C:\Python27
C:\Python27\lib\site-packages
Opening camera...
 Camera handle: 43742176
Setting sensor format...
Traceback (most recent call last):
  File "test.py", line 18, in <module>
    PCO_api.PCO_GetSensorFormat(camera_handle, ctypes.byref(wSensor))
  File "_ctypes/callproc.c", line 936, in GetResult
WindowsError: [Error -1609945086] Windows Error 0xA00A3002

C:\Users\Admin\Desktop\code>

Notice that a few of the DLL calls work, it isn't until I get to setting the sensor format that we go off the rails.

By inspecting the documentation that came with the DLL I'm calling, I see the Windows Error decodes to "The wSize of a buffer is to small." (sic). I'm not sure that's relevant. Just in case it matters, here's the API documentation.

When I see "works in IDLE, fails at prompt", I assume there must be some environment variable set differently. What should I check?

EDIT:

I added sys.path and os.getcwd() to the test code.

EDIT:

Not sure if this matters, but the DLL I load (SC2_Cam.dll) is in the current working directory. Also in this directory is another DLL (sc2_cl_me4.dll), which I believe is loaded by SC2_Cam.dll. If I remove sc2_cl_me4.dll from this directory, none of the calls to SC2_Cam.dll work, including PCO_OpenCamera.

EDIT:

The code above also works if I type it into the 'vanilla' interactive python interpreter. I don't need IDLE or ipython to make it work. Only calling 'python.exe test.py' fails.

Decillion answered 9/5, 2012 at 22:57 Comment(5)
Check os.getcwd() and sys.path for both in-IDLE and command-line executions.Capreolate
Good suggestion, Joel Cornett. I've modified the question as you suggest.Decillion
Does the Cpython on windows still make the wpython.exe vs python.exe distinction? If so, try wpython.exe test.py instead.Cattail
@Francis: did you mean pythonw.exe?Levigate
@Francis I tried pythonw.exe instead of python.exe. It's harder to tell what happens, since nothing gets printed to the terminal. I believe it still crashes with pythonw.exe substituted for python.exe. I added an import time and a time.sleep(10) to the end of the script above, and watched the pythonw.exe process in task manager. The process does not last 10 seconds, unless I comment out the line that crashes python.exe.Decillion
R
4

When you interface with a C program, you get all the difficulties of C. Any error you make can cause buffer overflows, stack overflows, segmentation violations, etc. If the program, because of an error, writes to a random memory location, its behavior will not be the same in all circumstances. On your machine, it seems to work in interactive mode, but crashes when run from the window command prompt. But on another operating system, or on another machine, or even in the same machine in another day, it could behave differently. Its behavior is not deterministic.

Given that, let's look at the following line:

PCO_api.PCO_OpenCamera(ctypes.byref(camera_handle), 0)

According to the API documentation, in the above call, the PCO_OpenCamera function does not just return a value in camera_handle; it also uses camera_handle as an input value. However, you leave camera_value uninitialized. I understand that you should set it to zero before the call. Another problem is that PCO_OpenCamera returns a value which should be checked. If there is a problem but the program continues as if there wasn't, it will continue to use a random value for the camera_handle. So one error in the program seems to be that the preceding line (save the print) should be

camera_handle = ctypes.c_ulong(0)

and another is that the return value of PCO_OpenCamera isn't checked. (I don't know if the rest is OK, I haven't examined carefully past that.)

Also, is c_ulong the proper type for the Windows HANDLE type? I don't know, and it may be ok. Even if c_ulong is larger than HANDLE, it's still probably OK. But probably is not enough; you must be certain that you know what you're doing.

Riser answered 15/5, 2012 at 15:43 Comment(8)
Good suggestions. I'll check the return value of the API call, and the initial value of camera_handle. As for the proper type for HANDLE, I believe I checked a header file to determine this, but that was a while ago, I'll check again.Decillion
Ok, regarding the return value of the API call: oledll handles it. The WindowsError messages I get match up to error codes described in the API. I open this file as an archive using 7zip, pull out PCO_err.h and PCO_errt.h, and match the WindowsError code to the corresponding error message. That's how I got the message "The wSize of a buffer is to small" that I reference in the question above.Decillion
Now, regarding the initial value of camera_handle: camera_handle = ctypes.c_ulong(0) and camera_handle = ctypes.c_ulong() both produce the same initial value of camera_handle.value, zero, whether they're run from IDLE or the command prompt.Decillion
Regarding the proper type for HANDLE: In the file sc2_SDKStructures.h, which I got from opening this file as an archive via 7zip, I read: "HANDLE will be 8byte on 64bit OS and 4byte on 32bit OS". I'm using 64-bit Windows 7.Decillion
Interesting. a = ctypes.c_ulong() followed by print ctypes.sizeof(a) gives 4...Decillion
HAHA! THAT DID IT! NICE WORK!Decillion
I just change camera_handle.ctypes.c_ulong() to camera_handle.ctypes.c_ulonglong() and the problem seems to go away! If I was never using the right size object for my camera handle, I wonder how it was working in IDLE, ipython, and the interactive python interpreter?Decillion
Ok, I'm going to poke around with the code a bit more, but if things continue to go well, there's a good chance you've given the correct answer. Thanks for the help.Decillion
N
5

Do you have more than one version of python installed on your system? Perhaps you are using a different version when you run interactively and when you run it from a file.

Naples answered 13/5, 2012 at 2:15 Comment(3)
Good question. I suppose I can check this with sys.executable?Decillion
Interesting. In IDLE, sys.executable is C:\Python27\pythonw.exe, and the test script works. In Ipython, sys.executable is C:\Python27\python.exe (note, python, not pythonw), and the test script works. From the Windows command prompt, sys.executable is C:\Python27\python.exe, and the test script fails.Decillion
Which is to say, I don't think this is the problem.Decillion
R
4

When you interface with a C program, you get all the difficulties of C. Any error you make can cause buffer overflows, stack overflows, segmentation violations, etc. If the program, because of an error, writes to a random memory location, its behavior will not be the same in all circumstances. On your machine, it seems to work in interactive mode, but crashes when run from the window command prompt. But on another operating system, or on another machine, or even in the same machine in another day, it could behave differently. Its behavior is not deterministic.

Given that, let's look at the following line:

PCO_api.PCO_OpenCamera(ctypes.byref(camera_handle), 0)

According to the API documentation, in the above call, the PCO_OpenCamera function does not just return a value in camera_handle; it also uses camera_handle as an input value. However, you leave camera_value uninitialized. I understand that you should set it to zero before the call. Another problem is that PCO_OpenCamera returns a value which should be checked. If there is a problem but the program continues as if there wasn't, it will continue to use a random value for the camera_handle. So one error in the program seems to be that the preceding line (save the print) should be

camera_handle = ctypes.c_ulong(0)

and another is that the return value of PCO_OpenCamera isn't checked. (I don't know if the rest is OK, I haven't examined carefully past that.)

Also, is c_ulong the proper type for the Windows HANDLE type? I don't know, and it may be ok. Even if c_ulong is larger than HANDLE, it's still probably OK. But probably is not enough; you must be certain that you know what you're doing.

Riser answered 15/5, 2012 at 15:43 Comment(8)
Good suggestions. I'll check the return value of the API call, and the initial value of camera_handle. As for the proper type for HANDLE, I believe I checked a header file to determine this, but that was a while ago, I'll check again.Decillion
Ok, regarding the return value of the API call: oledll handles it. The WindowsError messages I get match up to error codes described in the API. I open this file as an archive using 7zip, pull out PCO_err.h and PCO_errt.h, and match the WindowsError code to the corresponding error message. That's how I got the message "The wSize of a buffer is to small" that I reference in the question above.Decillion
Now, regarding the initial value of camera_handle: camera_handle = ctypes.c_ulong(0) and camera_handle = ctypes.c_ulong() both produce the same initial value of camera_handle.value, zero, whether they're run from IDLE or the command prompt.Decillion
Regarding the proper type for HANDLE: In the file sc2_SDKStructures.h, which I got from opening this file as an archive via 7zip, I read: "HANDLE will be 8byte on 64bit OS and 4byte on 32bit OS". I'm using 64-bit Windows 7.Decillion
Interesting. a = ctypes.c_ulong() followed by print ctypes.sizeof(a) gives 4...Decillion
HAHA! THAT DID IT! NICE WORK!Decillion
I just change camera_handle.ctypes.c_ulong() to camera_handle.ctypes.c_ulonglong() and the problem seems to go away! If I was never using the right size object for my camera handle, I wonder how it was working in IDLE, ipython, and the interactive python interpreter?Decillion
Ok, I'm going to poke around with the code a bit more, but if things continue to go well, there's a good chance you've given the correct answer. Thanks for the help.Decillion
G
1

The error you're getting leads me to believe that the 16 bit integer you're using to store the wSensor variable is too small. I looked at their API, which just specifies it as type WORD, which historically by Microsoft standards should be 16 bits, but since there is a lot of ambiguity around how big a word is, try upping the value to 32 or 64 bits.

As to why this would cause different behavior in different environments, are you using a 64-bit OS? Do you have a different version of python installed?

Guayule answered 13/5, 2012 at 2:36 Comment(3)
I am using 64-bit Windows 7. sys.version gives '2.7.2 (default, Jun 12 2011, 14:24:46) [MSC v.1500 64 bit (AMD64)]'. I'll try out changing the size of wSensor. Thanks for looking at the API!Decillion
I tried changing the type of wSensor from c_uint16 to c_int32 and c_uint64. Still works in IDLE, ipython, or the interactive interpreter, still fails at the windows command prompt.Decillion
In hindsight, I should have also checked camera_handle. This is a good suggestion.Decillion

© 2022 - 2024 — McMap. All rights reserved.