aboutsummaryrefslogtreecommitdiff
path: root/Src/omBrowser/winampHook.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/omBrowser/winampHook.cpp')
-rw-r--r--Src/omBrowser/winampHook.cpp288
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