delphiwinapiwindows-vistawindow-messages

Looking for an alternative to windows messages used in inter-process communication


I a have a multithread application (MIDAS) that makes uses of windows messages to communicate with itself.

MAIN FORM

The main form receives windows messages sent by the RDM LogData(‘DataToLog’)

Because windows messages are used they have the following attributes

  1. Received messages are Indivisible
  2. Received messages are Queued in the order they are sent

QUESTION:

Can you Suggest a better way doing this without using windows messages ?

MAIN FORM CODE

const
    UM_LOGDATA      = WM_USER+1002;

type

  TLogData = Record
      Msg        : TMsgNum;
      Src        : Integer;
      Data       : String;
  end;
  PLogData = ^TLogData;


  TfrmMain = class(TForm)
  //  
  private
    procedure LogData(var Message: TMessage);        message UM_LOGDATA;
  public
  //        
  end;


procedure TfrmMain.LogData(var Message: TMessage);
var LData : PLogData;
begin
    LData  :=  PLogData(Message.LParam);
    SaveData(LData.Msg,LData.Src,LData.Data);
    Dispose(LData);
end;

RDM CODE

procedure TPostBoxRdm.LogData(DataToLog : String);
var
  WMsg  : TMessage;
  LData : PLogData;
  Msg   : TMsgNum;
begin
  Msg := MSG_POSTBOX_RDM;
  WMsg.LParamLo := Integer(Msg);
  WMsg.LParamHi := Length(DataToLog);
  new(LData);
    LData.Msg    := Msg;
    LData.Src    := 255;
    LData.Data   := DataToLog;
  WMsg.LParam := Integer(LData);
  PostMessage(frmMain.Handle, UM_LOGDATA, Integer(Msg), WMsg.LParam);
end;

EDIT:

Why I want to get rid of the windows messages:


Solution

  • Use Named Pipes. If you don't know how to use them, then now is the time to learn.

    With named pipes, you can send any type of data structure (as long as both the server and the client know what that data structure is). I usually use an array of records to send large collections of info back and forth. Very handy.

    I use Russell Libby's free (and open-source) named pipe components. Comes with a TPipeServer and a TPipeClient visual component. They make using named pipes incredibly easy, and named pipes are great for inter-process communication (IPC).

    You can get the component here. The description from the source is: // Description : Set of client and server named pipe components for Delphi, as // well a console pipe redirection component.

    Also, Russell helped me out on Experts-Exchange with using an older version of this component to work in a console app to send/receive messages over named pipes. This may help as a guide in getting you up and running with using his components. Please note, that in a VCL app or service, you don't need to write your own message loop as I did in this console app.

    program CmdClient;
    {$APPTYPE CONSOLE}
    
    uses
      Windows, Messages, SysUtils, Pipes;
    
    type
      TPipeEventHandler =  class(TObject)
      public
         procedure  OnPipeSent(Sender: TObject; Pipe: HPIPE; Size: DWORD);
      end;
    
    procedure TPipeEventHandler.OnPipeSent(Sender: TObject; Pipe: HPIPE; Size: DWORD);
    begin
      WriteLn('On Pipe Sent has executed!');
    end;
    
    var
      lpMsg:         TMsg;
      WideChars:     Array [0..255] of WideChar;
      myString:      String;
      iLength:       Integer;
      pcHandler:     TPipeClient;
      peHandler:     TPipeEventHandler;
    
    begin
    
      // Create message queue for application
      PeekMessage(lpMsg, 0, WM_USER, WM_USER, PM_NOREMOVE);
    
      // Create client pipe handler
      pcHandler:=TPipeClient.CreateUnowned;
      // Resource protection
      try
         // Create event handler
         peHandler:=TPipeEventHandler.Create;
         // Resource protection
         try
            // Setup clien pipe
            pcHandler.PipeName:='myNamedPipe';
            pcHandler.ServerName:='.';
            pcHandler.OnPipeSent:=peHandler.OnPipeSent;
            // Resource protection
            try
               // Connect
               if pcHandler.Connect(5000) then
               begin
                  // Dispatch messages for pipe client
                  while PeekMessage(lpMsg, 0, 0, 0, PM_REMOVE) do DispatchMessage(lpMsg);
                  // Setup for send
                  myString:='the message I am sending';
                  iLength:=Length(myString) + 1;
                  StringToWideChar(myString, wideChars, iLength);
                  // Send pipe message
                  if pcHandler.Write(wideChars, iLength * 2) then
                  begin
                     // Flush the pipe buffers
                     pcHandler.FlushPipeBuffers;
                     // Get the message
                     if GetMessage(lpMsg, pcHandler.WindowHandle, 0, 0) then DispatchMessage(lpMsg);
                  end;
               end
               else
                  // Failed to connect
                  WriteLn('Failed to connect to ', pcHandler.PipeName);
            finally
               // Show complete
               Write('Complete...');
               // Delay
               ReadLn;
            end;
         finally
            // Disconnect event handler
            pcHandler.OnPipeSent:=nil;
            // Free event handler
            peHandler.Free;
         end;
      finally
         // Free pipe client
         pcHandler.Free;
      end;
    
    end.