winamp/Src/omBrowser/winampHook.cpp
2024-09-24 14:54:57 +02:00

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