I have a Python (3) script running on Linux, referred to as the main script, which has to call a routine from a proprietary DLL. So far, I have solved this with Wine using the following construct:
# Main script running on Linux import subprocess # [...] subprocess.Popen('echo "python dll_call.py %s" | wine cmd &' % options, shell = True) # [...]
The script dll_call.py is executed by a Windows Python (3) interpreter installed under Wine. It dumps the return values into a file which is then picked up by the waiting main script. It’s not exactly reliable and agonizingly slow if I have to do this a few times in a row.
I’d like to start the script dll_call.py once, offering some type of a simple server, which should expose the required routine in some sort of way. At the end of the day, I’d like to have a main script looking somewhat like this:
# Main script running on Linux import subprocess # [...] subprocess.Popen('echo "python dll_call_server.py" | wine cmd &', shell = True) # [...] return_values = call_into_dll(options)
How can this be implemented best (if speed is required and security not a concern)?
Thank you @jsbueno and @AustinHastings for your answers and suggestions.
For those having similar problems: Inspired by the mentioned answers, I wrote a small Python module for calling into Windows DLLs from Python on Linux. It is based on IPC between a regular Linux/Unix Python process and a Wine-based Python process. Because I have needed it in too many different use-cases / scenarios, I designed it as a “generic” ctypes
module drop-in replacement, which does most of the required plumbing automatically in the background.
Example: Assume you’re in Python on Linux, you have Wine installed, and you want to call into msvcrt.dll
(the Microsoft C runtime library). You can do the following:
from zugbruecke import ctypes dll_pow = ctypes.cdll.msvcrt.pow dll_pow.argtypes = (ctypes.c_double, ctypes.c_double) dll_pow.restype = ctypes.c_double print('You should expect "1024.0" to show up here: "%.1f".' % dll_pow(2.0, 10.0))
Source code (LGPL), PyPI package & documentation. It’s still a bit rough around the edges (i.e. alpha and insecure), but it does handle most types of parameters (including pointers).
Advertisement
Answer
You can use the XMLRPC client and servers built-in Python’s stdlib to do what you want. Just make your Wine-Python expose the desired functions as XMLRPC methods, and make an inter-process call from any other Python program to that.
It also works for calling functions running in Jython or IronPython from CPython, and also across Python2 and Python3 – the examples included in the module documentation themselves should be enough.Just check the docs: https://docs.python.org/2/library/xmlrpclib.html
If you need the calls to be asynchronous on the client side, or the server site to respond to more than one process, you can find other frameworks over which to build the calls – Celery should also work across several different Pythons while preserving call compatibility, and it is certainly enough performance-wise.