Home
Download
Screenshots

Wiki
Plugins
Translations
Developers
Donate

Forums/Help
Contact Us

StrokeIt

WinAmp + Lua + SendMessage to get filename/title currently playing

Posted by gemisigo 
WinAmp + Lua + SendMessage to get filename/title currently playing
January 29, 2010 06:22PM
There is this little piece of lua code:
require [[alien]]
--require [[clipboard]]

--define
local WM_USER = 0x400
local WM_COMMAND = 0x0
local PROCESS_ALL_ACCESS = 0x1F0FFF
local PROCESS_VM_READ = 0x0010
local PROCESS_VM_WRITE = 0x0020
local PROCESS_VM_OPERATION = 0x0008
local FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
local PAGE_EXECUTE = 0x10
local PAGE_EXECUTE_READ = 0X20
local PAGE_EXECUTE_READWRITE = 0x40
local WA_GET_PLAYLIST_INDEX = 125
local WA_GET_FILENAME = 211
local WA_GET_FILENAMEW = 214
local WA_GET_TITLE = 212
local WA_GET_TITLEW = 213


local FindWindow = alien.User32.FindWindowA
FindWindow:types{ret = 'long', abi = 'stdcall', 'string', 'string'}

local SendMessage = alien.User32.SendMessageA
SendMessage:types{ret = 'long', abi = 'stdcall', 'long', 'long', 'long', 'long'}

local GetWindowThreadProcessId = alien.User32.GetWindowThreadProcessId
GetWindowThreadProcessId:types{ret = 'long', abi = 'stdcall', 'long', 'pointer'}

local OpenProcess = alien.kernel32.OpenProcess
OpenProcess:types{ret = 'long', abi = 'stdcall', 'long', 'byte', 'long'}

local VirtualProtectEx = alien.kernel32.VirtualProtectEx
VirtualProtectEx:types{ret = 'long', abi = 'stdcall', 'long', 'long', 'long', 'long', 'pointer'}

local ReadProcessMemory = alien.kernel32.ReadProcessMemory
ReadProcessMemory:types{ret = 'int', abi = 'stdcall', 'long', 'long', 'pointer', 'long', 'pointer'}

local CloseHandle = alien.kernel32.CloseHandle
CloseHandle:types{ret = 'int', abi = 'stdcall', 'long'}

local GetLastError = alien.kernel32.GetLastError
GetLastError:types{ret = 'long', abi = 'stdcall'}


--implement
local hwnd_winamp = FindWindow('Winamp v1.x',NULL)
--print('hwnd_winamp  : ' .. hwnd_winamp)

local index = SendMessage(hwnd_winamp, WM_USER, 0, WA_GET_PLAYLIST_INDEX)
--print('index        : ' .. index)

local lp_filename = SendMessage(hwnd_winamp, WM_USER, index, WA_GET_FILENAME)
--print('lp_filename  : ' .. lp_filename)

local lp_songtitle = SendMessage(hwnd_winamp, WM_USER, index, WA_GET_TITLE)
--print('lp_songtitle : ' .. lp_songtitle)

local temp_handle = alien.buffer(4)
local process_id = GetWindowThreadProcessId(hwnd_winamp, temp_handle)
temp_handle = temp_handle:get(1, 'long')
--print('process_id   : ' .. process_id)
--print('temp_handle  : ' .. temp_handle)

local h_winamp = OpenProcess(PROCESS_ALL_ACCESS, false, temp_handle)
--print('h_winamp     : ' .. h_winamp)

local read_bytes = alien.buffer(4)
local buf = alien.buffer(255)
local buf2 = alien.buffer(255)
local oldprotect = alien.buffer(4)
local newprotect = alien.buffer(4)

newprotect[1] = PAGE_EXECUTE_READ

local vpe = VirtualProtectEx(h_winamp, lp_filename, 256, newprotect:get(1, 'long'), oldprotect)
--print('vpe alter success : ' ..vpe)
--print('       oldprotect : ' .. oldprotect:get(1, 'long'))
--print('       newprotect : ' .. newprotect:get(1, 'long'))
local rr = ReadProcessMemory(h_winamp, lp_filename, buf, 256, read_bytes)
local last_error = GetLastError()
--print('last error        : ' .. last_error)
--print('read success      : ' .. rr)
local rr = ReadProcessMemory(h_winamp, lp_songtitle, buf2, 256, read_bytes)
local last_error = GetLastError()
--print('last error        : ' .. last_error)
--print('read success      : ' .. rr)


vpe = VirtualProtectEx(h_winamp, lp_filename, 256, oldprotect:get(1,'long'), newprotect)
--print('vpe rest success  : ' ..vpe)
--print('       oldprotect : ' .. newprotect:get(1, 'long'))
--print('       newprotect : ' .. oldprotect:get(1, 'long'))

--print('read bytes read   : ' .. read_bytes:get(1, 'long'))
--print('buffer contents   : ' .. "'" .. tostring(buf) .. "'")
--print('buffer2 contents  : ' .. "'" .. tostring(buf2) .. "'")

local rv = CloseHandle(h_winamp)
--print('close success     : ' .. rv)
--clipboard.set(tostring(buf))

According to WinAmp SDK + google, sending those three messages to WinAmp will retrieve the playlist index, and two pointers pointing to the filename and the title of the song currently playing/selected. Those two pointer refer to memory locations in WinAmp's memory area but that does not matter, I can read them with ReadProcessMemory.

Now the problem is:
I can get the index and either of the filename or the title but not both. If I send the message to get the title, the returned pointer will point exactly to the same place where the filename pointer does. But when I try to read from that memory area, a very weird thing happens. It's not the filename that I get. It's the title.

I would like to ask those of you out there using WinAmp and Lua to try and see if you get the correct results from the code above, please. Or if you spot it, cast light on where I failed.

EDIT: I left the 'print'-s in the code (though commented them). It's easier to 'debug' in a lua environment than using StrokeIt.



Edited 2 time(s). Last edit at 01/29/2010 06:25PM by gemisigo.
Leo
Re: WinAmp + Lua + SendMessage to get filename/title currently playing
January 30, 2010 11:59AM
HWND hwndWinamp = FindWindow("Winamp v1.x",NULL);
char this_title[2048],*p;
GetWindowText(hwndWinamp,this_title,sizeof(this_title));
p = this_title+strlen(this_title)-8;
while (p >= this_title)
{

if (!strnicmp(p,"- Winamp",8)) break;
p--;

}
if (p >= this_title) p--;
while (p >= this_title && *p == ' ') p--;
*++p=0;
Re: WinAmp + Lua + SendMessage to get filename/title currently playing
February 02, 2010 04:21AM
Sorry Leo, but I cannot interpret your post. This is not Lua, this is c. What do you want to show me?
Re: WinAmp + Lua + SendMessage to get filename/title currently playing
February 02, 2010 09:36AM
I think he's suggesting that, if you only need the song title and not the filename, it's easier to just grab it from window title. I came to the same conclusion many years ago when writing winamp plugins.

-- Jeff
Re: WinAmp + Lua + SendMessage to get filename/title currently playing
February 02, 2010 12:05PM
Oh, I see. Well, that's nice, but the title is totally irrelevant to me, I just tried it on "it's just a moment away, try it" basis. It's the filename that I need. Thanks anyway.
Leo
Re: WinAmp + Lua + SendMessage to get filename/title currently playing
February 02, 2010 12:35PM
local TempHandle = 0
hwndWinamp = FindWindow("Winamp v1.x", NULL)
TrackPos = SendMessage(hwndWinamp, WM_USER, 0, 125)
MPointer = SendMessage(hwndWinamp, WM_USER, TrackPos, 211)--212 is Title
temp = GetWindowThreadProcessId(hwndWinamp, TempHandle)
hwndWinampP = OpenProcess(PROCESS_VM_READ, False, TempHandle)
local Data = alien.buffer(256)
nTemp = ReadProcessMemory(hwndWinampP, MPointer, Data, 256, temp)
pTemp = CloseHandle(hwndWinampP)
ShowFile = Data

should work but read a little google :)
http://forums.winamp.com/showthread.php?threadid=85389



Edited 4 time(s). Last edit at 02/02/2010 12:48PM by Leo.
Re: WinAmp + Lua + SendMessage to get filename/title currently playing
February 02, 2010 01:31PM
Thanks, Leo, but I think you misunderstood :) What you posted was exactly the way I was doing it. Meanwhile I solved it, I'll post it here so it might help others if they try the same.

WinAmp SDK states that message id 211 (with index in data) returns a pointer to the char* where a playlist item's filename is located and message id 212 returns a similar pointer to its title.

My presumption was (and I had no reason to doubt that I'm right - reason later :) ) that it points to two different locations. I should have smelled a rat when I saw that indexing another playlist entry it still returned the same value and the solution was within my grasp when it returned the same value for title message, too. I was just too dumb to recognize that my presumption was false (and that WinAmp SDK description is a bit misleading if you read it sloppily, as I did).

The pointer does point to a string containing filename/title. It does point to a string. The contents of these strings (which are exactly at the same address) depend on the message id. WinAmp does search for the playlist entry data in the memory but does not return a pointer to that address. It collects the data and copies to a certain address.

Issuing id 211 WinAmp placed the filename at that position and issuing 212 right after the first message (and prior reading it) resulted in WinAmp overwriting the string already placed there. That was the reason it did not work. The order of sending message/reading address was incorrect.

The lesson today : be careful when presuming. Check if you're not sure :)
Author:

Your Email:


Subject:


Spam prevention:
Please, solve the mathematical question and enter the answer in the input field below. This is for blocking bots that try to post this form automatically.
Question: how much is 16 plus 24?
Message: