请问有没有办法用Delphis测出当前机器是否已经联网,包括是局域网上网?(200分)

  • 主题发起人 主题发起人 教父
  • 开始时间 开始时间
这个问题好象从前做过!查一下吧!!
 
很多的方法啊,比如直接用api,或者是注册表,很多的帖子都有介绍,等我回家再贴一个
源程序出来!!!星期天
 
那些查注册表或是用API的我找了一大堆,但实际上好象都没有用。
 
如下方法可以解决:
function InternetConnected:Boolean;
var dwConnectionTypes:DWORD;
begin
dwConnectionTypes:=INTERNET_CONNECTION_MODEM+INTERNET_CONNECTION_LAN+INTERNET_CONNECTION_PROXY;
Result:=InternetGetConnectedState(@dwConnectionTypes,0);
end;

修改dwConnectionTypes=...那行可以解决(只取INTERNET_CONNECTION_LAN)
 
DWORD dwConnectState;
CString strConnectState;
BOOL bOK = InternetGetConnectedState( &dwConnectState, 0);
if ( bOK )
{
if ( dwConnectState & INTERNET_CONNECTION_LAN )
strConnectState = "Local system uses a local area network to connect to the Internet. ";
if ( dwConnectState & INTERNET_CONNECTION_MODEM )
strConnectState = "Local system uses a modem to connect to the Internet. ";
if ( dwConnectState & INTERNET_CONNECTION_MODEM_BUSY )
strConnectState = "No longer used. ";
if ( dwConnectState = INTERNET_CONNECTION_PROXY )
strConnectState = "Local system uses a proxy server to connect to the Internet. ";
}
测试连接是否有效,可以用:InternetCheckConnection

检测计算机是否联网比较简单的做法可以通过一个 Win32 Internet(WinInet) 函数 InternetCheckConnection来实现;
这个函数的功能是检查是否能够建立 Internet 连接。
它的实现是在 %SystemRoot%/System32/wininet.dll 中,Delphi 调用声明在 WinInet.pas 中,
其 API 声明如下:

BOOL InternetCheckConnection(
IN LPCSTR lpszUrl,
IN DWORD dwFlags,
IN DWORD dwReserved
);

参数的意义是:

lpszUrl: 需要测试能否建立连接的 URL 地址,可以为空;
dwFlags: 目前只能是 FLAG_ICC_FORCE_CONNECTION(这个常量 Delphi 中没有声明,其值为 $00000001);
dwReserved: 目前只能为 0。

调用的说明:

如果 lpszUrl 是非空的,Windows 从中解析出 Host 名然后 Ping 这个指定的 Host。
如果 lpszUrl 是空的,并且 WinInet 内部服务器的 database 中有一个关于最近的 Server 的纪录,Windows 就从这条纪录中解析出 Host 名然后 Ping 它。

如果能够成功的连接返回 True,否则返回 False;

以下是一个判断当前计算机是否联网的例子:

procedure TForm1.Button1Click(Sender: TObject);
begin
if InternetCheckConnection('http://www.yahoo.com/', 1, 0) then
edit1.text:= 'Connected'
else
edit1.text:= 'Disconnected';
end;

通过上述的方法只能检测出当前计算机是否物理联网,即网线是否接好,网卡是否能顺利工作,不能确定是否能够实现获得 Internet 服务,即是否能和 ISP 进行 Internet 连接。
这时可以通过另一个 Win32 Internet(WinInet) 函数 InternetQueryOption 来检测;
这个函数的功能是查询指定 Internet 句柄的状态、选项。
其 API 声明如下:

BOOL InternetQueryOption(
IN HINTERNET hInternet,
IN DWORD dwOption,
OUT LPVOID lpBuffer,
IN OUT LPDWORD lpdwBufferLength
);

参数的意义是:

hInternet:查询对象的 Internet 句柄(全局查询时为 nil),
dwOption:查询的项目;
lpBuffer:返回的查询结果;
lpdwBufferLength:查询结果的字节长度(包括 IN 和 OUT);

查询成功返回 True,否则返回 False;

我们要查询当前计算机的 Internet 连接状态时可以使用查询项目 INTERNET_OPTION_CONNECTED_STATE,

得到的 ConnectState 返回值可能是以下值的一个或几个值之和:

INTERNET_STATE_CONNECTED :$00000001 连接状态;
INTERNET_STATE_DISCONNECTED :$00000002 非连接状态(和 INTERNET_STATE_CONNECTED 对应);
INTERNET_STATE_DISCONNECTED_BY_USER :$00000010 用户请求的非连接状态
INTERNET_STATE_IDLE :$00000100 连接状态,并且空闲
INTERNET_STATE_BUSY :$00000200 连接状态,正在响应连接请求

以下是一个判断当前计算机是否可以获得 Internet 服务的例子:

function TForm1.CheckOffline: boolean;
var
ConnectState: DWORD;
StateSize: DWORD;
begin
ConnectState:= 0;
StateSize:= SizeOf(ConnectState);
result:= false;
if InternetQueryOption(nil, INTERNET_OPTION_CONNECTED_STATE, @ConnectState, StateSize) then
if (ConnectState and INTERNET_STATE_DISCONNECTED) <> 2 then result:= true;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
if CheckOffline then
edit1.text:= 'Connect To ISP'
else
edit1.text:= 'Disconnect To ISP';
end;

需要说明的是 InternetQueryOption 函数的检测结果只能表明当前的 Internet 设置是可用的,
并不能表示计算机一定能访问 Internet,例如网线掉了,网卡突然坏了之类的错误就没法检测出来,
要想检测当前计算机是否能够获得 Internet 服务了必须两个函数结合起来使用。

以上程序在 Win2000, Delphi5.0 下调试通过。

最后要提醒大家注意的是在 uses 中要加上 WinInet。
 
这篇贴子我也看过,但是实际上InternetCheckConnection这个函数有些危险,如果给的
地址连不上的话,整个程序都跟死了一样,我不希望这样。
 
呵呵。总算有了自己的地盘。

捕捉一下异常如何?
 
如何捕捉异常?关键是没有什么地方可以产生异常的
 
http://www.codelphi.com/jsjn/read.asp?ano=217
 
去看了,还是上面几位朋友提到的东西
 
听听, 也很想知道。
 
可以调用Ping操作测试是否联上网
需要ICMP.dll文件,在系统目录下可找到

procedure TfrmPing.FormCreate(Sender: TObject);
var
// WSAData: TWSAData;
hICMPdll: HMODULE;
begin
// Load the icmp.dll stuff
hICMPdll := LoadLibrary('icmp.dll');
@ICMPCreateFile := GetProcAddress(hICMPdll,'IcmpCreateFile');
if @ICMPCreateFile<>nil then
showmessage('not nill');
@IcmpCloseHandle := GetProcAddress(hICMPdll,'IcmpCloseHandle');
if @IcmpCloseHandle<>nil then
showmessage('not nill');
@IcmpSendEcho := GetProcAddress(hICMPdll,'IcmpSendEcho');
if @IcmpSendEcho<>nil then
showmessage('not nill');
hICMP := IcmpCreateFile;
StatusShow.Text := '';
StatusShow.Lines.Add('目的IP地址 字节数 返回时间(毫秒)');
end;

procedure TfrmPing.Button1Click(Sender: TObject);
var
IPOpt:TIPOptionInformation;// IP Options for packet to send
FIPAddress:DWORD;
pReqData,pRevData:PChar;
pIPE:PIcmpEchoReply;// ICMP Echo reply buffer
FSize: DWORD;
MyString:string;
FTimeOut:DWORD;
BufferSize:DWORD;
begin
if PingEdit.Text<>'' then
begin
FIPAddress :=inet_addr(Pchar(PingEdit.Text));
FSize := 40;
BufferSize := SizeOf(TICMPEchoReply) + FSize;
GetMem(pRevData,FSize);
GetMem(pIPE,BufferSize);
PERF_COUNTER_COUNTER
FillChar(pIPE^, SizeOf(pIPE^), 0);
pIPE^.Data := pRevData;
MyString := 'Hello,World,Hello,World,Hello,World';
pReqData := PChar(MyString);
FillChar(IPOpt, Sizeof(IPOpt), 0);
IPOpt.TTL := 64;
FTimeOut := 4000;
IcmpSendEcho(hICMP, FIPAddress, pReqData,Length(MyString),
@IPOpt, pIPE, BufferSize, FTimeOut);
if pReqData^ = pIPE^.Options.OptionsData^ then
begin
StatusShow.Lines.Add(PChar(PingEdit.Text) + ' '
+IntToStr(pIPE^.DataSize) + ' yy ' +IntToStr(pIPE^.RTT));
end
else
begin
StatusShow.Lines.Add(PChar(PingEdit.Text) + ' '
+IntToStr(pIPE^.DataSize) + ' nn ' +IntToStr(pIPE^.RTT));
end;
FreeMem(pRevData);
FreeMem(pIPE);
end;
end;
 
ping的效果和InternetCheckConnection是一样的.同样会出现:
"如果给的地址连不上的话,整个程序都跟死了一样"
用个比较安全稳定的网址吧, 比如政府网站啥的.
并且有的防火墙软件会拦截Ping的icmp包.

事实上,我猜测根本没有什么好的办法,君不见,若未连网,IE里输个地址,机器也要吭哧半天?
 
这个问题我认为:

可以通过多线程实现测试是否连接,将InternetCheckConnection放入一个辅助线程即可,
主线程提示用户现在正在与Internet相连(状态条)不就行了?

主线程有两个事件,一个是OnInetConnected,一个是OnInetDisconnected,辅助线程大致
如下:

TCheckInetThread = class(TThread)

public
fucntion Execute(...): Boolean; // 好像是这样声明吧:)
property MainThread: TYourMainThreadOrSomethingElse;
...

end;

fucntion TCheckInetThread.Execute(...): Boolean;
begin
if InternetCheckConnection then
MainThread.OnInetConnected
else
MainThread.OnInetDisconnected
end;

……

在主线程中建立辅助线程,将 Self 传给它,然后执行这个线程,然后等待OnInet...
事件即可!


 
To avant:

ping操作不会慢
 
这个问题正式宣告死亡,下面是我从ICS的网站上找到的东西。

Am I connected to the Internet
Steve Williams [stevewilliams@kromestudios.com]
25/02/2001
There is no perfect solution. Why? Because the Internet is just another network.
Your computer does not distinguish between LAN and Internet. They are both
networks. One of them just happens to be very big.

The Internet is no different to your local network. It is just a matter of size.

Think about your question. "Am I connected to the Internet?" Try rephrasing
your question to what you really want to ask. "Can I connect to a specific
remote host?" With the question worded like this, you can start to tackle the
problem. How do you find out if you can connect to the remote host? Try to
connect. Simple as that. If the connection attempt fails, there is no path
between you and the remote host or the remote host is refusing connections.

But, I hear you cry, I do not want the auto-dial the pop up. How do we get
around this? Ask the user how to make a connection. We see this all the time
in other Internet applications. Outlook Express, WinAmp, etc. They ask the user
what sort of network connection they have. From this information, the
applications can make the best choice about how to connect to a remote host.

doxpix在其它的贴子中给了我很多帮助,所以我要给他130分,各位不要误会啊 :)
 
我把:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=459242
的咱俩的讨论移过来了,然后把我的发言删掉了。
占用人家的地盘,真的于心不安。
**************************************************************************

来自:doxpix, 时间:2001-5-29 9:14:37, ID:545260
to 教父:
总算找到你了。解决方案如下:
在wininet.pas里有这么一段;

function InternetGetConnectedState(lpdwFlags: LPDWORD;
dwReserved: DWORD): BOOL; stdcall;
{$EXTERNALSYM InternetGetConnectedState}

{ Flags for InternetGetConnectedState }
const
INTERNET_CONNECTION_MODEM = 1;
{$EXTERNALSYM INTERNET_CONNECTION_MODEM}
INTERNET_CONNECTION_LAN = 2;
{$EXTERNALSYM INTERNET_CONNECTION_LAN}
INTERNET_CONNECTION_PROXY = 4;
{$EXTERNALSYM INTERNET_CONNECTION_PROXY}
INTERNET_CONNECTION_MODEM_BUSY = 8;
{$EXTERNALSYM INTERNET_CONNECTION_MODEM_BUSY}


来自:江小鱼儿, 时间:2001-5-29 9:24:26, ID:545273
看看


来自:netmoles, 时间:2001-5-29 10:08:31, ID:545330
to 教父:
可以使用FnugryRASNotify控件,如果需要,可以email给你


来自:教父, 时间:2001-5-29 10:10:31, ID:545332
to doxpix:实在是不好意思,我看了半天还是不知道怎么用这个函数,也没有找到帮助,
甚至到MSDN的网站上去找了都没找到,只好还要麻烦你指点一下了 :)


来自:doxpix, 时间:2001-5-29 10:25:25, ID:545345
to 教父:
以老兄的功力指点我哪敢呀。献丑了。
uses wininet;

procedure mycheck();
var flag:integer;
begin
InternetGetConnectedState( &flag, 0);
if (flag and INTERNET_CONNECTION_LAN)<>0 then
Showmessage('LAN')
else if (flag and INTERNET_CONNECTION_MODEM)<>0 then
Showmessage('Modem')
else if (flag = INTERNET_CONNECTION_PROXY) then
showmessage('Proxy');
end;

码代码的功底实在太差:(


来自:教父, 时间:2001-5-29 11:09:12, ID:545408
to doxpix:呵呵,你太谦虚了吧 :) 我也真是蠢,明明lpdwFlags声明是一个指针,我就是
没想到要用@,真是丢人,呵。
我把代码稍微改了一下,但还是不行 :(
procedure mycheck;
var
flag:Dword;
begin
InternetGetConnectedState( @flag, 0);
case flag of
INTERNET_CONNECTION_LAN:Showmessage('LAN');
INTERNET_CONNECTION_MODEM:Showmessage('Modem');
INTERNET_CONNECTION_PROXY:showmessage('Proxy');
INTERNET_CONNECTION_MODEM_BUSY:showmessage('Moden busy');
else Showmessage('Can not detect!');
end;
end;
运行中发现flag的值为86,所以检测不出来,另外为什么InternetGetConnectedState的
第二个参数为0 呢?我试了一下,如果设为其它值的话,函数都返回False,不知是怎么
回事?

to netmoles:那个控件是通过操作RAS来判断的吗?但是我的机子由于在局域网中,没有
装RAS,能有用吗?我的Mail:godfather_zhao@netease.com,谢谢。


来自:doxpix, 时间:2001-5-29 11:50:42, ID:545472
呵呵,不好意思咱们占了人家的地盘!
第二个参数是保留的,目前只能为0。

我的flag显示为18,为LAN。
恐怕不能象你那样直接用flag=INTERNET_CONNECTION_LAN
去判断吧。要先与一下。


来自:doxpix, 时间:2001-5-29 12:17:12, ID:545508
是对的呀,flag=86是LAN嘛。
86 ---------------------------------------- 01010110
INTERNET_CONNECTION_LAN(2)------------按位与00000010
-----------------------------------------------------
结果00000010(<>0嘛)


来自:热水, 时间:2001-5-29 12:57:05, ID:545555
关注


来自:netmoles, 时间:2001-5-29 13:02:08, ID:545565
to 教父:
FnugryRASNotify控件已email to you

如果有人兴趣,可到“http://www.torry.net/”寻找


来自:教父, 时间:2001-5-29 13:30:22, ID:545603
to doxpix:确实如你所说,我在我们的笔记本上测试它显示是Moden,但是我怀疑它不是
实际检测当前的网络连接,而是测试本机的连接方式,就是说如果上网的话,它是通过什
么方式,因为我把我的机器的网线拔了,它还是说我是'lan',那台笔记本没有上网,它
也说是'moden'。

to netmoles:我已收到,非常感谢!不过它需要RAS,而我们的机器是通过局域网上网,
不装拔号网络,所以不能用它了。
还有,占用了你的地盘,不好意思 :)


来自:doxpix, 时间:2001-5-29 13:41:30, ID:545619
既然已经占用,那就再占用一次。
netmoles兄弟,对不住了。

那就先判断是不是已经连上网了,同一个wininet单元里还有这个:
InternetCheckConnection.

偷一回懒,全文转贴了:
**********************************************************************************************
DWORD dwConnectState;
CString strConnectState;
BOOL bOK = InternetGetConnectedState( &dwConnectState, 0);
if ( bOK )
{
if ( dwConnectState & INTERNET_CONNECTION_LAN )
strConnectState = "Local system uses a local area network to connect to the Internet. ";
if ( dwConnectState & INTERNET_CONNECTION_MODEM )
strConnectState = "Local system uses a modem to connect to the Internet. ";
if ( dwConnectState & INTERNET_CONNECTION_MODEM_BUSY )
strConnectState = "No longer used. ";
if ( dwConnectState = INTERNET_CONNECTION_PROXY )
strConnectState = "Local system uses a proxy server to connect to the Internet. ";
}
测试连接是否有效,可以用:InternetCheckConnection

检测计算机是否联网比较简单的做法可以通过一个 Win32 Internet(WinInet) 函数 InternetCheckConnection来实现;
这个函数的功能是检查是否能够建立 Internet 连接。
它的实现是在 %SystemRoot%/System32/wininet.dll 中,Delphi 调用声明在 WinInet.pas 中,
其 API 声明如下:

BOOL InternetCheckConnection(
IN LPCSTR lpszUrl,
IN DWORD dwFlags,
IN DWORD dwReserved
);

参数的意义是:

lpszUrl: 需要测试能否建立连接的 URL 地址,可以为空;
dwFlags: 目前只能是 FLAG_ICC_FORCE_CONNECTION(这个常量 Delphi 中没有声明,其值为 $00000001);
dwReserved: 目前只能为 0。

调用的说明:

如果 lpszUrl 是非空的,Windows 从中解析出 Host 名然后 Ping 这个指定的 Host。
如果 lpszUrl 是空的,并且 WinInet 内部服务器的 database 中有一个关于最近的
Server 的纪录,Windows
就从这条纪录中解析出 Host 名然后 Ping 它。

如果能够成功的连接返回 True,否则返回 False;

以下是一个判断当前计算机是否联网的例子:

procedure TForm1.Button1Click(Sender: TObject);
begin
if InternetCheckConnection('http://www.yahoo.com/', 1, 0) then
edit1.text:= 'Connected'
else
edit1.text:= 'Disconnected';
end;

通过上述的方法只能检测出当前计算机是否物理联网,即网线是否接好,网卡是否能
顺利工作,不能确定是否能够实现获得 Internet 服务,即是否能和 ISP 进行 Internet
连接。这时可以通过另一个 Win32 Internet(WinInet) 函数 InternetQueryOption
来检测;这个函数的功能是查询指定 Internet 句柄的状态、选项。
其 API 声明如下:

BOOL InternetQueryOption(
IN HINTERNET hInternet,
IN DWORD dwOption,
OUT LPVOID lpBuffer,
IN OUT LPDWORD lpdwBufferLength
);

参数的意义是:

hInternet:查询对象的 Internet 句柄(全局查询时为 nil),
dwOption:查询的项目;
lpBuffer:返回的查询结果;
lpdwBufferLength:查询结果的字节长度(包括 IN 和 OUT);

查询成功返回 True,否则返回 False;

我们要查询当前计算机的 Internet 连接状态时可以使用查询项目 INTERNET_OPTION_CONNECTED_STATE,

得到的 ConnectState 返回值可能是以下值的一个或几个值之和:

INTERNET_STATE_CONNECTED :$00000001 连接状态;
INTERNET_STATE_DISCONNECTED :$00000002 非连接状态(和 INTERNET_STATE_CONNECTED 对应);
INTERNET_STATE_DISCONNECTED_BY_USER :$00000010 用户请求的非连接状态
INTERNET_STATE_IDLE :$00000100 连接状态,并且空闲
INTERNET_STATE_BUSY :$00000200 连接状态,正在响应连接请求

以下是一个判断当前计算机是否可以获得 Internet 服务的例子:

function TForm1.CheckOffline: boolean;
var
ConnectState: DWORD;
StateSize: DWORD;
begin
ConnectState:= 0;
StateSize:= SizeOf(ConnectState);
result:= false;
if InternetQueryOption(nil, INTERNET_OPTION_CONNECTED_STATE, @ConnectState, StateSize) then
if (ConnectState and INTERNET_STATE_DISCONNECTED) <> 2 then result:= true;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
if CheckOffline then
edit1.text:= 'Connect To ISP'
else
edit1.text:= 'Disconnect To ISP';
end;

需要说明的是 InternetQueryOption 函数的检测结果只能表明当前的 Internet 设置是可用的,
并不能表示计算机一定能访问 Internet,例如网线掉了,网卡突然坏了之类的错误就没法检测出来,
要想检测当前计算机是否能够获得 Internet 服务了必须两个函数结合起来使用。

以上程序在 Win2000, Delphi5.0 下调试通过。

最后要提醒大家注意的是在 uses 中要加上 WinInet。
********************************************************************************************


来自:doxpix, 时间:2001-5-29 13:52:11, ID:545633
那个InternetGetConnectedState判断的应该是当前的连接
方式(只是你拔掉网线后它不能自动更新)。(我就拔了一次,
害得我不得不重起一下,因为掉了)。

我的机子上设置了两种上网方式,modem and LAN,但是我当前
用LAN它就报告LAN。

没有连上网那判断连网状态岂不是多余的?



**************************************************************************
 
哪位高手知道QQ实时检测网络的功能是怎么实现的呀
 
后退
顶部