如何获取DLL消息调度过程并重定向到python标准输出?

时间:2017-05-29 17:04:47

标签: python

我正在试图弄清楚如何进行以及一般是否可行。

我使用外部DLL来控制机械延迟线。

此API具有单独窗口中的消息输出的内部过程。我非常希望能够捕获这个消息流并出现在我的python(PyQT5)编写的应用程序中。

在API描述中有一个函数:

int LS_SetProcessMessagesProc(void *pProc);

如果没有错误或者它存在,函数返回0或1。

根据dll描述 它可以替换LStep API的内部消息调度过程。

LStep API在等待确认主线程消息中的LStep时进行处理。如果要切换Message-Dispatching或使用onw代码替换,可以使用SetProcessMessagesProc来使用回调过程。

pProc必须是没有参数的stdcall过程的指针:

void MyProcessMessages() {...}

实施例: LS.SetProcessMessagesProc(安培; MyProcessMessages);

例如,如果我们使用python stdout,我该如何将消息发送给它?

2 个答案:

答案 0 :(得分:1)

  

了解ctypes tutorial
      加载动态链接程序库
      从加载的dll访问功能
      调用函数

Linux示例,它使用标准C库的qsort函数:

  1. 加载libc.so.6 dll。

    from ctypes import *
    libc = CDLL("libc.so.6")
    
  2. 获取指向qsort的函数指针。

    qsort = libc.qsort
    qsort.restype = None
    
  3. 创建回调函数的类型
    并实现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)
    
  4. 使用值
    定义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)
    
  5.   

    输出

    1 5 7 33 99
    

答案 1 :(得分:1)

我将在以下内容中说明一切:

这是你需要的(一个稍微复杂的例子):在外部 .dll 中定义的函数,它需要调用另一个自定义函数(由你在 Python中编写)),通过[Python]: ctypes module(在 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 是一个 ctypes 子模块,它定义了一堆 Ms 特定数据(常量,结构,枚举,...)
    • [Python]: pywin32是一个基于 C Win 函数的 Python 包装器,它基本上是一种更先进(和pythonic)的方法 ctypes 可以。默认情况下它没有 Python ,它必须手动安装;在我们的例子中,它是可选的
  • def enum_windows_proc(hwnd, l_param):
    • 这是BOOL CALLBACK EnumWindowsProc(_In_ HWND hwnd, _In_ LPARAM lParam);
    • Python 形式
    • 为每个窗口打印 hwnd (窗口句柄)(请注意,会有很多这样的窗口,因为大多数窗口对用户来说是“不可见的”)
    • 如果安装了 pywin32 模块,它将用于提取每个窗口的标题(标题)。当然,这也可以用 ctypes 完成,但它有点复杂
    • 标题过滤是为了避免打印无用的文本(对于大多数窗口)。如果您需要更多详细信息,请查看:[SO]: Get the title of a window of another program using the process name
  • main功能:
    • 首先,需要加载包含该函数的 .dll (在我们的示例中为 user32.dll )。这是使用[MSDN]: LoadLibrary function Ux [man]: dlopen)完成的。此外,初始化返回对象(user32_dll)的内部结构(下一行看起来如此简单)
    • 使用[MSDN]: GetProcAddress function Ux [man]: dlsym
    • 检索函数(或更好:指向它的指针)(enum_windows
    • 接下来的3行代码用于让 Python 知道有关加载的函数指针(返回类型和参数类型)的详细信息。请注意(在某些情况下)有一种更简单的方法(代码)来完成所有这些,但出于学习目的,可以通过整个事情
    • 最后,使用我们的自定义函数作为参数调用外部函数

由于会有很多输出(主要是内存地址),我不会在这里粘贴。

根据您在问题中粘贴的功能标题来解决您的问题,我们可以采用相同的方法(请注意,代码将工作复制/粘贴 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 调用约定)。如果那不是真的(它使用 cdecl ),你需要改变(为了严格起见,我会说两件事):

    • ctypes.windllctypes.cdll
    • ctypes.WINFUNCTYPEctypes.CFUNCTYPE
  • 导出 C 样式函数( C ++ ,这会破坏函数名称),我几乎100%肯定。但是,如果情况不是这样的话,对不起,这里无事可做。有关此主题的更多详细信息,请查看:[SO]: Excel VBA, Can't Find DLL Entry Point from a DLL file