【问题标题】:Sending WM_COPYDATA with Python 3使用 Python 3 发送 WM_COPYDATA
【发布时间】:2013-11-10 05:36:48
【问题描述】:

我正在尝试编写一个与我的stickies 副本交互的python 脚本。我在 Python 如何与 WM_COPYDATA 结构交互方面遇到了麻烦,不幸的是,我无法在网上找到很多示例。

使用代码:

import struct
import win32con
import win32gui

import struct, array
int_buffer = array.array("L", [0])
char_buffer = array.array('b', 'do new sticky')
int_buffer_address = int_buffer.buffer_info()[0]
char_buffer_address, char_buffer_size = char_buffer.buffer_info

copy_struct = struct.pack("pLp",
int_buffer_address,
char_buffer_size, char_buffer_address)

hwnd = win32gui.FindWindow("ZhornSoftwareStickiesMain", None)

win32gui.SendMessage(w, WM_COPYDATA, hwnd, copy_struct)

我收到以下错误:

C:\Users\%userprofile%\Desktop>python sender.py
Traceback (most recent call last):
  File "sender.py", line 7, in <module>
    char_buffer = array.array('b', 'do new sticky')
TypeError: an integer is required

我似乎无法弄清楚为什么会出现这样的错误。有什么想法吗?

编辑:一些部分工作的代码

import struct
import win32con
import win32gui
import struct, array


int_buffer = array.array("L", [0])
char_buffer = array.array('b', b"do manage open")
int_buffer_address = int_buffer.buffer_info()[0]

# Add () to buffer_info to call it.
char_buffer_address, char_buffer_size = char_buffer.buffer_info()

# Need P  type for the addresses.
copy_struct = struct.pack("PLP",int_buffer_address,char_buffer_size, char_buffer_address)

hwnd = win32gui.FindWindow(None, "ZhornSoftwareStickiesMain")
win32gui.SendMessage(hwnd, win32con.WM_COPYDATA, None, copy_struct)

【问题讨论】:

    标签: python python-3.3 wm-copydata


    【解决方案1】:

    在 Python 3 中,字符串是 Unicode。尝试使用字节串:

    >>> import array
    >>> array.array('b',b'do new sticky')
    array('b', [100, 111, 32, 110, 101, 119, 32, 115, 116, 105, 99, 107, 121])
    

    还有其他一些变化:

    import struct, array
    int_buffer = array.array("L", [0])
    char_buffer = array.array('b', b'do new sticky')
    int_buffer_address = int_buffer.buffer_info()[0]
    
    # Add () to buffer_info to call it.
    char_buffer_address, char_buffer_size = char_buffer.buffer_info()
    
    # Need P  type for the addresses.
    copy_struct = struct.pack("PLP",int_buffer_address,char_buffer_size, char_buffer_address)
    

    我没有安装软件,但我认为下一行应该是:

    hwnd = win32gui.FindWindow(None, "ZhornSoftwareStickiesMain")
    win32gui.SendMessage(hwnd, win32con.WM_COPYDATA, None, copy_struct)
    

    编辑

    我安装了软件。最初我无法使用任何命令,但 API 文档中没有明确的技巧是每个字符串必须以 api 开头:

    import struct
    import win32con
    import win32gui
    import array
    
    char_buffer = array.array('B', b'api do new sticky hello, world')
    char_buffer_address, char_buffer_size = char_buffer.buffer_info()
    copy_struct = struct.pack("PLP", 12345, char_buffer_size, char_buffer_address)
    hwnd = win32gui.FindWindow(None, "ZhornSoftwareStickiesMain")
    win32gui.SendMessage(hwnd, win32con.WM_COPYDATA, None, copy_struct)
    

    【讨论】:

    • 哇,我的代码到处乱七八糟。我抓住了关于 hwnd 变量关闭的最后一次编辑。这确实给了我一条消息,并且运行没有错误。我唯一的问题是,无论我在 char_buffer 中添加什么命令,它总是会创建一个新的粘性。不喜欢 Unicode 字符串的 Stickies 会不会有问题?
    • 你做得比我好。我继续安装了该应用程序,但无法显示消息。 SendMessage 失败。也许分享什么对你有用?
    • 将我的代码添加到编辑中。无论我做什么,我都会得到一个新的便签。如果提供的话,没有添加任何文字,只是一个新的便签。
    • 我什么也得不到。不知道我的系统有什么不同。我也在玩ctypes 作为@DavidHeffernan 发布的内容。不知道我的安装有什么问题。 Spy++ 显示 Stickies 也没有收到 WM_COPYDATA,但我们正在运行相同的代码。
    • 我正在运行 Python 3.3x64,我假设您拥有最新版本的 Stickies(x32,因为它是唯一的选择)。构建是否需要匹配?
    【解决方案2】:

    使用 ctypes 更容易做到这一点。此代码已使用简单的 Delphi 应用程序进行测试,该应用程序接收并显示通过 WM_COPYDATA 发送的字符串。

    import win32con
    import ctypes
    import ctypes.wintypes
    
    FindWindow = ctypes.windll.user32.FindWindowW
    SendMessage = ctypes.windll.user32.SendMessageW
    
    class COPYDATASTRUCT(ctypes.Structure):
        _fields_ = [
            ('dwData', ctypes.wintypes.LPARAM),
            ('cbData', ctypes.wintypes.DWORD),
            ('lpData', ctypes.c_wchar_p) 
            #formally lpData is c_void_p, but we do it this way for convenience
        ]
    
    hwnd = FindWindow('TheNameOfMyWindowClass', None)
    cds = COPYDATASTRUCT()
    cds.dwData = 0
    str = 'boo'
    cds.cbData = ctypes.sizeof(ctypes.create_unicode_buffer(str))
    cds.lpData = ctypes.c_wchar_p(str)
    
    SendMessage(hwnd, win32con.WM_COPYDATA, 0, ctypes.byref(cds))
    

    这假定接收者需要一个 UTF-16 编码的有效负载。如果收件人期待 ANSI 编码的有效负载,那么您需要使用此变体。

    import win32con
    import ctypes
    import ctypes.wintypes
    
    FindWindow = ctypes.windll.user32.FindWindowW
    SendMessage = ctypes.windll.user32.SendMessageW
    
    class COPYDATASTRUCT(ctypes.Structure):
        _fields_ = [
            ('dwData', ctypes.wintypes.LPARAM),
            ('cbData', ctypes.wintypes.DWORD),
            ('lpData', ctypes.c_char_p)
            #formally lpData is c_void_p, but we do it this way for convenience
    ]
    
    hwnd = FindWindow('TheNameOfMyWindowClass', None)
    cds = COPYDATASTRUCT()
    cds.dwData = 0
    str = b'boo'
    cds.cbData = ctypes.sizeof(ctypes.create_string_buffer(str))
    cds.lpData = ctypes.c_char_p(str)
    
    SendMessage(hwnd, win32con.WM_COPYDATA, 0, ctypes.byref(cds))
    

    现在,查看您发布的 Stickies 链接,您需要使用 ANSI 变体。如果你想接收通知,你需要在 SendMessage 调用中传递一个窗口句柄,而不是上面的 0。

    【讨论】:

    • 如果这样做,SendMessage 会抛出 TypeError: WPARAM must be a Unicode, int, or buffer object (got CArgObject)。是的,wParam。
    • (不能在上面编辑)需要的是类似 lParam = PCOPYDATASTRUCT.from_address(ctypes.addressof(cds)) where PCOPYDATASTRUCT = ctypes.POINTER(COPYDATASTRUCT)
    【解决方案3】:

    下一个变体支持 unicode 输入字符串不使用使用 ctypes lib:

    import array, struct, win32con, win32gui
    
    def copy_data(hwnd, message, dwData = 0):
        buffer = array.array('u', message + '\x00')
        buffer_address, buffer_length = buffer.buffer_info()
    
        copy_struct = struct.pack('PLP', dwData, buffer_length * buffer.itemsize, buffer_address)
    
        return win32gui.SendMessage(hwnd, win32con.WM_COPYDATA, None, copy_struct)
    
    hwnd = win32gui.FindWindow(None, 'ZhornSoftwareStickiesMain')
    copy_data(hwnd, 'Hello ?')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-27
      • 2021-08-21
      • 1970-01-01
      • 1970-01-01
      • 2011-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多