【问题标题】:How can Python know the signatures of a dll functionPython如何知道dll函数的签名
【发布时间】:2021-01-08 23:02:21
【问题描述】:

我正在开发一种编程语言,我希望它能够访问 dll(或共享库)。我知道 python 有一个 CDLL 函数可以做到这一点。在C语言中,我知道要调用dll函数,必须使用LoadLibrary加载库,并使用GetProcAddress获取过程,最后将其转换为函数。


typedef void (__stdcall *testf)();

HINSTANCE lib = LoadLibrary("test.dll");
testf proc = (testf) GetProcAddress(lib, "testf");
proc();

但是在python中,第三步没有做完。

from ctypes import *

lib = CDLL("test.dll")
lib.testf() #not casting the function anywhere

这是如何完成的,如何在 C 中实现相同的目标?

【问题讨论】:

  • Python 似乎在后台执行该步骤,我不明白您如何绕过需要找到加载到内存中的函数的地址。
  • 它不知道,它使用了duck-typing。尝试传递错误的参数,看看会发生什么。您的问题的所有答案都可以通过阅读documentation获得。
  • python 是自己执行这个任务,还是有一些底层的 C 代码。我的印象是 C 在后台运行,如果是,C 代码不应该需要强制转换吗?
  • 不清楚具体的实现,希望有人能给你一个彻底的答案。但是,强制转换实际上只是装饰性的,它给指针一个类型,所以foo() 在语法上是正确的。没有什么可以阻止您转换为错误的签名,因此ctypes 的 C impl 可以转换为您调用函数的签名,并捕获错误调用函数可能产生的任何异常。请参阅链接中的“外来函数”部分。或者它可以利用int(*)() 是一个接受任何参数的函数这一事实并做同样的事情。
  • 后者更有可能,它也符合默认情况下库期望函数返回int的声明。由于 C 没有模板,因此演员表必须硬连线。 void*(*)() 是我猜的最通用的。

标签: python c windows dll


【解决方案1】:

ctypes 真的什么都不知道。 ctypes 假定 每个符号 都是一个 函数(即使它是一个变量),它使用 默认参数提升,并且 返回int 即如果它在任何东西上都能正常工作,那真是一个奇迹。

【讨论】:

    【解决方案2】:

    ctypes 在猜测。 Python 是动态的 - lib.testf() 导致 python 调用 lib 对象的 __getattriute__ / __getattr__ 方法。该方法由ctypes 实现,使用其python 名称获取函数的入口点。然后它为您的 python 代码提供一个代理来编组调用的参数。该代理具有参数实际的默认规则。当您调用该函数时,此代理会获取您碰巧传入的任何参数,并再次猜测应该如何将这些参数转换为 C。如果默认值不正确,则可以使用模式配置代理以在 python 和C. 这在docs 中有介绍。

    注意:ctypes 可能会很快出错。

    ctypes 既有 python 级别的代码,也有 C 级别的代码。您可以在https://github.com/python/cpython 浏览 cpython 源代码。寻找Lib/ctypesModules/_ctypes

    【讨论】:

    • cffi 在这方面要简单得多,因为它解析标头中的 C 声明。
    • @ErykSun - 这是一个很好的观点。由于 OP 正在开发一种编程语言,SWIG 可能是一个不错的选择。
    • 我假设在 ABI 模式下使用 CFFI。但是如果你正在构建一个扩展模块来包装一个库,那么有几个流行的框架,包括 API 模式的 CFFI 和Cython
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-02
    • 1970-01-01
    • 1970-01-01
    • 2020-08-25
    • 1970-01-01
    • 1970-01-01
    • 2010-09-28
    相关资源
    最近更新 更多