在Python中接收WM_COPYDATA

在Python中接收WM_COPYDATA,python,windows,winapi,ctypes,pywin32,Python,Windows,Winapi,Ctypes,Pywin32,我正在尝试从Python读取一些应用程序(我正在使用Spotify)发送到WindowsLiveMessenger的WM_COPYDATA消息,以更新“我正在听的…”短语 据我所知,WM_COPYDATA消息以COPYDATASTRUCT的形式出现,其结构如下: dwData在本例中为0x547,以便它访问立即侦听功能 cbData带有接收到的字符串长度 lpData带有指向字符串本身的指针,可能包括Unicode字符 字符串应具有以下格式:\0音乐\0状态\0格式\0歌曲\0艺术家\0相册

我正在尝试从Python读取一些应用程序(我正在使用Spotify)发送到WindowsLiveMessenger的
WM_COPYDATA
消息,以更新“我正在听的…”短语

据我所知,
WM_COPYDATA
消息以
COPYDATASTRUCT
的形式出现,其结构如下:

  • dwData
    在本例中为0x547,以便它访问立即侦听功能
  • cbData
    带有接收到的字符串长度
  • lpData
    带有指向字符串本身的指针,可能包括Unicode字符
字符串应具有以下格式:
\0音乐\0状态\0格式\0歌曲\0艺术家\0相册\0
,如

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

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

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

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

有什么建议吗

更新1

WM_COPYDATA
事件由一个使用
win32gui
构建的隐藏窗口接收。copydata事件连接到一个名为
OnCopyData
的函数,这是它的头:
def OnCopyData(self、hwnd、msg、wparam、lparam):

与Spy++消息日志中的值相比,该函数传递的值是正确的

更新2

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

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)

我编写了以下简单的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()
然后,我从另一个应用程序(用Delphi编写)向窗口发送了一条
WM_COPYDATA
消息:

结果是:

461584
461584
74
658190
2620592
42
22
greetings!
因此,它似乎工作得很简单,就像您编写代码一样


我唯一能想到的是Spotify的
COPYDATASTRUCT
中的文本不是以null结尾的。通过读取数据,您应该能够非常轻松地检查这一点。利用
cbData
成员。

@Chiva有任何反馈吗?这对你有用吗?有用!但是它和我写的代码几乎完全一样。。。也许其他代码会破坏它。虽然这对我来说并不重要,但它在接收时会给我一个
UnicodeEncodeError
,放置utf-8编码行并不能修复它。很抱歉耽搁了,但我一整天都很忙。@Chiva试着看看断开的字符串的二进制表示,我们应该能够知道它是如何编码的。我是如何得到二进制表示的?你的更新真的是一个新问题。我已经回答了你的问题。不断地改变问题是不公平的!你现在应该接受这个答案(我相信我回答了你原来的问题),然后再问一个新问题。
461584
461584
74
658190
2620592
42
22
greetings!