How to send/receive data using Sendmessage or Postmessage API?

Asked

Viewed 3,525 times

3

I need to send several data to another process, the detail and the two processes are dlls, and I have customized my message. The message I can send and receive but when trying to process the data coming by WParam of violated access.

My data structure would be this:

type
  TMyStruct = packed record
    lpHandle: HWND;
    lpProcessid: DWORD;
  end;

var
  MyData: TMyStruct;

MyData.lpHandle:= handleprocess;
MyData.lpProcessid:= GetCurrentThreadId;
SendMessage(HWND_BROADCAST, WM_SHUTDOWN_THREADS, 0, LongInt(@MyData));

Oa receive:

type
  PMyStruct=^TMyStruct;
  TMyStruct = packed record
    lpHandle: HWND;
    lpProcessid: DWORD;
  end;

procedure TWinProc.WndProcedure(var _msg: TMessage);
var
  MyStruct: PMyStruct;
begin
  if _msg.Msg = WM_SHUTDOWN_THREADS then
  begin
    MyStruct:= PMyStruct(_msg.LParam);
    if (MyStruct^.lpBrowser = 0) then
      TerminaProcesso(MyStruct^.lpProcid)
    else
    if (not IsWindow(Wndthread)) then
    begin
      Fhandle:= MyStruct^.lpHandle;
      Wndthread:= CreateThread(nil, 0, @CallProcedure, nil, 0, WndthreadID);
    end;
  end
  else
    _msg.Result:= DefWindowProc(WinProc.WndProcHandle, _msg.Msg, _msg.WParam, _msg.LParam);
end;

If anyone knows how I can correct this communication I will be grateful.

  • Who sends and who receives are different processes? If yes, there is your explanation. You are sending an address in the parameter LongInt(@MyData), which is invalid for the process receiving the message. I believe this form of IPC does not support data of arbitrary sizes.

  • Thank you for answering... and yes are different processes, each process carries a different dll and would like them to communicate. What is the solution to this ?

  • Use a socket or named pipe. Named pipe is faster than sockets, but usually the staff feels more comfortable with socket. I couldn’t find an accessible tutorial in Delphi, but I did find one in C++, easily translatable to Delphi: http://avid-insight.co.uk/2012/03/introduction-to-win32-named-pipes-cpp/

1 answer

2

You are passing the data through lParam, wParam comes to the other empty process.

SendMessage(HWND_BROADCAST, WM_SHUTDOWN_THREADS, 0, LongInt(@MyData));
                                                 ↑

If I understand what you want to do, you will have a problem with the current code, because it is trying to pass the address of a structure to another process, an address only has meaning within a single process.

Because a process is a set of segments, all running in a single address space, each process has at least one segment, the main segment. Only segments of the same process can do the sharing resources, such as accessing any valid address on process address space.

You can do what the Vinicius Gobbo A. de Oliveira said in comment, utilise named Pipes. Here have an article explaining about the inter-process communication by means of named Pipes, applicable for Delphi and . NET.

An alternative is map the file in memory using the functions CreateFileMapping to create the mapping, OpenFileMapping to open the file and MapViewOfFile to read the contents of the file.

An alternative (a little simpler) that can be used is the Data Copy feature(Data Copy) which allows data to be sent from one application to another.

To use it you will have to send the message WM_COPYDATA through function PostMessage or SendMessage(to send to a segment of the same process can be used PostThreadMessage, but that is not the case!).

Data must be passed to a structure COPYDATASTRUCT.

The example below will send a structure that will contain the Handle and the PID of the process that will send the message.

type
  TMyStruct = packed record  // Estrutura que vai ser enviada a outro processo
    lpHandle: HWND;
    lpProcessid: DWORD;
end;

procedure PostData;   // Método responsável por enviar
var
  H: HWND;
  MyStruct: TMyStruct;
  copyDataStruct: TCopyDataStruct;
Begin
Try
  MyStruct.lpHandle := Application.Handle;       // Pega a handle da aplicação
  MyStruct.lpProcessid := GetCurrentProcessId(); // Pega o PID

  copyDataStruct.cbData := SizeOf(MyStruct);     // Tamanho em bytes dos dados apontados em lpdata
  copyDataStruct.lpData := @MyStruct;            // Dados que serão enviados a outro processo

  H := FindWindow(nil, 'Form2');                 // Pega a handle da janela que tenha o Form2 no título
  if IsWindow(h) then                            // Se for uma janela existente
    SendMessage(h, WM_COPYDATA, 0, Integer(@copyDataStruct)); // Envia a mensagem
Except
End;
end;

To receive the message (application you will receive):

type
  TMyStruct = packed record   // Estrutura que vai receber os dados do outro processo
    lpHandle: HWND;
    lpProcessid: DWORD;
  end;

type
  TForm1 = class(TForm)
  private
    { Private declarations }
    protected
     procedure WMCopyData(var Msg : TWMCopyData); message WM_COPYDATA; // Quando a aplicativo receber essa mensagem
  public
    { Public declarations }
  end;
// .....
procedure TForm1.WMCopyData(var Msg: TWMCopyData); // Método que vai tratar a mensagem WM_COPYDATA
var
  MyStruct: TMyStruct;
  TempHandle, TempProcessID: string;
Begin
  MyStruct := TMyStruct(Msg.CopyDataStruct.lpData^); // Coloca em MyStruct o que foi recebido
  TempHandle := Inttostr (MyStruct.lpHandle);        // Coloca em TempHandle a handle recebida de outro proceso
  TempProcessID := Inttostr( MyStruct.lpProcessid);  // Coloca em TempProcessID o PID do outro processo

  // Daqui em diante fazer algo...
  ShowMessage(Format('Dados do outro processo:'#13'Handle %s ProcessID %s', [TempHandle, TempProcessID]));
end;

The above example was done with forms, some things will not work for an application console or for a DLL, you will have to adapt according to your need.

There is a good article that explains about this in:

Browser other questions tagged

You are not signed in. Login or sign up in order to post.