288 lines
7.3 KiB
C++
288 lines
7.3 KiB
C++
|
#include "main.h"
|
||
|
#include "./winampHook.h"
|
||
|
#include "./ifc_winamphook.h"
|
||
|
#include "../winamp/wa_ipc.h"
|
||
|
|
||
|
#include <windows.h>
|
||
|
|
||
|
#define WINAMP_REFRESHSKIN 40291
|
||
|
#define WHPROCRECOVERY L"WaHookProcRecovery"
|
||
|
|
||
|
static ATOM WAWNDATOM = 0;
|
||
|
#define GetWinampHook(__hwnd) ((WinampHook*)GetProp((__hwnd), MAKEINTATOM(WAWNDATOM)))
|
||
|
|
||
|
WinampHook::WinampHook(HWND hwndWinamp)
|
||
|
: ref(1), hwnd(hwndWinamp), originalProc(NULL), flags(0), lastCookie(0)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
WinampHook::~WinampHook()
|
||
|
{
|
||
|
DetachFromWinamp();
|
||
|
|
||
|
if (0 != WAWNDATOM)
|
||
|
{
|
||
|
GlobalDeleteAtom(WAWNDATOM);
|
||
|
WAWNDATOM = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HRESULT WinampHook::CreateInstance(HWND hwndWinamp, WinampHook **instance)
|
||
|
{
|
||
|
if (NULL == instance) return E_POINTER;
|
||
|
|
||
|
*instance = NULL;
|
||
|
|
||
|
if (NULL == hwndWinamp || FALSE == IsWindow(hwndWinamp))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
*instance = new WinampHook(hwndWinamp);
|
||
|
if (NULL == *instance) return E_OUTOFMEMORY;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
ULONG WinampHook::AddRef()
|
||
|
{
|
||
|
return InterlockedIncrement((LONG*)&ref);
|
||
|
}
|
||
|
|
||
|
ULONG WinampHook::Release()
|
||
|
{
|
||
|
if (0 == ref)
|
||
|
return ref;
|
||
|
|
||
|
LONG r = InterlockedDecrement((LONG*)&ref);
|
||
|
if (0 == r)
|
||
|
delete(this);
|
||
|
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
HRESULT WinampHook::RegisterCallback(ifc_winamphook *callback, UINT *cookie)
|
||
|
{
|
||
|
if (NULL == cookie) return E_POINTER;
|
||
|
*cookie = 0;
|
||
|
|
||
|
if (NULL == callback) return E_INVALIDARG;
|
||
|
|
||
|
if (FAILED(AttachToWinamp()))
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
*cookie = ++lastCookie;
|
||
|
|
||
|
callbackMap.insert({ *cookie, callback });
|
||
|
callback->AddRef();
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT WinampHook::UnregisterCallback(UINT cookie)
|
||
|
{
|
||
|
if (0 == cookie) return E_INVALIDARG;
|
||
|
|
||
|
for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
|
||
|
{
|
||
|
if (cookie == iter->first)
|
||
|
{
|
||
|
ifc_winamphook *hook = iter->second;
|
||
|
callbackMap.erase(iter);
|
||
|
|
||
|
if (NULL != hook)
|
||
|
hook->Release();
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
}
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
|
||
|
HWND WinampHook::GetWinamp()
|
||
|
{
|
||
|
return hwnd;
|
||
|
}
|
||
|
|
||
|
LRESULT WinampHook::CallPrevWinampProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
if (NULL == originalProc || NULL == hwnd) return 0;
|
||
|
return (0 != (flagUnicode & flags)) ?
|
||
|
CallWindowProcW(originalProc, hwnd, uMsg, wParam, lParam) :
|
||
|
CallWindowProcA(originalProc, hwnd, uMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
LRESULT WinampHook::CallDefWinampProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
if (NULL == hwnd) return 0;
|
||
|
return (0 != (flagUnicode & flags)) ?
|
||
|
DefWindowProcW(hwnd, uMsg, wParam, lParam) :
|
||
|
DefWindowProcA(hwnd, uMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
HRESULT WinampHook::AttachToWinamp()
|
||
|
{
|
||
|
if (NULL == hwnd || !IsWindow(hwnd)) return E_UNEXPECTED;
|
||
|
|
||
|
if (0 == WAWNDATOM)
|
||
|
{
|
||
|
WAWNDATOM = GlobalAddAtom(L"WinampHook");
|
||
|
if (0 == WAWNDATOM) return E_FAIL;
|
||
|
}
|
||
|
|
||
|
WinampHook *hookInstance = GetWinampHook(hwnd);
|
||
|
if (this == hookInstance) return S_FALSE;
|
||
|
|
||
|
if (NULL != hookInstance || NULL != originalProc)
|
||
|
return E_FAIL;
|
||
|
|
||
|
flags = 0;
|
||
|
if (IsWindowUnicode(hwnd)) flags |= flagUnicode;
|
||
|
|
||
|
originalProc = (WNDPROC)(LONG_PTR)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)WinampWindowProc);
|
||
|
if (NULL == originalProc || FALSE == SetProp(hwnd, MAKEINTATOM(WAWNDATOM), this))
|
||
|
{
|
||
|
if (NULL != originalProc)
|
||
|
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)originalProc);
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT WinampHook::DetachFromWinamp()
|
||
|
{
|
||
|
if (NULL == hwnd || !IsWindow(hwnd)) return E_UNEXPECTED;
|
||
|
if (0 == WAWNDATOM) return E_FAIL;
|
||
|
|
||
|
for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
|
||
|
{
|
||
|
if (NULL != iter->second)
|
||
|
iter->second->Release();
|
||
|
}
|
||
|
callbackMap.clear();
|
||
|
|
||
|
WinampHook *hookInstance = GetWinampHook(hwnd);
|
||
|
if (this != hookInstance) return E_FAIL;
|
||
|
|
||
|
RemoveProp(hwnd, MAKEINTATOM(WAWNDATOM));
|
||
|
WNDPROC currentProc = (WNDPROC)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_WNDPROC);
|
||
|
if (currentProc == WinampWindowProc)
|
||
|
{
|
||
|
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)originalProc);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetProp(hwnd, WHPROCRECOVERY, (HANDLE)originalProc);
|
||
|
}
|
||
|
originalProc = NULL;
|
||
|
flags = 0;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
LRESULT WinampHook::OnWinampDestroy()
|
||
|
{
|
||
|
WNDPROC proc = originalProc;
|
||
|
DetachFromWinamp();
|
||
|
return (IsWindowUnicode(hwnd)) ?
|
||
|
CallWindowProcW(proc, hwnd, WM_DESTROY, 0, 0L) :
|
||
|
CallWindowProcA(proc, hwnd, WM_DESTROY, 0, 0L);
|
||
|
}
|
||
|
|
||
|
LRESULT WinampHook::OnWinampIPC(UINT commandId, WPARAM param)
|
||
|
{
|
||
|
switch(commandId)
|
||
|
{
|
||
|
case IPC_CB_RESETFONT:
|
||
|
for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
|
||
|
if (NULL != iter->second) iter->second->ResetFont();
|
||
|
break;
|
||
|
|
||
|
case IPC_HOOK_OKTOQUIT:
|
||
|
for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
|
||
|
if (NULL != iter->second && S_FALSE == iter->second->IsQuitAllowed()) return 0;
|
||
|
break;
|
||
|
|
||
|
case IPC_SKIN_CHANGED:
|
||
|
{
|
||
|
WCHAR szBuffer[MAX_PATH*2] = {0};
|
||
|
SENDWAIPC(hwnd, IPC_GETSKINW, szBuffer);
|
||
|
for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
|
||
|
if (NULL != iter->second) iter->second->SkinChanged(szBuffer);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case IPC_FF_ONCOLORTHEMECHANGED:
|
||
|
if (FALSE != IS_INTRESOURCE(param))
|
||
|
param = 0L;
|
||
|
for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
|
||
|
if (NULL != iter->second) iter->second->SkinColorChange((LPCWSTR)param);
|
||
|
break;
|
||
|
|
||
|
case IPC_FILE_TAG_MAY_HAVE_UPDATED:
|
||
|
{
|
||
|
WCHAR szBuffer[MAX_PATH*2] = {0};
|
||
|
param = (0 != MultiByteToWideChar(CP_ACP, 0, (char*)param, -1, szBuffer, ARRAYSIZE(szBuffer))) ?
|
||
|
(WPARAM)szBuffer : 0L;
|
||
|
|
||
|
for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
|
||
|
if (NULL != iter->second) iter->second->FileMetaChange((LPCWSTR)param);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case IPC_FILE_TAG_MAY_HAVE_UPDATEDW:
|
||
|
for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
|
||
|
if (NULL != iter->second) iter->second->FileMetaChange((LPCWSTR)param);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return CallPrevWinampProc(WM_WA_IPC, param, (LPARAM)commandId);
|
||
|
}
|
||
|
|
||
|
void WinampHook::OnWinampCommand(UINT commandId, UINT controlId, HWND hControl)
|
||
|
{
|
||
|
switch(commandId)
|
||
|
{
|
||
|
case WINAMP_REFRESHSKIN:
|
||
|
for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
|
||
|
if (NULL != iter->second) iter->second->SkinChanging();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void WinampHook::OnSysColorChange()
|
||
|
{
|
||
|
for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
|
||
|
if (NULL != iter->second) iter->second->SysColorChange();
|
||
|
}
|
||
|
|
||
|
LRESULT WinampHook::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
switch(uMsg)
|
||
|
{
|
||
|
case WM_DESTROY: return OnWinampDestroy();
|
||
|
case WM_WA_IPC: return OnWinampIPC((UINT)lParam, wParam);
|
||
|
case WM_COMMAND: OnWinampCommand(LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break;
|
||
|
case WM_SYSCOLORCHANGE: OnSysColorChange(); break;
|
||
|
}
|
||
|
return CallPrevWinampProc(uMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
static LRESULT CALLBACK WinampWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
WinampHook *hookInstance = GetWinampHook(hwnd);
|
||
|
if (NULL == hookInstance)
|
||
|
{
|
||
|
WNDPROC recovery = (WNDPROC)GetProp(hwnd, WHPROCRECOVERY);
|
||
|
if (NULL != recovery)
|
||
|
{
|
||
|
return (IsWindowUnicode(hwnd)) ?
|
||
|
CallWindowProcW(recovery, hwnd, uMsg, wParam, lParam) :
|
||
|
CallWindowProcA(recovery, hwnd, uMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
return (IsWindowUnicode(hwnd)) ?
|
||
|
DefWindowProcW(hwnd, uMsg, wParam, lParam) :
|
||
|
DefWindowProcA(hwnd, uMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
return hookInstance->WindowProc(uMsg, wParam, lParam);
|
||
|
}
|