user1009073
user1009073

Reputation: 3238

Delphi - Sending Records as Window Messages

Delphi Tokyo - I am wanting to send a record structure between forms via Windows Messages. Specifically, I have a "display running status" type of window. When behaviors occur elsewhere in my application, I need to send an "update the status window" type of message. I have found an example which passes a record via windows messages (but only within the same process), but am having issues making it work. Specifically, on the receiving side, I am having trouble compiling the windows message handler code. I have an 'Incompatible Type' error, but I can't figure out how to typecast to get it working. Here are the applicable code snippets.

In a globals.pas unit, which all forms access.

// Define my message
  const WM_BATCHDISPLAY_MESSAGE = WM_USER + $0001;
...
// Define the record which is basically the message payload
type
 TWMUCommand = record
    Min: Integer;
    Max: Integer;
    Avg: Integer;
    bOverBudget: Boolean;
    Param1: Integer;
    Param2: String;
  end;

...
// define a global variable
PWMUCommand : ^TWMUCommand;

Now for the sending of the message. This is currently just a button in order to test.

procedure TMainForm.BitBtn1Click(Sender: TObject);
var
  msg_prm: ^TWMUCommand;
begin
  New(msg_prm);
  msg_prm.Min := 5;
  msg_prm.Max := 10;
  msg_prm.Avg := 7;
  msg_prm.bOverBudget := True;
  msg_prm.Param1 := 0;
  msg_prm.Param2 := 'some string';
  PostMessage(Handle, WM_BATCHDISPLAY_MESSAGE, 0, Integer(msg_prm));
end;

On the receiving form, aka my status form... declare my message listener

procedure MessageHandler(var Msg: TMessage); message WM_BATCHDISPLAY_MESSAGE;

Now define the message handler.

procedure TBatchForm.MessageHandler(var Msg: TMessage);
var
   msg_prm: ^TWMUCommand;
begin
  try

    // Next line fails with Incompatible types
    msg_prm := ^TWMUCommand(Msg.LParam);
    ShowMessage(Format('min: %d; max: %d; avg: %d; ovrbdgt: %s; p1: %d; p2: %s',
                [msg_prm.Min, msg_prm.Max, msg_prm.Avg, BoolToStr(msg_prm.bOverBudget, True),
                 msg_prm.Param1, msg_prm.Param2]));
  finally
    Dispose(msg_prm);
  end;
end;

How do I cast Msg.LParam back into the record structure?

Upvotes: 4

Views: 2487

Answers (1)

David Heffernan
David Heffernan

Reputation: 612804

First of all, it's easier to declare a pointer type for the record:

type
  PWMUCommand = ^TWMUCommand;
  TWMUCommand = record
    ...
  end;

Then in the method that posts the message, declare the pointer to be PWMUCommand.

Your Integer cast assumes 32 bit code. Better to cast to the true type of that argument which is LPARAM.

PostMessage(..., LPARAM(msg_prm));

In the function the receives the message, declare the local variable using the pointer type:

var
  msg_prm: PWMUCommand;

Cast it like this:

msg_prm := PWMUCommand(Msg.LParam);

Note that when you call PostMessage you should check the return value in case of failure. If it fails, then you need to dispose of the memory then.

if not PostMessage(..., LPARAM(msg_prm)) then
begin
  Dispose(msg_prm);
  // handle error
end;

Finally, as I think that you are aware, this approach only works if the sender and receiver are in the same process.

Upvotes: 9

Related Questions