2011-03-09 126 views
4

我試圖從Python中讀取WM_COPYDATA消息一些應用程序(我試圖用Spotify)發送給WindowsLiveMessenger以更新「我在聽什麼......」短語。在Python中接收WM_COPYDATA

從我已經能夠找到,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)] 

然後使lParam是一個指針結構,從lpData得到字符串指針,最後用ctypes.string_at(lpData,cbData)得到的字符串。

任何提示?

更新1

通過與win32gui內置只是用於此目的的隱藏窗口收到的WM_COPYDATA事件。 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) 

回答

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() 

我然後被髮送窗口中的WM_COPYDATA消息從另一個應用程序(在Delphi編寫):

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成員。

+0

@Chiva有沒有反饋意見?這對你有用嗎? – 2011-03-10 16:37:53

+0

它的工作原理!但它與我寫的代碼幾乎完全一樣...也許其他代碼會打破它。雖然它對我來說並不重要,但在接收[帶有希臘字符的歌曲標題]時(http://open.spotify.com/track/4qamMrvmDXHSLBbdPpGu7P),它給了我一個'UnicodeEncodeError',使utf-8編碼行不會修理它。對不起,我一直忙着整天。 – Chiva 2011-03-10 19:53:02

+0

@Chiva嘗試查看打破的字符串的二進制表示,我們應該能夠計算出它是如何編碼的。 – 2011-03-10 19:54:16