Recibiendo WM_COPYDATA en Python

Estoy tratando de leer desde Python el mensaje WM_COPYDATA que algunas aplicaciones (estoy intentando con Spotify) envían a WindowsLiveMessenger para actualizar la frase “Lo que estoy escuchando …”.

Por lo que he podido encontrar, los mensajes WM_COPYDATA vienen en un COPYDATASTRUCT con la siguiente estructura:

  • dwData en nuestro caso 0x547 para que acceda a la función de escuchar ahora
  • cbData con la longitud de la cadena recibida
  • lpData con un puntero a la cadena, puede incluir caracteres Unicode

La cadena debe tener el siguiente formato: \0Music\0status\0format\0song\0artist\0album\0 como lo indica ListeningNowTracker

Lo que recibimos en un evento WM_COPYDATA es un puntero para lParam que contiene el COPYDATASTRUCT .

Comencé a juguetear con las funciones de pywin32 y recordé que no aceptan caracteres Unicode de experiencias pasadas, luego cambié a ctypes. A pesar de que este era un mundo casi nuevo en Python para mí, lo intenté con POINTER() y todo lo que obtuve fueron objetos desconocidos para mí o violaciones de acceso.

Creo que el código debería crear un COPYDATASTRUCT :

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

Luego, haga que lParam sea ​​un puntero a esa estructura, obtenga el puntero de cadena desde lpData y finalmente obtenga la cadena con ctypes.string_at(lpData,cbData) .

¿Algun consejo?

ACTUALIZACIÓN 1

El evento WM_COPYDATA se recibe mediante una ventana oculta creada con win32gui solo para este propósito. El evento copydata está conectado a una función llamada OnCopyData y este es su encabezado:
def OnCopyData(self, hwnd, msg, wparam, lparam):
Los valores que entrega la función son correctos en comparación con los del registro de mensajes de Spy ++.

ACTUALIZACIÓN 2

Esto debería estar cerca de lo que quiero, pero da un error de puntero NULO.

 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) 

Escribí la siguiente aplicación win32gui trivial:

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

Luego envié a la ventana un mensaje WM_COPYDATA desde otra aplicación (escrita en Delphi):

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

La salida fue:

 461584 461584 74 658190 2620592 42 22 greetings! 

Así que parece que funciona de forma trivial, más o menos como lo codificaste.

Lo único en lo que puedo pensar es que el texto en COPYDATASTRUCT de Spotify no está terminado en nulo. Debería poder comprobarlo fácilmente leyendo los datos. Hacer uso del miembro cbData .