summaryrefslogtreecommitdiff
path: root/Help/dlgboxsubclass.c
diff options
context:
space:
mode:
Diffstat (limited to 'Help/dlgboxsubclass.c')
-rw-r--r--Help/dlgboxsubclass.c455
1 files changed, 455 insertions, 0 deletions
diff --git a/Help/dlgboxsubclass.c b/Help/dlgboxsubclass.c
new file mode 100644
index 0000000..ff0706c
--- /dev/null
+++ b/Help/dlgboxsubclass.c
@@ -0,0 +1,455 @@
+/*
+Miranda IM Help Plugin
+Copyright (C) 2002 Richard Hughes, 2005-2007 H. Herkenrath
+
+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; either version 2
+of the License, or (at your option) any later version.
+
+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 (Help-License.txt); if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include <tchar.h>
+#define _WIN32_WINNT 0x0400
+#define __RPCASYNC_H__ /* header shows warnings in VS6 */
+#include <windows.h>
+#include <win2k.h>
+
+#define MIRANDA_VER 0x0600
+#include <newpluginapi.h>
+#include <m_langpack.h>
+#include <stdio.h>
+#include <m_system.h>
+#include <m_utils.h>
+#include "help.h"
+#include "m_help.h"
+
+#include "resource.h"
+
+#define SC_CONTEXTHELP_SEPARATOR SC_SEPARATOR+1
+#define SC_CONTEXTHELP_DIALOG SC_CONTEXTHELP+1
+
+#define PROP_CONTEXTSTATE _T("HelpPlugin_ContextState")
+#define PROPF_MENUFORCED 0x01 // always show help context menu for ctl (override default)
+#define PROPF_MENUDISABLED 0x02 // never show help context menu for ctl
+#define PROPF_AUTOTIPFORCED 0x04 // always show autotip for ctl (override default)
+#define PROPF_AUTOTIPDISABLED 0x08 // never show autotip for ctl
+
+extern HINSTANCE hInst;
+extern HWND hwndHelpDlg;
+extern WORD settingAutoTipDelay;
+static HHOOK hMessageHook,hKeyboardHook,hEatNextMouseHook=NULL;
+static HANDLE hServiceShowHelp,hServiceSetContext;
+
+struct DlgBoxSubclassData {
+ HWND hwndDlg;
+ WNDPROC pfnOldWndProc;
+ DWORD flags;
+} static *dlgBoxSubclass=NULL;
+static int dlgBoxSubclassCount=0;
+static CRITICAL_SECTION csDlgBoxSubclass;
+
+#define DBSDF_MINIMIZABLE 0x01 // WS_MINIMIZEBOX style was set on hooked window
+#define DBSDF_MAXIMIZABLE 0x02 // WS_MAXIMIZEBOX style was set on hooked window
+
+struct FindChildAtPointData {
+ HWND hwnd;
+ POINT pt;
+ int bestArea;
+};
+
+// ChildWindowFromPoint() messes up with group boxes
+static BOOL CALLBACK FindChildAtPointEnumProc(HWND hwnd,LPARAM lParam)
+{
+ if(IsWindowVisible(hwnd)) {
+ struct FindChildAtPointData *fcap=(struct FindChildAtPointData*)lParam;
+ RECT rcVisible,rc,rcParent;
+ GetWindowRect(hwnd,&rc);
+ GetWindowRect(GetParent(hwnd),&rcParent);
+ IntersectRect(&rcVisible,&rcParent,&rc);
+ if(PtInRect(&rcVisible,fcap->pt)) {
+ int thisArea=(rc.bottom-rc.top)*(rc.right-rc.left);
+ if(thisArea && (thisArea<fcap->bestArea || fcap->bestArea==0)) {
+ fcap->bestArea=thisArea;
+ fcap->hwnd=hwnd;
+ }
+ }
+ }
+ return TRUE;
+}
+
+// IsChild() messes up with owned windows
+int IsRealChild(HWND hwndParent,HWND hwnd)
+{
+ while(hwnd!=NULL) {
+ if(hwnd==hwndParent) return 1;
+ if(hwndParent==GetWindow(hwnd,GW_OWNER)) return 0;
+ hwnd=GetParent(hwnd);
+ }
+ return 0;
+}
+
+static BOOL CALLBACK RemovePropForAllChildsEnumProc(HWND hwnd,LPARAM lParam)
+{
+ RemoveProp(hwnd,(TCHAR*)lParam);
+ return TRUE;
+}
+
+static HWND hwndMouseMoveDlg=NULL;
+static UINT idMouseMoveTimer=0;
+static LONG cursorPos=MAKELONG(-1,-1);
+static int openedAutoTip=0;
+static void CALLBACK NoMouseMoveForDelayTimerProc(HWND hwnd,UINT msg,UINT idTimer,DWORD time)
+{
+ POINT pt;
+ HWND hwndCtl;
+ struct FindChildAtPointData fcap;
+ UNREFERENCED_PARAMETER(msg);
+ UNREFERENCED_PARAMETER(time);
+
+ KillTimer(hwnd,idTimer);
+ if(idMouseMoveTimer!=idTimer) return;
+ idMouseMoveTimer=0;
+ if(!settingAutoTipDelay || !IsWindow(hwndMouseMoveDlg)) return;
+
+ ZeroMemory(&fcap,sizeof(fcap));
+ if(!GetCursorPos(&pt)) return;
+ // ChildWindowFromPoint() messes up with group boxes
+ fcap.hwnd=NULL;
+ fcap.pt=pt;
+ EnumChildWindows(hwndMouseMoveDlg,FindChildAtPointEnumProc,(LPARAM)&fcap);
+ hwndCtl=fcap.hwnd;
+ if(hwndCtl==NULL) {
+ ScreenToClient(hwndMouseMoveDlg,&pt);
+ hwndCtl=ChildWindowFromPointEx(hwndMouseMoveDlg,pt,CWP_SKIPINVISIBLE);
+ if(hwndCtl==NULL) return;
+ }
+ { LONG flags=(LONG)GetProp(hwndCtl,PROP_CONTEXTSTATE);
+ if(flags&PROPF_AUTOTIPDISABLED) return;
+ flags=SendMessage(hwndCtl,WM_GETDLGCODE,(WPARAM)VK_RETURN,(LPARAM)NULL);
+ if(flags&DLGC_HASSETSEL || flags&DLGC_WANTALLKEYS) return; // autotips on edits are annoying
+ }
+ { CURSORINFO ci;
+ BOOL (WINAPI *pfnGetCursorInfo)(CURSORINFO*);
+ ci.cbSize=sizeof(ci);
+ *(FARPROC*)&pfnGetCursorInfo=GetProcAddress(GetModuleHandleA("USER32"),"GetCursorInfo");
+ if(pfnGetCursorInfo && IsWinVer2000Plus()) // call not safe for WinNT4
+ if(pfnGetCursorInfo(&ci) && !(ci.flags&CURSOR_SHOWING)) return;
+ }
+ if(IsRealChild(hwndMouseMoveDlg,hwndCtl) && hwndHelpDlg==NULL) {
+ hwndHelpDlg=CreateDialog(hInst,MAKEINTRESOURCE(IDD_HELP),NULL,HelpDlgProc);
+ if(hwndHelpDlg==NULL) return;
+ openedAutoTip=1;
+ PostMessage(hwndHelpDlg,M_CHANGEHELPCONTROL,0,(LPARAM)hwndCtl);
+ }
+}
+
+static LRESULT CALLBACK KeyboardInputHookProc(int code,WPARAM wParam,LPARAM lParam)
+{
+ if(code==HC_ACTION && idMouseMoveTimer!=0) {
+ KillTimer(NULL,idMouseMoveTimer);
+ idMouseMoveTimer=0;
+ }
+ return CallNextHookEx(hKeyboardHook,code,wParam,lParam);
+}
+
+// workaround for WM_HELP (SC_CONTEXTHELP causes an additional WM_LBUTTONUP when selecting)
+static LRESULT CALLBACK EatNextMouseButtonUpHookProc(int code,WPARAM wParam,LPARAM lParam)
+{
+ if(code>=0 && wParam==WM_LBUTTONUP) {
+ UnhookWindowsHookEx(hEatNextMouseHook); // unhook ourselves
+ hEatNextMouseHook=NULL;
+ return -1;
+ }
+ return CallNextHookEx(hEatNextMouseHook,code,wParam,lParam);
+}
+
+static LRESULT CALLBACK DialogBoxSubclassProc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ WNDPROC pfnWndProc;
+ DWORD flags;
+ int i;
+
+ EnterCriticalSection(&csDlgBoxSubclass);
+ for(i=0;i<dlgBoxSubclassCount;i++)
+ if(dlgBoxSubclass[i].hwndDlg==hwndDlg) break;
+ if(i==dlgBoxSubclassCount) {
+ LeaveCriticalSection(&csDlgBoxSubclass);
+ return 0;
+ }
+ pfnWndProc=dlgBoxSubclass[i].pfnOldWndProc;
+ flags=dlgBoxSubclass[i].flags;
+ if(msg==WM_NCDESTROY) {
+ struct DlgBoxSubclassData *buf;
+ MoveMemory(dlgBoxSubclass+i,dlgBoxSubclass+i+1,sizeof(struct DlgBoxSubclassData)*(dlgBoxSubclassCount-i-1));
+ dlgBoxSubclassCount--;
+ buf=(struct DlgBoxSubclassData*)mir_realloc(dlgBoxSubclass,sizeof(struct DlgBoxSubclassData)*dlgBoxSubclassCount);
+ if(buf!=NULL) dlgBoxSubclass=buf;
+ else if(!dlgBoxSubclassCount) dlgBoxSubclass=NULL;
+ }
+ LeaveCriticalSection(&csDlgBoxSubclass);
+
+ switch(msg) {
+ case WM_INITMENUPOPUP:
+ if(flags&DBSDF_MINIMIZABLE || flags&DBSDF_MAXIMIZABLE) {
+ HMENU hMenu=GetSystemMenu(hwndDlg,FALSE);
+ int isMin,isMax;
+ if((HMENU)wParam!=hMenu) break;
+ isMin=IsIconic(hwndDlg);
+ isMax=IsZoomed(hwndDlg);
+ EnableMenuItem(hMenu,SC_RESTORE,MF_BYCOMMAND|(isMin || isMax)?MF_ENABLED:MF_GRAYED);
+ EnableMenuItem(hMenu,SC_MINIMIZE,MF_BYCOMMAND|(flags&DBSDF_MINIMIZABLE && !isMin)?MF_ENABLED:MF_GRAYED);
+ EnableMenuItem(hMenu,SC_MAXIMIZE,MF_BYCOMMAND|(flags&DBSDF_MAXIMIZABLE && !isMax)?MF_ENABLED:MF_GRAYED);
+ EnableMenuItem(hMenu,SC_SIZE,MF_BYCOMMAND|(GetWindowLong(hwndDlg,GWL_STYLE)&WS_THICKFRAME && !isMin && !isMax)?MF_ENABLED:MF_GRAYED);
+ }
+ break;
+ case WM_MOUSEMOVE: // TrackMouseEvent() would disturb too much
+ if(!settingAutoTipDelay) break;
+ if(cursorPos==lParam) break;
+ cursorPos=lParam;
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_MOUSEWHEEL:
+ if(!settingAutoTipDelay) break;
+ if(msg!=WM_MOUSEMOVE && !idMouseMoveTimer) break;
+ if(openedAutoTip && IsWindow(hwndHelpDlg)) DestroyWindow(hwndHelpDlg);
+ openedAutoTip=0;
+ hwndMouseMoveDlg=hwndDlg;
+ if(hwndHelpDlg==NULL)
+ idMouseMoveTimer=SetTimer(NULL,idMouseMoveTimer,settingAutoTipDelay,NoMouseMoveForDelayTimerProc);
+ break;
+ case WM_CAPTURECHANGED:
+ if((HWND)lParam==hwndDlg) break;
+ case WM_SHOWWINDOW:
+ case WM_WINDOWPOSCHANGING:
+ case WM_MOVING:
+ case WM_SIZING:
+ case WM_CANCELMODE:
+ case WM_CHILDACTIVATE:
+ case WM_MOUSEACTIVATE:
+ case WM_ACTIVATEAPP:
+ case WM_ACTIVATE:
+ if(idMouseMoveTimer) KillTimer(NULL,idMouseMoveTimer);
+ idMouseMoveTimer=0;
+ break;
+ case WM_SYSCOMMAND:
+ if((UINT)wParam==SC_CONTEXTHELP_DIALOG) { // alt. "What's this Dialog?"
+ if(idMouseMoveTimer) KillTimer(NULL,idMouseMoveTimer);
+ idMouseMoveTimer=0;
+ if(hwndHelpDlg==NULL) {
+ hwndHelpDlg=CreateDialog(hInst,MAKEINTRESOURCE(IDD_HELP),NULL,HelpDlgProc);
+ if(hwndHelpDlg==NULL) break;
+ }
+ SendMessage(hwndHelpDlg,M_CHANGEHELPCONTROL,0,(LPARAM)hwndDlg);
+ return 0;
+ }
+ break;
+ case WM_CONTEXTMENU:
+ { POINT pt;
+ HWND hwndCtl;
+ struct FindChildAtPointData fcap;
+
+ // workaround for badly coded plugins that do display a context menu
+ // and pass the message to DefWindowProc afterwards (doing a "break;").
+ if(GetTickCount()-GetMessageTime()>10) return 0;
+
+ if(idMouseMoveTimer) KillTimer(NULL,idMouseMoveTimer);
+ idMouseMoveTimer=0;
+
+ ZeroMemory(&fcap,sizeof(fcap));
+ POINTSTOPOINT(pt,MAKEPOINTS(lParam));
+ // ChildWindowFromPoint() messes up with group boxes
+ fcap.hwnd=NULL;
+ fcap.pt=pt;
+ EnumChildWindows(hwndDlg,FindChildAtPointEnumProc,(LPARAM)&fcap);
+ hwndCtl=fcap.hwnd;
+ if(hwndCtl==NULL) {
+ ScreenToClient(hwndDlg,&pt);
+ hwndCtl=ChildWindowFromPointEx(hwndDlg,pt,CWP_SKIPINVISIBLE);
+ if(hwndCtl==NULL) break;
+ POINTSTOPOINT(pt,MAKEPOINTS(lParam));
+ }
+ { LONG flags=(LONG)GetProp(hwndCtl,PROP_CONTEXTSTATE);
+ if(flags&PROPF_MENUDISABLED) break;
+ else if(!(flags&PROPF_MENUFORCED)) {
+ int type=GetControlType(hwndCtl);
+ // showing a context menu on these looks silly (multi components)
+ if(type==CTLTYPE_TOOLBAR || type==CTLTYPE_LISTVIEW || type==CTLTYPE_TREEVIEW || type==CTLTYPE_STATUSBAR || type==CTLTYPE_CLC)
+ break;
+ }
+ }
+ if(IsRealChild(hwndDlg,hwndCtl)) {
+ HMENU hMenu=CreatePopupMenu();
+ AppendMenu(hMenu,MF_STRING,SC_CONTEXTHELP,(hwndCtl==hwndDlg)?TranslateT("&What's this Dialog?"):TranslateT("&What's this?"));
+ if(TrackPopupMenuEx(hMenu,TPM_LEFTALIGN|TPM_TOPALIGN|TPM_HORPOSANIMATION|TPM_VERPOSANIMATION|TPM_RIGHTBUTTON|TPM_RETURNCMD|TPM_NONOTIFY,pt.x,pt.y,hwndDlg,NULL)) {
+ if(hwndHelpDlg==NULL) {
+ hwndHelpDlg=CreateDialog(hInst,MAKEINTRESOURCE(IDD_HELP),NULL,HelpDlgProc);
+ if(hwndHelpDlg==NULL) {
+ DestroyMenu(hMenu);
+ break;
+ }
+ }
+ SendMessage(hwndHelpDlg,M_CHANGEHELPCONTROL,0,(LPARAM)hwndCtl);
+ }
+ DestroyMenu(hMenu);
+ }
+ return 0;
+ }
+ case WM_HELP:
+ { HELPINFO *hi=(HELPINFO*)lParam;
+ if(hi->iContextType!=HELPINFO_WINDOW) break;
+ // fix for SHBrowseForFolder() dialog, which sends unhandled help to parent
+ if(!IsRealChild(hwndDlg,hi->hItemHandle)) break;
+
+ if(idMouseMoveTimer) KillTimer(NULL,idMouseMoveTimer);
+ idMouseMoveTimer=0;
+
+ if(!IsWindow(hwndHelpDlg)) {
+ hwndHelpDlg=CreateDialog(hInst,MAKEINTRESOURCE(IDD_HELP),NULL,HelpDlgProc);
+ if(hwndHelpDlg==NULL) break;
+ }
+ SendMessage(hwndHelpDlg,M_CHANGEHELPCONTROL,0,(LPARAM)hi->hItemHandle);
+ // we need to eat the next WM_LBUTTONDOWN (if invoked by mouse)
+ if(GetKeyState(GetSystemMetrics(SM_SWAPBUTTON)?VK_RBUTTON:VK_LBUTTON)&0x8000 && hEatNextMouseHook==NULL)
+ hEatNextMouseHook=SetWindowsHookEx(WH_MOUSE,EatNextMouseButtonUpHookProc,NULL,GetCurrentThreadId());
+ return TRUE;
+ }
+ case WM_NCDESTROY:
+ if(idMouseMoveTimer) KillTimer(NULL,idMouseMoveTimer);
+ idMouseMoveTimer=0;
+ EnumChildWindows(hwndDlg,RemovePropForAllChildsEnumProc,(LPARAM)PROP_CONTEXTSTATE);
+ { TCHAR text[64];
+ mir_sntprintf(text,SIZEOF(text),_T("unhooked window 0x%X for context help\n"),hwndDlg);
+ OutputDebugString(text);
+ }
+ SetWindowLong(hwndDlg,GWL_WNDPROC,(LONG)pfnWndProc);
+ break;
+ }
+ return CallWindowProc(pfnWndProc,hwndDlg,msg,wParam,lParam);
+}
+
+static LRESULT CALLBACK HelpSendMessageHookProc(int code,WPARAM wParam,LPARAM lParam)
+{
+ if(code>=0) {
+ CWPSTRUCT *msg=(CWPSTRUCT*)lParam;
+ switch(msg->message) {
+ case WM_INITDIALOG: // dialogs and message boxes
+ if(GetClassLong(msg->hwnd,GCW_ATOM)!=32770) // class="#32770"
+ break;
+ if(msg->hwnd==hwndHelpDlg || (DLGPROC)GetWindowLong(msg->hwnd,DWL_DLGPROC)==HelpDlgProc)
+ break;
+#ifndef EDITOR
+ if((DLGPROC)GetWindowLong(msg->hwnd,DWL_DLGPROC)==ShadowDlgProc) break;
+#endif
+ { DWORD style,exStyle;
+ struct DlgBoxSubclassData *buf;
+
+ exStyle=GetWindowLong(msg->hwnd,GWL_EXSTYLE);
+ if(exStyle&WS_EX_CONTEXTHELP) break;
+ style=GetWindowLong(msg->hwnd,GWL_STYLE);
+
+ EnterCriticalSection(&csDlgBoxSubclass);
+ buf=(struct DlgBoxSubclassData*)mir_realloc(dlgBoxSubclass,sizeof(struct DlgBoxSubclassData)*(dlgBoxSubclassCount+1));
+ if(buf==NULL) {
+ LeaveCriticalSection(&csDlgBoxSubclass);
+ break;
+ }
+ dlgBoxSubclass=buf;
+ dlgBoxSubclass[dlgBoxSubclassCount].hwndDlg=msg->hwnd;
+ dlgBoxSubclass[dlgBoxSubclassCount].pfnOldWndProc=(WNDPROC)SetWindowLong(msg->hwnd,GWL_WNDPROC,(LONG)DialogBoxSubclassProc);
+ dlgBoxSubclass[dlgBoxSubclassCount].flags=0;
+
+ // WS_EX_CONTEXTHELP cannot be used in conjunction WS_MINIMIZEBOX or WS_MAXIMIZEBOX
+ // solution: switch off WS_MINIMIZEBOX or WS_MAXIMIZEBOX when only one of them is present
+ if(!(style&WS_MINIMIZEBOX) || !(style&WS_MAXIMIZEBOX)) {
+ if(style&WS_MINIMIZEBOX) dlgBoxSubclass[dlgBoxSubclassCount].flags|=DBSDF_MINIMIZABLE;
+ if(style&WS_MAXIMIZEBOX) dlgBoxSubclass[dlgBoxSubclassCount].flags|=DBSDF_MAXIMIZABLE;
+ SetWindowLong(msg->hwnd,GWL_STYLE,style&(~(WS_MINIMIZEBOX|WS_MAXIMIZEBOX)));
+ SetWindowLong(msg->hwnd,GWL_EXSTYLE,exStyle|WS_EX_CONTEXTHELP);
+ }
+ dlgBoxSubclassCount++;
+ LeaveCriticalSection(&csDlgBoxSubclass);
+ }
+ { HMENU hMenu;
+ hMenu=GetSystemMenu(msg->hwnd,FALSE);
+ if(hMenu!=NULL && AppendMenu(hMenu,MF_SEPARATOR,SC_CONTEXTHELP_SEPARATOR,NULL)) {
+ AppendMenu(hMenu,MF_STRING,SC_CONTEXTHELP,TranslateT("&What's this?"));
+ AppendMenu(hMenu,MF_STRING,SC_CONTEXTHELP_DIALOG,TranslateT("&What's this Dialog?"));
+ }
+ }
+ { TCHAR text[64];
+ mir_sntprintf(text,SIZEOF(text),_T("hooked window 0x%X for context help\n"),msg->hwnd);
+ OutputDebugString(text);
+ }
+ break;
+ }
+ }
+ return CallNextHookEx(hMessageHook,code,wParam,lParam);
+}
+
+static int ServiceShowHelp(WPARAM wParam,LPARAM lParam)
+{
+ UNREFERENCED_PARAMETER(lParam);
+ if(!IsWindow((HWND)wParam)) return 1;
+ if(idMouseMoveTimer) KillTimer(NULL,idMouseMoveTimer);
+ idMouseMoveTimer=0;
+ if(hwndHelpDlg==NULL) {
+ hwndHelpDlg=CreateDialog(hInst,MAKEINTRESOURCE(IDD_HELP),NULL,HelpDlgProc);
+ if(hwndHelpDlg==NULL) return 2;
+ }
+ PostMessage(hwndHelpDlg,M_CHANGEHELPCONTROL,0,(LPARAM)wParam);
+ return 0;
+}
+
+static int ServiceSetContextState(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ LONG flags;
+ EnterCriticalSection(&csDlgBoxSubclass);
+ for(i=0;i<dlgBoxSubclassCount;i++)
+ if(IsRealChild(dlgBoxSubclass[i].hwndDlg,(HWND)wParam)) break;
+ if(i==dlgBoxSubclassCount) {
+
+ LeaveCriticalSection(&csDlgBoxSubclass);
+
+ return 2;
+
+ }
+ LeaveCriticalSection(&csDlgBoxSubclass);
+ flags=(lParam&HCSF_CONTEXTMENU)?PROPF_MENUFORCED:PROPF_MENUDISABLED;
+ flags|=(lParam&HCSF_AUTOTIP)?PROPF_AUTOTIPFORCED:PROPF_AUTOTIPDISABLED;
+ return !SetProp((HWND)wParam,PROP_CONTEXTSTATE,(HANDLE)flags);
+}
+
+int InstallDialogBoxHook(void)
+{
+ InitializeCriticalSection(&csDlgBoxSubclass);
+ hServiceShowHelp=CreateServiceFunction(MS_HELP_SHOWHELP,ServiceShowHelp);
+ hServiceSetContext=CreateServiceFunction(MS_HELP_SETCONTEXTSTATE,ServiceSetContextState);
+ hMessageHook=SetWindowsHookEx(WH_CALLWNDPROC,HelpSendMessageHookProc,NULL,GetCurrentThreadId()); // main thread
+ hKeyboardHook=SetWindowsHookEx(IsWinVerNT()?WH_KEYBOARD_LL:WH_KEYBOARD,KeyboardInputHookProc,NULL,GetCurrentThreadId()); // main thread
+ return hMessageHook==NULL;
+}
+
+int RemoveDialogBoxHook(void)
+{
+ int i;
+ DestroyServiceFunction(hServiceShowHelp); // does NULL check
+ DestroyServiceFunction(hServiceSetContext); // does NULL check
+ UnhookWindowsHookEx(hMessageHook);
+ if(hKeyboardHook) UnhookWindowsHookEx(hMessageHook);
+ if(hEatNextMouseHook) UnhookWindowsHookEx(hEatNextMouseHook);
+ DeleteCriticalSection(&csDlgBoxSubclass);
+ for(i=0;i<dlgBoxSubclassCount;i++)
+ SetWindowLong(dlgBoxSubclass[i].hwndDlg,GWL_WNDPROC,(LONG)dlgBoxSubclass[i].pfnOldWndProc);
+ mir_free(dlgBoxSubclass); // does NULL check
+ return 0;
+}