Log in

View Full Version : Prevent application from receiving messages


diz
June 11th, 2004, 08:54
I would like to not allow some message (WM_CLOSE) to be received by some application. I mean, when I click on X in top right corner, I want the app to do nothing.

I though that it would be easy. I tried to set up a hook in to message queue. I used Iczelion tutorial and modified his sample a little:

Code:
GetMsgProc proc nCodeWORD,wParamWORD,lParamWORD
; invoke CallNextHookEx,hHook,nCode,wParam,lParam
mov edx,lParam
assume edx:PTR MSG
.if [edx].message==WM_CLOSE
invoke MessageBox,NULL,offset caption,offset caption,MB_OK
.endif
assume edx:nothing
xor eax,eax
ret
GetMsgProc endp

InstallHook proc hwndWORD
push hwnd
pop hWnd
invoke SetWindowsHookEx,WH_GETMESSAGE,addr GetMsgProc,hInstance,NULL
mov hHook,eax
ret
InstallHook endp

But it does not react on WM_CLOSE. Messagebox never popups, whenever I close some other application or app that sets the hook.
I also not sure, when (and do) I need to call CallNextHookEx function. It seems to make no difference.

What am I doing wrong? Maybe it's not possible to prevent app from receiving message?

JimmyClif
June 11th, 2004, 10:25
Check out the Hook Library.. If I remember correctly he suppresses WM_CLOSE in one of his example codes.

http://board.win32asmcommunity.net/showthread.php?s=&threadid=14463&highlight=hook

Cheers,
JC

diz
June 11th, 2004, 13:36
Very mucho thanks. It seems to do the trick.

Now I stumbled across another (even harder I think) problem. I need to limit blocking just to main windows, and not subwindows (or childs). But that's another story and I will try to do it by myself.

Thanks again

JimmyClif
June 11th, 2004, 14:24
No biggie..

Use a FindWindow and grab the handle of the app you want to hook. Then call GetWindowThreadProcessId using that handle. Now you got the thread id. Use it for the SetWindowHookEx call. Voila. Only your app gets hooked.

diz
June 11th, 2004, 15:00
Yeah, I already have ThreadId because I'm creating this process with CreateProcess.

But I must filter messages _within_ this thread because too much is blocked. For example menus are impossible too close, tabs etc.

The only thing, I want to block is closing of the main window. I'm not sure if this is possible (but I didn't looked into it yet).

Fake51
June 11th, 2004, 16:32
Quote:
[Originally Posted by diz]Yeah, I already have ThreadId because I'm creating this process with CreateProcess.

But I must filter messages _within_ this thread because too much is blocked. For example menus are impossible too close, tabs etc.

The only thing, I want to block is closing of the main window. I'm not sure if this is possible (but I didn't looked into it yet).


Just screen for hWnd. Get it from FindWindow.

Fake

dELTA
June 11th, 2004, 16:34
Subwindows use the message queue of the main window, simply filter the messages based on the hWnd parameter from your hook procedure to get the ones you really want.

EDIT: Damn Fake51, where are your manners, squeezing past me right on the goal line like that.

JimmyClif
June 11th, 2004, 17:48
Try it with WH_CALLWNDPROC as hook instead of the WH_MSGFILTER.

SheepShagger
June 11th, 2004, 18:02
Quote:
[Originally Posted by dELTA]EDIT: Damn Fake51, where are your manners, squeezing past me right on the goal line like that.


Don't complaint to much, you just did that to me in the crypto forum

dELTA
June 11th, 2004, 18:55
You should only know what I did just now to you in that same thread in the crypto forum then...

diz
June 11th, 2004, 19:55
Before I try with FindWindow (can be hard because window title is not constant), I tried with WH_CALLWNDPROC hook.

Yes, it catches WM_CLOSE, but I have no idea how to prevent WM_CLOSE from closing app.

This is a code snippet:
Code:
GetMsgProc proc nCodeWORD,wParamWORD,lParamWORD
mov edx,lParam
assume edx:PTR CWPSTRUCT
.if [edx].message == WM_CLOSE
invoke MessageBox,NULL,offset caption,offset caption,MB_OK
.else
invoke CallNextHookEx,hHook,nCode,wParam,lParam
.endif
assume edx:nothing
xor eax,eax
ret
GetMsgProc endp

InstallHook proc hwndWORD
push hwnd
pop hWnd
invoke SetWindowsHookEx,WH_CALLWNDPROC,addr GetMsgProc,hInstance,NULL
mov hHook,eax
ret
InstallHook endp

I you are looking at this code, and thinking 'WTF is this?' than feel free to correct me, cause I did some coding on my own and it can be very inncorect


I also have another code - a modified version of the Hook Library (thx JimmyClif) which uses WH_CBT hook and reacts on HCBT_DESTROYWND message.
This one prevents closing, but as I said before, also affects menus, tabs and every other widget. And I don't know how to get hWnd here without using FindWindow (like I said, window title changes).

The first version (using WH_CALLWNDPROC hook) seems better because it has CWPSTRUCT struct which holds hWnd of window. There is just the problem with preventing WM_CLOSE from happening. Maybe it's not possible this way? Maybe it's already too late when WM_CLOSE is sent?

dELTA
June 11th, 2004, 20:12
About the FindWindow call, you can use it with window class strings only, and I guess the window class doesn't change?

Also, if there is some pattern whatsoever to the changes of the window title (e.g. some static string followed by the name of the current open document/page/resouce/whatever, as is quite common), you can always enumerate all top-level windows and perform whatever string matching operation you want on their titles to find the one you want. You can even enumerate them and resolve the name of each of their executables, which should be effective no matter how much their window titles or even window class strings change. Go get 'em.

JimmyClif
June 11th, 2004, 22:21
You're right... WH_CALLWNDPROC hook can only examine the message but not modify it. This time I actually read a little bit about it, so try this:

Code:

GetMsgProc proc nCodeWORD,wParamWORD,lParamWORD
mov edx,lParam
.if [edx].MSG.message == WM_CLOSE
invoke MessageBox,NULL,offset caption,offset caption,MB_OK
.else
invoke CallNextHookEx,hHook,nCode,wParam,lParam
.endif
xor eax,eax
ret
GetMsgProc endp

InstallHook proc hwndWORD
push hwnd
pop hWnd
invoke SetWindowsHookEx,WH_GETMESSAGE,addr GetMsgProc,hInstance,NULL
mov hHook,eax
ret
InstallHook endp

Fake51
June 12th, 2004, 05:57
Quote:
[Originally Posted by dELTA]Subwindows use the message queue of the main window, simply filter the messages based on the hWnd parameter from your hook procedure to get the ones you really want.

EDIT: Damn Fake51, where are your manners, squeezing past me right on the goal line like that.


Sorry bout that, mate, wasn't intentional. Just here to help.

Fake

SheepShagger
June 12th, 2004, 12:58
Quote:
[Originally Posted by dELTA]You should only know what I did just now to you in that same thread in the crypto forum then...


Your move

diz
June 12th, 2004, 13:44
Quote:
[Originally Posted by JimmyClif]You're right... WH_CALLWNDPROC hook can only examine the message but not modify it. This time I actually read a little bit about it, so try this:

The WH_GETMESSAGE hook also catched the WM_CLOSE message, but... too late - app window was already closed then.

So I went back to Hooklib and made more changes to handle app recognition.
Finding window by class wasn't working, because it catched some other window of this app (which had same class).
As a last resort I tried dELTA tip with EnumWindows. This one in fact worked (thanks dELTA ). Thanks to constant string that is appended to window title.

So i already achived what I wanted to achieve
Last step is to send keystroke to this app. I need to send CTRL+H.

I tried:
invoke SendMessage,windowHandle,WM_KEYDOWN,VK_CONTROL or VK_H,0
invoke SendMessage,windowHandle,WM_KEYUP,VK_CONTROL or VK_H,0
but without luck so far.

Does somebody have other ideas how to send this keystroke?
I hope it's not a showstopper, it would be a shame now, when 90% of hook is done

dELTA
June 12th, 2004, 20:31
Press that key combination manually, then hook the message(s) it results in and make an exact duplicate them, that should work. :-)

JimmyClif
June 12th, 2004, 21:26
what about sending first the VK_CONTROL and then a "H" ?

Silver
June 13th, 2004, 07:37
IIRC you modify the LPARAM of the message to indicate if alt, control etc have been pressed. Been a while since I've done this though. Use Delta's suggestion, get a copy of Spy++ and trap all the messages to a window, then see what the exact params were for the control-h.

diz
June 13th, 2004, 08:59
Unfortunetly it does not use standard wm_keydown for keystrokes (nor wm_command and any other message - spy++ shows nothing when pressing for example CTRL+H).

I am a little bit confused. Does it means that the app is not using windows messages for controlling itself? This program is multiplatform so I guess it's the reason for not using windows specific solutions.

It's Opera browser by the way (I'm not about cracking so I think I'm safe with telling the name).

dELTA
June 13th, 2004, 09:15
You already have your own message hook procedure installed, right? Why use third-party programs when you can use your own hook and be sure that it works exactly as you like? Just capture all the messages with your own hook to see which they are. If you still don't get any messages at all in that one either, then something is fishy, but I really think you will.

diz
June 13th, 2004, 10:50
Ok, I used spy++ and saw that some of the child windows were receiving normal WM_KEYDOWN/KEYUP messages.
So I tried sending this to the top level window and it kinda works. It wasn't working before, because I used SendMessage (when I should have used PostMessage :rolleyes.

So I replicated sending keystroke with this:
Code:
invoke PostMessage,windowHandle,WM_KEYDOWN,VK_CONTROL,1D0001h
invoke PostMessage,windowHandle,WM_KEYDOWN,VK_H,22001h
invoke PostMessage,windowHandle,WM_KEYUP,VK_H,0C0220001h
invoke PostMessage,windowHandle,WM_KEYUP,VK_CONTROL,0C01D0001h

The lParam is taken from spy++. Unfortunately it's just sending H key, control seems to be omitted (same with 0 as lParam).
And I don't understand what's the problem.

Silver
June 13th, 2004, 11:10
Thats interesting. When I do the same with Spy++ on any random app, I get a WM_KEYDOWN with WPARAM 48 and LPARAM 230001 for the H key. Where are you getting 220001?

Incidentally, my bad, I double checked. Control key isn't a modifier for a keypress message, the sequence is exactly as you've written - control down, h down, h up, control up. The difference is the control modifier not triggering TranslateMessage() to convert keydowns to WM_CHAR.

diz
June 13th, 2004, 11:17
Yeah, lParam is bad in above code. It was for VK_G which I tried before.

I'm going to do some more testing, maybe I will make it work somehow.

diz
June 13th, 2004, 17:46
I did some test and I must say that it's a little beyond me

Tests were done on CTRL+SPACE keystroke and spyed with spy++.

Normal pressing by keyboard produces this:
Code:
invoke PostMessage,win,WM_KEYDOWN,VK_CONTROL,001D0001h
invoke PostMessage,win,WM_KEYDOWN,VK_SPACE,00390001h
invoke PostMessage,win,WM_KEYUP,VK_SPACE,0C039001h
invoke PostMessage,win,WM_KEYUP,VK_CONTROL,0C01D0001h

Well, it's already changed to invokes but you know what I mean.

Now, I've put this into simple asm app. Then I runned spy++ again and checked what this time the program is receiving.
To my suprise, the results are:
-------------------
scrap all this, was error in lParam (wrong cRepeat)
Code:
P WM_KEYDOWN nVirtKey:VK_CONTROL cRepeat:1 ScanCode:1D fExtended:0 fAltDown:0 fRepeat:0 fUp:0
P WM_KEYDOWN nVirtKey:VK_SPACE cRepeat:1 ScanCode:39 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
P WM_KEYUP nVirtKey:VK_SPACE cRepeat:36865 ScanCode:03 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
P WM_KEYUP nVirtKey:VK_CONTROL cRepeat:1 ScanCode:1D fExtended:0 fAltDown:0 fRepeat:1 fUp:1
P WM_CHAR chCharCode:'0020' (32) cRepeat:36865 ScanCode:03 fExtended:0 fAltDown:0 fRepeat:0 fUp:0

This WM_CHAR at the end is very interesting. I guess that it has something to do with TranslateMessage that Silver was mentioning.
But how to avoid it? I also tried to send this keys with PowerPro app, and this one sends CTRL+SPACE properly (lParam is exactly the same as in my code).
-------------------


So again, the spy++ message log is exactly the same when sending with PowerPro and with my app.
Unfortunetly, the first is working, the latter not (just sends space - no control).
Here's the log:
Code:

------- PowerPro
P WM_KEYUP nVirtKey:00FF cRepeat:1 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:0 fUp:1 probably nonimportant
P WM_KEYDOWN nVirtKey:VK_CONTROL cRepeat:1 ScanCode:1D fExtended:0 fAltDown:0 fRepeat:0 fUp:0
P WM_KEYDOWN nVirtKey:VK_SPACE cRepeat:1 ScanCode:39 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
P WM_KEYUP nVirtKey:VK_SPACE cRepeat:1 ScanCode:39 fExtended:0 fAltDown:0 fRepeat:1 fUp:1
P WM_KEYUP nVirtKey:VK_CONTROL cRepeat:1 ScanCode:1D fExtended:0 fAltDown:0 fRepeat:1 fUp:1
------ my app
P WM_KEYDOWN nVirtKey:VK_CONTROL cRepeat:1 ScanCode:1D fExtended:0 fAltDown:0 fRepeat:0 fUp:0
P WM_KEYDOWN nVirtKey:VK_SPACE cRepeat:1 ScanCode:39 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
P WM_KEYUP nVirtKey:VK_SPACE cRepeat:1 ScanCode:39 fExtended:0 fAltDown:0 fRepeat:1 fUp:1
P WM_KEYUP nVirtKey:VK_CONTROL cRepeat:1 ScanCode:1D fExtended:0 fAltDown:0 fRepeat:1 fUp:1