From 3268c774d2bc740445018650a719ea44cbe67f5d Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Sat, 28 May 2011 07:50:33 +0000 Subject: [PATCH] NowPlayingPlugin: Improved MusicBee & MediaMonkey support and fixed that the ClosePlayer bang with iTunes does not always work. --- Plugins/PluginNowPlaying/NowPlaying.cpp | 12 +- Plugins/PluginNowPlaying/PlayerCAD.cpp | 7 +- Plugins/PluginNowPlaying/PlayerCAD.h | 43 ----- Plugins/PluginNowPlaying/PlayerITunes.cpp | 15 +- Plugins/PluginNowPlaying/PlayerITunes.h | 1 - Plugins/PluginNowPlaying/PlayerWinamp.cpp | 61 ++++++- Plugins/PluginNowPlaying/PlayerWinamp.h | 9 +- .../PluginNowPlaying/PluginNowPlaying.vcxproj | 1 + .../PluginNowPlaying.vcxproj.filters | 6 + Plugins/PluginNowPlaying/SDKs/CAD/cad_sdk.h | 164 ++++++++++++++++++ 10 files changed, 256 insertions(+), 63 deletions(-) create mode 100644 Plugins/PluginNowPlaying/SDKs/CAD/cad_sdk.h diff --git a/Plugins/PluginNowPlaying/NowPlaying.cpp b/Plugins/PluginNowPlaying/NowPlaying.cpp index 8392ff30..c9a93ffd 100644 --- a/Plugins/PluginNowPlaying/NowPlaying.cpp +++ b/Plugins/PluginNowPlaying/NowPlaying.cpp @@ -140,6 +140,14 @@ UINT Initialize(HMODULE instance, LPCTSTR iniFile, LPCTSTR section, UINT id) } data->player = g_iTunes; } + else if (_wcsicmp(L"MediaMonkey", str) == 0) + { + if (!g_Winamp) + { + g_Winamp = new CPlayerWinamp(WA_MEDIAMONKEY); + } + data->player = g_Winamp; + } else if (_wcsicmp(L"MusicBee", str) == 0) { if (!g_CAD) @@ -156,11 +164,11 @@ UINT Initialize(HMODULE instance, LPCTSTR iniFile, LPCTSTR section, UINT id) } data->player = g_Spotify; } - else if (_wcsicmp(L"WinAmp", str) == 0 || _wcsicmp(L"MediaMonkey", str) == 0) + else if (_wcsicmp(L"WinAmp", str) == 0) { if (!g_Winamp) { - g_Winamp = new CPlayerWinamp(); + g_Winamp = new CPlayerWinamp(WA_WINAMP); } data->player = g_Winamp; } diff --git a/Plugins/PluginNowPlaying/PlayerCAD.cpp b/Plugins/PluginNowPlaying/PlayerCAD.cpp index de55a6e1..4035100a 100644 --- a/Plugins/PluginNowPlaying/PlayerCAD.cpp +++ b/Plugins/PluginNowPlaying/PlayerCAD.cpp @@ -18,6 +18,7 @@ #include "StdAfx.h" #include "PlayerCAD.h" +#include "CAD/cad_sdk.h" // This player emulates the CD Art Display IPC API. For now, only MusicBee // is supported, but this can easily be extended. @@ -121,6 +122,7 @@ void CPlayerCAD::Initialize() m_PlayerWindow = wnd; SendMessage(m_PlayerWindow, WM_USER, (WPARAM)m_Window, IPC_SET_CALLBACK_HWND); SendMessage(m_PlayerWindow, WM_USER, 0, IPC_GET_CURRENT_TRACK); + m_State = (PLAYERSTATE)SendMessage(m_PlayerWindow, WM_USER, 0, IPC_GET_PLAYER_STATE); } else { @@ -141,7 +143,6 @@ void CPlayerCAD::Uninitialize() UnregisterClass(L"NowPlayingCADClass", GetModuleHandle(NULL)); } - /* ** WndProc ** @@ -180,6 +181,7 @@ LRESULT CALLBACK CPlayerCAD::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM case IPC_SHUTDOWN_NOTIFICATION: p->m_PlayerWindow = NULL; + p->ClearInfo(); break; } return 0; @@ -376,7 +378,6 @@ void CPlayerCAD::SetVolume(int volume) { if (m_PlayerWindow) { - volume += m_Volume; if (volume < 0) { volume = 0; @@ -410,6 +411,8 @@ void CPlayerCAD::ChangeVolume(int volume) void CPlayerCAD::ClosePlayer() { SendMessage(m_PlayerWindow, WM_USER, 0, IPC_CLOSE_PLAYER); + m_PlayerWindow = NULL; + ClearInfo(); } /* diff --git a/Plugins/PluginNowPlaying/PlayerCAD.h b/Plugins/PluginNowPlaying/PlayerCAD.h index 964b446e..ea750665 100644 --- a/Plugins/PluginNowPlaying/PlayerCAD.h +++ b/Plugins/PluginNowPlaying/PlayerCAD.h @@ -44,49 +44,6 @@ public: virtual void UpdateData(); private: - enum IPCMESSAGE - { - IPC_PLAY = 100, - IPC_PLAYPAUSE, - IPC_FORCEPAUSE, - IPC_STOP, - IPC_NEXT, - IPC_PREVIOUS, - IPC_SET_VOLUME = 108, - IPC_GET_VOLUME, - IPC_GET_CURRENT_TRACK, - IPC_GET_DURATION = 113, - IPC_SET_POSITION, - IPC_IS_PLAYING, - IPC_IS_PAUSED, - IPC_GET_LIST_LENGTH, - IPC_SET_LIST_POS, - IPC_GET_LIST_ITEM, - IPC_SET_CALLBACK_HWND, // Recieved by player. wParam is handle to CAD window. - IPC_GET_LIST_POS, - IPC_GET_POSITION, - IPC_TRACK_CHANGED_NOTIFICATION, // Sent by player. - IPC_SHOW_PLAYER_WINDOW, - IPC_GET_PLAYER_STATE, - IPC_PLAYER_STATE_CHANGED_NOTIFICATION, // Sent by player. - IPC_AUTOENQUEUE_OPTIONS, // Ignored. - IPC_SET_REPEAT, - IPC_SHUTDOWN_NOTIFICATION, // Sent by/to player on exit. Player should NULL the CAD window handle. - IPC_GET_REPEAT, - IPC_CLOSE_PLAYER, // Player should exit upon receival. - IPC_GET_SHUFFLE = 140, - IPC_SET_SHUFFLE, - IPC_RATING_CHANGED_NOTIFICATION = 639, // Sent by/to player. - IPC_REGISTER_PLAYER = 700, // Sent by player to CAD on startup. - IPC_CURRENT_TRACK_INFO, - IPC_SEND_LYRICS, - IPC_SEND_NEW_LYRICS, - IPC_NEW_COVER_NOTIFICATION = 800, // Sent by player (ignored). - IPC_GET_CURRENT_LYRICS, - IPC_ADDFILE_PLAY_PLAYLIST, - IPC_ADDFILE_QUEUE_PLAYLIST - }; - void Initialize(); void Uninitialize(); static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); diff --git a/Plugins/PluginNowPlaying/PlayerITunes.cpp b/Plugins/PluginNowPlaying/PlayerITunes.cpp index 36e69952..9f66b955 100644 --- a/Plugins/PluginNowPlaying/PlayerITunes.cpp +++ b/Plugins/PluginNowPlaying/PlayerITunes.cpp @@ -29,15 +29,8 @@ extern CPlayer* g_iTunes; */ CPlayerITunes::CEventHandler::CEventHandler(CPlayerITunes* player) : m_iTunes(player), - m_TypeInfo(), m_RefCount() { - ITypeLib* pITypeLib = NULL; - HRESULT hr = LoadRegTypeLib(LIBID_iTunesLib, 1, 5, 0x00, &pITypeLib); - - // Get type information for the interface of the object. - hr = pITypeLib->GetTypeInfoOfGuid(DIID__IiTunesEvents, &m_TypeInfo); - pITypeLib->Release(); } /* @@ -64,13 +57,13 @@ HRESULT STDMETHODCALLTYPE CPlayerITunes::CEventHandler::QueryInterface(REFIID ii ULONG STDMETHODCALLTYPE CPlayerITunes::CEventHandler::AddRef() { - InterlockedIncrement(&m_RefCount); + ++m_RefCount; return m_RefCount; } ULONG STDMETHODCALLTYPE CPlayerITunes::CEventHandler::Release() { - InterlockedDecrement(&m_RefCount); + --m_RefCount; if (m_RefCount == 0) { delete this; @@ -568,9 +561,9 @@ void CPlayerITunes::ClosePlayer() { if (m_Initialized) { - m_Initialized = false; + m_UserQuitPrompt = true; m_iTunes->Quit(); - ClearInfo(); + Uninitialize(); } } diff --git a/Plugins/PluginNowPlaying/PlayerITunes.h b/Plugins/PluginNowPlaying/PlayerITunes.h index e5f2b677..70cc019e 100644 --- a/Plugins/PluginNowPlaying/PlayerITunes.h +++ b/Plugins/PluginNowPlaying/PlayerITunes.h @@ -74,7 +74,6 @@ private: private: ULONG m_RefCount; - ITypeInfo* m_TypeInfo; // Pointer to type information CPlayerITunes* m_iTunes; }; diff --git a/Plugins/PluginNowPlaying/PlayerWinamp.cpp b/Plugins/PluginNowPlaying/PlayerWinamp.cpp index e11b572c..bbd2bce0 100644 --- a/Plugins/PluginNowPlaying/PlayerWinamp.cpp +++ b/Plugins/PluginNowPlaying/PlayerWinamp.cpp @@ -21,6 +21,8 @@ #include "Winamp/wa_ipc.h" #include "Winamp/wa_cmd.h" +// This player retrieves data through the Winamp IPC API. + extern CPlayer* g_Winamp; /* @@ -29,7 +31,8 @@ extern CPlayer* g_Winamp; ** Constructor. ** */ -CPlayerWinamp::CPlayerWinamp() : CPlayer(), +CPlayerWinamp::CPlayerWinamp(WINAMPTYPE type) : CPlayer(), + m_WinampType(type), m_UseUnicodeAPI(false), m_HasCoverMeasure(false), m_Window() @@ -475,7 +478,18 @@ void CPlayerWinamp::ClosePlayer() { if (m_Window) { - SendMessage(m_Window, WM_CLOSE, 0, 0); + if (m_WinampType == WA_WINAMP) + { + SendMessage(m_Window, WM_CLOSE, 0, 0); + } + else // if (m_WinampType == WA_MEDIAMONKEY) + { + HWND wnd = FindWindow(L"TFMainWindow", L"MediaMonkey"); + if (wnd) + { + SendMessage(wnd, WM_CLOSE, 0, 0); + } + } } } @@ -487,7 +501,48 @@ void CPlayerWinamp::ClosePlayer() */ void CPlayerWinamp::OpenPlayer() { - ShellExecute(NULL, L"open", m_PlayerPath.empty() ? L"winamp.exe" : m_PlayerPath.c_str(), NULL, NULL, SW_SHOW); + if (m_WinampType == WA_WINAMP) + { + ShellExecute(NULL, L"open", m_PlayerPath.empty() ? L"winamp.exe" : m_PlayerPath.c_str(), NULL, NULL, SW_SHOW); + } + else // if (m_WinampType == WA_MEDIAMONKEY) + { + if (m_PlayerPath.empty()) + { + // Gotta figure out where Winamp is located at + HKEY hKey; + RegOpenKeyEx(HKEY_LOCAL_MACHINE, + L"SOFTWARE\\Clients\\Media\\MediaMonkey\\shell\\open\\command", + 0, + KEY_QUERY_VALUE, + &hKey); + + DWORD size = 512; + WCHAR* data = new WCHAR[size]; + DWORD type = 0; + + if (RegQueryValueEx(hKey, + NULL, + NULL, + (LPDWORD)&type, + (LPBYTE)data, + (LPDWORD)&size) == ERROR_SUCCESS) + { + if (type == REG_SZ) + { + ShellExecute(NULL, L"open", data, NULL, NULL, SW_SHOW); + m_PlayerPath = data; + } + } + + delete [] data; + RegCloseKey(hKey); + } + else + { + ShellExecute(NULL, L"open", m_PlayerPath.c_str(), NULL, NULL, SW_SHOW); + } + } } /* diff --git a/Plugins/PluginNowPlaying/PlayerWinamp.h b/Plugins/PluginNowPlaying/PlayerWinamp.h index c6fe76af..b5457957 100644 --- a/Plugins/PluginNowPlaying/PlayerWinamp.h +++ b/Plugins/PluginNowPlaying/PlayerWinamp.h @@ -21,10 +21,16 @@ #include "Player.h" +enum WINAMPTYPE +{ + WA_WINAMP, + WA_MEDIAMONKEY +}; + class CPlayerWinamp : public CPlayer { public: - CPlayerWinamp(); + CPlayerWinamp(WINAMPTYPE type); ~CPlayerWinamp(); virtual void Play(); @@ -49,6 +55,7 @@ private: bool m_HasCoverMeasure; bool m_UseUnicodeAPI; + WINAMPTYPE m_WinampType; HWND m_Window; // Winamp window HANDLE m_WinampHandle; // Handle to Winamp process LPCVOID m_WinampAddress; diff --git a/Plugins/PluginNowPlaying/PluginNowPlaying.vcxproj b/Plugins/PluginNowPlaying/PluginNowPlaying.vcxproj index 8bdbc8ef..6f346471 100644 --- a/Plugins/PluginNowPlaying/PluginNowPlaying.vcxproj +++ b/Plugins/PluginNowPlaying/PluginNowPlaying.vcxproj @@ -353,6 +353,7 @@ + diff --git a/Plugins/PluginNowPlaying/PluginNowPlaying.vcxproj.filters b/Plugins/PluginNowPlaying/PluginNowPlaying.vcxproj.filters index c55ae46f..617e5349 100644 --- a/Plugins/PluginNowPlaying/PluginNowPlaying.vcxproj.filters +++ b/Plugins/PluginNowPlaying/PluginNowPlaying.vcxproj.filters @@ -22,6 +22,9 @@ {8be2f033-c29f-41d2-affd-c7721f0df88b} + + {9e4422be-972a-442d-95f1-f238ef237a7b} + @@ -312,6 +315,9 @@ Players + + SDKs\CD Art Display + diff --git a/Plugins/PluginNowPlaying/SDKs/CAD/cad_sdk.h b/Plugins/PluginNowPlaying/SDKs/CAD/cad_sdk.h new file mode 100644 index 00000000..e1d39097 --- /dev/null +++ b/Plugins/PluginNowPlaying/SDKs/CAD/cad_sdk.h @@ -0,0 +1,164 @@ +/* + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __CADSDK_H__ +#define __CADSDK_H__ + +enum IPCMESSAGE +{ + /* + Most of these messages are sent to the player. Messages that the player + should send back to CAD are noted by '[Sent by player]' + + Based on information available in cad-sdk-2.1.pdf and in foo_cdartdisplay source. + */ + + // uMsg: WM_USER, wParam: 0, lParam: 100 + IPC_PLAY = 100, + + // uMsg: WM_USER, wParam: 0, lParam: 101 + IPC_PLAYPAUSE, + + // uMsg: WM_USER, wParam: 0, lParam: 102 + IPC_FORCEPAUSE, + + // uMsg: WM_USER, wParam: 0, lParam: 103 + IPC_STOP, + + // uMsg: WM_USER, wParam: 0, lParam: 104 + IPC_NEXT, + + // uMsg: WM_USER, wParam: 0, lParam: 105 + IPC_PREVIOUS, + + // uMsg: WM_USER, wParam: volume (0 - 100), lParam: 108 + IPC_SET_VOLUME = 108, + + // uMsg: WM_USER, wParam: 0, lParam: 109, result: 0 to 100 + IPC_GET_VOLUME, + + // uMsg: WM_USER, wParam: 0, lParam: 110 + // When the player recieves this message, it should send + // the IPC_CURRENT_TRACK message back to CAD + IPC_GET_CURRENT_TRACK, + + // uMsg: WM_USER, wParam: 0, lParam: 113 + IPC_GET_DURATION = 113, + + // uMsg: WM_USER, wParam: position (seconds), lParam: 114 + IPC_SET_POSITION, + + // uMsg: WM_USER, wParam: 0, lParam: 115, result: 1 if playing + IPC_IS_PLAYING, + + // uMsg: WM_USER, wParam: 0, lParam: 116, result: 1 if paused + IPC_IS_PAUSED, + + // uMsg: WM_USER, wParam: 0, lParam: 117 + IPC_GET_LIST_LENGTH, + + // uMsg: WM_USER, wParam: position, lParam: 118 + IPC_SET_LIST_POS, + + // uMsg: WM_USER, wParam: 0, lParam: 119 + IPC_GET_LIST_ITEM, + + // uMsg: WM_USER, wParam: hwnd, lParam: 120 + // CAD sends this mesage to the player on startup. The player + // should then send all future WM_COPYDATA messages to this window. + IPC_SET_CALLBACK_HWND, + + // uMsg: WM_USER, wParam: 0, lParam: 121 + IPC_GET_LIST_POS, + + // uMsg: WM_USER, wParam: 0, lParam: 122, result: position (in seconds) + IPC_GET_POSITION, + + // uMsg: WM_USER, wParam: 0, lParam: 123 [Sent by player] + // The player should send this message when the track changes. + IPC_TRACK_CHANGED_NOTIFICATION, + + // uMsg: WM_USER, wParam: 0, lParam: 124 + IPC_SHOW_PLAYER_WINDOW, + + // uMsg: WM_USER, wParam: 0, lParam: 125, result: 0 (stopped), 1 (playing), or 2 (paused) + IPC_GET_PLAYER_STATE, + + // uMsg: WM_USER, wParam: 0, lParam: 126 [Sent by player] + // The player should send this notification when the play state changes. + IPC_PLAYER_STATE_CHANGED_NOTIFICATION, + + // uMsg: WM_USER, wParam: 0, lParam: 127 [Not implemented in CAD yet] + IPC_AUTOENQUEUE_OPTIONS, + + // uMsg: WM_USER, wParam: 0 or 1, lParam: 128 + IPC_SET_REPEAT, + + // uMsg: WM_USER, wParam: 0 or 1, lParam: 128 [Sent by/to player] + // The player should send this message when it quits. + // CAD will also send this message on exit. Upon receival, the player should + // disconnect the communication interface and get ready for a IPC_SET_CALLBACK_HWND message. + IPC_SHUTDOWN_NOTIFICATION, + + // uMsg: WM_USER, wParam: 0, lParam: 130, result: 1 if shuffle is active + IPC_GET_REPEAT, + + // uMsg: WM_USER, wParam: 0, lParam: 131 + // The player should quit completely upon receival. + IPC_CLOSE_PLAYER, + + // uMsg: WM_USER, wParam: 0, lParam: 140, result: 1 if shuffle is active + IPC_GET_SHUFFLE = 140, + + // uMsg: WM_USER, wParam: 0 or 1, lParam: 141 + IPC_SET_SHUFFLE, + + // uMsg: WM_USER, wParam: rating (0 - 10), lParam: 141 [Sent by/to player] + // CAD sends this message to the player with the new rating (0 - 10). The + // player sends this message when the rating changes. + IPC_RATING_CHANGED_NOTIFICATION = 639, + + // uMsg: WM_COPYDATA, wParam: 700, lParam: COPYDATASTRUCT [Sent by player] + // The player sends this message on start up. Refer to the SDK manual for detailed info. + IPC_REGISTER_PLAYER = 700, // Sent by player to CAD on startup. + + // uMsg: WM_COPYDATA, wParam: 701, lParam: COPYDATASTRUCT [Sent by player] + // The player sends this when it receives the IPC_GET_CURRENT_TRACK message. + IPC_CURRENT_TRACK_INFO, + + // uMsg: WM_COPYDATA, wParam: 702, lParam: COPYDATASTRUCT [Sent by player] + // The player sends this when it receives the IPC_GET_CURRENT_LYRICS message. + IPC_CURRENT_LYRICS, + + // uMsg: WM_COPYDATA, wParam: 703, lParam: COPYDATASTRUCT [Sent by player] + // The player sends this when, for example, new lyrics have been retrieved. + IPC_NEW_LYRICS, + + // uMsg: WM_COPYDATA, wParam: 800, lParam: COPYDATASTRUCT [Sent by player] + // The player sends this when a new cover is available for playing track. + IPC_NEW_COVER = 800, + + // uMsg: WM_USER, wParam: 0, lParam: 801 + IPC_GET_CURRENT_LYRICS, + + + IPC_ADDFILE_PLAY_PLAYLIST, + IPC_ADDFILE_QUEUE_PLAYLIST +}; + +#endif