0

I am having issues using ctypes to connect with a gaussmeter (F.W. Bell 5180). The manufacturer provides DLLs for the interface and a header file called FWB5180.h:

FWB5180.h:

    // The following ifdef block is the standard way of creating macros which make exporting
    // from a DLL simpler. All files within this DLL are compiled with the USB5100_EXPORTS
    // symbol defined on the command line. this symbol should not be defined on any project
    // that uses this DLL. This way any other project whose source files include this file see
    // USB5100_API functions as being imported from a DLL, whereas this DLL sees symbols
    // defined with this macro as being exported.
    #ifdef USB5100_EXPORTS
    #define USB5100_API __declspec(dllexport)
    #else
    #define USB5100_API __declspec(dllimport)
    #endif
    extern "C" USB5100_API unsigned int openUSB5100(void);
    extern "C" USB5100_API void closeUSB5100(unsigned int fwb5000ID);
    extern "C" USB5100_API int scpiCommand(unsigned int usbID, char* cmd, char* result, int len);

My ctypes Python code is the following, where all I try to do is initialize the device then close it:

import ctypes,time

# open DLL
path = "C:\\Users\\Roger\\fw_bell_magnetic_field_probe\\usb5100-x64\\x64-dist\\usb5100.dll"
fwbell = ctypes.WinDLL(path)

# define open and close functions with argument and return types 
openUSB5100 = fwbell.openUSB5100 
openUSB5100.argtypes = None
openUSB5100.restype = ctypes.c_int

closeUSB5100 = fwbell.closeUSB5100
closeUSB5100.argtypes = [ctypes.c_int]
closeUSB5100.restype = None

# open device
idn = openUSB5100()
print(idn, type(idn))

# close device
time.sleep(0.1)
closeUSB5100(idn)

Expected behavior: it says elsewhere in the documentation that idn is a four bit unsigned integer, so it should return a number like 10203045. So I would expect an idn like that, and no errors while closing the connection.

Actual behavior: In my code, openUSB5100 always returns 0, whether the device is plugged in or not. The print statement always outputs 0 <class 'int'>. Then, the closeUSB5100 function errors out with something like OSError: exception: access violation reading 0x0000000000000028. I have also tried using different types for idn like c_ulong, but that didn't seem to help.

I'm on Windows 10 using python 3.9. Both are 64-bit, as are the DLLs.

I will note that I can use the gaussmeter using their provided dummy programs so its not strictly a connectivity issue. Though, I think they are using a 32-bit application with 32 bit drivers because when I try to use the DLLs that they seem to use, I get the following error: OSError: [WinError 193] %1 is not a valid Win32 application. When I use the DLLs marked as 64 bit I don't get this error.

Any tips or things to try with my code? This is my first foray into ctypes, so I accept there is likely egregious errors.

EDIT: Here is the exact error message that I am getting.

PS C:\Users\Roger\fw_bell_magnetic_field_probe\usb5100-x64\x64-dist> python .\fw_bell_py.py
Traceback (most recent call last):
  File "C:\Users\Roger\fw_bell_magnetic_field_probe\usb5100-x64\x64-dist\fw_bell_py.py", line 30, in <module>
    idn = openUSB5100()
OSError: exception: access violation reading 0x00000000B56B1D68

The last value, 0x ... , typically changes a little bit if I run the code more than once.

Additionally, I have discovered that apparently the gauss meter might be really slow at being ready to use after being detected by the PC. So if I wait a long time between plugging in the device (or monitoring with usb.core.list_devices until something shows up) and running this code, the code always errors out on the open command, it doesn't make it to the close command.

bpound
  • 28
  • 5
  • Technically, use `openUSB5100.argtypes = ()` for no parameters and `ctypes.c_uint` for `unsigned int` parameters, but it shouldn't make a difference in this case. Also, `WinDLL` is for `__stdcall` functions so use `CDLL` but that only affects portability to 32-bit. `WinDLL` and `CDLL` are the same calling convention on 64-bit. Otherwise, I don't see a problem with the code. The error on closing the `idn` is that the open failed so `idn` is invalid. – Mark Tolonen Jun 02 '22 at 16:27
  • I made the changes you suggested and they didn't fix the issue, unfortunately. I did discover that without the device plugged in, I always get `idn=0` and the code fails at the close. With the device plugged in the same thing happens the first time I run the code, but on subsequent code runs I get `OSError`s at the _open_ statement instead. Maybe its relevant that there are two dlls, that the one I referenced in the code explicitly, `usb5800.dll`, depends on another dll (essentially libusb-win32). Is there something I need to do about that, other than keep it in the working directory? – bpound Jun 02 '22 at 19:05
  • I didn't think they would. You should be able to call `open` without setting argtypes or restype for this simple case, so it is some kind of path issue if it works normally from C. Use a tool like [Process Monitor](https://learn.microsoft.com/en-us/sysinternals/downloads/procmon) to monitor DLL loading failures. See [this answer](https://stackoverflow.com/a/18650202/235698). – Mark Tolonen Jun 02 '22 at 19:08
  • The traceback of the `OSError` might give a clue if you want to edit your question and post it. – Mark Tolonen Jun 02 '22 at 19:14
  • I commented out the argtypes and restype, it didn't do anything as you might have expected. I edited the question with the traceback. – bpound Jun 02 '22 at 19:33
  • That error just seems like a problem with the implementation of the library. A simple open shouldn’t crash so it isn’t handling an error correctly. Again, it is probably a path problem with library the will take a tool like Procmon to investigate. You could try installing 32-bit python, or try using their 64-bit libraries from C to see if it is a 64-bit library problem but I’m just shooting in the dark now – Mark Tolonen Jun 02 '22 at 19:57
  • I used Process Monitor. I found the CreateFile operations whose paths had "usb5800.dll" and "libusb0.dll" in the path that I specified, and both had "SUCCESSFUL" in their result column. There were, however, many non successful operations as it searched in a variety of paths for usb-1.0.dll, libusb-1.0.dll, usb.dll, and openusb.dll ... finally, it seemed to do a successful CreateFile for a different libusb0.dll in C:\Windows\System32, sometime after the CreateFile for the libusb0 in the proper path ... maybe that's the issue? I'll try these other things too. – bpound Jun 02 '22 at 20:11
  • 1
    Haha, my code works with the 32-bit libraries and 32-bit python, but the same code run in 64-bit python doesn't seem to work with the 64-bit libraries. ProcMon looks about the same too. Thanks for your help! – bpound Jun 02 '22 at 20:32

1 Answers1

0

There were some issues with the code (see the discussion), but the larger problem is that there is some problem with the DLL files themselves.

bpound
  • 28
  • 5