07 October 2009

Hooking to handle Gfa_hWnd messages?

In the Why you cannot subclass Gfa_hWnd I explained why the Gfa_hWnd cannot be subclassed to extend the editor's functionality.

Still, I need to intercept and modify messages for the main IDE window Gfa_hWnd. Some kind of subclassing is required. The other feature Windows offers is the 'hooking', known as Windows Hooks. "Hooking is a sort of subclassing, only it isn't associated with a single window, but with a thread or even the whole system. It's a kind of filter of Windows' messages that allow you to override, or add functionalities when a particular message is received." Sounds promising, doesn't it? 

Hooking Example

In fact, I did create a test program. First, two hooks are installed, the WH_GETMESSAGE and the WH_CALLWNDPROC hooks. There are other hooks, but these seem to be the most logical ones. Just to show how hooking might be done in GFA-BASIC 32, I present some code.
After declaring two global Handle variables, the hooks are initialized as follows:

Global Handle hGetMsgHook, hCallWndHook
' Process or modify all messages (of any type) for the system whenever a
' GetMessage or a PeekMessage function is called (WH_GETMESSAGE).
hGetMsgHook = SetWindowsHookEx(WH_GETMESSAGE , ProcAddr( GetMsgProc), App.hInstance, GetCurrentThreadId())

' Process or modify all messages (of any type) whenever a SendMessage
' function is called (WH_CALLWNDPROC).
hCallWndHook = SetWindowsHookEx(WH_CALLWNDPROC , ProcAddr( CallWndProc), App.hInstance, GetCurrentThreadId())

From this code you can see that both hooks are thread wide, meaning all messages for the thread are passed on to the hook filter functions GetMsgProc() and CallWndProc(). This is one of the reasons I didn't use the hook technique to 'subclass' the Gfa_hWnd window. Later more.
The application defined hook filter functions are defined as:

' WH_GETMESSAGE Hook
Function GetMsgProc(ByVal idHook As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  Dim msg As Pointer MSG
  Pointer(msg) = lParam
  If msg.hwnd == GfahWnd && msg.mess > 0 && msg.mess <> 275
    Trace msg.mess
  EndIf
  Return CallNextHookEx(hGetMsgHook, idHook, wParam, lParam)
End Function
'
' WH_CALLWNDPROC Hook
Function CallWndProc(ByVal idHook As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  Dim msg As Pointer MSG
  Pointer(msg) = lParam
  If msg.hwnd == GfahWnd && msg.mess > 0 && msg.mess <> 275
    Trace msg.mess
  EndIf
  Return CallNextHookEx(hGetMsgHook, idHook, wParam, lParam)
End Function

The GfahWnd variable contains the Gfa_hWnd value and MSG is an API user-defined type to store the message parameters. All well known I presume.

Is hooking a solution?
Does Windows Hooking offer a solution to my problem? The answer is no. Subclassing goes further than hooking. Subclassing functions can return values in response to messages, hooking filter functions cannot. Another issue is the use of thread wide filter functions, that are called for every message that is sent through SendMessage or retrieved with GetMessage. Not only do these hook functions significantly drain on system performance, they might also interfere with the application at hand, that is, the program currently being developed and run in the IDE.

I need another solution.

No comments:

Post a Comment