タイトル取得

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

人見知りソフトウェアエンジニアです。ビジュアル系、お笑い、Pixarが好き。勢いで吉本超合金おたけびBOTを作った。オールザッツ漫才が放送されない東京在住。

趣味や日常からアウトプットの場としてブログを書いています。自作のWordPressプラグインにGitHub Flavored MarkdownAmazonJSなど。