python - 在 Python 中接收 WM_COPYDATA

标签 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 事件中收到的是一个指向包含 COPYDATASTRUCTlParam 的指针。

我开始修补 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 的函数,这是它的 header :
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)

最佳答案

我编写了以下简单的 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 消息:

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 中的文本不是以 null 结尾的。您应该能够通过读取数据很容易地进行检查。使用 cbData 成员。

关于python - 在 Python 中接收 WM_COPYDATA,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5249903/

相关文章:

python - Boto3云信息错误: Template format error: unsupported structure

python - 我的 Python 脚本中的奇怪输出 - [0m 或 [32m

c# - 通过代码,我怎样才能让硬盘驱动器进入休眠状态

c++ - 查找通过 RegisterWindowMessage Windows API 获取的消息的原始名称

Python:如何在终端中显示计时器

python - Django View ,其中列从另一个表引用为外部列

c - 无法在 win32 项目中包含 ntifs.h

c++ - 如何禁用辅助监视器(使用 ChangeDisplaySettingsEx)?

c++ - 编写音频源过滤器用作 Lync 麦克风

c - 每 X 秒执行一次目录中的任意 X 文件