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; }