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:
我有一个在Linux上运行的Python(3)脚本,称为主脚本,它必须从私有的DLL调用一个例程。到目前为止,我已经用Wine解决了这个问题:
# 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.
脚本dll_call。py由在Wine下安装的Windows Python(3)解释器执行。它将返回值转储到一个文件中,然后由等待的主脚本拾取。如果我必须连续做几次的话,这并不完全可靠,速度也非常缓慢。
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:
我想启动脚本dll_call。py一次提供了某种类型的简单服务器,它应该以某种方式公开所需的例程。在一天结束的时候,我想要一个主要的脚本看起来有点像这样:
# 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.
谢谢@jsbueno和@AustinHastings的回答和建议。
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.
对于有类似问题的人:受上述答案的启发,我编写了一个小Python模块,用于在Linux上调用Python的Windows dll。它基于IPC,介于常规的Linux/Unix Python进程和基于wintpython进程之间。因为我在太多不同的用例/场景中都需要它,所以我将它设计为“通用”ctype模块的内插式替换,它在后台自动完成大部分所需的管道工作。
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:
示例:假设您在Linux上的Python中,您已经安装了Wine,并且希望调用msvcrt。dll(微软C运行时库)。你可以做以下事情:
import zugbruecke as 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).
源代码(LGPL), PyPI包和文档。它仍然有点粗糙(比如alpha和不安全),但是它确实处理了大多数类型的参数(包括指针)。
2 个解决方案
#1
2
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.
您可以使用XMLRPC客户端和内置Python的stdlib的服务器来执行所需的操作。只需要让您的Python Python公开所需的函数作为XMLRPC方法,并从任何其他Python程序中进行一个进程间调用。
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
它还适用于从CPython调用在Jython或IronPython中运行的函数,也适用于跨Python2和Python3——模块文档中包含的示例应该足够了。只需检查文档: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.
如果你需要在客户端调用是异步的,或服务器站点响应多个进程,你可以找到其他框架的构建调用——芹菜也应该工作在几个不同的蟒蛇,同时保留叫兼容性,它肯定是足够的属性。
#2
1
You want to communicate between two processes, where one of them is obscured by being under the control of the WINE engine.
您希望在两个进程之间进行通信,其中一个进程被控制在葡萄酒引擎的控制之下。
My first thought here is to use a very decoupled form of IPC. There are just too many things that can go wrong with tight coupling and something like WINE involved.
我的第一个想法是使用一种非常解耦的IPC。有太多的东西会因为紧密耦合而出错,比如葡萄酒。
And finally, how can this be made easy for someone new to this kind of stuff?
最后,对于一个刚接触这类东西的人来说,如何使这变得容易呢?
The obvious answer is to set up a web server. There are plenty of tutorials using plenty of packages in Python to respond to HTTP requests, and to generate HTTP requests.
显而易见的答案是建立一个web服务器。有很多教程使用Python中的大量包响应HTTP请求并生成HTTP请求。
So, set up a little HTTP responder in your WINE process, listen to some non-standard port (not 8080 or 80), and translate requests into calls to your DLL. If you're clever, you'll interpret web requests (http://localhost:108000/functionname?arg1=foo&arg2=bar) into possibly different DLL calls.
因此,在WINE进程中设置一个小HTTP应答器,侦听一些非标准端口(不是8080或80),并将请求转换为对DLL的调用。如果您够聪明,可以将web请求(http://localhost:108000/functionname?arg1=foo&arg2=bar)解释为可能不同的DLL调用。
On the other side, create a HTTP client in your non-WINE code and make requests to your server.
另一方面,在非wine代码中创建HTTP客户机,并向服务器发出请求。
#1
2
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.
您可以使用XMLRPC客户端和内置Python的stdlib的服务器来执行所需的操作。只需要让您的Python Python公开所需的函数作为XMLRPC方法,并从任何其他Python程序中进行一个进程间调用。
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
它还适用于从CPython调用在Jython或IronPython中运行的函数,也适用于跨Python2和Python3——模块文档中包含的示例应该足够了。只需检查文档: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.
如果你需要在客户端调用是异步的,或服务器站点响应多个进程,你可以找到其他框架的构建调用——芹菜也应该工作在几个不同的蟒蛇,同时保留叫兼容性,它肯定是足够的属性。
#2
1
You want to communicate between two processes, where one of them is obscured by being under the control of the WINE engine.
您希望在两个进程之间进行通信,其中一个进程被控制在葡萄酒引擎的控制之下。
My first thought here is to use a very decoupled form of IPC. There are just too many things that can go wrong with tight coupling and something like WINE involved.
我的第一个想法是使用一种非常解耦的IPC。有太多的东西会因为紧密耦合而出错,比如葡萄酒。
And finally, how can this be made easy for someone new to this kind of stuff?
最后,对于一个刚接触这类东西的人来说,如何使这变得容易呢?
The obvious answer is to set up a web server. There are plenty of tutorials using plenty of packages in Python to respond to HTTP requests, and to generate HTTP requests.
显而易见的答案是建立一个web服务器。有很多教程使用Python中的大量包响应HTTP请求并生成HTTP请求。
So, set up a little HTTP responder in your WINE process, listen to some non-standard port (not 8080 or 80), and translate requests into calls to your DLL. If you're clever, you'll interpret web requests (http://localhost:108000/functionname?arg1=foo&arg2=bar) into possibly different DLL calls.
因此,在WINE进程中设置一个小HTTP应答器,侦听一些非标准端口(不是8080或80),并将请求转换为对DLL的调用。如果您够聪明,可以将web请求(http://localhost:108000/functionname?arg1=foo&arg2=bar)解释为可能不同的DLL调用。
On the other side, create a HTTP client in your non-WINE code and make requests to your server.
另一方面,在非wine代码中创建HTTP客户机,并向服务器发出请求。