Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Pass a String in a TMessage 1

Status
Not open for further replies.

Griffyn

Programmer
Jul 11, 2002
1,077
AU
Hi all,

I have a custom component that needs to send some text to a TMemo control on a form. The TMemo is acting like a log, and I want my custom components to be able to show what they're doing via this log.

I tried simply adding the form's unit to my component's unit's uses clause, but that caused issues (my component is part of a package). I'm happy to continue exploring that option, but I figure sending a windows message is probably the best way to go about it.

But how do I send a string? I presume I allocate some memory and pass a pointer to it, but I'd like some advice and perhaps some code if possible.

Thanks.
 
Hi Griffyn.

windows messaging is indeed the best option.

first define your own user message :

const WM_LOGMESSAGE = WM_USER+$1000; // anything above WM_USER is okay, just don't exceed word value (65535)

make sure that the string variable that you're using exists at message sending time or else you'll get AV's.

here's a sample project:


Code:
unit Unit1;

interface

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

const WM_LOGMESSAGE = WM_USER+$1000;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    Edit1: TEdit;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    procedure LogMessage(var message : TMessage); message WM_LOGMESSAGE;
  public
    { Public declarations }
    StrMessage : string;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


procedure TForm1.LogMessage(var Message : TMessage);

var P : PChar;

begin
 P:=PChar(Message.wParam);
 Memo1.Lines.Add(String(P));
end;



procedure TForm1.Button1Click(Sender: TObject);

var P : PChar;

begin
 StrMessage:=Edit1.Text;
 P:=PChar(StrMessage);
 PostMessage(Handle, WM_LOGMESSAGE, Integer(P),0);
end;

end.



-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
Thanks whosrdaddy - that's what I'm after.

However - if my component that does the PostMessage is not on the same form that will be reading the message, does that matter?

If so, how do I get the window handle of the form I want to send it to?
 
make a public property in your component and pass the handle of your form into that property, or use a sort of register procedure and store it in a list.

like this :
Code:
YourComponent = Class(TComponent)
...
private
  FLogForms : TList;
  procedure LogMessage(str : string);
...
public 
  procedure RegisterLogForm(Handle : THandle);
  procedure DeregisterLogForm(Handle : THandle);
...
end;

...

procedure YourComponent.RegisterLogForm(Handle : THandle
begin
 FLogForms.Add(Pointer(Handle));
end;

procedure YourComponent.DeRegisterLogForm(Handle : THandle

var Index : integer;

begin
 Index:=FLogForms.IndexOf(Pointer(Handle));
 if Index > -1 then
  FLogForms.Delete(Index);
end;


procedure YourComponent.LogMessage(Str : string);

var Index : integer;
    P     : PChar;

begin
 P:=PChar(Str);
 if FLogForms.Count > 0 then
  for Index:=0 to FLogForms.Count-1 do 
   PostMessage(Integer(FLogForms[Index]), WM_LOGMESSAGE, Integer(P),0);  
end;

I'm sure there are thousands of other ways to do this, it's up to you what to choose...

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
Hi
Dont use WM_USER it is not the last message, use WM_APP
indeed.
 

pranavjosh, what is your basis for saying that?

WM_APP = 0x8000 and according to the SDK help file, messages in the range 0x800 thru xBFFF are "reserved for future use by Windows"

WM_USER thru 0x7FFF are "Integer messages for use by private window classes."

WM_USER is currently defined as 0x0400 (but the implication is that it could change) and some Windows-provided components have defined messages in the WM_USER thru WM_USER+101 range.

I recommend to define your own base such as MESSAGE_BASE as WM_USER+200 and then define messages as offsets from that.

Of course generally in Delphi there is not as much need for user-defined messages as such, since you can have user-defined events.

 
Of course! I've set up heaps of components and custom events etc. but for some reason it didn't occur to me to do it for this. So I could easily do:

Code:
type
  TLogEvent = procedure(Sender: TObject; AMessage: String) of object;

  TMyComponent = class(TCustomListBox)
  private
    FOnLog: TLogEvent;
    ...
  protected
    procedure DoLog;
    ...
  published
    property OnLog: TLogEvent read FOnLog write FOnLog;
    ...
  end;

implementation

procedure TMyComponent.DoLog;
var
  s : String;
begin
  if Assigned(FOnLog) then
  begin
    // Do whatever so that var s contains the log message
    ...
    FOnLog(Self, s);
  end;
end;

And then I can add the form that has my TMemo log component to the uses clause of the form that contains the instance of TMyComponent. That way the unit containing the definition of TMyComponent (as above) doesn't need to have the unit reference, and the package will work ok.

But thanks again whosrdaddy for the primer. I had already set it up with the windows message and it works great.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top