News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Message-only window

Started by PeterRod, November 04, 2008, 02:23:59 PM

Previous topic - Next topic

PeterRod

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

gwapo

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]

gwapo

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

PeterRod

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


   

gwapo

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]