在Python中接收WM_COPYDATA

时间:2011-03-09 17:42:56

标签: python windows winapi ctypes pywin32

我试图从Python中读取WM_COPYDATA消息,一些应用程序(我正在尝试使用Spotify)发送到WindowsLiveMessenger来更新“我正在听的......”这句话。

根据我的能力,WM_COPYDATA消息来自COPYDATASTRUCT,具有以下结构:

  • dwData在我们的案例中为0x547,以便它可以访问立即监听功能
  • cbData收到字符串的长度
  • lpData带有指向字符串本身的指针,可能包含Unicode字符

字符串应采用以下格式:ListeningNowTracker

所述的\0Music\0status\0format\0song\0artist\0album\0

我们在WM_COPYDATA事件中收到的内容是包含lParam的{​​{1}}指针。

我开始修补pywin32函数,我记得他们不接受过去经验中的Unicode字符,然后我切换到ctypes。尽管对我来说这是一个几乎全新的Python世界,但我尝试使用COPYDATASTRUCT,我得到的只是我的未知对象或访问违规。

我认为代码应该创建POINTER()

COPYDATASTRUCT

然后让class CopyDataStruct(Structure): _fields_ = [('dwData', c_int), ('cbData', c_int), ('lpData', c_void_p)] 成为指向该结构的指针,从lParam获取字符串指针,最后得到lpData的字符串。

任何提示?

更新1

ctypes.string_at(lpData,cbData)事件是由WM_COPYDATA构建的隐藏窗口收到的,仅用于此目的。 copydata事件连接到一个名为win32gui的函数,这是它的标题:
OnCopyData
与Spy ++消息日志中的值相比,函数提供的值是正确的。

更新2

这应该接近我想要的,但是会给出NULL指针错误。

def OnCopyData(self, hwnd, msg, wparam, lparam):

1 个答案:

答案 0 :(得分:5)

我写了以下简单的win32gui app:

import win32con, win32api, win32gui, ctypes, ctypes.wintypes

class COPYDATASTRUCT(ctypes.Structure):
    _fields_ = [
        ('dwData', ctypes.wintypes.LPARAM),
        ('cbData', ctypes.wintypes.DWORD),
        ('lpData', ctypes.c_void_p)
    ]
PCOPYDATASTRUCT = ctypes.POINTER(COPYDATASTRUCT)

class Listener:

    def __init__(self):
        message_map = {
            win32con.WM_COPYDATA: self.OnCopyData
        }
        wc = win32gui.WNDCLASS()
        wc.lpfnWndProc = message_map
        wc.lpszClassName = 'MyWindowClass'
        hinst = wc.hInstance = win32api.GetModuleHandle(None)
        classAtom = win32gui.RegisterClass(wc)
        self.hwnd = win32gui.CreateWindow (
            classAtom,
            "win32gui test",
            0,
            0, 
            0,
            win32con.CW_USEDEFAULT, 
            win32con.CW_USEDEFAULT,
            0, 
            0,
            hinst, 
            None
        )
        print self.hwnd

    def OnCopyData(self, hwnd, msg, wparam, lparam):
        print hwnd
        print msg
        print wparam
        print lparam
        pCDS = ctypes.cast(lparam, PCOPYDATASTRUCT)
        print pCDS.contents.dwData
        print pCDS.contents.cbData
        print ctypes.wstring_at(pCDS.contents.lpData)
        return 1

l = Listener()
win32gui.PumpMessages()

然后我从另一个应用程序(用Delphi编写)发送了一个WM_COPYDATA消息窗口:

Text := 'greetings!';
CopyData.cbData := (Length(Text)+1)*StringElementSize(Text);
CopyData.lpData := PWideChar(Text);
SendMessage(hwnd, WM_COPYDATA, Handle, NativeInt(@CopyData));

输出结果为:

461584
461584
74
658190
2620592
42
22
greetings!

所以看起来它很简单,就像你编码它一样。

我唯一能想到的是Spotify的COPYDATASTRUCT中的文本不是以空值终止的。您应该能够通过读取数据来轻松检查。使用cbData成员。