Winamp SDKにはメタデータ取得のためのAPI(message)があり、これを駆使して再生中のコンテンツのタイトルやらアーティストやらを取ることが可能です。が、おそらくこれらのAPIは同一プロセス内のPlug-inから呼び出されることを最初は想定しているもの。で、SongWidgetのように外部プロセスからアクセスするにはメモリのプロセス間共有が必要です。
例えば再生中のfilepathを取得する場合には、Winamp領域のメモリを読む必要があります。ウインドウハンドルは分かっているので、GetWindowThreadProcessIdでProcessIDを取得し、OpenProcessでプロセスハンドルを取得、ReadProcessMemoryで指定のプロセスのメモリを読ませてもらいます。コードにすると以下のようになります。
CStringA str;
char szBuffer[_MAX_PATH] = {0};
DWORD dwPID;
GetWindowThreadProcessId(hWnd, &dwPID);
HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, dwPID);
if (hProcess) {
DWORD dwRead;
BOOL bRet = ReadProcessMemory(hProcess, psz, szBuffer, sizeof(szBuffer), &dwRead);
if (bRet) str = szBuffer;
CloseHandle(hProcess);
}
さて、さらにアーティストやらメタを取る場合はさらに大変です。Winampプロセスにまずメモリを確保して、そこにメタデータを書いてもらい、さらに取得する。さらっと書くとこんな感じです。98/Meと2000/XPでメモリの確保の方法を変えないといけないのでちょっと面倒です。
typedef LPVOID (WINAPI *virtAllocEx)(
HANDLE hProcess, // process within which to allocate memory
LPVOID lpAddress, // desired starting address of allocation
DWORD dwSize, // size, in bytes, of region to allocate
DWORD flAllocationType,
// type of allocation
DWORD flProtect // type of access protection
);
typedef BOOL (WINAPI *virtFreeEx)(
HANDLE hProcess, // process within which to free memory
LPVOID lpAddress, // starting address of memory region to free
DWORD dwSize, // size, in bytes, of memory region to free
DWORD dwFreeType // type of free operation
);
CStringA getMetadataInfo(HWND hWnd, const CStringA& strFileName, const CStringA& strField)
{
CStringA strMetadata;
const int cbSize = 1024; // TBD
OSVERSIONINFO osVersion;
extendedFileInfoStruct extFileStruct;
osVersion.dwOSVersionInfoSize = sizeof(osVersion);
GetVersionEx(&osVersion);
// for pointer in Winamp process
extendedFileInfoStruct* pExtFileStructRemote = NULL;
char* pszFileNameRemote = NULL;
char* pszFieldRemote = NULL;
char* pszBufferRemote = NULL;
if (osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
HINSTANCE hKernel = GetModuleHandle("kernel32.dll");
if (!hKernel) return strMetadata;
// Get handle over WinAmp process
DWORD dwWinAmpProcId;
GetWindowThreadProcessId(hWnd, &dwWinAmpProcId);
HANDLE hWinampProc = OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ, FALSE, dwWinAmpProcId);
if (!hWinampProc) return strMetadata;
virtAllocEx allocEx = (virtAllocEx)GetProcAddress(hKernel, "VirtualAllocEx");
virtFreeEx freeEx = (virtFreeEx)GetProcAddress(hKernel, "VirtualFreeEx");
// Allocate the buffers in WinAmp address space
pExtFileStructRemote = (extendedFileInfoStruct*)allocEx(hWinampProc, NULL, sizeof(extFileStruct), MEM_COMMIT,PAGE_READWRITE);
pszFileNameRemote = (char*)allocEx(hWinampProc, NULL, strFileName.GetLength()+1, MEM_COMMIT,PAGE_READWRITE);
pszFieldRemote = (char*)allocEx(hWinampProc, NULL, strField.GetLength()+1, MEM_COMMIT,PAGE_READWRITE);
pszBufferRemote = (char*)allocEx(hWinampProc, NULL, cbSize, MEM_COMMIT, PAGE_READWRITE);
// Fill the buffers allocated
DWORD dwRet;
WriteProcessMemory(hWinampProc, pszFileNameRemote, (void*)((LPCSTR)strFileName), strFileName.GetLength()+1, &dwRet);
WriteProcessMemory(hWinampProc, pszFieldRemote, (void*)((LPCSTR)strField), strField.GetLength()+1, &dwRet);
extFileStruct.filename = pszFileNameRemote;
extFileStruct.metadata = pszFieldRemote;
extFileStruct.ret = pszBufferRemote;
extFileStruct.retlen = cbSize;
WriteProcessMemory(hWinampProc, pExtFileStructRemote, &extFileStruct, sizeof(extFileStruct), &dwRet);
// Send request to Winamp
if ( SendMessage(hWnd, WM_WA_IPC, (WPARAM)pExtFileStructRemote, IPC_GET_EXTENDED_FILE_INFO) ) {
char* pszBuffer = new char[cbSize+1];
if (pszBuffer) {
ReadProcessMemory(hWinampProc, pszBufferRemote, pszBuffer, cbSize, &dwRet);
strMetadata = pszBuffer;
delete [] pszBuffer;
}
}
// Clean the Winamp address space
freeEx(hWinampProc, pExtFileStructRemote, 0, MEM_DECOMMIT);
freeEx(hWinampProc, pszFileNameRemote, 0, MEM_DECOMMIT);
freeEx(hWinampProc, pszFieldRemote, 0, MEM_DECOMMIT);
freeEx(hWinampProc, pszBufferRemote, 0, MEM_DECOMMIT);
// Close the process
CloseHandle(hWinampProc);
}
else if (osVersion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
{
// Allocate the buffers in global address space
HANDLE hFileExtFileStruct = CreateFileMapping((HANDLE)-1, NULL, PAGE_READWRITE|SEC_COMMIT, 0, sizeof(extFileStruct), NULL);
HANDLE hFileFileName = CreateFileMapping((HANDLE)-1, NULL, PAGE_READWRITE|SEC_COMMIT, 0, strFileName.GetLength()+1, NULL);
HANDLE hFileField = CreateFileMapping((HANDLE)-1, NULL, PAGE_READWRITE|SEC_COMMIT, 0, strField.GetLength()+1, NULL);
HANDLE hFileBuffer = CreateFileMapping((HANDLE)-1, NULL, PAGE_READWRITE|SEC_COMMIT, 0, cbSize, NULL);
pExtFileStructRemote = (extendedFileInfoStruct*)MapViewOfFile(hFileExtFileStruct, FILE_MAP_WRITE, 0, 0, 0);
pszFileNameRemote = (char*)MapViewOfFile(hFileFileName, FILE_MAP_WRITE, 0, 0, 0);
pszFieldRemote = (char*)MapViewOfFile(hFileField, FILE_MAP_WRITE, 0, 0, 0);
pszBufferRemote = (char*)MapViewOfFile(hFileBuffer, FILE_MAP_WRITE, 0, 0, 0);
// Fill the buffers allocated
strcpy(pszFileNameRemote, (LPCSTR)strFileName);
strcpy(pszFieldRemote, (LPCSTR)strField);
pExtFileStructRemote->filename = pszFileNameRemote;
pExtFileStructRemote->metadata = pszFieldRemote;
pExtFileStructRemote->ret = pszBufferRemote;
pExtFileStructRemote->retlen = cbSize;
// Send request to Winamp
if (SendMessage(hWnd, WM_WA_IPC, (WPARAM)pExtFileStructRemote, IPC_GET_EXTENDED_FILE_INFO)) {
char* pszBuffer = new char[cbSize+1];
if (pszBuffer) {
memcpy(pszBuffer, pszBufferRemote, cbSize);
strMetadata = pszBuffer;
delete [] pszBuffer;
}
}
// Clean the global address space
UnmapViewOfFile(pExtFileStructRemote);
UnmapViewOfFile(pszFileNameRemote);
UnmapViewOfFile(pszFieldRemote);
UnmapViewOfFile(pszBufferRemote);
CloseHandle(hFileExtFileStruct);
CloseHandle(hFileFileName);
CloseHandle(hFileField);
CloseHandle(hFileBuffer);
}
return strMetadata;
}