rainmeter-studio/Plugins/PluginNowPlaying/PlayerAIMP.cpp

364 lines
7.5 KiB
C++

/*
Copyright (C) 2011 Birunthan Mohanathas (www.poiru.net)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "StdAfx.h"
#include "PlayerAIMP.h"
#include "AIMP/aimp2_sdk.h"
#include "Winamp/wa_ipc.h"
Player* PlayerAIMP::c_Player = nullptr;
/*
** Constructor.
**
*/
PlayerAIMP::PlayerAIMP() : Player(),
m_Window(),
m_WinampWindow(),
m_LastCheckTime(0),
m_LastFileSize(0),
m_LastTitleSize(0),
m_FileMap(),
m_FileMapHandle()
{
}
/*
** Destructor.
**
*/
PlayerAIMP::~PlayerAIMP()
{
c_Player = nullptr;
if (m_FileMap) UnmapViewOfFile(m_FileMap);
if (m_FileMapHandle) CloseHandle(m_FileMapHandle);
}
/*
** Creates a shared class object.
**
*/
Player* PlayerAIMP::Create()
{
if (!c_Player)
{
c_Player = new PlayerAIMP();
}
return c_Player;
}
/*
** Try to find AIMP periodically.
**
*/
bool PlayerAIMP::CheckWindow()
{
DWORD time = GetTickCount();
// Try to find AIMP every 5 seconds
if (time - m_LastCheckTime > 5000)
{
m_LastCheckTime = time;
m_Window = FindWindow(L"AIMP2_RemoteInfo", L"AIMP2_RemoteInfo");
if (m_Window)
{
m_WinampWindow = FindWindow(L"Winamp v1.x", nullptr);
m_FileMapHandle = OpenFileMapping(FILE_MAP_READ, FALSE, L"AIMP2_RemoteInfo");
if (m_FileMapHandle)
{
m_FileMap = (LPVOID)MapViewOfFile(m_FileMapHandle, FILE_MAP_READ, 0, 0, 2048);
if (m_FileMap)
{
m_Initialized = true;
}
}
}
}
return m_Initialized;
}
/*
** Called during each update of the main measure.
**
*/
void PlayerAIMP::UpdateData()
{
if (!m_Initialized)
{
if (m_LastTitleSize != 0)
{
m_LastFileSize = 0;
m_LastTitleSize = 0;
}
if (!CheckWindow()) return;
}
// If initialized
m_State = (StateType)SendMessage(m_Window, WM_AIMP_COMMAND, WM_AIMP_STATUS_GET, AIMP_STS_Player);
if (m_State == STATE_STOPPED)
{
// Make sure AIMP is still active
if (!IsWindow(m_Window))
{
m_Initialized = false;
ClearData();
if (m_FileMap) UnmapViewOfFile(m_FileMap);
if (m_FileMapHandle) CloseHandle(m_FileMapHandle);
}
else if (m_State != STATE_STOPPED)
{
ClearData(false);
m_LastFileSize = 0;
m_LastTitleSize = 0;
}
// Don't continue if AIMP has quit or is stopped
return;
}
m_Position = (UINT)SendMessage(m_Window, WM_AIMP_COMMAND, WM_AIMP_STATUS_GET, AIMP_STS_POS);
m_Volume = (UINT)SendMessage(m_Window, WM_AIMP_COMMAND, WM_AIMP_STATUS_GET, AIMP_STS_VOLUME);
AIMP2FileInfo* info = (AIMP2FileInfo*)m_FileMap;
if (info->cbSizeOf > 0 &&
info->nFileSize != m_LastFileSize || // Avoid reading the same file
info->nTitleLen != m_LastTitleSize)
{
m_LastFileSize = info->nFileSize;
m_LastTitleSize = info->nTitleLen;
// 44 is sizeof(AIMP2FileInfo) / 2 (due to WCHAR being 16-bit).
// Written explicitly due to size differences in 32bit/64bit.
LPCTSTR stringData = (LPCTSTR)m_FileMap;
stringData += 44;
m_Album.assign(stringData, info->nAlbumLen);
stringData += info->nAlbumLen;
m_Artist.assign(stringData, info->nArtistLen);
stringData += info->nArtistLen;
stringData += info->nDateLen;
std::wstring filepath(stringData, info->nFileNameLen);
stringData += info->nFileNameLen;
stringData += info->nGenreLen;
m_Title.assign(stringData, info->nTitleLen);
m_Duration = info->nDuration / 1000;
m_Number = (UINT)info->nTrackID;
m_Shuffle = SendMessage(m_Window, WM_AIMP_COMMAND, WM_AIMP_STATUS_GET, AIMP_STS_SHUFFLE) != 0;
m_Repeat = SendMessage(m_Window, WM_AIMP_COMMAND, WM_AIMP_STATUS_GET, AIMP_STS_REPEAT) != 0;
// Get rating through the AIMP Winamp API
m_Rating = (UINT)SendMessage(m_WinampWindow, WM_WA_IPC, 0, IPC_GETRATING);
if (filepath != m_FilePath)
{
m_FilePath = filepath;
++m_TrackCount;
if (m_Measures & MEASURE_COVER) FindCover();
if (m_Measures & MEASURE_LYRICS) FindLyrics();
}
}
}
/*
** Handles the Pause bang.
**
*/
void PlayerAIMP::Pause()
{
SendMessage(m_Window, WM_AIMP_COMMAND, WM_AIMP_CALLFUNC, AIMP_PAUSE);
}
/*
** Handles the Play bang.
**
*/
void PlayerAIMP::Play()
{
SendMessage(m_Window, WM_AIMP_COMMAND, WM_AIMP_CALLFUNC, AIMP_PLAY);
}
/*
** Handles the Stop bang.
**
*/
void PlayerAIMP::Stop()
{
SendMessage(m_Window, WM_AIMP_COMMAND, WM_AIMP_CALLFUNC, AIMP_STOP);
}
/*
** Handles the Next bang.
**
*/
void PlayerAIMP::Next()
{
SendMessage(m_Window, WM_AIMP_COMMAND, WM_AIMP_CALLFUNC, AIMP_NEXT);
}
/*
** Handles the Previous bang.
**
*/
void PlayerAIMP::Previous()
{
SendMessage(m_Window, WM_AIMP_COMMAND, WM_AIMP_CALLFUNC, AIMP_PREV);
}
/*
** Handles the SetPosition bang.
**
*/
void PlayerAIMP::SetPosition(int position)
{
SendMessage(m_Window, WM_AIMP_COMMAND, WM_AIMP_STATUS_SET, MAKELPARAM(position, AIMP_STS_POS));
}
/*
** Handles the SetRating bang.
**
*/
void PlayerAIMP::SetRating(int rating)
{
// Set rating through the AIMP Winamp API
if (m_State != STATE_STOPPED)
{
SendMessage(m_WinampWindow, WM_WA_IPC, rating, IPC_SETRATING);
m_Rating = rating;
}
}
/*
** Handles the SetVolume bang.
**
*/
void PlayerAIMP::SetVolume(int volume)
{
SendMessage(m_Window, WM_AIMP_COMMAND, WM_AIMP_STATUS_SET, MAKELPARAM(volume, AIMP_STS_VOLUME));
}
/*
** Handles the SetShuffle bang.
**
*/
void PlayerAIMP::SetShuffle(bool state)
{
m_Shuffle = state;
SendMessage(m_Window, WM_AIMP_COMMAND, WM_AIMP_STATUS_SET, MAKELPARAM(m_Shuffle, AIMP_STS_SHUFFLE));
}
/*
** Handles the SetRepeat bang.
**
*/
void PlayerAIMP::SetRepeat(bool state)
{
m_Repeat = state;
SendMessage(m_Window, WM_AIMP_COMMAND, WM_AIMP_STATUS_SET, MAKELPARAM(m_Repeat, AIMP_STS_REPEAT));
}
/*
** Handles the ClosePlayer bang.
**
*/
void PlayerAIMP::ClosePlayer()
{
SendMessage(m_Window, WM_CLOSE, 0, 0);
}
/*
** Handles the OpenPlayer bang.
**
*/
void PlayerAIMP::OpenPlayer(std::wstring& path)
{
if (path.empty())
{
// Check for AIMP2 first
DWORD size = 512;
WCHAR* data = new WCHAR[size];
DWORD type = 0;
HKEY hKey;
RegOpenKeyEx(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\AIMP2",
0,
KEY_QUERY_VALUE,
&hKey);
if (RegQueryValueEx(hKey,
L"DisplayIcon",
nullptr,
(LPDWORD)&type,
(LPBYTE)data,
(LPDWORD)&size) == ERROR_SUCCESS)
{
if (type == REG_SZ)
{
ShellExecute(nullptr, L"open", data, nullptr, nullptr, SW_SHOW);
path = data;
}
}
else
{
// Let's try AIMP3
RegCloseKey(hKey);
RegOpenKeyEx(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\AIMP3",
0,
KEY_QUERY_VALUE,
&hKey);
if (RegQueryValueEx(hKey,
L"DisplayIcon",
nullptr,
(LPDWORD)&type,
(LPBYTE)data,
(LPDWORD)&size) == ERROR_SUCCESS)
{
if (type == REG_SZ)
{
path = data;
path.resize(path.find_last_of(L'\\') + 1);
path += L"AIMP3.exe";
ShellExecute(nullptr, L"open", path.c_str(), nullptr, nullptr, SW_SHOW);
}
}
}
delete [] data;
RegCloseKey(hKey);
}
else
{
ShellExecute(nullptr, L"open", path.c_str(), nullptr, nullptr, SW_SHOW);
}
}