/* Copyright (C) 2012-14 Miranda NG team (http://miranda-ng.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "commonheaders.h" struct MSubclassData { HWND m_hWnd; int m_iHooks; WNDPROC *m_hooks; WNDPROC m_origWndProc; ~MSubclassData() { free(m_hooks); } }; static LIST arSubclass(10, LIST::FTSortFunc(HandleKeySortT)); ///////////////////////////////////////////////////////////////////////////////////////// static LRESULT CALLBACK MSubclassWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { MSubclassData *p = arSubclass.find((MSubclassData*)&hwnd); if (p != NULL) { if (p->m_iHooks) return p->m_hooks[p->m_iHooks-1](hwnd, uMsg, wParam, lParam); return p->m_origWndProc(hwnd, uMsg, wParam, lParam); } return DefWindowProc(hwnd, uMsg, wParam, lParam); } MIR_CORE_DLL(void) mir_subclassWindow(HWND hWnd, WNDPROC wndProc) { MSubclassData *p = arSubclass.find((MSubclassData*)&hWnd); if (p == NULL) { p = new MSubclassData; p->m_hWnd = hWnd; p->m_origWndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)MSubclassWndProc); p->m_iHooks = 0; p->m_hooks = (WNDPROC*)malloc( sizeof(WNDPROC)); arSubclass.insert(p); } else { for (int i=0; i < p->m_iHooks; i++) if (p->m_hooks[i] == wndProc) return; p->m_hooks = (WNDPROC*)realloc(p->m_hooks, (p->m_iHooks+1)*sizeof(WNDPROC)); } p->m_hooks[p->m_iHooks++] = wndProc; } MIR_CORE_DLL(void) mir_subclassWindowFull(HWND hWnd, WNDPROC wndProc, WNDPROC oldWndProc) { MSubclassData *p = arSubclass.find((MSubclassData*)&hWnd); if (p == NULL) { p = new MSubclassData; p->m_hWnd = hWnd; p->m_origWndProc = oldWndProc; p->m_iHooks = 0; p->m_hooks = (WNDPROC*)malloc( sizeof(WNDPROC)); arSubclass.insert(p); SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)MSubclassWndProc); } else { for (int i=0; i < p->m_iHooks; i++) if (p->m_hooks[i] == wndProc) return; p->m_hooks = (WNDPROC*)realloc(p->m_hooks, (p->m_iHooks+1)*sizeof(WNDPROC)); } p->m_hooks[p->m_iHooks++] = wndProc; } ///////////////////////////////////////////////////////////////////////////////////////// static void removeHook(MSubclassData *p, int idx) { WNDPROC saveProc = p->m_hooks[idx]; // untie hook from a window to prevent calling mir_callNextSubclass from saveProc for (int i=idx+1; i < p->m_iHooks; i++) p->m_hooks[i-1] = p->m_hooks[i]; p->m_iHooks--; } MIR_CORE_DLL(void) mir_unsubclassWindow(HWND hWnd, WNDPROC wndProc) { MSubclassData *p = arSubclass.find((MSubclassData*)&hWnd); if (p == NULL) return; for (int i=0; i < p->m_iHooks; i++) { if (p->m_hooks[i] == wndProc) { removeHook(p, i); i--; } } if (p->m_iHooks == 0) { arSubclass.remove(p); delete p; } } ///////////////////////////////////////////////////////////////////////////////////////// MIR_CORE_DLL(LRESULT) mir_callNextSubclass(HWND hWnd, WNDPROC wndProc, UINT uMsg, WPARAM wParam, LPARAM lParam) { MSubclassData *p = arSubclass.find((MSubclassData*)&hWnd); if (p == NULL) return DefWindowProc(hWnd, uMsg, wParam, lParam); for (int i=p->m_iHooks-1; i >= 0; i--) { if (p->m_hooks[i] != wndProc) continue; // next hook exists, call it if (i != 0) return p->m_hooks[i-1](hWnd, uMsg, wParam, lParam); // last hook called, ping the default window procedure if (uMsg != WM_DESTROY) return p->m_origWndProc(hWnd, uMsg, wParam, lParam); WNDPROC saveProc = p->m_origWndProc; arSubclass.remove(p); delete p; SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)saveProc); return saveProc(hWnd, uMsg, wParam, lParam); } // invalid / closed hook return 0; } ///////////////////////////////////////////////////////////////////////////////////////// MIR_CORE_DLL(void) KillModuleSubclassing(HMODULE hInst) { for (int i=arSubclass.getCount()-1; i >= 0; i--) { MSubclassData *p = arSubclass[i]; for (int j=0; j < p->m_iHooks; j++) { if ( GetInstByAddress(p->m_hooks[j]) == hInst) { removeHook(p, j); j--; } } if (p->m_iHooks == 0) { arSubclass.remove(p); delete p; } } }