`

DELPHI:实现程序间的数据传递

阅读更多
在实际应用中,我们经常需要多个程序相互配合来完成某些特定功能。例如两个应用程序间的同步、互斥;应用程序在起第二份实例时的参数自动传递…。要实现这些功能,就必须能实现程序间的数据传递。

有些特殊的高级技术可在不同的程序间传递数据,如剪贴板、动态数据交换以及OLE自动化,但有条件限制并且相对较复杂。这里,我介绍三种有效的底层技术,希望对编程爱好者有所帮助。

利用WM_COPYDATA消息
 
使用该消息涉及一个TcopyDataStruct结构类型的指针。该结构中有三个成员:
dwData 是一个32位的附加参数
cbData 表示要传递的数据区的大小
lpData 表示要传递的数据区的指针

下面举个例子。该例子由两个程序构成,分别为SendData和GetData。

SendData程序向GetData程序发送消息,并传递edit1中的字符串;GetData在收到消息后,把SendData发送的字符串接受下来,并显示在相应的edit1中。

SendData程序:
……

var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var
ds: TCopyDataStruct;
hd: THandle;
begin
ds.cbData := Length (Edit1.Text) + 1;
GetMem (ds.lpData, ds.cbData ); //为传递的数据区分配内存
StrCopy (ds.lpData, PChar (Edit1.Text));
Hd := FindWindow (nil, 'Form2'); // 获得接受窗口的句柄
if Hd <> 0 then
SendMessage (Hd, WM_COPYDATA, Handle,
Cardinal(@ds)) // 发送WM_COPYDATA消息
else
ShowMessage ('目标窗口没找到!');
FreeMem (ds.lpData); //释放资源
end;

GetData程序:
 
TForm2 = class(TForm)
Edit1: TEdit;
private
{ Private declarations }
public
procedure Mymessage(var t:TWmCopyData);message WM_COPYDATA;
{ Public declarations }
end;

var
Form2: TForm2;
implementation
procedure TForm2.Mymessage(var t:TWmCopyData);
begin
Edit1.text:=StrPas(t.CopyDataStruct^.lpData);//接受数据并显示。
end;

使用这种方法是WIN32应用程序进行交互的最简单的方法。

使用全局原子
Win32系统中,为了实现信息共享,系统维护了一张全局原子表。每个原子中存放了一些共享数据。关于对原子的操作,有一组专门的API函数:

GlobalAddAtom 在表中增加全局原子
GlobalDeleteAtom 在表中删除全局原子
GlobalFindAtom 在表中搜索全局原子
GlobalGetAtomName 从表中获取全局原子

笔者用这种方法实现了避免程序二次启动,但把第二次启动所带的参数传到第一个实例中以进行相应的处理的程序。基本处理如下:

在工程文件中:

program Pvdde;
uses
Forms,shellapi,Windows,dialogs,dde in 'dde.pas' {Form1};
{$R *.RES}
begin
if GlobalFindAtom(PChar('PDDE_IS_RUNNING')) = 0 then
//避免二次启动
begin
K:=GlobalAddAtom(PChar('PDDE_IS_RUNNING'));
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end
else
begin

//传递二次启动时的参数到第一个实例

H := FindWindow(PChar('TForm1'), PChar('资料保密 严禁外传'));
if ParamCount > 0 then
begin
L := GlobalAddAtom(PChar(ParamStr(1)));
if H<>0 then
SendMessage(H, WM_MYMESSAGE, 0, L);
{ 传递原子句柄 }
GlobalDeleteAtom(L); { 使用后释放 }
end;

Application.Terminate;
end;
end.

在相应的窗口单元dde.pas增加对自定义消息WM_MYMESSAGE的处理:

procedure TForm1.MyMessage(var T:TMessage);
{对 WM_MYMESSAGE消息进行处理 }
var
P:Array [0..255] of char;
begin
GlobalGetAtomName(T.LParam, P,255); { 接受数据到p数组中 }
。。。

end;

使用存储映象文件
这种方法相对较复杂一些。

当Win95与Winows Nt向内存中装载文件时,使用了特殊的全局内存区。在该区域内,应用程序的虚拟内存地址和文件中的相应位置一一对应。由于所有进程共享了一个用于存储映象文件的全局内存区域,因而当两个进程装载相同模块(应用程序或DLL文件)时,它们实际可以在内存中共享其执行代码。

笔者通过调用一个带有特殊参数的CreateFileMapping函数,来间接达到程序间共享内存的目的。下面简要解释一下该函数。

HANDLE CreateFileMapping(
HANDLE hFile, //文件句柄
LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // 可选安全属性
DWORD flProtect, // 映象文件保护方式
DWORD dwMaximumSizeHigh, // 映象文件区域的底值
DWORD dwMaximumSizeLow, // 映象文件区域的顶值
LPCTSTR lpName // 映象文件的名字
);

如果hFile是0xFFFFFFFF,在调用程序中必须指定dwMaximumSizeHigh 和dwMaximumSizeLow参数的值以确定映象文件的大小。通过这样的参数指定,该函数就创建了一个由操作系统页文件支持的特殊逻辑映象文件,而不是由实际操作系统的文件支持的逻辑映象文件。这个逻辑映象文件可以通过复制、继承或者按名字来达到共享。至于其它参数的详细说明,请参看在线帮助。

在建立了映象文件之后,我们可以通过调用另外一个API函数MapViewOfFile来访问它的内存,该函数会返回一个指向共享内存块的特定指针。

LPVOID MapViewOfFile(
HANDLE hFileMappingObject, // 映象文件句柄
DWORD dwDesiredAccess, // 访问方式
DWORD dwFileOffsetHigh, // 映象文件区域的底值
DWORD dwFileOffsetLow, // 映象文件区域的顶值
DWORD dwNumberOfBytesToMap // 映射字节数
);

如果 dwNumberOfBytesToMap 是0,映射整个文件。以下举例说明:

private
hMapfile: THandle;
MapFilePointer: Pointer;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
hMapFile := CreateFileMapping (
$FFFFFFFF, // 特殊内存映射句柄
nil, page_ReadWrite, 0,10000,
'DdhDemoMappedFile'); // 文件名
if hMapFile <> 0 then
MapFilePointer := MapViewOfFile (
hMapFile, // 上面映象文件的句柄
File_Map_All_Access,
0, 0, 0) // 访问整个映象文件
else
ShowMessage ('hMapFile = 0');
if MapFilePointer = nil then
ShowMessage ('MapFilePointer = nil');
end;

procedure TForm1.BtnWriteClick(Sender: TObject);
begin
StrCopy (PChar (MapFilePointer),
PChar (EditWrite.Text));//把内容写入共享内存
end;

procedure TForm1.BtnReadClick(Sender: TObject);
var
S: string;
begin
S := PChar (MapFilePointer);//从共享内存读出内容
EditRead.Text := S;
end;

用这种方法,不但可以在不同的程序之间共享数据,还可以在同一程序的不同实例间共享数据。为了及时通知其它进程共享数据的变化,可以自定义一条用户消息,通过发消息来实现,这里不再赘述。

利用以上三种方法均可以有效地实现数据传递、共享,所有的例子程序均在Delphi 3.0,4.0下调试通过。如需源码,写信至wj_email@yahoo.com索要 
 
分享到:
评论

相关推荐

    Delphi程序间消息传递.txt

    Delphi程序间消息传递 使用该消息涉及一个TcopyDataStruct结构类型的指针。该结构中有三个成员: dwData 是一个32位的附加参数 cbData 表示要传递的数据区的大小 lpData 表示要传递的数据区的指针 下面举个例子。该...

    通过串口传递数据的Delphi实现

    摘要:Delphi源码,网络相关,串口通信 一个Delphi串口通信实例,通过串口传递数据的Delphi实例,程序编译运行后的截图如上示,选择串口是哪一个,若无占用,则打开串口,然后输入相关内容实现传送。一个Windows系统与...

    Delphi进程间通讯

    Delphi进程间通讯,两个不同的exe程序通过消息机制传递数据

    解决Delphi7因数据执行保护导致的Webservice无法访问错误

    更新此代码,解决Delphi7编译出的程序在调用WebService时总是因windows数据执行保护而失败的问题。

    Delphi用来操作XML配置文件写入数据库的示例.rar

    Delphi用来操作XML配置文件写入数据库的示例,以一个配置程序为例,介绍Delphi操作XML getCurrentDir 函数功能:返回当前路径 返 回 值:以\结束 GetStrLength: 函数功能:在Delphi中,通过什么函数犬我们123‘此...

    delphi XE5 ANDROID平台 调用 webservice并访问操作MSSQL数据库

    然后,将获取的数据转换为 XML 格式,并将其传递给客户端。 在客户端上,使用 THTTPRIO 控件来调用服务端的函数,并获取 XML 格式的数据。然后,使用 StringGrid 控件来显示获取的数据。 使用 Delphi XE5 可以轻松...

    Delphi开发范例宝典目录

    实例078 程序运行时对TStringGrid中的数据进行计算 94 实例079 利用TStringGrid实现表单式批量录入数据 96 实例080 在TStringGrid中实现单元格下拉列表 98 实例081 在TStringGrid组件中绘图 99 实例082 ...

    Delphi7下读取JPG文件Exif信息的类及示例,可以读取缩略图

    Delphi7写的读取JPEG文件Exif信息的类(含中文注释及Exif v2.3官方文档,含显示TIF...可继承TDefaultTranslate、TFileTranslate或另外实现IExifTranslate接口并传递给TExif的Create方法,以实现自己需要的转换方式。

    Delphi.7应用教程

    第1章 Delphi 7程序设计入门 1.1 理论知识 1.1.1 算法与程序设计 1.1.2 面向对象程序设计基础 1.1.3 Delphi 7概述 1.1.4 Delphi 7的集成开发环境 1.1.5 利用Delphi开发应用程序的方法步骤 1.1.6 Delphi 7程序的组成 ...

    Delphi中制作DLL中回调函数的应用

    但变量是在各进程的地址空间中,因此你不能借助dll的全局变量来达到两个应用程序间的数据 传递,除非你用内存映像文件。 五、其他:调用方式按照标准的Windows调用方式. 六、关于参数传递 •Delphi程序之间调用...

    Delphi 7.0 彻底更换桌面壁纸及剪贴板监控程序范例.rar

    Delphi彻底更换桌面壁纸及剪贴板监控程序,需要使用到下列delphi类库:  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,  StdCtrls, registry, Clipbrd, ExtCtrls{监视剪贴板单元}; ...

    Delphi7.完美经典

    第17章 数据程序设计——使用Delphi组件 17-1 TADOConnection组件 17-1-1 TADOConnection组件常用的属性 17-1-2 TADOConnection组件常用的方法 17-1-3 TADOConnection组件常用的事件 17-2 TADOCommand组件 17...

    Delphi 实例程序

    简单编码工具,base64编码规范及相关实现原理; Base64编码是从二进制到字符的过程,可...在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式。此时,采用Base64编码具有不可读性

    Delphi 5编程实例与技巧

    5.3.7 不同程序间的拖曳操作 127 第6章 文件、目录和驱动器 129 6.1 文件 129 6.2 文件对话框组件 129 6.3 Win3.1相关组件 131 6.4 常用函数 131 6.4.1 文件操作常用函数 131 6.4.2 目录操作常用函数 136 6.4.3 驱动...

    DELPHI技巧集(集合各种开发源码)

    12 Colorcour.htm 让彩色光标出现在Delphi程序中 2K 13 Compon_mk.htm 面向组件的系统开发方法 2K 14 Comtech.htm COM/DCOM如何传递数组 2K 15 Comvsdcom.htm COM/DCOM的区别与联系 2K 16 Cookite....

    delphi EhLib 9.5.012 Full Source 专业版 .rar

    数据访问的相应驱动程序。 -------------------- 2.安装库 -------------------- -------------------- 2.1自动安装库 -------------------- 从“安装程序”文件夹中运行EhLibInstaller.exe程序以在以下位置...

    delphi 序列化

    这两个过程结合起来,可以轻松地存储和传输数据。 序列化的目的  1、以某种存储形式使自定义对象持久化;  2、将对象从一个地方传递到另一个地方。  3、使程序更具维护性 在Delphi中 只要从 TPersistent继承后就...

    Delphi多线程编程之三 同步读写全局数据

    当线程调用ReleaseMutex()函数并传递一个互斥对象的句柄作为参数时,这种拥有关系就被解除,互斥对象重新进入发信号状态。 注意除WaitForSingleObject()函数外,你还可以使用WaitForMultipleObject()和...

    DLL在Delphi程序开发中的应用 (2007年)

    动态链接库是用来编写Windows应用程序的关键组成部分,使用DLL可以共享代码、系统资源并隐藏实现的代码,易于实现应用程序的模块化...实现了VC与Delphi程序代码的共享以及在不同应用程序开发语言中实现数据的实时传递.

Global site tag (gtag.js) - Google Analytics