diff options
Diffstat (limited to 'Src/omBrowser/winampHook.cpp')
-rw-r--r-- | Src/omBrowser/winampHook.cpp | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/Src/omBrowser/winampHook.cpp b/Src/omBrowser/winampHook.cpp new file mode 100644 index 00000000..ba4604be --- /dev/null +++ b/Src/omBrowser/winampHook.cpp @@ -0,0 +1,288 @@ +#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); +}
\ No newline at end of file |