I have been trying for two days to get a simple message-only window to work.
I have processA which uses SendMessage to send a simple ASCII message.
I have processB which is a vb.net Window app which receives the message and displays it. Thats ok. works fine
I also have processC which contains a message-only window but when I send a message from processA to processC, the message is not received by processC and processA hangs.
This is the code in processC
wc WNDCLASSEX <>
ClassName byte "MsgOnly",0
WindowName byte "Sample",0
;---------------------------
CreateMsgOnly proc
;---------------------------
invoke GetModuleHandle, NULL
mov hModule,eax
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style,NULL
mov wc.lpfnWndProc, offset WinProc
mov wc.cbClsExtra,0
mov wc.cbWndExtra,0
mov wc.hInstance,eax
mov wc.hIcon,NULL
mov wc.hCursor,NULL
mov wc.hbrBackground,NULL
mov wc.lpszMenuName,NULL
mov wc.lpszClassName, offset ClassName
mov wc.hIconSm,NULL
invoke RegisterClassEx, addr wc
invoke CreateWindowEx,NULL,addr ClassName,addr WindowName,NULL,0,0,0,0,HWND_MESSAGE ,NULL,hModule,NULL
mov hMsgOnly,eax
ret
CreateMsgOnly endp
;---------------------------
WinProc proc hWin:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
;---------------------------
mov eax,uMsg
cmp eax,WM_COPYDATA
je ProcessMsg
invoke DefWindowProc,hWin,uMsg,wParam,lParam
ret
ProcessMsg:
xor eax,eax
ret
WinProc endp
I use the debugger to ensure that the sending app ,processA, has the correct value for hMsgOnly
I also monitor in the debugger what uMsg's arrive at WinProc.
The only messages that arrive at WinProc are WM_GETMINMAXINFO 024h , WM_NCCREATE 081h , WM_NCCALCSIZE 083h and
WA_ACTIVE 01
These messages occur when MsgOnly window is created.
No other messages arrive at WinProc !!
What am I doing wrong?
I dont think the problem is in the sending app as it sends to the vb.net window just fine.
There is no message loop in processC because I read that SendMessage calls the WndProc of the receiving window directly even if the receiving window is in a different process/thread.
Any help would be appreciated.
Thanks
PeterRod
Hi PeterRod,
I think you still have to create a message-loop for your message-only window to start receiving messages.
See the attached program I've created that shows message-only window.
HTH,
-chris
[attachment deleted by admin]
Quote
... SendMessage calls the WndProc of the receiving window directly even if the receiving window is in a different process/thread.
I didn't know this., can you cite an article discussing about it?
Thanks,
-chris
Hi Chris,
Thank lots for your helpful posts.
Following is a quote from MSDN SendMessage Function
Quote
If the specified window was created by the calling thread, the window procedure is called immediately as a subroutine. If the specified window was created by a different thread, the system switches to that thread and calls the appropriate window procedure. Messages sent between threads are processed only when the receiving thread executes message retrieval code.
I now have my program working but there are a few issues I would like to discuss with you
(1) I ran your MsgOnly.exe first then ran your Dialog.exe and obtained the expected MB etc.
On closing the MB and Dialog.exe the MsgOnlyWnd remains open (although hidden)
I verified this using WinTreeSnap
Although your WndProc is set up to handle WM_CLOSE, I dont think WM_CLOSE is received at WndProc.
(2) As to the above quote I did not quite grasp the significance of the last sentence. IMHO, a message-only window may not need a message loop but it definitely needs an Invoke GetMessage instruction.
For example, place a dummy statement in your message loop immediately after the invoke GetMessage instruction say 'xor ebx,ebx' and place a breakpoint at the dummy statement.
I dont believe that execution will ever hit the breakpoint.
Point is that a message loop is needed for Posted messages not for Sent messages. See the following from MSDN GetMessage function
Quote
The function dispatches incoming sent messages until a posted message is available for retrieval.
...
During this call, the system delivers pending, nonqueued messages, that is, messages sent to windows owned by the calling thread using the SendMessage, SendMessageCallback, SendMessageTimeout, or SendNotifyMessage function. Then the first queued message that matches the specified filter is retrieved.
So if the MsgOnlyWnd sole purpose is to receive SentMessages then only Invoke GetMessage is required.
GetMessage stays in an infinite OS loop at '7C90E4F2 0F 34 sysenter' waiting on a sent or posted message.
If you replace your Message Loop with an 'invoke GetMessage, addr msg, hwnd, 0, 0' your programs will function the same way.
Now if you were to add 'invoke PostMessage,hWnd,WM_PAINT,0,0' after your 'invoke MessageBox, hWnd, ...' in WndProc, the message loop is definitely needed to process the paint message, which arrives at WndProc via DispatchMessage.
This is my understanding of SendMessage and GetMessage as they apply to message-only windows but I am known to be wrong very often.
Please let me have your comments.
Thanks
PeterRod
Hi PeterRod, sorry for the late response, I wasn't around with computers these past days :bdg
Quote from: PeterRod on November 05, 2008, 02:47:29 PM
Hi Chris,
Thank lots for your helpful posts.
Following is a quote from MSDN SendMessage Function
Quote
If the specified window was created by the calling thread, the window procedure is called immediately as a subroutine. If the specified window was created by a different thread, the system switches to that thread and calls the appropriate window procedure. Messages sent between threads are processed only when the receiving thread executes message retrieval code.
I now have my program working but there are a few issues I would like to discuss with you
(1) I ran your MsgOnly.exe first then ran your Dialog.exe and obtained the expected MB etc.
On closing the MB and Dialog.exe the MsgOnlyWnd remains open (although hidden)
I verified this using WinTreeSnap
Although your WndProc is set up to handle WM_CLOSE, I dont think WM_CLOSE is received at WndProc.
Yup, because I forgot to include sending of WM_CLOSE to the test program (Dialog.exe) where I was intending to add close MsgOnly.exe by sending WM_CLOSE. I've updated the sample program to reflect the change.
Quote from: PeterRod on November 05, 2008, 02:47:29 PM
(2) As to the above quote I did not quite grasp the significance of the last sentence. IMHO, a message-only window may not need a message loop but it definitely needs an Invoke GetMessage instruction.
For example, place a dummy statement in your message loop immediately after the invoke GetMessage instruction say 'xor ebx,ebx' and place a breakpoint at the dummy statement.
I dont believe that execution will ever hit the breakpoint.
Point is that a message loop is needed for Posted messages not for Sent messages. See the following from MSDN GetMessage function
Quote
The function dispatches incoming sent messages until a posted message is available for retrieval.
...
During this call, the system delivers pending, nonqueued messages, that is, messages sent to windows owned by the calling thread using the SendMessage, SendMessageCallback, SendMessageTimeout, or SendNotifyMessage function. Then the first queued message that matches the specified filter is retrieved.
So if the MsgOnlyWnd sole purpose is to receive SentMessages then only Invoke GetMessage is required.
GetMessage stays in an infinite OS loop at '7C90E4F2 0F 34 sysenter' waiting on a sent or posted message.
If you replace your Message Loop with an 'invoke GetMessage, addr msg, hwnd, 0, 0' your programs will function the same way.
Now if you were to add 'invoke PostMessage,hWnd,WM_PAINT,0,0' after your 'invoke MessageBox, hWnd, ...' in WndProc, the message loop is definitely needed to process the paint message, which arrives at WndProc via DispatchMessage.
This is my understanding of SendMessage and GetMessage as they apply to message-only windows but I am known to be wrong very often.
Please let me have your comments.
I'm not sure whether or not the MSDN is saying the truth or not. From what I've read from "Programming Windows 95 by Peter Petzold", window messages (whether Posted or Sent) will be placed on the message-queue and they will remain there until it met any of the condition:
1. The owner of the message-queue got destroyed.
2. The message was retrieved for processing (using GetMessage function)
PostMessage and SendMessage as far as I know function similarly, except that PostMessage doesn't wait until the posted message got process. Both of these functions only places message to the queue. I've been trying to create a small program to make these functions post/send message directly (non-queued) but with no luck. Maybe non-queued is possible, but I haven't encountered it yet.
Regarding the message loop of my first sample program, yes I have to admit that the loop was created too lazy (copy-pasted from one of my previously working program). You actually don't need TranslateMessage and DispatchMessage calls in a message-only loop as you probably wont receive any input messages since it's not visible. A simple loop like this is enough:
.while TRUE
invoke GetMessage, addr msg, hwnd, 0, 0
.break .if eax != TRUE ; Terminate the loop for any quit messages
.endw
Hope this helps,
-chris
[attachment deleted by admin]