• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1400
  • Last Modified:

WM_USER message does not arrive

OK. I give up.

My app does not receive my own messages (WM_USER + n) sent from
another instance of the same app.

Sample app:

------------------------------ code ----------------------------
type
  TForm1 = class(TForm)
    BitBtn1: TBitBtn;
    Label1: TLabel;
    Edit1: TEdit;
    procedure BitBtn1Click(Sender: TObject);
  protected
    procedure WMUser(var M: TMessage); message WM_User;
  end;

procedure TForm1.WMUser(var M: TMessage);
begin
  label1.caption:= 'received '+IntToStr(M.lParam);
  inherited;
end;

procedure TForm1.BitBtn1Click(Sender: TObject);
begin
  PostMessage(HWND_BROADCAST, WM_USER, 0, StrToInt(Edit1.Text));
end;
--------------------------- end code ---------------------------

Then:
start two instances of this app (one for send, one for receive)
in one instance:
  enter a number in the editbox (ex: 23),
  press the button,

the other instance does not write 'received 23'.

Why? And what to do? Thanks in advance.
0
krisz
Asked:
krisz
  • 9
  • 7
  • 5
  • +3
1 Solution
 
jackb022197Commented:
You can not send a msg from one instance to another instance this way. You need to look at IPC to exchange info between different processes. Check the Win32 API help file for this.
0
 
kriszAuthor Commented:
Why not? Delphi or windows prevents it? Please be more verbose,
this answer is not acceptable.

Using DDE or pipes requires sending messages, and I see
no reason to prevent it between two instances of an app.
0
 
ygolanCommented:
Notice that you should not broadcast a WM_USER. WM_USER-based messages are defined only within a window class - different applications respond differently to WM_USER. For all you know, there might be a running application that considers WM_USER to be a command to shut down, delete a file or format the hard disk :-)

I suggest that (if you wish to avoid IPC, which BTW is very easy to use) you create a hidden window with a special name, use FindWindow to find it from the other instance, and use its handle to PostMessage directly to it.
0
Cloud Class® Course: Microsoft Windows 7 Basic

This introductory course to Windows 7 environment will teach you about working with the Windows operating system. You will learn about basic functions including start menu; the desktop; managing files, folders, and libraries.

 
kriszAuthor Commented:
Thanks for this comment. But I think it's not really the point.
Or registered messages will arrive? If so, the problem is no
more. If won't, bad. I'll try it.

Also I have to disagree about IPC.
Actually I'm trying to set up an IPC communication. I want to
train myself in the usage of unnamed pipes, the problem is I
have to tell to the other app the handles of the pipe. Messages
look the easiest way for this. Yes, I can use shared memory, but
if I do why do I need the pipe?

I can't believe that there is no way to send messages between
two instances of an app.
0
 
julio011597Commented:
Hello, just a guess:

procedure WMUser(var M: TMessage); message WM_User;
----------------------------------------------^^^^

should be WM_USER (all uppercase).

Does this makes any difference?

-julio
0
 
kriszAuthor Commented:
Ok. I reject jackb's answer, and increase points to 150.

Note to julio: letter case is not the solution.
0
 
kriszAuthor Commented:
Adjusted points to 150
0
 
ygolanCommented:
> Yes, I can use shared memory, but  if I do why do I need the > pipe?

You don't :-) that's the whole point.

I've got source code that makes  IPC easy. Email me for it - ygolan@hyperact.com
0
 
kriszAuthor Commented:
Look!

It's NOT about IPC! I talk about _messages_.
I've used shared memory earlier. I've used pipes too.
IPC is cool, but I want messages, messages, MESSAGES!!!!!

Meanwhile I found a workaround. I still don't know what is
the problem with my code above, but the new code works, so
the 'what to do?' part of the question is no more.

I'm still waiting for somebody who can tell me what's the
problem.

(Note: this 150 points are the final offer)
0
 
andrewjbCommented:
Try using WM_USER + n, where n is about 100. Delphi itself uses some of the user messages in its own components. Who knows what! So the message might be being trapped by something else.
0
 
andrewjbCommented:
Try using WM_USER + n, where n is about 100. Delphi itself uses some of the user messages in its own components. Who knows what! So the message might be being trapped by something else.
0
 
kriszAuthor Commented:
Bad.

I tried it with registered messages. Still doesn't work.
0
 
andrewjbCommented:
Got it!

The BROADCAST message sends to all the APPLICATIONS, not the forms. So you have to trap application messages :

TForm1.FormCreate...
begin
  ......
  Application.OnMessage := TrapAppMessages;
  ....
end;

TForm1.TrapAppMessages( var Msg: TMsg; var Handled: Boolean);
begin
  if ( Msg.Message = WM_MYMSG ) then
  begin
    .... { Do your stuff }
    Handled := True;
  end;
end;

Still use WM_USER + n ( n = about 150 or so )

0
 
kriszAuthor Commented:
This was a clue!

-- Win32.hlp, PostMessage ----------------------------
HWND_BROADCAST:

The message is posted to all top-level windows
in the system, including disabled or invisible
unowned windows, overlapped windows, and pop-up
windows. The message is not posted to child windows.
-- end -----------------------------------------------

But all windows including the main form are child windows
in delphi. The top-level window is hidden, and you can
get it's handle with Application.Handle.

It's not in the help, but you can see it in Forms.pas.
See TApplication.Create and TApplication.CreateHandle.

It's an inconsistency in Delphi. I think the MainWndProc
should forward all messages sent to the top-level window
to the main window.

Solutions:
- Application.OnMessage
- Application.HookMainWindow

(And still don't broadcast WM_USER+n messages, use
registered messages instead!)

Because you gave only a clue, and not a detailed description,
I offer you an 'acceptable' grading. Comment if you want more.
0
 
mirek071497Commented:
Hi krisz.
I have a question for you.
I try too broadcast messages (WM_USER+n) and when I set OnMessage for Application i can't get this message, Can You boadcast WM_USER now ? If You can than How ?
0
 
andrewjbCommented:
For mirek :

( Form with a button on it )


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    procedure AppMsg (var Msg: TMsg; var Handled: Boolean);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

const
  WM_MYMSG = WM_USER + 150;

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
  PostMessage( HWND_BROADCAST , WM_MYMSG , 0 , 0 );
end;

procedure tForm1.AppMsg (var Msg: TMsg; var Handled: Boolean);
begin
  if ( Msg.Message = WM_MYMSG ) then
  begin
      { This just prints something on the screen }
    AllocConsole;
    writeln('Hello there!');
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Application.OnMessage := AppMsg;
end;

end.
0
 
mirek071497Commented:
Yes i write this in the same way but this don't working. Delphi3.
Why ?
When You try this i think so this is working. Mayby this depend of Delphi version ?
0
 
andrewjbCommented:
Works OK for me in Delphi 3.

0
 
mirek071497Commented:
It's seems as impossible, but I know so This working for You. Do you have any idea why this not working for me ?
0
 
andrewjbCommented:
The FormCreate and Button1Click methods are event handlers. You are attaching them to the form / button correctly, I assume ...

AJB

0
 
mirek071497Commented:
Yes.

In MS-SDK i found :


When SendMessage() is used to send a broadcast message (hwnd = 0xFFFF or
hwnd = -1), the message is sent to all top-level windows. A message
broadcast by PostMessage() is only sent to top-level windows that are
visible, enabled, and have no owner.

You might observe the effect of the difference when, for example, the top-
level window of your application calls DialogBox() to present a modal
dialog box. While the modal dialog box exists, its owner (your top-level
window) will be disabled. Messages broadcast using PostMessage() will not
reach the top-level window because the window is disabled, and will not
reach the dialog box because the dialog box has an owner. Messages
broadcast using SendMessage() will reach both the top-level window and the
dialog.

In Windows 3.1, PostMessage() will broadcast to invisible and disabled
windows just like SendMessage() already does.


But Send Message don't working too !!!.
0
 
kriszAuthor Commented:
No differences between SendMessage and PostMessage.

----- win32.hlp -----------------------
SendMessage:
If this parameter is HWND_BROADCAST, the message is sent to all top-level windows in the system, including disabled or invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows.

PostMessage
The message is posted to all top-level windows in the system, including disabled or invisible unowned windows, overlapped windows, and pop-up windows. The message is not posted to child windows.
----- end ------------------------------

Application.OnMessage should work. If not, the problem is
something else.

andrewjb, if you agree, I won't grade your answer until this
conversation is going on, because the grading prevents
adding more comments. Tell me if you disagree.
0
 
andrewjbCommented:
Indeedy, I don't know why mirek is having problems. Perhaps you should post the code you're trying to execute, mirek ??


0
 
mirek071497Commented:
Sorry. You can grade the answer if this work for you. This is Your question not My.
0
 
kriszAuthor Commented:
Mirek! Ask your question as a separate one. This thread is
going to close.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: SQL Server Core 2016

This course will introduce you to SQL Server Core 2016, as well as teach you about SSMS, data tools, installation, server configuration, using Management Studio, and writing and executing queries.

  • 9
  • 7
  • 5
  • +3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now