Recent

Author Topic: PostMessage problem  (Read 22186 times)

mrdebug

  • Full Member
  • ***
  • Posts: 160
PostMessage problem
« on: March 22, 2008, 08:12:48 pm »
I wrote this simple program

Code: [Select]

unit Unit1;

{$mode objfpc}{$H+}

interface

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

type

  { TMainForm }

  TMainForm = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    WM_MY_MESSAGE: UINT;
  public
    { public declarations }
    procedure WndProc(var Msg: TMessage); override;
  end;

var
  MainForm: TMainForm;

implementation

procedure TMainForm.FormCreate(Sender: TObject);
begin
  WM_MY_MESSAGE:= RegisterWindowMessage('LazarusProva');
end;

procedure TMainForm.Button1Click(Sender: TObject);
begin
  PostMessage(HWND_BROADCAST, WM_MY_MESSAGE, 0, 0)
  //PostMessage(Self.Handle, WM_MY_MESSAGE, 0, 0)
end;

procedure TMainForm.WndProc(var Msg: TMessage);
begin
  if Msg.msg= WM_MY_MESSAGE then begin
    Memo1.Lines.Append('Ok');
  end else inherited WndProc(Msg);
end;

initialization
  {$I Unit1.lrs}

end.                    


Clicking Button1 should send a message to the WndProc procedure. But nothing happens. What's wrong?

Phil

  • Hero Member
  • *****
  • Posts: 2737
Re: PostMessage problem
« Reply #1 on: March 22, 2008, 09:11:18 pm »
Quote from: "mrdebug"
I wrote this simple program

Clicking Button1 should send a message to the WndProc procedure. But nothing happens. What's wrong?


I think you almost had it. RegisterWindowMessage is strictly a Win API function and offhand I suspect that its return value doesn't mean much to Lazarus.

I recreated your example using WM_USER + 1 as the message value and it works fine with Delphi, Lazarus on Windows and Lazarus on OS X (Carbon widgetset). If you're starting with Delphi, you can convert your apps to Lazarus and retain Delphi compatibility using XDev Toolkit:

http://wiki.lazarus.freepascal.org/XDev_Toolkit

unit Unit1;

interface

uses
  {$IFNDEF LCL} Windows, Messages, {$ELSE} LclIntf, LMessages, LclType, LResources, {$ENDIF}
  SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

{$IFDEF LCL}
type
  TMessage = TLMessage;
{$ENDIF}

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    WM_MY_MESSAGE: UINT;
  public
    { public declarations }
    procedure WndProc(var Msg: TMessage); override;
  end;

var
  Form1: TForm1;

implementation

{$IFNDEF LCL}
{$R *.dfm}
{$ENDIF}

procedure TForm1.Button1Click(Sender: TObject);
begin
//  PostMessage(HWND_BROADCAST, WM_MY_MESSAGE, 0, 0)
  PostMessage(Self.Handle, WM_MY_MESSAGE, 0, 0)
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
//  WM_MY_MESSAGE:= RegisterWindowMessage('LazarusProva');
  WM_MY_MESSAGE := WM_USER + 1;
end;

procedure TForm1.WndProc(var Msg: TMessage);
begin
  if Msg.msg= WM_MY_MESSAGE then begin
    Memo1.Lines.Append('Ok');
  end else inherited WndProc(Msg);
end;

initialization
{$IFDEF LCL}
{$I unit1.lrs}  {Include form's resource file}
{$ENDIF}

end.

mrdebug

  • Full Member
  • ***
  • Posts: 160
PostMessage problem
« Reply #2 on: March 22, 2008, 11:03:26 pm »
Are you sure that works with Lazarus? In my PC is not working.
And can I send a message to another appicazione? And receive?

Phil

  • Hero Member
  • *****
  • Posts: 2737
PostMessage problem
« Reply #3 on: March 22, 2008, 11:12:17 pm »
Quote from: "mrdebug"
Are you sure that works with Lazarus? In my PC is not working.
And can I send a message to another appicazione? And receive?


What version of Lazarus are you using? At one time PostMessage and SendMessage did not work, but I believe these were fixed not too long ago.

Previously I used a workaround where I trapped PostMessage calls and implemented it myself like this:

function PostMessage(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): BOOL;
 {Use control's Perform method to force it to respond to posted message.}
var
  AWinControl : TWinControl;
begin
  AWinControl := FindOwnerControl(hWnd);
  if AWinControl <> nil then
    AWinControl.Perform(Msg, wParam, lParam);
  Result := True;
end;

And something similar for SendMessage.

If you're using an older version of Lazarus, try this and see if it works.

I don't know about inter-application communcation. Looking at the Win API docs, I see now that RegisterWindowMessage is used along with HWND_BROADCAST to do that, but I have no knowledge of whether something like that is supported with Lazarus. Remember that Lazarus is a cross-platform tool so some Windows-specific things don't make sense for it.

Thanks.

-Phil

Paul Ishenin

  • Sr. Member
  • ****
  • Posts: 274
PostMessage problem
« Reply #4 on: March 26, 2008, 04:17:25 am »

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
PostMessage problem
« Reply #5 on: March 26, 2008, 02:26:23 pm »
By the way, what widgetset are you using?
SendMessage works different on the gtk+ widgetset than win32.

on Win32. SendMessage sends the message to the queue, and blocks sending thread, until executing thread process the message. If sending thread is the same as process thread, the message is processed immediatly.
But on gtk+ widgetset Send Message is processed directly from the sending thread, instead of putting message to the queue and wait for processing thread to process it! And this cause bugs, especially with GUI applications.

is it a bug or feature?
 
As for me temporary workaround is to emulate SendMessage, using TEvent and PostMessage, but this is bad style of cross-platform coding!

Phil

  • Hero Member
  • *****
  • Posts: 2737
PostMessage problem
« Reply #6 on: March 26, 2008, 03:00:20 pm »
Quote from: "skalogryyz"

As for me temporary workaround is to emulate SendMessage, using TEvent and PostMessage, but this is bad style of cross-platform coding!


I've always simulated SendMessage like this:

function SendMessage(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;
 var
  AWinControl : TWinControl;
begin
  AWinControl := FindOwnerControl(hWnd);
  if AWinControl <> nil then
    Result := AWinControl.Perform(Msg, wParam, lParam);
end;

Thanks.

-Phil

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
PostMessage problem
« Reply #7 on: March 26, 2008, 04:31:26 pm »
Phil, are you sure this will work in multi-threaded environment?
Because, as far as I can see Perform calls directly for WindowProc.

Usually. I use SendMessage to make some syncronize multiple threads.

If message handler is called from another thread and tries to modify some GUI properties, the application can fall, Because most of GUI routines are thread unsafe and must be called from the main thread.

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
PostMessage problem
« Reply #8 on: March 26, 2008, 04:48:29 pm »
well, my English is bad :), so let's talk on the language we all understand clearly

Code: [Select]

unit mainform;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, LclIntf, LResources, LMessages, Forms, Controls, Graphics, Dialogs, StdCtrls;

type

  { TMyThread }

  TMyThread = class(TThread)
  protected
    procedure Execute; override;
  end;
 
  { TForm1 }

  TForm1 = class(TForm)
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
    procedure WndProc(var Msg: TLMessage); override;
  end;

var
  Form1: TForm1;

implementation

{ TMyThread }

procedure TMyThread.Execute;
begin
  Sleep(5000);
  SendMessage(Form1.Handle, LM_USER, 0, 0);
end;

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
var
  t:  TMyThread;
begin
  Memo1.Lines.Add(IntToStr(LongWord(ThreadID)));
  t := TMyThread.Create(false);
  t.FreeOnTerminate := true;
end;

procedure TForm1.WndProc(var Msg: TLMessage);
var
  s : WideString;
begin
  inherited WndProc(Msg);
  if Msg.Msg = LM_USER then begin
    s := IntToStr(LongWord(ThreadID));
    Memo1.Lines.add(s);
  end;
end;            


this application starts and writes a ThreadID to the memo. It also launches a second thread, that after 5 seconds of waiting sends a message to the window.
The purpose of the test is to determine the thread where LM_USER msg is executed.
On carbon and gtk+, LM_USER is executed in the second thread.
On win32, LM_USER is executed in the main thread... or am i wrong?

Phil

  • Hero Member
  • *****
  • Posts: 2737
PostMessage problem
« Reply #9 on: March 26, 2008, 05:15:49 pm »
Quote from: "skalogryyz"
Phil, are you sure this will work in multi-threaded environment?
Because, as far as I can see Perform calls directly for WindowProc.


I've used this workaround for years but don't know about using it in multi-threaded app. For many types of end-user apps, adding multi-threading support is just an invitation to chaos and instability, so I avoid it.

This workaround just processes the message immediately, unlike PostMessage, but I believe that's how SendMessage is supposed to work.

Thanks.

-Phil

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
PostMessage problem
« Reply #10 on: March 26, 2008, 05:50:20 pm »
Quote from: "Phil"

For many types of end-user apps, adding multi-threading support is just an invitation to chaos and instability, so I avoid it.

This workaround just processes the message immediately, unlike PostMessage, but I believe that's how SendMessage is supposed to work.

Thanks for the answer Phill!

IMHO: multi-threading is not scary :) it's easy!

Phil

  • Hero Member
  • *****
  • Posts: 2737
PostMessage problem
« Reply #11 on: March 27, 2008, 02:20:13 am »
Quote from: "skalogryyz"
IMHO: multi-threading is not scary :) it's easy!


Ah, if only that were true in real life as well.

What happens to many programmers when they make their program multi-threading is that they end up with a non-deterministic program that cannot be relied on to give the correct results. To me this is the kiss of death for a software project.

I'm not suggesting this is the case with your programming. In the right hands multi-threading can be appropriate. The problem is that so often it falls into the wrong hands.

Do you have any personal experience with how well various programming languages support multi-threading (for example, C++, Java, Delphi, FPC -- I hear conflicting reports).

Thanks.

-Phil

Paul Ishenin

  • Sr. Member
  • ****
  • Posts: 274
PostMessage problem
« Reply #12 on: March 27, 2008, 03:18:39 am »
Thread and interprocess communications had not been taken into account while implementing SendMessage and PostMessage. I implemented them for carbon and qt only for similar use as described in blog. I think that in 80%-90% cases delphi component developers used them for the similar things.

But we are always accept patches.

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
PostMessage problem
« Reply #13 on: March 27, 2008, 08:52:04 am »
Quote from: "Phil"

Do you have any personal experience with how well various programming languages support multi-threading (for example, C++, Java, Delphi, FPC -- I hear conflicting reports).

Usually programming languages rely multi-threading support to the underlying OS (C, C#, C++, Delphi and FPC... don't know about Java). Some other languages like Oberon provides it's own syncronization objects.

 

TinyPortal © 2005-2018