在WIN2000/XP系统中带有动态连接库Netapi32.dll,其中包含了API函数NetMessageBufferSend的定义和实现,利用此函数可以实现如Win9X下的WINPOP.EXE的功能。NetMessageBufferSend函数的定义为:
NET_API_STATUS NetMessageBufferSend(LPWSTR servername,LPWSTR msgname,LPWSTR fromname,LPBYTE buf,DWORD buflen);
其中各参数的含义如下:servername的含义是包含Unicode字符串的远程服务器名。这个函数就在这个服务器上执行。为空指针或空字符串时表示函数就在本机执行。msgname是指向Unicode字符串的指针,指定消息发送的对象。fromname指向Unicode字符串的指针,指定消息从何处发来,为空则表示消息从本机登陆用户发送。Buf指向要发送的消息内容指针。buflen表示以字节为单位的Buf中的字符个数。在这里还要对Unicode做一下简单的介绍。Unicode是一种双字节编码机制的字符集,使用0-65535之间的双字节无符号整数对每个字符进行编码。这样,在Unicode字符集中,至少可以定义65536个不同的字符,因此Unicode能使用世界上几乎所有的语言,足以应付目前绝大多数场合的需要。
此函数成功调用时返回NERR_Success。调用失败时则返回如下值:ERROR_ACCESS_DENIED(表示用户无权请求信息),ERROR_INVALID_PARAMETER(表示指定参数不正确),ERROR_NOT_SUPPORTED(表示不支持此网络请求),NERR_NAMENOTFound(表示找不到消息发送目标),NERR_NetworkError(表示网络硬件出现问题)。作者通过此函数的调用,在WIN2000/XP下实现了消息的实时发送,开发工具是Delphi6。下面是程序的整个设计过程。新建一个应用程序,放入如下几个主要的控件:
MesText:TMemo; 用于输入要发送的信息
BtnExit:TBitBtn; 退出按钮
BtnSend:TBitBtn; 发送按钮
AddrBox:TComboBox; 输入要发送的目标IP或机器名
StatusLabel:TLabel; 显示发送信息后的返回值
程序界面如下:
图1 信使服务程序设计界面
下面介绍实现程序的几个主要的过程或函数。首先是程序的初始化过程:
procedure TfrmMain.FormCreate(Sender: TObject);
var Ip,ipstr:string;
buffer:array[1..32] of char;
WSData:TWSAData;
Host:PHostEnt;
i:byte;
begin
if WSAstartup(2,WSData)<>0 then //调用WS2_32.DLL实现WINSOCK的初始化
begin
showmessage('WS2_32.DLL初始化失败!');
halt;
end;
if gethostname(@buffer[1],32)<>0 then
begin
showmessage('没有得到主机名!');
halt;
end;
Host:=gethostbyname(@buffer[1]);
if Host=nil then
begin
showmessage('IP地址为空!');
halt;
end
else
for i:=1 to 4 do
begin
Ip:=inttostr(Ord(Host.h_addr^[i-1]));
Ipstr:=Ipstr+Ip;
if i<4 then Ipstr:=Ipstr+'.'
end;
//以上过程是查询本机(发送端)的IP地址
MesText.Lines.Clear; //清空
MessageHeader := TStringList.Create;
MessageHeader.Add('-----------------------------------------------------');
MessageHeader.Add(' 从IP地址: '+ipstr+ ' 发来的消息');
MessageHeader.Add('-----------------------------------------------------');
//以上语句是建立消息的标题行,其中包括本机(发送端)的IP地址
end;
发送信息事件代码如下:
procedure TfrmMain.btnSendClick(Sender: TObject);
var res: Integer;
begin
if AddrBox.Text <> '' then
begin
StatusLabel.Font.Color := clBlack;
StatusLabel.Caption := '请等待... '; //正在找目标主机
Update; //刷新
if AddrBox.Items.IndexOf(AddrBox.Text) = -1 then
AddrBox.Items.Add(AddrBox.Text); //如果组合框中目标主机是新目//标则将其记录下来
res := SendMsg(AddrBox.Text,'',MessageHeader.Text+mesText.Text); //发送消息
if res = 0
then frmMain.StatusLabel.Font.Color := clBlue //成功返回
else frmMain.StatusLabel.Font.Color := clRed; //调用失败
case res of
0 : frmMain.StatusLabel.Caption := '信息成功发送!';
87 : frmMain.StatusLabel.Caption := '指定参数不正确!';
123 : frmMain.StatusLabel.Caption := '不支持此网络请求!';
2273 : frmMain.StatusLabel.Caption := '找不到信息发送目标:'+frmMain.AddrBox.Text;
else frmMain.StatusLabel.Caption := '错误号码: '+IntToStr(res);
end;
end;
end;
发送消息函数及其相关函数的定义和实现如下,首先是Unicode字符集的转化函数:
function ToUnicode(str:string;dest:PWideChar):integer;
var len:integer;
begin
StringToWideChar(str,dest,len);
Result:=len;
end;
API函数NetMessageBufferSend的定义:
function NetMessageBufferSend; external 'netapi32.dll' name 'NetMessageBufferSend';
发送消息函数的实现:
function SendMsg(Toh,From,Msg:string):integer;
var ToName :array [0..64] of WideChar;
WMsgText:array [0..1000] of WideChar;
MsgLen, i:integer;
begin
for i := 0 to 64 do ToName[i] := #0; //用NUL字符填充
ToUnicode(Toh,ToName);
for i := 0 to 1000 do WMsgText[i] := #0;
ToUnicode(Msg,WMsgText);
Result:=NetMessageBufferSend(nil,ToName,nil,@WMsgText,MsgLen);
end;
程序运行结果如图2、图3所示:
图2 信使服务程序运行结果——发送端(10.67.236.10)
图3 信使服务程序运行结果——接受端(10.67.236.33)
本程序的IP地址项可以输入主机名,但对方必须是在同一网段内的主机。此程序只能运行在Win2000/XP系统中,在Win9X下运行会出错,因为Win9X中的Netapi32.dll动态连接库中没有定义NetMessageBufferSend函数,只在Win2000/XP系统中有相关的定义。此程序在DELPHI6+Win2000环境下调试通过。
|