判断本地连接网络电缆是否连接的一个小问题 ( 积分: 20 )

  • 主题发起人 主题发起人 czhfy
  • 开始时间 开始时间
C

czhfy

Unregistered / Unconfirmed
GUEST, unregistred user!
查了一晚上资料,终于发现了iphlpapi中的GetIfEntry函数,代码也基本完成,可现在却无法调用成功,返回的值不是NO_ERROR而是ERROR_INVALID_DATA(13),所以判断的结果不正确。请教大家我这儿使用的哪儿有问题?谢谢!程序里其实有些东西我也不太明白,请各位指教。

附我的程序:
unit main;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TIPMainForm = class(TForm)
Button1: TButton;
info: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure GetMIBIFRow;
end;

var
IPMainForm: TIPMainForm;

implementation

{$R *.dfm}

Const

MAX_INTERFACE_NAME_LEN = 256; { mrapi.h }
MAXLEN_PHYSADDR = 8; { iprtrmib.h }
MAXLEN_IFDESCR = 256;

MIB_IF_OPER_STATUS_NON_OPERATIONAL = 0;
{$EXTERNALSYM MIB_IF_OPER_STATUS_NON_OPERATIONAL}
MIB_IF_OPER_STATUS_UNREACHABLE = 1;
{$EXTERNALSYM MIB_IF_OPER_STATUS_UNREACHABLE}
MIB_IF_OPER_STATUS_DISCONNECTED = 2;
{$EXTERNALSYM MIB_IF_OPER_STATUS_DISCONNECTED}
MIB_IF_OPER_STATUS_CONNECTING = 3;
{$EXTERNALSYM MIB_IF_OPER_STATUS_CONNECTING}
MIB_IF_OPER_STATUS_CONNECTED = 4;
{$EXTERNALSYM MIB_IF_OPER_STATUS_CONNECTED}
MIB_IF_OPER_STATUS_OPERATIONAL = 5;
{$EXTERNALSYM MIB_IF_OPER_STATUS_OPERATIONAL}

Type

PMIBIFRow = ^TMIBIFRow;
TMIBIFRow = Record {MIB_IFROW}
wszName: array [0..MAX_INTERFACE_NAME_LEN] of WideChar;
dwIndex: Longword;
dwType: Longword;
dwMtu: Longword;
dwSpeed: Longword;
dwPhysAddrLen: Longword;
bPhysAddr: array [0..MAXLEN_PHYSADDR - 1] of byte;
dwAdminStatus: Longword;
dwOperStatus: Longword;
dwLastChange: Longword;
dwInOctets: Longword;
dwInUcastPkts: Longword;
dwInNUcastPkts: Longword;
dwInDiscards: Longword;
dwInErrors: Longword;
dwInUnknownProtos: Longword;
dwOutOctets: Longword;
dwOutUcastPkts: Longword;
dwOutNUcastPkts: Longword;
dwOutDiscards: Longword;
dwOutErrors: Longword;
dwOutQLen: Longword;
dwDescrLen: Longword;
bDescr: array [0..MAXLEN_IFDESCR - 1] of byte;
end;

function GetIfEntry(IE: PMIBIFRow): integer;
StdCall; External 'iphlpapi.dll' Name 'GetIfEntry';

procedure TIPMainForm.Button1Click(Sender: TObject);
begin
GetMIBIFRow;
end;

procedure TIPMainForm.GetMIBIFRow;
var
IR: PMIBIFRow;
Size: integer;
Res: integer;
s: string;
begin
Size := 40960;
GetMem(IR, Size);
Res := GetIfEntry(IR);
if (Res <> NO_ERROR) then
begin
SetLastError(Res);
RaiseLastWin32Error;
end;
with info do
begin
Clear;
case IR^.dwOperStatus of
MIB_IF_OPER_STATUS_NON_OPERATIONAL: s := 'LAN adapter has been disabled, for example because of an address conflict.';
MIB_IF_OPER_STATUS_UNREACHABLE: s := 'WAN adapter that is not connected.';
MIB_IF_OPER_STATUS_DISCONNECTED: s := 'For LAN adapters: network cable disconnected. For WAN adapters: no carrier.';
MIB_IF_OPER_STATUS_CONNECTING: s := 'WAN adapter that is in the process of connecting.';
MIB_IF_OPER_STATUS_CONNECTED: s := 'WAN adapter that is connected to a remote peer.';
MIB_IF_OPER_STATUS_OPERATIONAL: s := 'Default status for LAN adapters';
else s := '';
end;
Lines.Add('本地连接:' + s);
end;
FreeMem(IR);
end;

end.
 
查了一晚上资料,终于发现了iphlpapi中的GetIfEntry函数,代码也基本完成,可现在却无法调用成功,返回的值不是NO_ERROR而是ERROR_INVALID_DATA(13),所以判断的结果不正确。请教大家我这儿使用的哪儿有问题?谢谢!程序里其实有些东西我也不太明白,请各位指教。

附我的程序:
unit main;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TIPMainForm = class(TForm)
Button1: TButton;
info: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure GetMIBIFRow;
end;

var
IPMainForm: TIPMainForm;

implementation

{$R *.dfm}

Const

MAX_INTERFACE_NAME_LEN = 256; { mrapi.h }
MAXLEN_PHYSADDR = 8; { iprtrmib.h }
MAXLEN_IFDESCR = 256;

MIB_IF_OPER_STATUS_NON_OPERATIONAL = 0;
{$EXTERNALSYM MIB_IF_OPER_STATUS_NON_OPERATIONAL}
MIB_IF_OPER_STATUS_UNREACHABLE = 1;
{$EXTERNALSYM MIB_IF_OPER_STATUS_UNREACHABLE}
MIB_IF_OPER_STATUS_DISCONNECTED = 2;
{$EXTERNALSYM MIB_IF_OPER_STATUS_DISCONNECTED}
MIB_IF_OPER_STATUS_CONNECTING = 3;
{$EXTERNALSYM MIB_IF_OPER_STATUS_CONNECTING}
MIB_IF_OPER_STATUS_CONNECTED = 4;
{$EXTERNALSYM MIB_IF_OPER_STATUS_CONNECTED}
MIB_IF_OPER_STATUS_OPERATIONAL = 5;
{$EXTERNALSYM MIB_IF_OPER_STATUS_OPERATIONAL}

Type

PMIBIFRow = ^TMIBIFRow;
TMIBIFRow = Record {MIB_IFROW}
wszName: array [0..MAX_INTERFACE_NAME_LEN] of WideChar;
dwIndex: Longword;
dwType: Longword;
dwMtu: Longword;
dwSpeed: Longword;
dwPhysAddrLen: Longword;
bPhysAddr: array [0..MAXLEN_PHYSADDR - 1] of byte;
dwAdminStatus: Longword;
dwOperStatus: Longword;
dwLastChange: Longword;
dwInOctets: Longword;
dwInUcastPkts: Longword;
dwInNUcastPkts: Longword;
dwInDiscards: Longword;
dwInErrors: Longword;
dwInUnknownProtos: Longword;
dwOutOctets: Longword;
dwOutUcastPkts: Longword;
dwOutNUcastPkts: Longword;
dwOutDiscards: Longword;
dwOutErrors: Longword;
dwOutQLen: Longword;
dwDescrLen: Longword;
bDescr: array [0..MAXLEN_IFDESCR - 1] of byte;
end;

function GetIfEntry(IE: PMIBIFRow): integer;
StdCall; External 'iphlpapi.dll' Name 'GetIfEntry';

procedure TIPMainForm.Button1Click(Sender: TObject);
begin
GetMIBIFRow;
end;

procedure TIPMainForm.GetMIBIFRow;
var
IR: PMIBIFRow;
Size: integer;
Res: integer;
s: string;
begin
Size := 40960;
GetMem(IR, Size);
Res := GetIfEntry(IR);
if (Res <> NO_ERROR) then
begin
SetLastError(Res);
RaiseLastWin32Error;
end;
with info do
begin
Clear;
case IR^.dwOperStatus of
MIB_IF_OPER_STATUS_NON_OPERATIONAL: s := 'LAN adapter has been disabled, for example because of an address conflict.';
MIB_IF_OPER_STATUS_UNREACHABLE: s := 'WAN adapter that is not connected.';
MIB_IF_OPER_STATUS_DISCONNECTED: s := 'For LAN adapters: network cable disconnected. For WAN adapters: no carrier.';
MIB_IF_OPER_STATUS_CONNECTING: s := 'WAN adapter that is in the process of connecting.';
MIB_IF_OPER_STATUS_CONNECTED: s := 'WAN adapter that is connected to a remote peer.';
MIB_IF_OPER_STATUS_OPERATIONAL: s := 'Default status for LAN adapters';
else s := '';
end;
Lines.Add('本地连接:' + s);
end;
FreeMem(IR);
end;

end.
 
使用KEEPALIVE!
 
谢谢!能说详细一点吗?
 
使用KEEPALIVE参数来定义一个套接字,那么这个套接字就会定期的发送一个心跳包。
当对方的网线断掉以后,在调用RECV函数的时候就会返回0值。
 
我没有使用过这样的方法,你可以给我一个例子之类的吗?或者指点一下到哪儿看帮助?很感谢!
 
在函数setsockopt中设置,具体你查查看MSDN。
SO_KEEPALIVE BOOL Send keepalives
 
uses
WinInet;

function InternetConnected: Boolean;
CONST
// local system uses a modem to connect to the Internet.
INTERNET_CONNECTION_MODEM = 1;
// local system uses a local area network to connect to the Internet.
INTERNET_CONNECTION_LAN = 2;
// local system uses a proxy server to connect to the Internet.
INTERNET_CONNECTION_PROXY = 4;
// local system's modem is busy with a non-Internet connection.
INTERNET_CONNECTION_MODEM_BUSY = 8;

VAR
dwConnectionTypes : DWORD;
BEGIN
dwConnectionTypes :=
INTERNET_CONNECTION_MODEM + INTERNET_CONNECTION_LAN +
INTERNET_CONNECTION_PROXY;
Result := InternetGetConnectedState(@dwConnectionTypes,0);
END;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
if InternetConnected then
caption:=' Connected'
else caption:=' not Connected';
end;
 
谢谢二位,我的问题已经解决。用我这种方法也可以,出错原因是在调用GetIfEntry时需先设置其中的索引,表示取第几个网络接口,而我一开始没设。
另外我重新定义的record也有点问题。

给想了解相关知识的xdjm们提个醒,设置索引时一般本地连接是2,1为默认的loopback口,这也是为什么在查询本地网络状态时明明只插了一块网卡,但还会看到有两个网络接口的原因,其中一个是自带的测试环回用的。可以用GetIfTable函数查询到当前有多少接口。

感谢fsh7622和weiliu,你们说的这两种方法我还要好好研究一下:)

附正确代码如下:

unit main;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TIPMainForm = class(TForm)
Button1: TButton;
info: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure GetMIBIFRow;
end;

var
IPMainForm: TIPMainForm;
aDnsList:TStrings;

implementation

{$R *.dfm}

Const
MAX_HOSTNAME_LEN = 128; { from IPTYPES.H }
MAX_DOMAIN_NAME_LEN = 128;
MAX_SCOPE_ID_LEN = 256;
MAX_ADAPTER_NAME_LENGTH = 256;
MAX_ADAPTER_DESCRIPTION_LENGTH = 128;
MAX_ADAPTER_ADDRESS_LENGTH = 8;

MAX_INTERFACE_NAME_LEN = 256; { mrapi.h }
MAXLEN_PHYSADDR = 8; { iprtrmib.h }
MAXLEN_IFDESCR = 256; { --"--- }

MIB_IF_OPER_STATUS_NON_OPERATIONAL = 0;
{$EXTERNALSYM MIB_IF_OPER_STATUS_NON_OPERATIONAL}
MIB_IF_OPER_STATUS_UNREACHABLE = 1;
{$EXTERNALSYM MIB_IF_OPER_STATUS_UNREACHABLE}
MIB_IF_OPER_STATUS_DISCONNECTED = 2;
{$EXTERNALSYM MIB_IF_OPER_STATUS_DISCONNECTED}
MIB_IF_OPER_STATUS_CONNECTING = 3;
{$EXTERNALSYM MIB_IF_OPER_STATUS_CONNECTING}
MIB_IF_OPER_STATUS_CONNECTED = 4;
{$EXTERNALSYM MIB_IF_OPER_STATUS_CONNECTED}
MIB_IF_OPER_STATUS_OPERATIONAL = 5;
{$EXTERNALSYM MIB_IF_OPER_STATUS_OPERATIONAL}

ANY_SIZE = 1;
{$EXTERNALSYM ANY_SIZE}

Type

PMIB_IFROW = ^MIB_IFROW;
{$EXTERNALSYM PMIB_IFROW}
_MIB_IFROW = record
wszName: array [0..MAX_INTERFACE_NAME_LEN - 1] of WCHAR;
dwIndex: DWORD;
dwType: DWORD;
dwMtu: DWORD;
dwSpeed: DWORD;
dwPhysAddrLen: DWORD;
bPhysAddr: array [0..MAXLEN_PHYSADDR - 1] of BYTE;
dwAdminStatus: DWORD;
dwOperStatus: DWORD;
dwLastChange: DWORD;
dwInOctets: DWORD;
dwInUcastPkts: DWORD;
dwInNUcastPkts: DWORD;
dwInDiscards: DWORD;
dwInErrors: DWORD;
dwInUnknownProtos: DWORD;
dwOutOctets: DWORD;
dwOutUcastPkts: DWORD;
dwOutNUcastPkts: DWORD;
dwOutDiscards: DWORD;
dwOutErrors: DWORD;
dwOutQLen: DWORD;
dwDescrLen: DWORD;
bDescr: array[0..MAXLEN_IFDESCR - 1] of BYTE;
end;
{$EXTERNALSYM _MIB_IFROW}
MIB_IFROW = _MIB_IFROW;
{$EXTERNALSYM MIB_IFROW}
TMibIfRow = MIB_IFROW;
PMibIfRow = PMIB_IFROW;

function GetIfEntry(IE: PMIBIFRow): Longword;
StdCall; External 'iphlpapi.dll' Name 'GetIfEntry';

procedure TIPMainForm.Button1Click(Sender: TObject);
begin
GetMIBIFRow;
end;

procedure TIPMainForm.GetMIBIFRow;
var
IR: PMIBIFRow;
Size: integer;
Res: integer;
s: string;
begin
Size := 1024;
GetMem(IR, Size);
IR^.dwIndex := 2;
Res := GetIfEntry(IR);
if (Res <> NO_ERROR) then
begin
SetLastError(Res);
RaiseLastWin32Error;
end;
with info do
begin
Clear;
case IR^.dwOperStatus of
MIB_IF_OPER_STATUS_NON_OPERATIONAL: s := 'LAN adapter has been disabled, for example because of an address conflict.';
MIB_IF_OPER_STATUS_UNREACHABLE: s := 'WAN adapter that is not connected.';
MIB_IF_OPER_STATUS_DISCONNECTED: s := 'For LAN adapters: network cable disconnected. For WAN adapters: no carrier.';
MIB_IF_OPER_STATUS_CONNECTING: s := 'WAN adapter that is in the process of connecting.';
MIB_IF_OPER_STATUS_CONNECTED: s := 'WAN adapter that is connected to a remote peer.';
MIB_IF_OPER_STATUS_OPERATIONAL: s := 'Default status for LAN adapters';
else s := '';
end;
Lines.Add('本地连接:' + s);
end;
FreeMem(IR);
end;

end.
 
后退
顶部