A simple python program not being able to access my dll - python

I have created a simple MFC .dll file and I am able to access it via another MFC Application program. I was trying to do the same thing using Python 3.2.2 but after I load my library, It does not detect the function in my dll and gives an error like:
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
File "C:\Python32\lib\ctypes\__init__.py", line 353, in __getattr__
func = self.__getitem__(name)
File "C:\Python32\lib\ctypes\__init__.py", line 358, in __getitem__
func = self._FuncPtr((name_or_ordinal, self))
AttributeError: function 'SayHello' not found
..
I have trying to find a simple program to access my MFC dll file using Python but have got no success as of yet. Just to let everyone know, I have read on ctypes and have been searching lots to get this working. My main aim is to use Python as a scripting language to interface with my MFC C++ dll. I have been reading lots and the closest one I could get to was with PythonWin. Please help in this regard.
Cheers.

I have been able to get a hold of my problem and have solved it. For those who might expect this in the future, I would just like to paste the python script code in order to make your functions accessible in your python scripts. The way to go with your C++ function is obviously to declare this in your .dll file.
extern "C" __declspec(dllexport) int SayHello(int strNo);
and your Python script should go something like this: (getattr() function is required to access your c++ function in your python script)
mydll = cdll.LoadLibrary("Location.dll")
hellofunc = getattr(mydll,'SayHello')
func2.restype = c_int
func2.argtypes = [c_int]
x = func2(34)
print(x)
...
If anyone thinks I might be wrong, please feel free to correct me. I am a beginner in Python, it worked for me this way and I am able to go ahead with my scripting after this.
Hope this helps others.
Cheers.

Related

CEFPython won't initialized when called from an application

I have a very very specific problem.
I am trying to figure out a way to embed an HTML brower in my app, in order to show some generated HTML content with included javascript.
I tried to do it with wx.html2, but the javascript part just seems to not work.
So I decided to give a try to CEFPython by taking example of the provided wxPython.py demo.
At first, it worked great in the UI I designed.
BUT, the problem is that this UI is intended to be called from another application, as a sort of "plug-in UI". And when launching my wxPython UI from this application, it crashes as soon as cef is initialized (through:
sys.excepthook = cef.ExceptHook
settings = {
"debug": True,
"log_severity": cef.LOGSEVERITY_INFO,
"log_file": "debug.log",
}
cef.Initialize(settings=settings)
app = CefApp(False)
app.MainLoop()
del app
cef.Shutdown()
I keep getting this error:
Python exception: AttributeError
'module' object has no attribute 'argv'
Traceback (most recent call last):
File "<string>", line 248, in <module>
File "<string>", line 36, in main
File "cefpython_py27.pyx", line 626, in cefpython_py27.Initialize
(cefpython_py27.cpp:99136)
AttributeError: 'module' object has no attribute 'argv'
So in the end I have 2 questions:
is there a way with wx.html2 to show HTML content embedding javascript
if not, do you have a clue of what would cause the launched UI to crash? I guess it's a threading matter but I'm not even sure.
Please excuse my english mistakes by the way, as I'm not native.
It seems that your Python environment doesn't behave in a standard manner, you don't provide details how is your Python code called.
The error in cefpython is thrown on this line:
if "--debug" in sys.argv:
application_settings["debug"] = True
https://github.com/cztomczak/cefpython/blob/bbf3597ba47f72db66cf304ab8eb3ccfc3a7130c/src/cefpython.pyx#L631
You have to find out why your Python didn't define "sys.argv". You can easily fix this with code like this: sys.argv = [] before calling cef.Initialize, however you may still encounter other issues due to your non-standard Python environment.

Are there any "tricks" to building a VB6 DLL so it can be consumed by Python?

I have a VB6 program. It is compiled (no buildable source) and comprised of an .EXE and a few .DLLs.
I created a simple Python script to call some of the public methods in the libraries. Unfortunately, none the methods are available in Python or I'm not calling them correctly.
The code:
from ctypes import *
test = windll.LoadLibrary("C:/.../ComDlg32.ocx")
print test
print test.DLLGetDocumentation
outputs this:
<WinDLL 'C:/.../ComDlg32.ocx', handle 217a0000 at 23a3b10>
<_FuncPtr object at 0x023834E0>
Process finished with exit code 0
I'm okay with the results shown above. It gives me more information than when I run the same code and try to use one of our own DLLs. I think Comdlg32.ocx is a vender-provided control.
When I run the same code against one of our own DLLs with a method that, without a doubt, exists in the DLL, I get this:
Traceback (most recent call last):
<WinDLL 'C:/.../ABC123.exe', handle 5f0000 at 2373b30>
File "C:/.../XYZ123.py", line 11, in <module>
print test.Init
File "C:\...\lib\ctypes\__init__.py", line 366, in __getattr__
func = self.__getitem__(name)
File "C:\...\lib\ctypes\__init__.py", line 371, in __getitem__
func = self._FuncPtr((name_or_ordinal, self))
AttributeError: function 'Init' not found
Process finished with exit code 1
The above result is from an EXE but a DLL returns the same results, minus the method name.
I tried using DUMPBIN with the /exports option. It doesn't show me any of the public methods. DUMPBIN is how I found DLLGetDocumentation in the OCX.
Is there anything else I can try to call methods in a VB6 DLL? Does the VB6 project need to be compiled with specific switches in order for public methods to be callable from Python? How can I tell / verify if the VB6 was compiled in a manner than should allow methods to be callable?

second python execution fails

I'm having a problem embedding the python 3 engine for an app that need to run custom scripts in python. Since the scripts might be completely different, and sometimes user provided, I am trying to make each execution isolated and there is not need to preserve any data between execution of the different scripts.
So, my solution is to wrap each execution between Py_Initialize and Py_Finalize. It looks something like that:
void ExecuteScript(const char* script)
{
Py_Initialize();
PyRun_SimpleString( script );
Py_Finalize();
}
However, this fails for a particular python script the second time a script is executed with:
done!
Traceback (most recent call last):
File "<string>", line 8, in <module>
File "\Python33Test\Output\Debug\Python33\Lib\copy.py", line 89, in copy
rv = reductor(2)
TypeError: attribute of type 'NoneType' is not callable
The python script looks like this:
class Data:
value1 = 'hello'
value2 = 0
import copy
d = Data()
dd = copy.copy( d )
print ( 'done!' )
As you can see, the first time around the script was executed the 'done!' was printed out. But the second time it rises an exception inside the copy function.
It looks like the python engine was left in some weird state after the first initialize-finalize. Note, this is python 3.
Also, it is very interesting to note that Python 2.7 did not have this problem.
I guess there might be other examples that could reveal better what's going, but i haven't had the time to find yet.
Full sources of the test project can be found here:
https://docs.google.com/file/d/0B86-G0mwwxZvNGpoM1Jia3E2Wmc/edit?usp=sharing
Note, the file is 8MB because it includes the python distribution.
Any ideas of how to solve this are appreciated.
EDIT: I also put a copy of the project containing flag to switch between Python 3 and Python 2.7 (the file is 31 MB): https://docs.google.com/file/d/0B86-G0mwwxZvbWRldTd5b2NNMWM/edit?usp=sharing
EDIT: Well, I tested with Python3.2 and it worked fine. So it seems to be bug in Python3.3 only. Adding as an issue: http://bugs.python.org/issue17408#
Well, this was fast.
They actually found the issue being a problem in Python 3.3 code.
http://bugs.python.org/issue17408#

Python ActiveX automation

I am trying to use ActiveX automation with python to control Audio Precision ATS-2. I am using pywin32 32-bit Windows XP with Python 2.7.
I installed the audio Precision software. Then I used makepy utility which found Audio Precision in the list and created a wrapper for it. Everything is going well until I attempt to call dispatch function abd I am stuck.
from guides I found online,
win32com.client.Dispatch("Excel.Application")
What should I put in the area that says "Excel.Application"?
How can I find this?
When I used OLE/COM Object viewer, I see Audio Precision entries under type library, but I am unsure how does the information in it could help me.
I have attempted few things on my own, but got almost no result. The best result I got was when I entered the CLSID in dispatch function, which I found in the wrapper object makepy created.
win32com.client.Dispatch("{80EC6E76-D94F-48EB-8F4C-05BDD7850BF1}")
which gave me the following error:
Traceback (most recent call last):
File "C:\Python27\Lib\site-packages\win32com\gen_py\APtest.py", line 5, in <module>
xlApp = win32com.client.Dispatch("{80EC6E76-D94F-48EB-8F4C-05BDD7850BF1}")
File "C:\Python27\lib\site-packages\win32com\client\__init__.py", line 95, in Dispatch
dispatch, userName = dynamic._GetGoodDispatchAndUserName(dispatch,userName,clsctx)
File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 108, in _GetGoodDispatchAndUserName
return (_GetGoodDispatch(IDispatch, clsctx), userName)
File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 85, in _GetGoodDispatch
IDispatch = pythoncom.CoCreateInstance(IDispatch, None, clsctx, pythoncom.IID_IDispatch)
com_error: (-2147221164, 'Class not registered', None, None)
I have:
looked under the registry, and the ID is indeed not registered anywhere. There are few Audio Precision entries, but doesn't look like it has anything that could fix this.
attempted reinstalling the Audio Precision software, but it didn't help.
attempted to register the dll objects in the Audio Precision control(ATS 1.60) software with regsrv32, but all gave errors and would not register(which I suspect aren't the right ones I need to register)
How can I fix this?
Possible way to solve this:
Identify the Audio Precision ATS-2 dll you want to call. E.g. "C:\path\my.dll"
Now go to the registry and look for "C:\path\my.dll". You'll find a few things around but what you really want is an entry in CLSID...\InprocServer32 folder, or something similar
There will be a ProgID entry as well, something like "AudioPrecison.ATS2"
Now in Python try win32com.client.Dispatch("AudioPrecison.ATS2")
To use the pywin32 module with an activex class you need to generate a wrapper file. To do this locate your makepy.py file in C:\Python27\Lib\site-packages\win32com\client (or your simmilar dir). Then run it, locate the NAME of your activex class then run it. It should generate a wrapper file in the gen_py folder C:\Python27\Lib\site-packages\win32com\gen_py with the CLSID in it. You can then access it like the excel example and the same way you would in other languages.
I had the same issue. I didn't know where to get that, which from what I can gather is the name of the CoClass (which I believe is the wrapper for the dll) created by the makepy program (maybe I'm wrong). After I read the answer by #NotAUser I found it, but when I inspected the file created by the makepy program, and right before the last class, (if more than one are created) I found the following:
from win32com.client import CoClassBaseClass
# This CoClass is known by the name 'ZKFPEngXControl.ZKFPEngX'
class ZKFPEngX(CoClassBaseClass): # A CoClass
So, there, in the same file there was the name I needed to use.

ctypes loading a c shared library that has dependencies

On Linux, I have a c shared library that depends on other libs. LD_LIBRARY_PATH is properly set to allow the linker to load all the libraries. When I do:
libgidcwf = ctypes.cdll.LoadLibrary(libidcwf_path)
I get the following error:
Traceback (most recent call last):
File "libwfm_test.py", line 12, in <module>
libgidcwf = ctypes.cdll.LoadLibrary(libidcwf_path)
File "/usr/lib/python2.5/ctypes/__init__.py", line 431, in LoadLibrary
return self._dlltype(name)
File "/usr/lib/python2.5/ctypes/__init__.py", line 348, in __init__
self._handle = _dlopen(self._name, mode)
OSError: path-to-my-lib/libwav.so: undefined symbol: ODBCGeneralQuery
It seems that LD_LIBRARY_PATH has no effect here.
Is there a way to have these dependency library "loadable"?
Thanks in advance for the help.
It would seem that libwav.so does not declare it's dependency on the library defining ODBCGeneralQuery. Try running ldd path-to-my-lib/libwav.so and see if there's something missing. If this is a shared library that you are building you should add -llibname to the linking command (the one that is something like gcc -shared -o libwav.so a.o b.o c.o) for each library that the library's code uses. Any other libraries referenced by the original shared library in this way should automatically be loaded as well.
I found I had to use RTLD_LAZY due to an undefined symbol that was not linked because it was not being used. Since there is no ctypes.RTLD_LAZY in my ctypes, I had to use:
ctypes.CDLL(libidcwf_path, mode=1)
I found this mode by inspecting /usr/include/bits/dlfcn.h which is probably not standard. Hat tip to this 2006 thread on the ctypes mailing list.
You should use RTLD_GLOBAL. I have a mixed platform system, so my code looks something like this:
import numpy, ctypes
try:
if "Linux" in esmfos:
_ESMF = ctypes.CDLL(libsdir+'/libesmf.so', mode=ctypes.RTLD_GLOBAL)
else:
_ESMF = numpy.ctypeslib.load_library('libesmf', libsdir)
except:
traceback.print_exc(file=sys.stdout)
sys.exit(ESMP_ERROR_SHAREDLIB)
I had the same problem.
Two things were required in order to solve it:
use the RTLD_GLOBAL as other users said
You need to load every library that is used by your library. So if ODBCGeneralQuery is defined in lets say libIDCodbc, you need first run this line:
ctypes.CDLL("libIDCodbc.so", mode = ctypes.RTLD_GLOBAL)
When you compile the shared object, be sure to put all the -lsomething at the end of the string command. For me it solved the problem.
Based on Walter Nissen's answer above, you can modify the code to be:
import os
ctypes.CDLL(libidcwf_path, mode=os.RTLD_LAZY)

Categories