这篇文章适合你:
DELPHI中使用WINDOWS系统原子
原子和原子表:
Win32系统中,为了实现信息共享,系统维护了一张全局原子表,用于保存字符串与之
对应的标志符的组合。应用程序将一个字符串放到原子表中,并接受系统返回的一个16位
的整数,这个整数被称为原子(ATOM),用于访问可变长度的字符串,而放到原子表保存
的字符串称为原子名称。
原子表分为全局(GLOBAL)原子表和局部(LOCAL)原子表,全局原子表可以被所
有的应用程序使用,当一个程序把字符串注册到原子表中以后,系统产生一个原子,原子是
一个唯一的整型ID,用来访问可变长度的字符串,Windows NT 和 Windows 98 的系统库
都在全局原子表中为已注册的系统信息和已注册的剪贴板格式创建原子。因为这些值是在进
程间共享的,所以,它们必须驻留在共享内存区,在 Windows 98 上原子值的数目为 1K,
在 Windows NT 上原子值的数目为 16K。因为原子的唯一性,通过查询全局原子表,任何
程序都可以用全局原子获得它所标志的字符串;与全局原子表相关的API函数有
GLOBALAddAtom,GLOBALDeleteAtom,GLOBALFINDATOM,GLOBALGetAtomNam;
局部原子表只能被创建这个原子表的应用程序使用。局部原子是把在应用程序中大量出
现的相同字符串放到系统原子表中,在结构中包含这些原子,这样就不必把每个字符串放到
结构中,一个字符串在内存中只出现一次,从而减少了占用的内存!与局部原子表相关的
API函数有ADDATOM,DELETEATOM,FINDATOM,GETATOMNAME;
本文用到的相关的API函数:
ATOM GlobalAddAtom( //将字符串添加到系统全局原子表中,该函数返回原子
LPCTSTR lpString
);
ATOM GlobalDeleteAtom( //从全局原子表中删除该原子
ATOM nAtom //ATOM为原子
);
ATOM GlobalFindAtom( //从全局原子表中查找字符串
LPCTSTR lpString //要查找的字符名称
);
UINT GlobalGetAtomName( //在消息过程中获得字符串
ATOM nAtom, //将要查找的原子
LPTSTR lpBuffer, //要保存到的字符变量
int nSize //长度
);
FindWindow( //返回一个窗口的句柄
lpClassName: PChar; //类名称 , 就是这个 Window 在系统中注册的名字。
lpWindowName: PChar //窗口名称,就是这个 Window Window 可显示出來的Text 。
): HWND;
BOOL PostMessage( //向指定窗口发送消息
HWND hWnd, //目的窗口的句柄
UINT Msg, //要发送的消息
WPARAM wParam,, //第一个消息的参数
LPARAM lParam // 第二个消息的参数
);
原子表在系统编程中的应用:
一、保证程序只运行一次(使用全局原子表)
程序思路:在每次程序运行之前,查询系统全局原子表,看是否有指定的字符串存在,要用
到GLOBALFINDATOM,如果GLOBALFINDATOM返回不为0,说明程序副本已经运行,
提示错误信息,并关闭程序;如果返回为0,说明程序副本没有运行,添加指定字符串到系
统全局原子表(GLOBALADDATOM,并运行程序;在软件关闭之前,要将指定的字符串在
系统原子表中删除(GLOBALDELETEATOM);
程序源码如下:
procedure TForm1.FormCreate(Sender: TObject);
const atom_id='这里存放你的程序标示';
//注意这个地方的ATOM_id要与FORMCLOSE的ATOM_id要一致才可以
var
testatom:integer;
begin
testatom:=globalfindatom(pchar(atom_id));
if testatom=0 then
begin
testatom:=globaladdatom(pchar(atom_id));
end
else
begin
showmessage('程序副本已经运行,按确定后终止该程序!');
application.Terminate;
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
const atom_id='这里存放你的程序标示';
var
testatom:integer;
begin
testatom:=globalfindatom(pchar(atom_id));
globaldeleteatom(testatom);
end;
二、 在程序之间传输字符串数据(使用全局原子表)
在实际应用中,我们经常需要多个程序相互配合来完成某些特定功能。例如两个应用程序间
的同步、互斥;应用程序在起第二份实例时的参数自动传递…。要实现这些功能,就必须能
实现程序间的数据传递。
思路:
1、 先定义自定义的消息,WM_ATOMDATA;
2、 A程序中要用到API函数获得B程序的句柄,如HN;
3、 A程序将要传输的字符串加到系统全局原子表中GLOBALADDATOM;
4、 用POSTMESSAGE(HN,WM_ATOMDATA,ATOM,0)将刚添加的全局原子投递到
B窗口,其中WM_ATOMDATA是用户自定义的消息。
5、 B程序中处理WM_ATOMDATA消息,来得到A程序中传输过来的原子
6、 用GLOBALGETATOMNAME(ATOM(A程序传输的原子),BUFFER(存放原子名称),
256(长度,最多为256个字符));来接受原子;
程序代码如下:
(1)、发送端源程序如下:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
CONST WM_Atomdata=WM_USER+200;
//自定义的消息,注意要与接受程序的WM_ATOMDATA一致;
type
Treceive_atom = class(TForm)
Myedit: TEdit;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
receive_atom: Treceive_atom;
implementation
{$R *.DFM}
procedure Treceive_atom.Button1Click(Sender: TObject);
const atom_id='这里存放你的程序间传输的字符串';
var
Hn:HWND;
test_atom:integer;
begin
test_atom:=globaladdatom(pchar(atom_id)); //将字符串添加到全局原子表;
hn:=findwindow('TSend_atom','Send_atom'); //查找目的窗口的句柄;
postmessage(hn, WM_Atomdata,test_atom,0); //想目的窗口发送消息;
end;
procedure Treceive_atom.FormClose(Sender: TObject;
var Action: TCloseAction);
const atom_id='这里存放你的程序间传输的字符串';
//这个与上面的第一一定要一致才可以!!!
var
test_atom:integer;
begin
test_atom:=globalfindatom(pchar(atom_id)); //在全局原子表中查找指定字符串;
globaldeleteatom(test_atom); //删除程序一开始建立的原子;
end;
end.
(2)、接受端源程序:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
CONST WM_Atomdata=WM_USER+200;
//自定义的消息,注意要与发送程序的WM_ATOMDATA一致;
type
Tsend_atom = class(TForm)
Edit1: TEdit;
procedure proc(var message:tmessage);message WM_ATOMDATA;
//定义用自定义消息的处理函数
private
{ Private declarations }
public
{ Public declarations }
end;
var
send_atom: Tsend_atom;
implementation
{$R *.DFM}
procedure tsend_atom.proc(var message:tmessage);
var
myatom:integer;
buffer
char;
leng:integer;
begin
showmessage('已经接受到发送程序发送的消息了!'); //显示框提示受到消息;
myatom:=message.WParam; //取得原子
getmem(buffer,256);
leng:=globalgetatomname(myatom,buffer,256);
//查找全局原子表,并把查找到的字符串放到BUFFER中
edit1.text:=buffer;
//在edit1中显示字符串
freemem(buffer);
//释放内存
end;
end.
测试步骤:
1、 运行发送程序;
2、 运行接受程序;
3、 在接受程序运行完毕后,按下发送程序的BUTTON1;
4、 看看接受程序中的EDIT1里面是否为'这里存放你的程序间传输的字符串'。
注意:
1、 原子名称最长为255个字符,所以在程序间传输的字符串最长长度为256!
2、将某一个字符串加入 全局原子表后,一定要有相对应的删除动作,不然即使应用程序已
经結束了,該 原子还是回保留在系统中,直到删除动作发生或则关机。
//==========================
作者联系地址:
以上程序均在DELPHI5+WIN 2000下调试通过,如果大家有什么意见或有什么更好的想法,
请EMAIL到jiaorg@ah163.com。