python使用ctypes调用C编译dll函数方法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python使用ctypes调用C编译dll函数方法相关的知识,希望对你有一定的参考价值。

参考技术A 在函数声明加入前缀,如
__declspec(dllexport) int Fun(int a, int b)
否则在加载该dll时会提示找不到该符号

在windows下可以通过vs自带的dumpbin工具查看可被调用符号
dumpbin /exports test.dll

C函数在调用过程中关于参数传递和压栈由多种规定,作为dll提供给其他程序调用时,必须明确并统一为同一种调用规定,否则会导致栈破坏,编译器负责具体实现调用规定,主要有以下几种调用规定

python下调用C库有多种方式,ctypes是其中一种比较方便的,调用时首先需要加载dll文件,根据C dll的调用规定不同需要使用不同接口,使用ctypes需要 import ctypes 库

对于简单的C函数,例如 int add(int a, int b) , 此时就可以直接调用了,如

对于较复杂的C函数的参数情况,ctypes调用时对入参和出餐做一定处理,这里分情况讨论

以上包含了几种主要的参数传递情况,ctypes也提供了一个较为完整的python类型和C类型的对照,如下:

使用 Python ctypes 在 AutoIt DLL 中调用函数

【中文标题】使用 Python ctypes 在 AutoIt DLL 中调用函数【英文标题】:Call functions in AutoIt DLL using Python ctypes 【发布时间】:2013-11-25 11:20:20 【问题描述】:

我想从一个 AutoIt dll 调用函数,我使用 Python 在 C:\Program Files (x86)\AutoIt3\AutoItX\AutoItX3.dll 中找到了该函数。我知道我可以使用win32com.client.Dispatch("AutoItX3.Control"),但我无法安装应用程序或在系统中注册任何内容。

到目前为止,这是我所在的位置:

from ctypes import *
path = r"C:\Program Files (x86)\AutoIt3\AutoItX\AutoItX3.dll"
autoit = windll.LoadLibrary(path)

以下是有效的方法:

autoit.AU3_WinMinimizeAll() # windows were successfully minimized.
autoit.AU3_Sleep(1000) # sleeps 1 sec.

这是我的问题,当我调用像这样的其他方法时,python 崩溃了。我从 Windows 中得到 python.exe 已停止工作...

autoit.AU3_WinGetHandle('Untitled - Notepad', '')

还有一些其他方法不会使 python 崩溃,但只是不起作用。这个不关闭窗口返回0:

autoit.AU3_WinClose('Untitled - Notepad', '')

这个另一个返回 1 但窗口仍然最小化:

autoit.AU3_WinActivate('Untitled - Notepad', '')

我已经使用Dispatch("AutoItX3.Control") 测试了这些示例,并且一切正常。

似乎应该返回字符串以外的东西的方法正在崩溃 python。但是,像WinClose 这样的其他人甚至都没有工作......

提前感谢您的帮助!

编辑:

这些方法现在在使用 unicode 字符串时有效:

autoit.AU3_WinClose(u'Untitled - Notepad', u'')
autoit.AU3_WinActivate(u'Untitled - Notepad', u'')

我找到了AU3_WinGetHandle的原型:

AU3_API void WINAPI AU3_WinGetHandle(const char szTitle, /[in,defaultvalue("")]*/const char *szText, char *szRetText, int nBufSize);

现在我可以使用以下代码检索返回值!

from ctypes.wintypes import LPCWSTR
s = LPCWSTR(u'')
print AU3_WinGetHandle(u'Untitled - Notepad', u'', s, 100) # prints 1
print s.value # prints '000705E0'!

感谢帮助过我的人!

【问题讨论】:

你知道这些函数的正确原型吗?如果是这样,您应该为每个函数设置argtypesrestype,而不仅仅是调用它。这样,如果 Python 可以将你的参数转换为正确的类型,它就会,否则它会给你一个错误。你这样做的方式,Python 必须猜测它应该转换成哪种类型,如果它猜错了,你就会崩溃。 【参考方案1】:

如果您有尝试调用的函数的原型,那么我们可以帮助您调试调用而无需猜测。或者,更重要的是,我们不会帮助您调试调用,因为您可以让 ctypes 为您完成。

请参阅文档中的 Specifying the required argument types。

例如,假设函数如下所示(只是随机猜测!):

void AU3_WinClose(LPCWSTR name, LPCWSTR someotherthing);

你可以这样做:

autoit.AU3_WinClose.argtypes = (LPCWSTR, LPCWSTR)
autoit.AU3_WinClose.restype = None

如果您这样做,ctypes 将尝试将您的参数转换为指定类型(LPWSTR,它是指向用于 Windows UTF-16 字符串的宽字符的指针),如果不能,则引发异常,并且不会期望任何返回值。

如果您这样做,ctypes 将尝试猜测正确的东西来将您的参数转换为,可能会猜测错误,并将尝试将不存在的返回值解释为 int .因此,它通常会崩溃,直到您设法准确猜出要向它抛出的类型以使其猜测要传递给函数的正确类型。

【讨论】:

谢谢你,我越来越近了!我编辑了我的问题,我找到了原型,但我不知道如何从指针中获取返回值...【参考方案2】:

它是否适用于 unicode 字符串?

autoit.AU3_WinClose(u'Untitled - Notepad', u'')

autoit.AU3_WinActivate(u'Untitled - Notepad', u'')

实际上您可能必须显式创建 unicode 缓冲区,例如:

autoit.AU3_WinClose(create_unicode_buffer('Untitled - Notepad'), create_unicode_buffer(''))

通过一些谷歌搜索,看起来AU3_WinGetHandle 需要 4 个参数,而不是 2 个。所以你需要解决这个问题。

【讨论】:

或者,更好的是,只需设置autoit.AU3_WinClose.argtypes=(LPCWSTR, LPCWSTR) 并让 ctypes 自动创建缓冲区并进行任何其他转换。尝试手动完成这些工作需要做很多额外的工作,而且很容易出错,如果幸运的话,通常会导致崩溃。 对这个问题的猜测不错,但是通过快速搜索 AU3_WinClose 原型,我得到了this thread,它似乎是//AU3_API long WINAPI AU3_WinClose(const char *szTitle, /*[in,defaultvalue("")]*/const char *szText);——换句话说,是 8 位字符串,而不是 Unicode,他们是 const 所以我们不需要创建一个可变缓冲区。也许是 long 返回值? 我会的!只要我有足够的声望! :-)

以上是关于python使用ctypes调用C编译dll函数方法的主要内容,如果未能解决你的问题,请参考以下文章

python--ctypes模块:调用C函数

Python Cookbook(第3版)中文版:15.1 使用ctypes访问C代码

在 Python 中从 dll 调用函数

怎样用python调用dll

python中的ctypes,在DLL中调用函数的问题

Python 外部函数调用库ctypes简介