/* Copyright (C) 2012-13 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; } ///////////////////////////////////////////////////////////////////////////////////////// MIR_CORE_DLL(void) mir_unsubclassWindow(HWND hWnd) { } ///////////////////////////////////////////////////////////////////////////////////////// MIR_CORE_DLL(LRESULT) mir_callNextSubclass(HWND hWnd, WNDPROC wndProc, UINT uMsg, WPARAM wParam, LPARAM lParam) { MSubclassData *p = arSubclass.find((MSubclassData*)&hWnd); if (p) { for (int i=p->m_iHooks-1; i >= 0; i--) { if (p->m_hooks[i] == wndProc) { // next hook exitst, 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) { WNDPROC saveProc = p->m_origWndProc; arSubclass.remove(p); delete p; SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)saveProc); LONG res = 0; __try { res = saveProc(hWnd, uMsg, wParam, lParam); } __except(EXCEPTION_EXECUTE_HANDLER) { } return res; } return p->m_origWndProc(hWnd, uMsg, wParam, lParam); } } // invalid / closed hook return 0; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } ///////////////////////////////////////////////////////////////////////////////////////// MIR_CORE_DLL(void) KillModuleSubclassing(HMODULE hInst) { for (int i=0; i < arSubclass.getCount(); i++) { MSubclassData *p = arSubclass[i]; for (int j=0; j < p->m_iHooks; ) { if ( GetInstByAddress(p->m_hooks[j]) == hInst) { WNDPROC saveProc = p->m_hooks[j]; // untie hook from a window to prevent calling mir_callNextSubclass from saveProc for (int k=j+1; k < p->m_iHooks; k++) p->m_hooks[k-1] = p->m_hooks[k]; p->m_iHooks--; // emulate window destruction saveProc(p->m_hWnd, WM_DESTROY, 0, 0); saveProc(p->m_hWnd, WM_NCDESTROY, 0, 0); } else j++; } } }