Here is some code that should help get you started along. It is able to detect network changes, enumerate the adapter/interface pairs, and also allows you to disable/re-enable any specific interface. I am posting the sample app code first, then the component code. The component code requires the ip helper conversion units from jedi (the link is displayed in the component.).
If you have questions, please do not ask me, ask Sir Ciuly, because he knows better than me.
Sample app code (form with 2 buttons and 1 memo on it)
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, NetState, IpRtrMib;
type
TForm1 = class(TForm)
Button1: TButton;
NetAdapter1: TNetAdapter;
Memo1: TMemo;
Button2: TButton;
procedure NetAdapter1Connect(Sender: TObject; IntfAdapter: _MIB_IFROW);
procedure NetAdapter1Disconnect(Sender: TObject; IntfAdapter: _MIB_IFROW);
procedure NetAdapter1StateChange(Sender: TObject; IntfAdapter: _MIB_IFROW; LastState, LastAdminState: Cardinal);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure UpdateInfo(Memo: TMemo; Row: _MIB_IFROW);
begin
with Memo do
begin
Lines.Add(Format(' Name: %s', [InterfaceName(Row)]));
Lines.Add(Format(' Operational State: %d', [Row.dwOperStatus]));
Lines.Add(Format(' Admin State: %d', [Row.dwAdminStatus]));
end;
end;
procedure TForm1.NetAdapter1Connect(Sender: TObject; IntfAdapter: _MIB_IFROW);
begin
Memo1.Lines.Add(Format('%s connected', [InterfaceName(IntfAdapter)]));
UpdateInfo(Memo1, IntfAdapter);
end;
procedure TForm1.NetAdapter1Disconnect(Sender: TObject; IntfAdapter: _MIB_IFROW);
begin
Memo1.Lines.Add(Format('%s disconnected', [InterfaceName(IntfAdapter)]));
UpdateInfo(Memo1, IntfAdapter);
end;
procedure TForm1.NetAdapter1StateChange(Sender: TObject; IntfAdapter: _MIB_IFROW; LastState, LastAdminState: Cardinal);
begin
Memo1.Lines.Add(Format('%s state change', [InterfaceName(IntfAdapter)]));
UpdateInfo(Memo1, IntfAdapter);
if InterfaceIsConnected(IntfAdapter) then
Memo1.Lines.Add('-- Connected -- ')
else
Memo1.Lines.Add('-- Disconnected -- ');
end;
procedure TForm1.Button1Click(Sender: TObject);
var dwIndex: Integer;
begin
for dwIndex:=0 to Pred(NetAdapter1.IntfAdapterCount) do
NetAdapter1.DisableIntfAdapter(NetAdapter1[dwIndex]);
end;
procedure TForm1.Button2Click(Sender: TObject);
var dwIndex: Integer;
begin
for dwIndex:=0 to Pred(NetAdapter1.IntfAdapterCount) do
NetAdapter1.EnableIntfAdapter(NetAdapter1[dwIndex]);
end;
------------------- Component Code --------------------
unit NetState;
//
http://ftp://delphi-jedi.org/api/IPHlpAPI.zipinterface
////////////////////////////////////////////////////////////////////////////////
// Include Units (IP Helper units:
http://ftp://delphi-jedi.org/api/IPHlpAPI.zip)
////////////////////////////////////////////////////////////////////////////////
uses
Windows,
SysUtils,
Messages,
Classes,
Graphics,
Controls,
ExtCtrls,
Forms,
Dialogs,
WinSock,
WinInet,
IpExport,
IpHlpApi,
IpTypes,
IpIfConst,
IpRtrMib;
////////////////////////////////////////////////////////////////////////////////
// Network adapter constants
////////////////////////////////////////////////////////////////////////////////
const
SPEED_MODEM = 9600;
////////////////////////////////////////////////////////////////////////////////
// Network adapter component
////////////////////////////////////////////////////////////////////////////////
type
// Event handler type declarations
TOnConnect = procedure(Sender: TObject; IntfAdapter: TMibIfRow) of object;
TOnDisconnect = procedure(Sender: TObject; IntfAdapter: TMibIfRow) of object;
TOnStateChange = procedure(Sender: TObject; IntfAdapter: TMibIfRow; LastState, LastAdminState: DWORD) of object;
// Component declaration
TNetAdapter = class(TComponent)
private
// Private declarations
FTimer: TTimer;
FTable: PMibIfTable;
FOnConnect: TOnConnect;
FOnDisconnect: TOnDisconnect;
FOnStateChange: TOnStateChange;
protected
// Protected declarations
function GetInterval: Integer;
function GetWatch: Boolean;
function GetIntfAdapters(Index: Integer): TMibIfRow;
function GetIntfAdapterCount: Integer;
procedure GetIntfAdapterTable;
procedure OnWatchFired(Sender: TObject);
procedure SetInterval(Value: Integer);
procedure SetWatch(Value: Boolean);
public
// Public declarations
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure DisableIntfAdapter(Row: TMibIfRow);
procedure EnableIntfAdapter(Row: TMibIfRow);
property IntfAdapterCount: Integer read GetIntfAdapterCount;
property IntfAdapters[Index: Integer]: TMibIfRow read GetIntfAdapters; default;
published
// Published declarations
property OnConnect: TOnConnect read FOnConnect write FOnConnect;
property OnDisconnect: TOnDisconnect read FOnDisconnect write FOnDisconnect;
property OnStateChange: TOnStateChange read FOnStateChange write FOnStateChange;
property WatchChanges: Boolean read GetWatch write SetWatch;
property WatchInterval: Integer read GetInterval write SetInterval;
end;
////////////////////////////////////////////////////////////////////////////////
// Utility functions for handling of the interface row information
////////////////////////////////////////////////////////////////////////////////
function InterfaceName(IntfAdapter: TMibIfRow): PChar;
function InterfaceIsConnected(IntfAdapter: TMibIfRow): Boolean;
function InterfaceIsModem(IntfAdapter: TMibIfRow): Boolean;
procedure Register;
implementation
function InterfaceName(IntfAdapter: TMibIfRow): PChar;
begin
result:=PChar(@IntfAdapter.bDescr);
end;
function InterfaceIsConnected(IntfAdapter: TMibIfRow): Boolean;
begin
result:=(IntfAdapter.dwAdminStatus = MIB_IF_ADMIN_STATUS_UP) and (IntfAdapter.dwOperStatus >= MIB_IF_OPER_STATUS_CONNECTED);
end;
function InterfaceIsModem(IntfAdapter: TMibIfRow): Boolean;
begin
result:=((IntfAdapter.dwType = MIB_IF_TYPE_ETHERNET) and (IntfAdapter.dwSpeed = SPEED_MODEM)) or (IntfAdapter.dwType = MIB_IF_TYPE_PPP);
end;
// TNetAdapter
procedure TNetAdapter.DisableIntfAdapter(Row: TMibIfRow);
begin
// Set admin status for row and call SetIfEntry
Row.dwAdminStatus:=MIB_IF_ADMIN_STATUS_DOWN;
// Set entry
SetIfEntry(Row);
end;
procedure TNetAdapter.EnableIntfAdapter(Row: TMibIfRow);
begin
// Set admin status for row and call SetIfEntry
Row.dwAdminStatus:=MIB_IF_ADMIN_STATUS_UP;
// Set entry
SetIfEntry(Row);
end;
function TNetAdapter.GetInterval: Integer;
begin
// Return the interval for the timer control
result:=FTimer.Interval;
end;
function TNetAdapter.GetWatch: Boolean;
begin
// Return the timer control enabled state
result:=FTimer.Enabled;
end;
procedure TNetAdapter.SetInterval(Value: Integer);
begin
// Update the timer control interval
FTimer.Interval:=Value;
end;
procedure TNetAdapter.SetWatch(Value: Boolean);
begin
// Update the timer control enabled state
FTimer.Enabled:=Value;
end;
function TNetAdapter.GetIntfAdapters(Index: Integer): TMibIfRow;
begin
// Check the table to make sure the request is in range
if (FTable = nil) or (Index < 0) or (DWORD(Index) >= FTable^.dwNumEntries) then raise Exception.Create('Invalid Index');
// Return the row
result:=FTable^.Table[Index];
end;
function TNetAdapter.GetIntfAdapterCount: Integer;
begin
// Check table
if Assigned(FTable) then
// Return the current count of interface/adapters
result:=FTable^.dwNumEntries
else
// No table
result:=0;
end;
procedure TNetAdapter.GetIntfAdapterTable;
var lpIntfTable: PMibIfTable;
lpSwap: Pointer;
dwIndex: ULONG;
dwOldIndex: ULONG;
dwSize: ULONG;
bChanged: Boolean;
bExists: Boolean;
begin
// Set the default table
lpIntfTable:=nil;
// Make the call to get the required size
try
// Set the default size to allocate
dwSize:=0;
// Make the call to get the table size
if (GetIfTable(nil, dwSize, True) = ERROR_INSUFFICIENT_BUFFER) then
begin
// Allocate memory for the table
lpIntfTable:=AllocMem(dwSize);
// Make the call again
if (GetIfTable(lpIntfTable, dwSize, True) = NO_ERROR) then
begin
// We now have the table. If the old table is nil, then this is the
// first call and there is nothing to compare to, so just assign the
// table over.
if (FTable = nil) then
begin
// Assign and clear var so the memory is not freed
FTable:=lpIntfTable;
lpIntfTable:=nil;
end
else
begin
// Swap table pointers
lpSwap:=FTable;
FTable:=lpIntfTable;
lpIntfTable:=lpSwap;
// Check for connects first and changes first
for dwIndex:=0 to Pred(FTable^.dwNumEntries) do
begin
// Check to see if this is a new entry
bExists:=False;
bChanged:=False;
dwOldIndex:=0;
while (dwOldIndex < lpIntfTable^.dwNumEntries) do
begin
// Check index
if (FTable^.table[dwIndex].dwIndex = lpIntfTable^.table[dwOldIndex].dwIndex) then
begin
// Entry exists
bExists:=True;
// Has it changed?
bChanged:=not((FTable^.table[dwIndex].dwAdminStatus = lpIntfTable^.table[dwOldIndex].dwAdminStatus) and
(FTable^.table[dwIndex].dwOperStatus = lpIntfTable^.table[dwOldIndex].dwOperStatus));
// Done either way
break;
end;
// Next index
Inc(dwOldIndex);
end;
// Does the entry exist? If not, then we will need to fire a connect change
if bExists then
begin
// Check for change
if bChanged and Assigned(FOnStateChange) then
FOnStateChange(Self, FTable^.table[dwIndex], lpIntfTable^.table[dwOldIndex].dwOperStatus, lpIntfTable^.table[dwOldIndex].dwAdminStatus);
end
else if Assigned(FOnConnect) then
// Fire the OnConnect event
FOnConnect(Self, FTable^.table[dwIndex]);
end;
// Now we need to check for disconnects (those in old table but not in new)
for dwOldIndex:=0 to Pred(lpIntfTable^.dwNumEntries) do
begin
// Check to see if this entry still exists
bExists:=False;
dwIndex:=0;
while (dwIndex < FTable^.dwNumEntries) do
begin
// Check index
if (FTable^.table[dwIndex].dwIndex = lpIntfTable^.table[dwOldIndex].dwIndex) then
begin
// Entry exists
bExists:=True;
// Done either way
break;
end;
// Next index
Inc(dwIndex);
end;
// Does the entry exist? If not, then we will need to fire a disconnect event
if not(bExists) and Assigned(FOnDisconnect) then FOnDisconnect(Self, lpIntfTable^.table[dwOldIndex]);
end;
end;
end;
end;
finally
// Free the table memory
if Assigned(lpIntfTable) then FreeMem(lpIntfTable);
end;
end;
procedure TNetAdapter.OnWatchFired(Sender: TObject);
begin
// Resource protection
try
// Disable the timer
FTimer.Enabled:=False;
// Update the network interface table
GetIntfAdapterTable;
finally
// Re-enable the timer
FTimer.Enabled:=True;
end;
end;
constructor TNetAdapter.Create(AOwner: TComponent);
begin
// Perform inherited
inherited Create(AOwner);
// Starting defaults
FTimer:=TTimer.Create(Self);
FTimer.Interval:=1000;
FTimer.Enabled:=False;
FTimer.OnTimer:=OnWatchFired;
FTable:=nil;
// Load the initial table
GetIntfAdapterTable;
end;
destructor TNetAdapter.Destroy;
begin
// Stop and free the timer
FTimer.Enabled:=False;
FTimer.Free;
// Free memory allocated for the table
if Assigned(FTable) then FreeMem(FTable);
// Perform inherited
inherited Destroy;
end;
procedure Register;
begin
// Register the component with the IDE
RegisterComponents('Additional', [TNetAdapter]);
end;
end.
Got it from other sites. (^_^)
And a sample code in zip format that may help you analyze:
http://www.yeahware.com/download/enable.ziprionroc
Delphi zombie, because delphi is always alive.