I have a C++ DLL. I want to make a Flask server to call the functions in this DLL. So I use ctypes inside Flask. Here is my code in views.py:
from flask import render_template
from MusicServer_Flask import app
from ctypes import *
import os
#load Dll:
cppdll = CDLL("C:\\VS_projects\\MusicServer_Flask\\NetServerInterface.dll")
#wrapping DLL function:
initnetwork = getattr(cppdll, "?InitNetwork##YAHQAD0H#Z") #The function can be accessed successfully
initnetwork.argtypes = [c_char_p,c_char_p,c_int]
initnetwork.restype = wintypes.BOOL
#define route:
#app.route('/InitNetwork/<LocalIP>/<ServerIP>/<LocalDeviceID>')
def InitNetwork(LocalIP, ServerIP, LocalDeviceID):
return initnetwork(LocalIP, ServerIP, LocalDeviceID)
With the help of this question, I can call this function in Python interactice window successfully using this:InitNetwork(b"192.168.1.101",b"192.168.1.101",555):
However, when I run the Flask project and enter this route:http://192.168.1.102:8081/InitNetwork/b"192.168.1.102"/b"22192.168.1.102"/555 It gives me an error like this:
It seems that the b"192.168.1.102" becomes b%22192.168.1.102%22 in the requested URL. Why this happens? How can I use the right URL to call this function?
Thank you for your attention.
Edit:
Thanks to #Paula Thomas 's answer, I think I moved one step towards the answer.I changed the code as below to convert the first and second input parameters into bytes:
#app.route('/InitNetwork/<LocalIP>/<ServerIP>/<LocalDeviceID>')
def InitNetwork(LocalIP, ServerIP, LocalDeviceID):
b_LocalIP = bytes(LocalIP,'utf-8')
b_ServerIP = bytes(ServerIP,'utf-8')
return initnetwork(b_LocalIP, b_ServerIP, LocalDeviceID)
However, neither http://172.16.4.218:8081/InitNetwork/172.16.4.218/172.16.4.218/555 nor http://172.16.4.218:8081/InitNetwork/"172.16.4.218"/"172.16.4.218"/555 works. Still gives me wrong type error. Would somebody please help?
I think you'll find that Flask is passing you strings (type str) whereas your C or C++ function is expecting bytes (hence the 'b' before two of the parameters) for the first two parameters and an int for the third. It is your responsibility to convert them.
Related
I'm trying to run some motor controllers using a library supplied by Maxon. The library is a DLL file that I'm reading in using ctypes and pythonNet. The library is working, I can drive the motors and most functions I've used so far have been fine. However, to read position data back from the controller I need to use a function called VcsGetObject. Every call I've made to the function has resulted in an error because I don't have the proper inputs or outputs:
TypeError: No method matches given arguments for VcsGetObject
The VcsGetObject function accepts a data input by reference and returns position data through that variable. I've tried various methods of passing data to the function but haven't been successful yet. I've tried giving the function extra outputs, since I've read that PythonNet can do that automatically. I've tried passing in tuples or lists, or passing ctypes datatypes using ctypes.byref().
I'm honestly not sure where the problem is, and I want to know if there's some way to look at what the function expects in. I have documentation for the C++ function, but since I'm importing it from a DLL I can't really tell where the problem is. I apologize for the vagueness of this question, I honestly feel like there are so many places this could be going wrong but maybe there's something really obvious I just don't know about.
import time
import clr #pythonnet, manually installed with a downloaded wheel and pip
import ctypes #module to open dll files
import System
clr.AddReference('EposCmd.Net')
EposCmd64 = ctypes.CDLL('.\EposCmd64.dll')
from EposCmd.Net.VcsWrapper import Device
print("START")
print()
Device.Init()
nodeID = 1
baudrate = 1000000
timeout = 500
errorCode = 0
index = int('0x606C',16)
subindex = 0
dataLength = 4
# These functions all work as expected, so the library is being imported correctly
keyHandle, error = Device.VcsOpenDevice('EPOS4', 'MAXON SERIAL V2', 'USB', 'USB0', errorCode) #opens EPOS
print(errorCode)
Device.VcsSetProtocolStackSettings(keyHandle, baudrate, timeout, errorCode) #set baudrate
Device.VcsClearFault(keyHandle, nodeID, errorCode) #clear all faults
# # Trying to use lists or tuples doesn't work
#data = [0]
#readLength = [0]
#output = Device.VcsGetObject(keyHandle,nodeID,index,subindex,data,readLength,errorCode)
# # Using ctypes and .byref(), also doesn't work
#data = ctypes.c_byte()
#readLength = ctypes.c_byte()
#output = Device.VcsGetObject(keyHandle,nodeID,index,subindex,ctypes.byref(data),ctypes.byref(readLength),errorCode)
# # Trying to use PythonNet to turn by ref inputs into outputs
output, data, readLength = Device.VcsGetObject(keyHandle,nodeID,index,subindex,errorCode)
#print(data)
#print(readLength)
I've included links to the maxon documentation, GetObject is in section 4.1.4.
https://www.maxongroup.com/medias/sys_master/8823917281310.pdf
Firstly, your function calls looks incorrect. This is untested, but your open device call should look more like:
from ctypes import byref, c_byte, c_void_p
from ctypes.wintypes import WORD, DWORD
# Set type
errorCode = DWORD()
# Pass error by reference
handle = Device.VcsOpenDevice(
'EPOS4',
'MAXON SERIAL V2',
'USB',
'USB0',
byref(errorCode))
# Read error code after function call
print(errorCode.value)
According to your linked doc VCS_GetObject looks like this:
nodeId = WORD(1)
objectIndex = WORD(0x606C)
objectSubIndex = c_byte(0)
NbOfBytesToRead = DWORD(
data = c_void_p()
# Vary this to read more or less data
NbOfBytesToRead = DWORD(4)
NbOfBytesRead = DWORD()
errorCode = DWORD()
return_value = Device.VcsGetObject(
handle,
nodeId,
objectIndex,
objectSubIndex,
byref(data),
NbOfBytesToRead,
byref(NbOfBytesRead),
byref(errorCode))
print(errorCode.value)
You should also set your restype and argtypes.
I'm at the moment in the middle of writing my Bachelor thesis and for it creating a database system with Postgres and Flask.
To ensure the safety of my data, I was working on a file to prevent SQL injections, since a user should be able to submit a string via Http request. Since most of my functions which I use to analyze the Http request use Kwargs and a dict based on JSON in the request I was wondering if it is possible to inject python code into those kwargs.
And If so If there are ways to prevent that.
To make it easier to understand what I mean, here are some example requests and code:
def calc_sum(a, b):
c = a + b
return c
#app.route(/<target:string>/<value:string>)
def handle_request(target,value):
if target == 'calc_sum':
cmd = json.loads(value)
calc_sum(**cmd)
example Request:
Normal : localhost:5000/calc_sum/{"a":1, "b":2}
Injected : localhost:5000/calc_sum/{"a":1, "b:2 ): print("ham") def new_sum(a=1, b=2):return a+b":2 }
Since I'm not near my work, where all my code is I'm unable to test it out. And to be honest that my code example would work. But I hope this can convey what I meant.
I hope you can help me, or at least nudge me in the right direction. I've searched for it, but all I can find are tutorials on "who to use kwargs".
Best regards.
Yes you, but not in URL, try to use arguments like these localhost:5000/calc_sum?func=a+b&a=1&b=2
and to get these arguments you need to do this in flask
#app.route(/<target:string>)
def handle_request(target):
if target == 'calc_sum':
func= request.args.get('func')
a = request.args.get('a')
b = request.args.get('b')
result = exec(func)
exec is used to execute python code in strings
Issue
I'm trying to call CAPL general functions (in my case timeNowNS) but I don't know if it's possible.
What I'm using?
I'm using Python 3.7 and Vector CANoe 11.0.
The connection is done using the .NET CANoe API.
This is how i've accesed the DLLs.
import clr
sys.path.append("C:\Program Files\Vector CANoe 11.0\Exec64") # path to CANoe DLL Files
clr.AddReference('Vector.CANoe.Interop') # add reference to .NET DLL file
import CANoe # import namespace from DLL file
What I've tried?
I opened the CANoe simulation succesfully, started the measure and I'm having access to signals, env variables and sys variables.
Then I've created the CAPL Object and tried using the GetFunction method to obtain the CAPLFunction object so i could call it.
def begin_can(self, sCfgFile, fPrjInitFunc = None):
self.open_can()
self.load_can_configuration(sCfgFile)
self.start_can_measurement(fPrjInitFunc)
def open_can(self):
self.mCANoeApp = CANoe.Application()
self.mCANoeMeasurement = CANoe.Measurement(self.mCANoeApp.Measurement)
self.mCANoeEnv = CANoe.Environment(self.mCANoeApp.Environment)
self.mCANoeBus = CANoe.Bus(self.mCANoeApp.get_Bus("CAN"))
self.mCANoeSys = CANoe.System(self.mCANoeApp.System)
self.mCANoeNamespaces = CANoe.Namespaces(self.mCANoeSys.Namespaces)
self.mCANoeCAPL = CANoe.CAPL(self.mCANoeApp.CAPL)
self.mCANoeCAPL.Compile()
def getFunction(self):
function1 = self.mCANoeCAPL.GetFunction('timeNowNS')
# here I tried also CANoe.CAPLFunction(self.mCANoeCAPL.GetFunction('timeNowNS'))
# but i got attribute error: doesn't exist or something like that
result = function1.Call()
Expected results
I should get the current simulation time using this function.
Actual results
Using the above code I get:
**COMException**: Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))
at CANoe.ICAPL5.GetFunction(String Name)
I've tried different variations of the code but didn't get anywhere.
Is it possible to be a hardware problem?
Should I do some settings in the CANoe Simulation?
If you need more information, please ask me! Thanks in advance
Update: I've added a photo of my measure setup after adding the CAPL block
You have to write a CAPL function in which you call timeNowNS. This CAPL function can then be called from Python in the way you have implemented.
GetFunction only works with (user-written) CAPL functions. You cannot call CAPL intrinsics (i.e. built-in CAPL functions) directly.
Put this into a CAPL file:
int MyFunc()
{
return timeNowNS();
}
and call like this from Python:
def getFunction(self):
function1 = self.mCANoeCAPL.GetFunction('MyFunc')
result = function1.Call()
After a long session of try and error and the help of #m-spiller I found the solution.
function2 = None
def open_can(self):
self.mCANoeApp = CANoe.Application()
self.mCANoeMeasurement = self.mCANoeApp.Measurement # change here: no cast necessary
self.mCANoeEnv = CANoe.Environment(self.mCANoeApp.Environment)
self.mCANoeBus = CANoe.Bus(self.mCANoeApp.get_Bus("CAN"))
self.mCANoeSys = CANoe.System(self.mCANoeApp.System)
self.mCANoeNamespaces = CANoe.Namespaces(self.mCANoeSys.Namespaces)
self.mCANoeCAPL = CANoe.CAPL(self.mCANoeApp.CAPL)
self.mCANoeMeasurement.OnInit += CANoe._IMeasurementEvents_OnInitEventHandler(self.OnInit)
# change here also: explained below
def OnInit(self):
global function2
function2 = CANoe.CAPLFunction(mCANoeCAPL.GetFunction('MyTime')) # cast here is necessary
def callFunction(self):
result = function2.Call()
What was the problem with the initial code?
The problem was that i tried to assign a function to a variable after the measure has started.
As stated here in chapter 2.7, the assignment of a CAPL Function to a variable can only be done in the OnInit event handler of the Measurement object.
I've added this line, studying the documentation:
self.mCANoeMeasurement.OnInit += CANoe._IMeasurementEvents_OnInitEventHandler(self.OnInit)
After adding it, on init the OnInit function was executed and the CAPL function was assigned to a variable and afterwards i could use that variable to call the function.
Thank you again, #m-spiller !
I'm using python scripting for Strand/Straus7 importing his DLL.
I'm trying to call a function for set the units, called St7SetUnits, following the manual (Img.1) and watching the .py scripting of the DLL that I imported (Img.2). The function expected a c_long and a ctypes.POINTER.(c_long), as specify in the script (Img.3)
Here the complete manual strand7.com/downloads/Strand7%20R246%20API%20Manual%20TOC.pdf
and here the .py scripting https://www.dropbox.com/s/88plz2funjqy1vb/St7API.py?dl=0
As specify at the beginning of the manual I have to convert the list in ctypes array (Img.4).
The function I call is the same of the example, but I can't call it correctly.
I write
import St7API as SA
import ctypes
SA.St7Init()
unitsArray = ctypes.c_int * SA.kLastUnit
units = unitsArray()
units[0] = 0
units[1] = 1
units[2] = 3
units[3] = 1
units[4] = 1
units[5] = 2
SA.St7SetUnits(1, units)
But returns error
expected c_long, got c_long_Array_6
If I try something else, for example an int from the array
SA.St7SetUnits(1, units[0])
the error change in
expected LP_c_long, got int
I tried many solution, but no one works.
Can anyone help me?
Thanks a lot
I know its been a while, but this works for me:
units_type=ctypes.c_long*6
Units = units_type(0,1,3,1,1,2)
St7API.St7SetUnits(1,Units)
From your screenshots it looks like you might be using Grasshopper. If so, you might need to explicitly cast the units array to a pointer by adding this line to the top of your script:
PI = ctypes.POINTER(ctypes.c_long)
And do this whenever you pass an array from IronPython to St7API:
SA.St7SetUnits(1, PI(units))
This answer has slightly more.
Alright, so a couple days ago I decided to try and write a primitive wrapper for the PARI library. Ever since then I've been playing with ctypes library in loading the dll and accessing the functions contained using code similar to the following:
from ctypes import *
libcyg=CDLL("<path/cygwin1.dll") #It needs cygwin to be loaded. Not sure why.
pari=CDLL("<path>/libpari-gmp-2.4.dll")
print pari.fibo #fibonacci function
#prints something like "<_FuncPtr object at 0x00BA5828>"
So the functions are there and they can potentially be accessed, but I always receive an access violation no matter what I try. For example:
pari.fibo(5) #access violation
pari.fibo(c_int(5)) #access violation
pari.fibo.argtypes = [c_long] #setting arguments manually
pari.fibo.restype = long #set the return type
pari.fibo(byref(c_int(5))) #access violation reading 0x04 consistently
and any variation on that, including setting argtypes to receive pointers.
The Pari .dll is written in C and the fibonacci function's syntax within the library is GEN fibo(long x).
Could it be the return type that's causing these errors, as it is not a standard int or long but a GEN type, which is unique to the PARI library? Any help would be appreciated. If anyone is able to successfully load the library and use ANY function from within python, please tell; I've been at this for hours now.
EDIT: Seems as though I was simply forgetting to initialize the library. After a quick pari.pari_init(4000000,500000) it stopped erroring. Now my problem lies in the in the fact that it returns a GEN object; which is fine, but whenever I try to reference the address to which it points, it's always 33554435, which I presume is still an address. I'm trying further commands and I'll update if I succeed in getting the correct value of something.
You have two problems here, one give fibo the correct return type and two convert the GEN return type to the value you are looking for.
Poking around the source code a bit, you'll find that GEN is defined as a pointer to a long. Also, at looks like the library provides some converting/printing GENs. I focused in on GENtostr since it would probably be safer for all the pari functions.
import cytpes
pari = ctypes.CDLL("./libpari.so.2.3.5") #I did this under linux
pari.fibo.restype = ctypes.POINTER(ctypes.c_long)
pari.GENtostr.restype = ctypes.POINTER(ctypes.c_char)
pari.pari_init(4000000,500000)
x = pari.fibo(100)
y = pari.GENtostr(x)
ctypes.string_at(y)
Results in:
'354224848179261915075'