我试图弄清楚如何进行以及一般是否可行或不可行。
我与外部DLL一起控制我的机械延迟线。
此API具有内部过程,用于在单独的窗口中输出消息。我强烈希望抓住此消息流并出现在我的Python(Pyqt5(书面应用程序中。
API描述中有一个函数:
int LS_SetProcessMessagesProc(void *pProc);
函数返回0或1,如果没有错误或分别存在。
根据DLL描述它可以替换LSTEP API的内部消息触摸过程。
在等待主线消息中的LSTEP确认时,LSTEP API处理。如果要切换消息键入或用ONW代码替换,则可以使用SetProcessMessagesProc来使用回调。
pproc必须是没有参数的stdcall程序的指针:
void MyProcessMessages() {...}
示例:ls.setProcessMessagesProc(& myProcessMessages(;
作为例如,如果我们采用Python Stdout,我如何将消息发送给它?
我要去为了说明:
上的所有内容- [MSDN]:Enumwindows函数 - 列举屏幕上的所有窗口,并且每个窗口都称为 callback 函数 - 检查下一个子弹
- [MSDN]:EnumwindowsProc回调函数 - 用于处理每个枚举窗口
是(一个更复杂的示例(您需要的内容:在外部 .dll 中定义的功能,需要调用另一个自定义函数(您在 python中编写了您的 python (,通过[python]:ctypes模块(on win (。
代码:
import ctypes
from ctypes import wintypes
try:
from win32gui import GetWindowText
pywin32_present = True
except ImportError:
pywin32_present = False
def enum_windows_proc(hwnd, l_param):
print("HWND: {}n".format(hwnd))
if pywin32_present:
txt = GetWindowText(hwnd)
if txt and "MSCTFIME UI" not in txt and "Default IME" not in txt:
print(" Window text: {}n".format(txt))
return 1
def main():
user32_dll = ctypes.windll.LoadLibrary("user32.dll")
enum_windows = user32_dll.EnumWindows
WND_ENUM_PROC_TYPE = ctypes.WINFUNCTYPE(wintypes.BOOL, wintypes.HWND, wintypes.LPARAM)
enum_windows.argtypes = (WND_ENUM_PROC_TYPE, wintypes.LPARAM)
enum_windows.restype = wintypes.BOOL
enum_windows(WND_ENUM_PROC_TYPE(enum_windows_proc), wintypes.LPARAM(0))
if __name__ == "__main__":
main()
注释:
-
import
S:- wintypes 是A ctypes 子模块,它定义了一堆 ms 特定数据(常数,结构,枚举,...(
- [python]:Pywin32是 python c c win 函数,这基本上是一种更高级(和pythonic(的方法 ctypes 做。默认情况下,它不带有 python ,必须手动安装;在我们的示例中,这是可选的
-
def enum_windows_proc(hwnd, l_param):
:- 这是
BOOL CALLBACK EnumWindowsProc(_In_ HWND hwnd, _In_ LPARAM lParam);
的 python - 为每个窗口打印 hwnd (窗口句柄((请注意,将有很多这样的窗口,因为大多数窗口对用户都是"不可见的"(
- 如果安装了 pywin32 模块,则将用于提取每个窗口的标题(标题(。当然,这也可以使用 ctypes 来完成,但要复杂一些
- 标题过滤是避免打印无用的文本(对于大多数窗口(。如果您需要更多详细信息,请检查:[so]:使用过程名称 获取另一个程序的窗口标题
- 这是
-
main
功能:- 首先,需要加载包含该函数的 .dll (在我们的情况下 user32.dll (。这是使用[MSDN]:LoadLibrary函数( ux :[man]:dlopen(完成的。另外,返回对象(
user32_dll
(的内部结构(下一行看起来很简单(是初始化的 - 使用[msdn]的功能(或更好:一个指针(正在检索(
enum_windows
(:getProcAddress函数( ux :[man]:dlsym( - 接下来的3行代码用于让 python 知道有关加载功能指针的详细信息(返回类型和参数类型(。请注意,(在某些情况下(有一种更简单的方法(编码(来完成所有操作,但是出于学习目的,可以浏览整个过程
- 首先,需要加载包含该函数的 .dll (在我们的情况下 user32.dll (。这是使用[MSDN]:LoadLibrary函数( ux :[man]:dlopen(完成的。另外,返回对象(
- 最后,以我们的自定义函数为参数 调用外部函数
由于会有很多输出(并且主要是内存地址(,所以我不会在这里粘贴它。
根据您在问题中粘贴的功能标题来解决您的问题,我们可以采用相同的方法(请注意,代码将不是工作复制/粘贴 ootb :
import ctypes
from ctypes import wintypes
def my_process_messages():
# Your code here (delete the next (`pass`) line)
pass
dll_name = "your dll path (full or relative)"
dll_object = ctypes.windll.LoadLibrary(dll_name)
ls_set_process_messages_proc = dll_object.LS_SetProcessMessagesProc
PROCESS_MESSAGES_TYPE = ctypes.WINFUNCTYPE(None)
ls_set_process_messages_proc.argtypes = (PROCESS_MESSAGES_TYPE,)
ls_set_process_messages_proc.restype = ctypes.c_int
print("ls_set_process_messages_proc returned: {}n".format(ls_set_process_messages_proc(PROCESS_MESSAGES_TYPE(my_process_messages))))
注意:示例基于以下事实:外部 .dll :
是 win 样式(使用 stdcall 调用justnuction(。如果那不是真的(它使用 cdecl (,您需要更改(为了严格的缘故,我要说两件事(:
-
ctypes.windll
toctypes.cdll
-
ctypes.WINFUNCTYPE
toctypes.CFUNCTYPE
-
导出 c 样式函数(不是 c 哪个mangles函数名称(,我几乎可以肯定。但是,如果不是这种情况,那就对不起,这里无事可做。有关此主题的更多详细信息,请检查:[so]:Excel VBA,找不到DLL文件的DLL入口点。
阅读有关CTYPES教程的信息
加载动力 - 链路上线
从已加载的DLL访问功能
调用功能
Linux示例,使用标准C库的QSORT函数:
-
加载
libc.so.6
DLL。from ctypes import * libc = CDLL("libc.so.6")
-
获取函数指针到
qsort
。qsort = libc.qsort qsort.restype = None
-
创建回调函数的类型
并实现Python
回调功能。CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int)) def py_cmp_func(a, b): return a[0] - b[0] cmp_func = CMPFUNC(py_cmp_func)
-
定义具有值的C型整数数组
并使用qsort
使用cmp_func
对数组进行排序。IntArray5 = c_int * 5 ia = IntArray5(5, 1, 7, 33, 99) qsort(ia, len(ia), sizeof(c_int), cmp_func) for i in ia: print(i)
输出
1 5 7 33 99