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:
dwDatain our case 0x547 so that it access the listening now featurecbDatawith the length of the string receivedlpDatawith 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)
I wrote the following trivial win32gui app:
I then sent the window a
WM_COPYDATAmessage from another app (written in Delphi):The output was:
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
COPYDATASTRUCTis not null-terminated. You should be able to check that quite easily by reading out the data. Make use of thecbDatamember.