1
0

winampHook.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. #include "main.h"
  2. #include "./winampHook.h"
  3. #include "./ifc_winamphook.h"
  4. #include "../winamp/wa_ipc.h"
  5. #include <windows.h>
  6. #define WINAMP_REFRESHSKIN 40291
  7. #define WHPROCRECOVERY L"WaHookProcRecovery"
  8. static ATOM WAWNDATOM = 0;
  9. #define GetWinampHook(__hwnd) ((WinampHook*)GetProp((__hwnd), MAKEINTATOM(WAWNDATOM)))
  10. WinampHook::WinampHook(HWND hwndWinamp)
  11. : ref(1), hwnd(hwndWinamp), originalProc(NULL), flags(0), lastCookie(0)
  12. {
  13. }
  14. WinampHook::~WinampHook()
  15. {
  16. DetachFromWinamp();
  17. if (0 != WAWNDATOM)
  18. {
  19. GlobalDeleteAtom(WAWNDATOM);
  20. WAWNDATOM = 0;
  21. }
  22. }
  23. HRESULT WinampHook::CreateInstance(HWND hwndWinamp, WinampHook **instance)
  24. {
  25. if (NULL == instance) return E_POINTER;
  26. *instance = NULL;
  27. if (NULL == hwndWinamp || FALSE == IsWindow(hwndWinamp))
  28. return E_INVALIDARG;
  29. *instance = new WinampHook(hwndWinamp);
  30. if (NULL == *instance) return E_OUTOFMEMORY;
  31. return S_OK;
  32. }
  33. ULONG WinampHook::AddRef()
  34. {
  35. return InterlockedIncrement((LONG*)&ref);
  36. }
  37. ULONG WinampHook::Release()
  38. {
  39. if (0 == ref)
  40. return ref;
  41. LONG r = InterlockedDecrement((LONG*)&ref);
  42. if (0 == r)
  43. delete(this);
  44. return r;
  45. }
  46. HRESULT WinampHook::RegisterCallback(ifc_winamphook *callback, UINT *cookie)
  47. {
  48. if (NULL == cookie) return E_POINTER;
  49. *cookie = 0;
  50. if (NULL == callback) return E_INVALIDARG;
  51. if (FAILED(AttachToWinamp()))
  52. return E_UNEXPECTED;
  53. *cookie = ++lastCookie;
  54. callbackMap.insert({ *cookie, callback });
  55. callback->AddRef();
  56. return S_OK;
  57. }
  58. HRESULT WinampHook::UnregisterCallback(UINT cookie)
  59. {
  60. if (0 == cookie) return E_INVALIDARG;
  61. for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
  62. {
  63. if (cookie == iter->first)
  64. {
  65. ifc_winamphook *hook = iter->second;
  66. callbackMap.erase(iter);
  67. if (NULL != hook)
  68. hook->Release();
  69. return S_OK;
  70. }
  71. }
  72. return S_FALSE;
  73. }
  74. HWND WinampHook::GetWinamp()
  75. {
  76. return hwnd;
  77. }
  78. LRESULT WinampHook::CallPrevWinampProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
  79. {
  80. if (NULL == originalProc || NULL == hwnd) return 0;
  81. return (0 != (flagUnicode & flags)) ?
  82. CallWindowProcW(originalProc, hwnd, uMsg, wParam, lParam) :
  83. CallWindowProcA(originalProc, hwnd, uMsg, wParam, lParam);
  84. }
  85. LRESULT WinampHook::CallDefWinampProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
  86. {
  87. if (NULL == hwnd) return 0;
  88. return (0 != (flagUnicode & flags)) ?
  89. DefWindowProcW(hwnd, uMsg, wParam, lParam) :
  90. DefWindowProcA(hwnd, uMsg, wParam, lParam);
  91. }
  92. HRESULT WinampHook::AttachToWinamp()
  93. {
  94. if (NULL == hwnd || !IsWindow(hwnd)) return E_UNEXPECTED;
  95. if (0 == WAWNDATOM)
  96. {
  97. WAWNDATOM = GlobalAddAtom(L"WinampHook");
  98. if (0 == WAWNDATOM) return E_FAIL;
  99. }
  100. WinampHook *hookInstance = GetWinampHook(hwnd);
  101. if (this == hookInstance) return S_FALSE;
  102. if (NULL != hookInstance || NULL != originalProc)
  103. return E_FAIL;
  104. flags = 0;
  105. if (IsWindowUnicode(hwnd)) flags |= flagUnicode;
  106. originalProc = (WNDPROC)(LONG_PTR)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)WinampWindowProc);
  107. if (NULL == originalProc || FALSE == SetProp(hwnd, MAKEINTATOM(WAWNDATOM), this))
  108. {
  109. if (NULL != originalProc)
  110. SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)originalProc);
  111. return E_FAIL;
  112. }
  113. return S_OK;
  114. }
  115. HRESULT WinampHook::DetachFromWinamp()
  116. {
  117. if (NULL == hwnd || !IsWindow(hwnd)) return E_UNEXPECTED;
  118. if (0 == WAWNDATOM) return E_FAIL;
  119. for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
  120. {
  121. if (NULL != iter->second)
  122. iter->second->Release();
  123. }
  124. callbackMap.clear();
  125. WinampHook *hookInstance = GetWinampHook(hwnd);
  126. if (this != hookInstance) return E_FAIL;
  127. RemoveProp(hwnd, MAKEINTATOM(WAWNDATOM));
  128. WNDPROC currentProc = (WNDPROC)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_WNDPROC);
  129. if (currentProc == WinampWindowProc)
  130. {
  131. SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)originalProc);
  132. }
  133. else
  134. {
  135. SetProp(hwnd, WHPROCRECOVERY, (HANDLE)originalProc);
  136. }
  137. originalProc = NULL;
  138. flags = 0;
  139. return S_OK;
  140. }
  141. LRESULT WinampHook::OnWinampDestroy()
  142. {
  143. WNDPROC proc = originalProc;
  144. DetachFromWinamp();
  145. return (IsWindowUnicode(hwnd)) ?
  146. CallWindowProcW(proc, hwnd, WM_DESTROY, 0, 0L) :
  147. CallWindowProcA(proc, hwnd, WM_DESTROY, 0, 0L);
  148. }
  149. LRESULT WinampHook::OnWinampIPC(UINT commandId, WPARAM param)
  150. {
  151. switch(commandId)
  152. {
  153. case IPC_CB_RESETFONT:
  154. for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
  155. if (NULL != iter->second) iter->second->ResetFont();
  156. break;
  157. case IPC_HOOK_OKTOQUIT:
  158. for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
  159. if (NULL != iter->second && S_FALSE == iter->second->IsQuitAllowed()) return 0;
  160. break;
  161. case IPC_SKIN_CHANGED:
  162. {
  163. WCHAR szBuffer[MAX_PATH*2] = {0};
  164. SENDWAIPC(hwnd, IPC_GETSKINW, szBuffer);
  165. for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
  166. if (NULL != iter->second) iter->second->SkinChanged(szBuffer);
  167. }
  168. break;
  169. case IPC_FF_ONCOLORTHEMECHANGED:
  170. if (FALSE != IS_INTRESOURCE(param))
  171. param = 0L;
  172. for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
  173. if (NULL != iter->second) iter->second->SkinColorChange((LPCWSTR)param);
  174. break;
  175. case IPC_FILE_TAG_MAY_HAVE_UPDATED:
  176. {
  177. WCHAR szBuffer[MAX_PATH*2] = {0};
  178. param = (0 != MultiByteToWideChar(CP_ACP, 0, (char*)param, -1, szBuffer, ARRAYSIZE(szBuffer))) ?
  179. (WPARAM)szBuffer : 0L;
  180. for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
  181. if (NULL != iter->second) iter->second->FileMetaChange((LPCWSTR)param);
  182. }
  183. break;
  184. case IPC_FILE_TAG_MAY_HAVE_UPDATEDW:
  185. for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
  186. if (NULL != iter->second) iter->second->FileMetaChange((LPCWSTR)param);
  187. break;
  188. }
  189. return CallPrevWinampProc(WM_WA_IPC, param, (LPARAM)commandId);
  190. }
  191. void WinampHook::OnWinampCommand(UINT commandId, UINT controlId, HWND hControl)
  192. {
  193. switch(commandId)
  194. {
  195. case WINAMP_REFRESHSKIN:
  196. for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
  197. if (NULL != iter->second) iter->second->SkinChanging();
  198. break;
  199. }
  200. }
  201. void WinampHook::OnSysColorChange()
  202. {
  203. for(CallbackMap::iterator iter = callbackMap.begin(); iter != callbackMap.end(); iter++)
  204. if (NULL != iter->second) iter->second->SysColorChange();
  205. }
  206. LRESULT WinampHook::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
  207. {
  208. switch(uMsg)
  209. {
  210. case WM_DESTROY: return OnWinampDestroy();
  211. case WM_WA_IPC: return OnWinampIPC((UINT)lParam, wParam);
  212. case WM_COMMAND: OnWinampCommand(LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break;
  213. case WM_SYSCOLORCHANGE: OnSysColorChange(); break;
  214. }
  215. return CallPrevWinampProc(uMsg, wParam, lParam);
  216. }
  217. static LRESULT CALLBACK WinampWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  218. {
  219. WinampHook *hookInstance = GetWinampHook(hwnd);
  220. if (NULL == hookInstance)
  221. {
  222. WNDPROC recovery = (WNDPROC)GetProp(hwnd, WHPROCRECOVERY);
  223. if (NULL != recovery)
  224. {
  225. return (IsWindowUnicode(hwnd)) ?
  226. CallWindowProcW(recovery, hwnd, uMsg, wParam, lParam) :
  227. CallWindowProcA(recovery, hwnd, uMsg, wParam, lParam);
  228. }
  229. return (IsWindowUnicode(hwnd)) ?
  230. DefWindowProcW(hwnd, uMsg, wParam, lParam) :
  231. DefWindowProcA(hwnd, uMsg, wParam, lParam);
  232. }
  233. return hookInstance->WindowProc(uMsg, wParam, lParam);
  234. }