在Python中接收WM_COPYDATA

发布于 2024-10-20 20:16:09 字数 1828 浏览 7 评论 0原文

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

据我所知,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 的函数,这是它的标头:
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)

I am trying to read from Python the WM_COPYDATA message some applications (I'm trying with Spotify) send to WindowsLiveMessenger to update the "What I'm listening to..." phrase.

From what I have been able to find, WM_COPYDATA messages come in a COPYDATASTRUCT with the following structure:

  • dwData in our case 0x547 so that it access the listening now feature
  • cbData with the length of the string received
  • lpData with a pointer to the string itself, may include Unicode characters

The string should have the following format: \0Music\0status\0format\0song\0artist\0album\0 as stated by ListeningNowTracker

What we receive in a WM_COPYDATA event is a pointer for lParam that contains the COPYDATASTRUCT.

I started tinkering with pywin32 functions and I remembered that they do not accept Unicode characters from past experience, then I switched to ctypes. Despite this being an almost new world in Python for me, I tried with POINTER() and all I got was unknown objects for me or access violations.

I think that the code should create a COPYDATASTRUCT:

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

Then make the lParam be a pointer to that structure, get the string pointer from lpData and finally get the string with ctypes.string_at(lpData,cbData).

Any tips?

UPDATE 1

The WM_COPYDATA event is received by a hidden window built with win32gui just for this purpose. The copydata event is connected to a function called OnCopyData and this is its header:
def OnCopyData(self, hwnd, msg, wparam, lparam):
The values the function delivers are correct as compared with the ones from the Spy++ messages log.

UPDATE 2

This should be close to what I want, but gives a NULL pointer error.

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

童话 2024-10-27 20:16:09

我编写了以下简单的 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 成员。

I wrote the following trivial 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()

I then sent the window a WM_COPYDATA message from another app (written in Delphi):

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

The output was:

461584
461584
74
658190
2620592
42
22
greetings!

So it seems that it works trivially, pretty much as you coded it.

The only thing that I can think of is that the text in Spotify's COPYDATASTRUCT is not null-terminated. You should be able to check that quite easily by reading out the data. Make use of the cbData member.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文