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

6
我希望能够使用Python从位于 C:\Program Files (x86)\AutoIt3\AutoItX\AutoItX3.dll 中的 AutoIt 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 必须猜测应该转换成哪种类型,如果猜错了,程序就会崩溃。 - abarnert
2个回答

4

它能处理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 自动创建缓冲区并进行任何其他转换。手动尝试这些操作会增加很多额外的工作量,并且很容易出错,通常会导致崩溃(如果你很幸运的话)。 - abarnert
猜测不错,但是我快速搜索了AU3_WinClose原型,得到了这个线程,在那里它似乎是//AU3_API long WINAPI AU3_WinClose(const char *szTitle, /*[in,defaultvalue("")]*/const char *szText);——换句话说,是8位字符串,而不是Unicode,并且它们是常量,所以我们不需要创建可变缓冲区。也许是long返回值? - abarnert
我会的!只要我有足够的声望! :-) - Josh

4
如果您有尝试调用的函数原型,那么我们可以帮助您调试调用而不是猜测。或者更重要的是,我们不必帮助您调试调用,因为您可以让ctypes来完成这项工作。
请参见文档中的指定所需的参数类型
例如,假设该函数看起来像这样(只是随机猜测!):
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。因此,通常会崩溃,直到你成功猜出要传递给函数的确切类型为止。

谢谢,我离成功更近了!我编辑了我的问题,我找到了原型,但我不知道如何从指针中获取返回值... - Josh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接