Using a DLL in python - cannot locate functions or classes - python

I'm currently struggling to get some python code to locate functions within a DLL file.
I have looked at several posts on here about this and the various methods don't seem to work for me.
Please ignore the fact that the code could be implements using the GUI library in Python, this is not an option for me.
So my header file is as follows:
#pragma once
#ifdef MOBILEFUNC_EXPORTS
#define MOBILEFRONTEND_API __declspec(dllexport)
#else
#define MOBILEFRONTEND_API __declspec(dllimport)
#endif
#ifdef __cplusplus
class mobileFrontEnd{
public:
char* getPath();
};
#else typedef struct _frontEnd frontEnd;
#endif
#ifdef __cplusplus
extern "C" {
#endif
MOBILEFRONTEND_API mobileFrontEnd *frontend_create();
MOBILEFRONTEND_API char* getPath();
#ifdef __cplusplus
}
#endif
using namespace System;
using namespace System::Windows::Forms;
namespace frontEnd {
class MOBILEFRONTEND_API mobileFrontEnd
{
public:
static char* getPath();
};
}
And my main C++ file is:
#include "stdafx.h"
#include "mobileFrontEnd.h"
using namespace::Runtime::InteropServices;
namespace frontEnd
{
mobileFrontEnd *frontend_create()
{
mobileFrontEnd *self = new mobileFrontEnd;
return self;
}
char* mobileFrontEnd::getPath()
{
FolderBrowserDialog^ openDialog1 = gcnew FolderBrowserDialog();
if (openDialog1->ShowDialog() == DialogResult::OK)
{
String^ path = openDialog1->SelectedPath;
return (char*)(void*)Marshal::StringToHGlobalAnsi(path);
}
else
{
return 0;
}
}
}
The DLL imports using the CDLL or WinDLL functions in python, however any attempts to access functions or class result in an error stating the class/function does not exists.
I don't have any real python code for this so fa as I've been attempting to check it in python command prompt.
Am I missing something to ensure it exports functions correctly?
Edited with some python code:
So something similar to this (from http://eli.thegreenplace.net/2008/08/31/ctypes-calling-cc-code-from-python)
import ctypes
>>> test_dll = ctypes.CDLL("C:\\Users\\xxxx\\Documents\\Visual Studio 2012\\Projects\\mobileFrontEnd\\Release\\mobilefrontend.dll")
>>> test_cb = test_dll.getPath();
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
test_cb = test_dll.getPath();
File "C:\Python27\lib\ctypes\__init__.py", line 378, in __getattr__
func = self.__getitem__(name)
File "C:\Python27\lib\ctypes\__init__.py", line 383, in __getitem__
func = self._FuncPtr((name_or_ordinal, self))
AttributeError: function 'getPath' not found
>>>
Edit 2:
Also just in case it isn't clear from the code (Windows form being used), the DLL is compiled in Visual Studio 2012 express and include 'common library runtime' support

Using the following code seems to work for accessing the functions:
import ctypes
test_dll = ctypes.CDLL("**path to dll**")
test1 = ctypes.WINFUNCTYPE(None)
test2 = test1(("getPath",test_dll))
test2()
No idea why the functions cannot be seen in the attributes of test_dll

Related

SWIG Attribute Error: module has no attribute 'delete_...'

I have been trying to get this to work for a while now. I am trying to wrap a LOT of c++ classes in swig, but I can't even get the first one to work. The error is at the bottom. Here is my interface file, setup.py, and class file.
Interface
//This file is automatically generated from "build_swig_files.py
//Makes changes to build_swig_files.py to edit jcm.i
%module jcm
%{
#include "jtag/GenericJTAGDevice.h"
typedef unsigned int u32;
%}
class GenericJTAGDevice {
public:
virtual ~GenericJTAGDevice();
GenericJTAGDevice(int irLength, int idCode);
unsigned int getIrLength();
unsigned int getIdCode();
private:
unsigned int idCode;
unsigned int irLength;
};
typedef unsigned int u32;
%include <std_string.i>
using std::string;
%include "cpointer.i"
%pointer_functions(u32, u32p);
%include "carrays.i"
%array_class(u32, u32a);
%include "std_vector.i"
namespace std {
%template(IntVector) vector<int>;
}
setup.py
from distutils.core import setup, Extension
jcm_sources = [
"jcm.i",
"/root/git/jcm/jcm_source/base/src/jtag/GenericJTAGDevice.cpp"
]
jcm_module = Extension('_jcm',
sources=jcm_sources,
swig_opts=[ '-I/root/git/jcm/jcm_source/base/include',
'-I/root/git/jcm/jcm_source/base/include/jtag',
'-I/root/git/jcm/jcm_source/base/include/util',
'-I/root/git/jcm/jcm_source/base/include/xilinx',
'-c++'],
include_dirs=[ '/root/git/jcm/jcm_source/base/include',
'/root/git/jcm/jcm_source/base/include/jtag',
'/root/git/jcm/jcm_source/base/include/util',
'/root/git/jcm/jcm_source/base/include/xilinx'],
libraries=['supc++'])
setup (name = 'jcm', version = '0.3', author = 'BYUCCL', ext_modules = [jcm_module], py_modules = ["jcm"])
Class Header
#ifndef GENERIC_JTAG_DEVICE_H
#define GENERIC_JTAG_DEVICE_H
#include <string>
#include <vector>
//#include "JTAGDevice.h"
using namespace std;
/**
* #brief Basic implementation of a JTAGDevice
*
* \class GenericJTAGDevice
*
**/
class GenericJTAGDevice {
public:
virtual ~GenericJTAGDevice();
GenericJTAGDevice(int irLength, int idCode);
unsigned int getIrLength();
unsigned int getIdCode();
private:
unsigned int idCode;
unsigned int irLength;
};
#endif // GENERIC_JTAG_DEVICE_H
Here is the error:
>>> import sys
>>> sys.path.insert(0, '/root/git/JCM/jcm_source/python/swig')
>>> import jcm
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/root/git/jcm/jcm_source/python/swig/jcm.py", line 64, in <module>
class GenericJTAGDevice(object):
File "/root/git/jcm/jcm_source/python/swig/jcm.py", line 67, in GenericJTAGDevice
__swig_destroy__ = _jcm.delete_GenericJTAGDevice
AttributeError: module '_jcm' has no attribute 'delete_GenericJTAGDevice'
I have tried a couple variations in the interface file, such as not having the whole class definition and just doing %include GenericJTAGDevice.h. I have a feeling it has to do with the virtual destructor, but I don't know how to fix that because I need the destructor.
Edit: I tried with another class and it did the same thing. So perhaps I am understanding the interface file wrong.
Edit: All I am running is python3 setup.py build
So I saw the answer in the link below before but didn't understand what it was saying. Basically, my process to build swig didn't include making a new _jcm.so. So pretty much the first time I ran it was it, and after that all the changes I made to the .i or the code or setup.py didn't mean anything because the _jcm.so wasn't being rewritten. In my case, I run a "make clean" from my make file and it deletes the _jcm.so. After that I build the _jcm.so again, and then run setup.py.
Simple, but hard to find.
http://swig.10945.n7.nabble.com/Req-module-object-has-no-attribute-delete-TSP-CA-td2271.html

How to open('file-path', 'rb') in a a python file that is embedded in C++?

I have some C++ code which is calling a function inside a python file. If I try to read a pickled file in the python code then I get the following error:
Exception ignored in: <module 'threading' from 'C:\\Anaconda3\\envs\\Deep_Learning\\lib\\threading.py'>
Traceback (most recent call last):
File "C:\Anaconda3\envs\Deep_Learning\lib\threading.py", line 1289, in _shutdown
assert tlock.locked()
SystemError: <built-in method locked of _thread.lock object at 0x000002328D1EAAA8> returned a result with an error set
Python file:
def test():
print("In function test of pyemb.py file \n")
import pickle
with open('filepath', 'rb') as f_in:
C = pickle.load(f_in)
C++ (This file is calling the python file)
#include <stdio.h>
#include <conio.h>
#include <pyhelper.hpp>
#include <iostream>
int main()
{
CPyInstance hInstance;
CPyObject pName = PyUnicode_FromString("pyemb");
CPyObject pModule = PyImport_Import(pName); //importing the file
if (pModule)
{
std::cout << "Module load successful" << std::endl;
CPyObject pFunc1 = PyObject_GetAttrString(pModule, "test"); //passing name of function to be called
if (pFunc1 && PyCallable_Check(pFunc1)) // checking if not null and callable
{
PyObject_CallObject(pFunc1, NULL);
}
else
{
printf("ERROR: function test didn't run as intended\n");
}
}
else
{
printf_s("ERROR: Module not imported\n");
}
return 0;
}
C++(pyhelper.hpp to handle Py_Initialize ,Py_Finalize etc)
#ifndef PYHELPER_HPP
#define PYHELPER_HPP
#pragma once
#include <Python.h>
// This will take care of closing the session when CPyInstance scope ends,
// as destructor will be implicitly called to close the Py instance
class CPyInstance
{
public:
CPyInstance()
{
// Setting Python home path for reading lib and bin
Py_SetPythonHome(const_cast<wchar_t*>(L"C:\\Anaconda3\\envs\\Deep_Learning"));
// Initializing Python interpreter
Py_Initialize();
// Setting path for python to find our python model files
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append(\"C:\\python_files\")");
}
~CPyInstance()
{
Py_Finalize(); // closes the python interpreter instance
}
};
...More code for other stuff...
How can I fix this?
Please help.

WindowsError: exception: access violation or Windows Error 193 when creating a DLL using ctypes from C++ to Python

I get this error from PyCharm:
WindowsError: exception: access violation reading 0x000000504D414C43
It only occurs in Pycharm. When I run the python script from Windows Powershell, it says WindowsError: [Error 193] %1 is not a valid Win32 application. I checked the debugger and a value is being passed but it errors out sometimes gives me null pointers. At first, I thought I was running off the array, but even if I just return 7 (As you see at the bottom) and comment out all of the code it will still do as described.
Questions:
1) Do you have any solutions?
2) Did I set up the DLL properly?
3)Any suggestions?
Thank you so much for your help.
Here is my C++ code:
#include <iostream>
#include <string>
#include <array>
#include "external_lists.h"
extern creation_object A1[];
extern creation_object A2[];
extern int A1size;
extern int A2size;
#define DLLEXPORT extern "C" __declspec(dllexport)
DLLEXPORT int get_creation_data(std::string needed_name){
int A1_size = ( A1size/ sizeof(A1[0])) ;
int A2_size = ( A2size / sizeof(A2[0])) ;
for (int i = 0; i < A1_size; i++) {
if (A1[i].name == needed_name)
{
return A1[i].value->section;
}
}
return 7;
}
Here is my python wrapper:
import os, sys, re
from ctypes import *
def get_creation_values(value_name):
trimdll = CDLL('C:\\Documents\\creation.dll')
return valuedll.get_creation_data(value_name)
if __name__ == "__main__":
val = get_value('CLAMP')
print(val)
Overall goal:
I have a large file I cannot modify but need to access in C++. There are large lists in the C++ file and I need to iterate through those lists and return a value to a python script.
ctypes only understands C types. You can pass a byte string as const char* and assign it to a std::string if needed. Here's a complete, working example:
C++ code (test.cpp)
#include <string>
#define DLLEXPORT extern "C" __declspec(dllexport)
DLLEXPORT int get_creation_data(const char* name) {
std::string needed_name(name);
if(needed_name == "Armaja")
return 1;
return 0;
}
Python code
from ctypes import *
def get_creation_values(value_name):
trimdll = CDLL('test')
trimdll.get_creation_data.argtypes = [c_char_p]
trimdll.get_creation_data.restype = c_int
return trimdll.get_creation_data(value_name)
if __name__ == "__main__":
val = get_creation_values(b'Armaja')
print(val)
Output:
1
Note how the argument types and return value of the DLL function can be specified. That helps catch errors. For example, try passing a Unicode string 'Armaja' instead of the byte string b'Armaja' (Python 3 syntax):
Traceback (most recent call last):
File "C:\test.py", line 10, in <module>
val = get_creation_values('Armaja')
File "C:\test.py", line 7, in get_creation_values
return trimdll.get_creation_data(value_name)
ctypes.ArgumentError: argument 1: <class 'TypeError'>: wrong type

How to use opencv functions in C++ file and bind it with Python?

I want to pass an image from python script to c++ code for opencv computations. To bind the two I have followed this. The binding is working fine But when I use any opencv in-built functions it gives me error.
Traceback (most recent call last):
File "/home/prashant/Desktop/example.py", line 1, in
import pbcvt # your module, also the name of your compiled dynamic library file w/o the extension
ImportError: /usr/local/lib/python2.7/dist-packages/pbcvt.so: undefined symbol: _ZN2cv8cvtColorERKNS_11_InputArrayERKNS_12_OutputArrayEii
I am using opencv 3.1 and python 2.7.Any help/guidance is much appreciated.`
Code for reference.
Python file.
import pbcvt
import numpy as np
import cv2
a = cv2.imread("/home/prashant/Documents/opencv-practice/screenshot.png")
c = pbcvt.dot(a)
cv2.imshow("gray image",c)
cv2.waitKey(0)
cv2.destroyAllWindows()
C++ code:
#include <pyboostcvconverter/pyboostcvconverter.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
namespace pbcvt {
using namespace std;
using namespace boost::python;
cv::Mat dot(PyObject *image) {
cv::Mat matImage, greyMat;
matImage = pbcvt::fromNDArrayToMat(image);
cv::cvtColor(matImage, greyMat, CV_BGR2GRAY);
return greyMat;
}
cv::Mat dot2(cv::Mat leftMat, cv::Mat rightMat) {
auto c1 = leftMat.cols, r2 = rightMat.rows;
if (c1 != r2) {
PyErr_SetString(PyExc_TypeError,
"Incompatible sizes for matrix multiplication.");
throw_error_already_set();
}
cv::Mat result = leftMat * rightMat;
return result;
}
#if (PY_VERSION_HEX >= 0x03000000)
static void *init_ar() {
#else
static void init_ar(){
#endif
Py_Initialize();
import_array();
return NUMPY_IMPORT_ARRAY_RETVAL;
}
BOOST_PYTHON_MODULE (pbcvt) {
//using namespace XM;
init_ar();
//initialize converters
to_python_converter<cv::Mat,
pbcvt::matToNDArrayBoostConverter>();
pbcvt::matFromNDArrayBoostConverter();
//expose module-level functions
def("dot", dot);
def("dot2", dot2);
}
} //end namespace pbcvt
It could be that you have to edit the CMakeLists.txt in line 27 find_package(OpenCV COMPONENTS core REQUIRED) and add more components like find_package(OpenCV COMPONENTS core imgproc highgui REQUIRED)

Creating instance with methods in C++ and passing it to Python

I'm trying to create an instance of Game, pass it into the main namespace of the test.py as the variable game, then call game.add(e) to run the C++ function that will add Entity e into the std::vector. However, this code produces the error:
unbound method Boost.Python.function object must be called with Game instance as first argument (got Entity instance instead)
(Some context: I'm trying to let Python create instances that will be kept in a container for C++ to run through every tick and update. I thought I had it working a few weeks ago but I came back to it and apparently it wasn't working - I know, source control.)
#include <vector>
class Entity{
public:
Entity(){}
Entity(float x, float y){}
};
class Game{
public:
Game();
void add(Entity* entity);
private:
std::vector<Entity*> objects_;
};
Game::Game(){
}
void Game::add(Entity* entity){
objects_.push_back(entity);
}
main.cpp:
#include <iostream>
#include <boost/python.hpp>
#include "Game.h"
#include "Entity.h"
using namespace boost::python;
BOOST_PYTHON_MODULE(sfgame){
class_<Game>("Game")
.def("add", &Game::add)
;
class_<Entity>("Entity", init<float, float>())
;
}
int main(){
PyImport_AppendInittab("sfgame", &initsfgame);
Py_Initialize();
object main_module = import("__main__");
object main_namespace = main_module.attr("__dict__");
import("sfgame");
Game* game = new Game();
try{
main_namespace["game"] = ptr(game);
exec_file("test.py", main_namespace);
}
catch (const boost::python::error_already_set &){
PyObject *ptype, *pvalue, *ptraceback;
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
std::string error;
error = boost::python::extract<std::string>(pvalue);
std::cout << error << std::endl;
}
delete game;
system("PAUSE");
return 0;
}
test.py:
from sfgame import *
e = Entity(5,5)
game.add(e)
You would receive that error if you set the variable name in the main namespace to Game, as it would be the same as the class name.
However, the code posted is correct. You must have compiled the .pyd file using the variable Game, realised your error, then changed it to game and compiled the C++ file to test it without recompiling the .pyd file so the error remained.

Categories