I'm working in Python and have installed the lastest version of NI-VISA. I'm using the ctypes package in order to load the visa32.dll installed with NI-VISA.
I used both the NI-VISA documentation, as well as the following page as a base for my code.
I already know of the pyVisa wrapper and using their find_resources function does return the instruments connected. However, I do not wish to use this wrapper and would rather use the VISA DLL file directly.
I've also been browsing the pyVisa code to see how they do it, and tried to learn from it, but it seems I still don't get it.
Here is my current unfinished code:
import sys
from ctypes import *
visa = windll.LoadLibrary("visa32.dll")
resourceManagerHandle = c_int(0)
visa.viOpenDefaultRM(byref(resourceManagerHandle))
instr_list = c_ulong(0)
nb = c_ulong(0)
desc = create_string_buffer(128)
print(visa.viFindRsrc(resourceManagerHandle,
"?*INSTR",
byref(instr_list),
byref(nb),
byref(desc)))
# The previous line prints: -1073807343
print(instr_list)
# The previous line prints: c_ulong(0)
I've been trying to find the meaning of the error code -1073807343 (4000FFEF in hex) on the Internet and though I have found some forum threads about it on the National Instruments forums, I still don't quite understand what it means.
I would welcome any advice, guidance or link towards relevant information.
The literal "?*INSTR" creates an str object, which is Unicode in Python 3. ctypes converts a unicode string to a wchar_t *. On Windows, wchar_t is 2 bytes, so ctypes passes a pointer to the UTF-16 encoded buffer "?\x00*\x00I\x00N\x00S\x00T\x00R\x00". Bear in mind that the function expects a null-terminated string.
To pass a byte string instead, prefix the literal with b to create a bytes object, i.e. use b"?*INSTR".
To prevent a mistake like this from passing unnoticed, define the function pointer's argtypes. ctypes will raise an ArgumentError if a unicode str argument is passed for a parameter that's defined to be c_char_p.
from ctypes import *
visa = WinDLL("visa32.dll") # or windll.visa32
def vi_status_check(vi_status, func, args):
if vi_status < 0:
raise RuntimeError(hex(vi_status + 2**32))
return args
visa.viOpenDefaultRM.errcheck = vi_status_check
visa.viOpenDefaultRM.argtypes = [POINTER(c_uint32)]
visa.viFindRsrc.errcheck = vi_status_check
visa.viFindRsrc.argtypes = [c_uint32, # sesn
c_char_p, # expr
POINTER(c_uint32), # findList
POINTER(c_uint32), # retcnt
c_char_p] # desc
rm_session = c_uint32()
visa.viOpenDefaultRM(byref(rm_session))
expr = b"?*INSTR"
instr_list = c_uint32()
nb = c_uint32()
desc = create_string_buffer(256)
visa.viFindRsrc(rm_session,
expr,
byref(instr_list),
byref(nb),
desc)
The NI-VISA Programmer Reference Manual says on page 5-30 that instrDesc should be at least 256 bytes.
Related
By running the code of python below with python main.py wmi.dll, I want to get the loading address of DLL. However, the value of loadAddr is 0. What is wrong in the code?
from ctypes import *
import sys
import string
kernel32 = windll.kernel32
print(kernel32)
if len(sys.argv)!=2:
print("Usage : dll.py<DLL to resolve>")
sys.exit(0)
windll.LoadLibrary(sys.argv[1])
loadAddr = kernel32.GetModuleHandleA(sys.argv[1])
print(str(loadAddr)+"\n")
print(sys.argv[1])
print(hex(loadAddr) + " Load Address")
print(hex(loadAddr + int("0x1000",16)) + " Text segment")
Make sure to define the .argtypes and .restype of the functions you are using with ctypes. GetModuleHandleA takes a LPCSTR (equivalent to a bytes object in Python), and GetModuleHandleW takes a LPCWSTR (equivalent to a str object in Python). Additionally, they both return HDMODULE, which is a 64-bit value of 64-bit systems, but the default .restype if unspecified is c_int (32-bit).
Here's correct code to call either version:
import ctypes as ct
from ctypes import wintypes as w
k32 = ct.WinDLL('kernel32')
k32.GetModuleHandleA.argtypes = w.LPCSTR,
k32.GetModuleHandleA.restype = w.HMODULE
k32.GetModuleHandleW.argtypes = w.LPCWSTR,
k32.GetModuleHandleW.restype = w.HMODULE
wmi = ct.WinDLL('wmi')
print(k32.GetModuleHandleA(b'wmi')) # byte string
print(k32.GetModuleHandleW('wmi')) # Unicode string
print(k32.GetModuleHandleA('wmi')) # calling with wrong type
Sample output below. Note this value is larger than a 32-bit value could hold (>4294967295) and would be truncated and incorrect if .restype wasn't set, and the error message would not occur if .argtypes wasn't set.
1864530853888
1864530853888
Traceback (most recent call last):
File "C:\test.py", line 15, in <module>
print(k32.GetModuleHandleA('wmi'))
ctypes.ArgumentError: argument 1: <class 'TypeError'>: wrong type
Listing [Python.Docs]: ctypes - A foreign function library for Python.
There are some problems with your code:
The main one:
[MS.Docs]: GetModuleHandleA function (libloaderapi.h) (or any ANSI function variant from WinAPI) takes a 8bit string (char*) as argument
In Python 3 (I assume that's what you are using) strings are 16bit (wchar_t*)
To get past this you should use: kernel32.GetModuleHandleW. Example:
>>> import ctypes as ct
>>> # kernel32 is alsready loaded
>>> ct.windll.kernel32.GetModuleHandleA("kernel32")
0
>>> ct.windll.kernel32.GetModuleHandleW("kernel32")
-1613692928
Check [SO]: C function called from Python via ctypes returns incorrect value (#CristiFati's answer) for details on calling functions from .dlls via CTypes (in particular, you should set restype to a 64bit value, e.g. wintypes.HMODULE)
There's no need for GetModuleHandle (making the previous 2 bullets moot for this particular case, but I left them because they contain useful general info). You could simply use load_addr = windll.LoadLibrary(sys.argv[1])._handle
Argument validation should come 1st
I have the following code:
GetForegroundWindow = windll.user32.GetForegroundWindow
GetWindowTextLength = windll.user32.GetWindowTextLengthW
GetWindowText = windll.user32.GetWindowTextW
hwnd = GetForegroundWindow() # Get handle to foreground window. Here hwnd is a Python int.
length = GetWindowTextLength(hwnd) # Get length of the window text in title bar. Here hwnd is expected to be a Windows Handle.
buff = create_unicode_buffer(length + 1) # Create buffer to store the window title buff
GetWindowText(hwnd, buff, length + 1) # Get window title and store in buff
print(buff.value) # print the value of buff
On line 4, a handle is retrieved, which in ctypes is assumed to be a Python int. On the next line, it is passed where a Windows handle is expected. Is Python automatically converting it into the correct type? Don't we have to convert it explicitly?
No, don’t assume. Set .argtypes and .restype on each function to inform ctypes what the argument types and return type are. For example on 64-bit Python the handle is 64 bits and the assumed c_int return value will truncate it to 32 bits.
For example, extending your code using some predefined Windows types provided:
from ctypes import wintypes as w
...
GetForegroundWindow.argtypes = ()
GetForegroundWindow.restype = w.HWND
Now the correct value will be returned, regardless of OS. Repeat for other functions used and parameters will be type-checked and checked for number of arguments and return values will be correct.
We are building a project using active RFID, and this RFID needs to be coded on Python to use it on Raspberry PI3
SAAT RFID already has DLL file, RFIDAPI.lib and RFIDAPIEXPORT.h and various API calling function
For instance and the basic code I need to execute
bool SAAT_TCPInit (void** pHandle,char *pHostName,int nsocketPort)
HANDLE hp; if(!SAAT_TCPInit(&hp,”192.168.0.238”,7086) )
{
printf("reader initialization failed!\n"); return false;
}
How can I convert this code into Python to get into RFID?
Untested, but illustrates what you need to do. I assumed Python 3, but Python 2 is similar.
#!python3
import ctypes
# import the DLL
dll = ctypes.CDLL('RFIDAPI')
# declare the argument and return value types
dll.SAAT_TCPInit.argtypes = ctypes.POINTER(ctypes.c_void_p),ctypes.c_char_p,ctypes.c_int)
dll.SAAT_TCPInit.restype = ctypes.c_bool
# For the output parameter, create an instance to be passed by reference.
hp = ctypes.c_void_p()
if not dll.SAAT_TCPInit(ctypes.byref(hp),b'192.168.0.238',7086):
print('reader initialization failed!')
Note the byte string for the IP. In Python 3 byte strings are the correct input for c_char_p.
I'm trying to write a very simple controller for a camera on a WinXP machine. Instead of writing c code, I thought I would simply use ctypes to access the dll.
To start the camera, you have to call:
BeginHVDevice(int nDevice, HHV *pHandle)
*pHandle is a pointer to a camera handle, which in the.h file is simply defined as
typedef HANDLE HHV;
I had thought that the following should work
from ctypes import *
from ctypes.wintypes import *
ailt_lib = cdll.LoadLibrary("HVDAILT")
load_camera = ailt_lib.BeginHVDevice
load_camera.restype = c_int
load_camera.argtypes = [c_int, POINTER(HANDLE)]
def initDev(res=(800,600)):
cam_int = c_int(1)
cam_handle_type = POINTER(HANDLE)
print cam_handle_type
cam_handle = cam_handle_type()
print cam_handle
cam_stat = load_camera(cam_int, cam_handle )
print cam_stat
return cam_handle
but, when I call initDev(), I get a ValueError: Procedure called with not enough arguments (8 bytes missing) or wrong calling convention. I'm pretty sure this means that I have not produced a compatible pointer to pass, but I can't figure out what the function actually wants to receive.
I've spent a couple of days search stackoverflow, looking at ctypes documentation and trying all sorts of permutations, but I have not found the answer.
It seems the function is using stdcall instead of the cdecl calling convention, i.e. use ctypes.WinDLL instead of ctypes.CDLL. Also, it wants a pointer to a memory location where it can store the handle, but you passed it a NULL pointer. Instead pass it a reference to a wintypes.HANDLE.
from ctypes import *
from ctypes.wintypes import *
ailt_lib = WinDLL("HVDAILT")
load_camera = ailt_lib.BeginHVDevice
load_camera.restype = c_int
load_camera.argtypes = [c_int, POINTER(HANDLE)]
def initDev(res=(800,600)):
cam_int = 1
cam_handle = HANDLE()
cam_stat = load_camera(cam_int, byref(cam_handle))
print 'cam_stat:', cam_stat
print 'cam_handle:', cam_handle
return cam_handle
I need help to call a function(Struct C) that detects the devices, so I'm calling the function this way:
from ctypes import *
fp = CDLL('./libfprint.so.0')
fp.fp_discover_devs.argtypes = None
fp.fp_discover_devs.restype = c_char_p
ret = fp.fp_discover_devs()
print ret # is "0"
That is not detected any device, because the return is "0".
See the documentation of the function:
struct fp_dscv_dev\** fp_discover_devs (void) [read]
Returns:
a NULL-terminated list of discovered devices.
I'm using Ubuntu and I downloaded the "fprint_demo" and works perfectly. Did you install any package missing?
Thanks.