【发布时间】:2015-08-17 19:32:00
【问题描述】:
我尝试在 Windows 中的两个应用程序之间交换数据。我使用来自Zarko Gajic 的示例。它使用 Windows 消息传递,示例效果很好。有一个发送者和一个接收应用程序以及一些共享数据:全部为 VCL 编码。代码如下所示。
unit SenderMain;
{ How to send information (String, Image, Record) between two Delphi applications
http://delphi.about.com/od/windowsshellapi/a/wm_copydata.htm
Learn how to send the WM_CopyData message between two Delphi
applications to exchange information and make two applications
communicate. The accompanying source code demonstrates how to
send a string, record (complex data type) and even graphics
to another application.
~Zarko Gajic
About Delphi Programming
http://delphi.about.com
}
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, TlHelp32,
shared_data;
type
TSenderMainForm = class(TForm)
Button_Send_Data: TButton;
Log: TListBox;
procedure Button_Send_DataClick (Sender: TObject);
protected
procedure Loaded; override;
procedure SendString (send_string: aString);
end; // Class: TSenderMainForm //
var
SenderMainForm: TSenderMainForm;
implementation
{$R *.dfm}
{**************** NextWindow ****************}
function NextWindow (wnd: Thandle; list: Tstringlist):boolean; stdcall;
{This is the callback function which is called by EnumWindows procedure
for each top-level window. Return "true" to keep retrieving, return
"false" to stop EnumWindows from calling}
var
title: array [0..255] of char;
receiverHandle: HWND;//THandle;
win_name: PChar;
s: AnsiString;
begin
getwindowtext (wnd, title, 256);
s := AnsiString (pchar(@title));
if (s <> '') and (list.indexof (string (s)) < 0) then
begin
win_name := PaString (s);
receiverHandle := FindWindow (win_name, nil); // Find receiving app
s := AnsiString (Format ('%s (%d)', [s, receiverHandle]));
list.add (string (s));
end; // if
result:=true;
end;
procedure TSenderMainForm.Loaded;
begin
inherited Loaded;
enumwindows (@nextwindow, lparam (Log.Items)); {pass the list as a parameter}
end;
procedure TSenderMainForm.SendString (send_string: aString);
var copyDataStruct: TCopyDataStruct; { Declared in Windows.pas: TCopyDataStruct}
receiverHandle: THandle;
res: integer;
begin
// Copy string to CopyDataStruct
copyDataStruct.dwData := 1; //use it to identify the message contents
copyDataStruct.cbData := (1 + Length (send_string)) * SizeOf (Char);
copyDataStruct.lpData := PaString (send_string);
receiverHandle := FindWindow (PaString (cClassName), nil); // Find receiving app
if receiverHandle = 0 then // not found
begin
Log.Items.Add ('CopyData Receiver NOT found!');
end else // found, send message
begin
res := SendMessage (receiverHandle, WM_COPYDATA, Integer(Handle), Integer(@copyDataStruct));
Log.Items.Add (Format ('String sent, len = %d, result = %d', [copyDataStruct.cbData, res]));
Log.Items.Add ('"' + PaString (copyDataStruct.lpData) + '"');
end; // if
end; // SendString
procedure TSenderMainForm.Button_Send_DataClick (Sender: TObject);
begin
SendString (ParamStr (0));
end;
====================== Unit copyDataReceiver ================
unit ReceiverMain;
{ How to send information (String, Image, Record) between two Delphi applications
http://delphi.about.com/od/windowsshellapi/a/wm_copydata.htm }
interface
uses
Windows, Messages,
SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, shared_data;
type
TReceiverMainForm = class (TForm)
Log: TListBox;
procedure FormCreate(Sender: TObject);
private
procedure WMCopyData (var Msg: TWMCopyData); message WM_COPYDATA;
procedure WMSignalClose (var Msg: TMessage); message WM_SIGNAL_CLOSE;
procedure HandleCopyDataString (copyDataStruct: PCopyDataStruct);
end;
var ReceiverMainForm: TReceiverMainForm;
implementation
{$R *.dfm}
procedure TReceiverMainForm.FormCreate (Sender: TObject);
begin
Log.Clear;
end;
procedure TReceiverMainForm.WMSignalClose (var Msg: TMessage);
var pfn: PaString;
fn: aString;
begin
Log.Items.Add (Format ('Signal received, WParam = %d, LParam = %d', [Msg.WParam, Msg.LParam]));
pfn := PaString (Msg.LParam);
fn := aString (pfn);
Log.Items.Add (fn);
end;
procedure TReceiverMainForm.WMCopyData (var Msg: TWMCopyData);
var copyDataType: Int32;
begin
copyDataType := Msg.CopyDataStruct.dwData;
//Handle of the Sender
Log.Items.Add (Format ('WM_CopyData (type: %d) from: %d', [copyDataType, msg.From]));
HandleCopyDataString (Msg.CopyDataStruct);
//Send something back
msg.Result := Log.Items.Count;
end;
procedure TReceiverMainForm.HandleCopyDataString (copyDataStruct: PCopyDataStruct);
var mess: aString;
begin
mess := aString (PaString (copyDataStruct.lpData));
Log.Items.Add (Format ('Received string of length %d at %s', [Length (mess), DateToStr (Now)]));
Log.Items.Add ('"' + mess + '"');
end;
end.
================ unit shared_data ==========================
unit shared_data;
interface
uses Messages;
const
WM_SIGNAL_CLOSE = WM_APP + 2012;
ARG_AMI_1 = 285;
ARG_AMI_2 = 1;
cClassName = 'TReceiverMainForm';
type
aString = string;
PaString = PChar;
implementation
end.
发送方应用程序的关键在于它向接收方发送 WM_COPYDATA。为了找到接收者,FindWindow 与接收应用程序的名称(硬编码)一起使用,它返回窗口句柄。如果句柄为零,则显示错误。
当我在 FMX 应用程序中复制它时,会出现问题。 FMX 接收部分不起作用,而 VCL 接收器可以接收来自 VCL 发送器或 FMX 发送器的消息。 FMX接收器的代码如下所示。
因为我不确定窗口的名称,所以我枚举了所有窗口,将数字句柄添加到每个窗口名称,并将其显示在发送方的列表框中。所有句柄都为零。我有两个问题:
- 为什么枚举中的所有句柄都为零?
- 为什么我无法向 FMX 接收应用程序发送消息?
任何帮助将不胜感激。
unit copyDataReceiver;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Layouts, FMX.ListBox,
Windows, Messages, shared_data;
type
TReceiverMainForm = class (TForm)
Log: TListBox;
procedure FormCreate(Sender: TFMXObject);
private
procedure WMCopyData (var Msg: TWMCopyData); message WM_COPYDATA;
procedure WMSignalClose (var Msg: TMessage); message WM_SIGNAL_CLOSE;
procedure HandleCopyDataString (copyDataStruct: PCopyDataStruct);
end;
var ReceiverMainForm: TReceiverMainForm;
implementation
{$R *.fmx}
procedure TReceiverMainForm.FormCreate (Sender: TFMXObject);
begin
Log.Clear;
end;
procedure TReceiverMainForm.WMSignalClose (var Msg: TMessage);
var pfn: PaString;
fn: aString;
begin
Log.Items.Add (Format ('Signal received, WParam = %d, LParam = %d', [Msg.WParam, Msg.LParam]));
pfn := PaString (Msg.LParam);
fn := aString (pfn);
Log.Items.Add (fn);
end;
procedure TReceiverMainForm.WMCopyData (var Msg: TWMCopyData);
var copyDataType: Int32;
begin
copyDataType := Msg.CopyDataStruct.dwData;
//Handle of the Sender
Log.Items.Add (Format ('WM_CopyData (type: %d) from: %d', [copyDataType, msg.From]));
HandleCopyDataString (Msg.CopyDataStruct);
//Send something back
msg.Result := Log.Items.Count;
end;
procedure TReceiverMainForm.HandleCopyDataString (copyDataStruct: PCopyDataStruct);
var mess: aString;
begin
mess := aString (PaString (copyDataStruct.lpData));
Log.Items.Add (Format ('Received string of length %d at %s', [Length (mess), DateToStr (Now)]));
Log.Items.Add ('"' + mess + '"');
end;
end.
【问题讨论】:
标签: windows delphi firemonkey sendmessage