在Python中接收WM_COPYDATA

Chi*_*iva 5 python windows winapi ctypes pywin32

我试图从Python中读取WM_COPYDATA消息,一些应用程序(我正在尝试使用Spotify)发送到WindowsLiveMessenger来更新"我正在听什么......"的短语.

根据我能够找到的WM_COPYDATA消息,消息来自COPYDATASTRUCT以下结构:

  • dwData 在我们的情况下0x547,以便它访问立即监听功能
  • cbData 收到的字符串长度
  • lpData 使用指向字符串本身的指针,可能包含Unicode字符

该字符串应具有以下格式:\0Music\0status\0format\0song\0artist\0album\0ListeningNowTracker所述

我们在一个WM_COPYDATA事件中收到的是一个lParam包含指针的指针COPYDATASTRUCT.

我开始修改pywin32函数,我记得他们不接受过去经验中的Unicode字符,然后我切换到ctypes.尽管对我来说这是一个几乎全新的Python世界,但我尝试过POINTER()并且我得到的所有内容都是针对我的未知对象或访问违规行为.

我认为代码应该创建一个COPYDATASTRUCT:

class CopyDataStruct(Structure):
    _fields_ = [('dwData', c_int),
                ('cbData', c_int),
                ('lpData', c_void_p)]
Run Code Online (Sandbox Code Playgroud)

然后使它lParam成为指向该结构的指针,从中获取字符串指针lpData,最后得到字符串ctypes.string_at(lpData,cbData).

有小费吗?

更新1

WM_COPYDATA事件由win32gui为此目的而构建的隐藏窗口接收.copydata事件连接到一个被调用的函数OnCopyData,这是它的标题:
def OnCopyData(self, hwnd, msg, wparam, lparam):
与Spy ++消息日志中的值相比,函数提供的值是正确的.

更新2

这应该接近我想要的,但给出一个NULL指针错误.

class CopyDataStruct(ctypes.Structure):
    _fields_ = [('dwData', c_int),
                ('cbData', c_int),
                ('lpData', c_wchar_p)]

PCOPYDATASTRUCT = ctypes.POINTER(CopyDataStruct)
pCDS = ctypes.cast(lparam,  PCOPYDATASTRUCT)
print ctypes.wstring_at(pCDS.contents.lpData)
Run Code Online (Sandbox Code Playgroud)

Dav*_*nan 5

我写了以下琐碎的win32gui应用程序:

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()
Run Code Online (Sandbox Code Playgroud)

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

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

输出是:

461584
461584
74
658190
2620592
42
22
greetings!
Run Code Online (Sandbox Code Playgroud)

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

我唯一能想到的是Spotify中的文本COPYDATASTRUCT不是以null结尾的.您应该能够通过读取数据来轻松检查.利用cbData会员.