The Road to Delphi

Delphi – Free Pascal – Oxygene

Using the Network List Manager (NLM) API from Delphi

4 Comments

Network-Internet-Connection-iconThe Network List Manager (NLM) API (introduced on Windows Vista) allows you to retrieve a list of available connections and properties of each network .Also the  NLM API  support notifications (events) about the availability of new network connections or changes to existing network connections. This API is useful for  filter networks, based on his attributes and signatures. Also  you can use this API in your own  Application to adjust their logic depending on: which network they are connected to; or what the network properties are.

 

Ok, So the first step to use this API from Delphi is import the Network List Manager Type Library (C:\WINDOWS\system32\netprofm.dll) from the option Component-> Import Component as is show below.

 

Wizard1

Wizard2

After of this the NETWORKLIST_TLB unit will be created containing all the Interfaces, Types and Enumerations of the NLM API.

Note: Depending of  your Windows version the content of the imported type library can change, because some additional Interfaces and types was added in Windows 8.

INetworkListManager

The INetworkListManager is the main interface to access the methods to perform  NLM API functions Like enumerate Networks, Connections and check the overall connectivity state of the current machine.

This is the definition of the INetworkListManager interface.

  INetworkListManager = interface(IDispatch)
    ['{DCB00000-570F-4A9B-8D69-199FDBA5723B}']
    function GetNetworks(Flags: NLM_ENUM_NETWORK): IEnumNetworks; safecall;
    function GetNetwork(gdNetworkId: TGUID): INetwork; safecall;
    function GetNetworkConnections: IEnumNetworkConnections; safecall;
    function GetNetworkConnection(gdNetworkConnectionId: TGUID): INetworkConnection; safecall;
    function Get_IsConnectedToInternet: WordBool; safecall;
    function Get_IsConnected: WordBool; safecall;
    function GetConnectivity: NLM_CONNECTIVITY; safecall;
    procedure SetSimulatedProfileInfo(var pSimulatedInfo: NLM_SIMULATED_PROFILE_INFO); safecall; //Introduced on Windows 8.1
    procedure ClearSimulatedProfileInfo; safecall; //Introduced on Windows 8.1
    property IsConnectedToInternet: WordBool read Get_IsConnectedToInternet;
    property IsConnected: WordBool read Get_IsConnected;
  end;

In order to access to this interface you must declare a INetworkListManager variable and call the CoNetworkListManager.Create; method to get an instance to such Interface.

Check the next sample console application which shows the current connectivity of the machine and if the internet connection is available.

{$APPTYPE CONSOLE}

uses
  SysUtils,
  ActiveX,
  ComObj,
  Windows,
  NETWORKLIST_TLB in 'NETWORKLIST_TLB.pas';


//https://msdn.microsoft.com/en-us/library/windows/desktop/aa370795(v=vs.85).aspx
function GetNetworkConnectivity(Connectivity : NLM_CONNECTIVITY) : string;
begin
 Result:='';
    if NLM_CONNECTIVITY_DISCONNECTED and Connectivity <> 0 then  Result := Result+ 'Disconnected, ';
    if NLM_CONNECTIVITY_IPV4_NOTRAFFIC and Connectivity <> 0 then  Result := Result+ 'Connected but not ipv4 traffic, ';
    if NLM_CONNECTIVITY_IPV6_NOTRAFFIC  and Connectivity <> 0 then  Result := Result+  'Connected but not ipv6 traffic, ';
    if NLM_CONNECTIVITY_IPV4_SUBNET  and Connectivity <> 0 then  Result := Result+  'Subnet ipv4, ';
    if NLM_CONNECTIVITY_IPV4_LOCALNETWORK  and Connectivity <> 0 then  Result := Result+  'LocalNetwork ipv4, ';
    if NLM_CONNECTIVITY_IPV4_INTERNET  and Connectivity <> 0 then  Result := Result+  'Internet ipv4, ';
    if NLM_CONNECTIVITY_IPV6_SUBNET  and Connectivity <> 0 then  Result := Result+  'Subnet ipv6, ';
    if NLM_CONNECTIVITY_IPV6_LOCALNETWORK  and Connectivity <> 0 then  Result := Result+ 'LocalNetwork ipv6, ';
    if NLM_CONNECTIVITY_IPV6_INTERNET  and Connectivity <> 0 then  Result := Result+'Internet ipv6, ';

    Result:= StringReplace('['+Result+']', ', ]', ']', [rfReplaceAll]);
end;


procedure GetNetworkListManagerInfo;
var
  NetworkListManager: INetworkListManager;
begin
  NetworkListManager := CoNetworkListManager.Create;
  Writeln(Format('Connected       : %s', [boolToStr(NetworkListManager.IsConnected, True)]));
  Writeln(Format('Internet        : %s', [boolToStr(NetworkListManager.IsConnectedToInternet, True)]));
  Writeln(Format('Connectivity    : %s', [GetNetworkConnectivity(NetworkListManager.GetConnectivity)]));
end;

begin
 try
  //Check is Windows Vista at least
  if TOSVersion.Check(6) then
   begin
      CoInitialize(nil);
      try
        GetNetworkListManagerInfo;
      finally
        CoUninitialize;
      end;
   end
   else
   Writeln('This windows version doesn''t support the NLM API');
 except
    on E:EOleException do
        Writeln(Format('EOleException %s %x', [E.Message, E.ErrorCode]));
    on E:Exception do
        Writeln(E.Classname, ':', E.Message);
 end;
 Writeln('Press Enter to exit');
 Readln;
end.

Enumerating Connections

The NLM API allow you to enumerate network connections using the INetworkListManager.GetNetworkConnections method, this function returns an instance to the IEnumNetworkConnections interface that enumerates all network connections on the machine, each element returned by the IEnumNetworkConnections.Next method represents a INetworkConnection object.

  INetworkConnection = interface(IDispatch)
    ['{DCB00005-570F-4A9B-8D69-199FDBA5723B}']
    function GetNetwork: INetwork; safecall;
    function Get_IsConnectedToInternet: WordBool; safecall;
    function Get_IsConnected: WordBool; safecall;
    function GetConnectivity: NLM_CONNECTIVITY; safecall;
    function GetConnectionId: TGUID; safecall;
    function GetAdapterId: TGUID; safecall;
    function GetDomainType: NLM_DOMAIN_TYPE; safecall;
    property IsConnectedToInternet: WordBool read Get_IsConnectedToInternet;
    property IsConnected: WordBool read Get_IsConnected;
  end;

Check the next sample console application which shows how enumerate the connections with his connectivity, domain type, network adapters associated and so on.

{$APPTYPE CONSOLE}

uses
  SysUtils,
  ActiveX,
  ComObj,
  Windows,
  NETWORKLIST_TLB in 'NETWORKLIST_TLB.pas';


//https://msdn.microsoft.com/en-us/library/windows/desktop/aa370796(v=vs.85).aspx
function GetNetworkDomainType(DomainType : NLM_DOMAIN_TYPE) : string;
begin
 Result:='';
  case DomainType of
    NLM_DOMAIN_TYPE_NON_DOMAIN_NETWORK   : Result := 'Non Domain Network'; //The Network is not an Active Directory Network
    NLM_DOMAIN_TYPE_DOMAIN_NETWORK       : Result := 'Domain Network';//The Network is an Active Directory Network, but this machine is not authenticated against it.
    NLM_DOMAIN_TYPE_DOMAIN_AUTHENTICATED : Result := 'Domain Network Authenticated';//The Network is an Active Directory Network, and this machine is authenticated against it.
  end;
end;


//https://msdn.microsoft.com/en-us/library/windows/desktop/aa370795(v=vs.85).aspx
function GetNetworkConnectivity(Connectivity : NLM_CONNECTIVITY) : string;
begin
 Result:='';
    if NLM_CONNECTIVITY_DISCONNECTED and Connectivity <> 0 then  Result := Result+ 'Disconnected, ';
    if NLM_CONNECTIVITY_IPV4_NOTRAFFIC and Connectivity <> 0 then  Result := Result+ 'Connected but not ipv4 traffic, ';
    if NLM_CONNECTIVITY_IPV6_NOTRAFFIC  and Connectivity <> 0 then  Result := Result+  'Connected but not ipv6 traffic, ';
    if NLM_CONNECTIVITY_IPV4_SUBNET  and Connectivity <> 0 then  Result := Result+  'Subnet ipv4, ';
    if NLM_CONNECTIVITY_IPV4_LOCALNETWORK  and Connectivity <> 0 then  Result := Result+  'LocalNetwork ipv4, ';
    if NLM_CONNECTIVITY_IPV4_INTERNET  and Connectivity <> 0 then  Result := Result+  'Internet ipv4, ';
    if NLM_CONNECTIVITY_IPV6_SUBNET  and Connectivity <> 0 then  Result := Result+  'Subnet ipv6, ';
    if NLM_CONNECTIVITY_IPV6_LOCALNETWORK  and Connectivity <> 0 then  Result := Result+ 'LocalNetwork ipv6, ';
    if NLM_CONNECTIVITY_IPV6_INTERNET  and Connectivity <> 0 then  Result := Result+'Internet ipv6, ';

    Result:= StringReplace('['+Result+']', ', ]', ']', [rfReplaceAll]);
end;


procedure GetConnections;
var
  NetworkListManager: INetworkListManager;
  EnumNetworkConnections: IEnumNetworkConnections;
  NetworkConnection : INetworkConnection;
  pceltFetched: ULONG;
begin
   NetworkListManager := CoNetworkListManager.Create;
   EnumNetworkConnections :=  NetworkListManager.GetNetworkConnections();
   while true do
   begin
     EnumNetworkConnections.Next(1, NetworkConnection, pceltFetched);
     if (pceltFetched>0)  then
     begin
        Writeln(Format('Adapter Id      : %s', [GuidToString(NetworkConnection.GetAdapterId)]));
        Writeln(Format('Connection Id   : %s', [GuidToString(NetworkConnection.GetConnectionId)]));
        Writeln(Format('Domain Type     : %s', [GetNetworkDomainType(NetworkConnection.GetDomainType)]));
        Writeln(Format('Connected       : %s', [boolToStr(NetworkConnection.IsConnected, True)]));
        Writeln(Format('Internet        : %s', [boolToStr(NetworkConnection.IsConnectedToInternet, True)]));
        Writeln(Format('Network         : %s', [NetworkConnection.GetNetwork.GetName]));
        Writeln(Format('Connectivity    : %s', [GetNetworkConnectivity(NetworkConnection.GetConnectivity)]));
     end
     else
     Break;
   end;
end;

begin
 try
   //Check is Windows Vista at least
   if TOSVersion.Check(6) then
   begin
      CoInitialize(nil);
      try
        GetConnections;
      finally
        CoUninitialize;
      end;
   end
   else
   Writeln('This windows version doesn''t support the NLM API');
 except
    on E:EOleException do
        Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
    on E:Exception do
        Writeln(E.Classname, ':', E.Message);
 end;
 Writeln('Press Enter to exit');
 Readln;
end.

Enumerating Networks

For enumerate the networks available on the local machine you must use the INetworkListManager.GetNetworks method passing a valid NLM_ENUM_NETWORK value.

  • NLM_ENUM_NETWORK_CONNECTED Returns connected networks
  • NLM_ENUM_NETWORK_DISCONNECTED Returns disconnected networks
  • NLM_ENUM_NETWORK_ALL Returns connected and disconnected networks

from here you can gain access to several elements related to the network like Name, Description, Connectivity, Network Category and the local date and time when the network was created and connected.

Sample code to enumerate the networks using the NLM API

{$APPTYPE CONSOLE}

uses
  SysUtils,
  ActiveX,
  ComObj,
  Windows,
  NETWORKLIST_TLB in 'NETWORKLIST_TLB.pas';


//https://msdn.microsoft.com/en-us/library/windows/desktop/aa370796(v=vs.85).aspx
function GetNetworkDomainType(DomainType : NLM_CONNECTIVITY) : string;
begin
 Result:='';
  case DomainType of
    NLM_DOMAIN_TYPE_NON_DOMAIN_NETWORK   : Result := 'Non Domain Network'; //The Network is not an Active Directory Network
    NLM_DOMAIN_TYPE_DOMAIN_NETWORK       : Result := 'Domain Network';//The Network is an Active Directory Network, but this machine is not authenticated against it.
    NLM_DOMAIN_TYPE_DOMAIN_AUTHENTICATED : Result := 'Domain Network Authenticated';//The Network is an Active Directory Network, and this machine is authenticated against it.
  end;
end;

function GetNetworkCategory(Category : NLM_NETWORK_CATEGORY) : string;
begin
 Result:='';
  case Category of
    NLM_NETWORK_CATEGORY_PUBLIC               : Result := 'Public';
    NLM_NETWORK_CATEGORY_PRIVATE              : Result := 'Private';
    NLM_NETWORK_CATEGORY_DOMAIN_AUTHENTICATED : Result := 'Authenticated';
  end;
end;

procedure GetNetworks;
var
  NetworkListManager: INetworkListManager;
  EnumNetworks: IEnumNetworks;

  EnumNetworksConnections: IEnumNetworkConnections;
  NetworkConnection : INetworkConnection;

  Network: INetwork;
  fetched, pceltFetched: ULONG;

  pdwLowDateTimeCreated: LongWord;
  pdwHighDateTimeCreated: LongWord;
  pdwLowDateTimeConnected: LongWord;
  pdwHighDateTimeConnected: LongWord;

  lpFileTime : TFileTime;
  lpSystemTime: TSystemTime;
  LDateTime : TDateTime;
begin
   NetworkListManager := CoNetworkListManager.Create;
   EnumNetworks :=  NetworkListManager.GetNetworks(NLM_ENUM_NETWORK_CONNECTED);
   while true do
   begin
     EnumNetworks.Next(1, Network, fetched);
     if (fetched>0)  then
     begin
       Writeln(Format('%s - %s', [Network.GetName, Network.GetDescription]));
       Writeln(Format('Network Id  : %s', [GuidToString(Network.GetNetworkId)]));
       Writeln(Format('Domain Type : %s', [GetNetworkDomainType(Network.GetDomainType)]));
       Writeln(Format('Category    : %s', [GetNetworkCategory(Network.GetCategory)]));

       //https://msdn.microsoft.com/en-us/library/windows/desktop/aa370787(v=vs.85).aspx
       Network.GetTimeCreatedAndConnected(pdwLowDateTimeCreated, pdwHighDateTimeCreated, pdwLowDateTimeConnected, pdwHighDateTimeConnected);

       lpFileTime.dwLowDateTime := pdwLowDateTimeCreated;
       lpFileTime.dwHighDateTime := pdwHighDateTimeCreated;
       if FileTimeToSystemTime(lpFileTime, lpSystemTime) then
       begin
          LDateTime := SystemTimeToDateTime(lpSystemTime);
          Writeln('Created         : '+FormatDateTime('dd/mm/yyyy hh:nn', LDateTime));
       end;

       lpFileTime.dwLowDateTime := pdwLowDateTimeConnected;
       lpFileTime.dwHighDateTime := pdwHighDateTimeConnected;
       if FileTimeToSystemTime(lpFileTime, lpSystemTime) then
       begin
          LDateTime := SystemTimeToDateTime(lpSystemTime);
          Writeln('Last Connection : '+FormatDateTime('dd/mm/yyyy hh:nn', LDateTime));
       end;

       Writeln(Format('Connected       : %s', [boolToStr(Network.IsConnected, True)]));
       Writeln(Format('Internet        : %s', [boolToStr(Network.IsConnectedToInternet, True)]));

         EnumNetworksConnections := Network.GetNetworkConnections();

         Writeln;
         Writeln('Connections');
         Writeln('-----------');
         while true do
         begin
            EnumNetworksConnections.Next(1, NetworkConnection, pceltFetched);
              if (pceltFetched>0)  then
              begin
                Writeln(Format('  Adapter Id    : %s', [GuidToString(NetworkConnection.GetAdapterId)]));
                Writeln(Format('  Connection Id : %s', [GuidToString(NetworkConnection.GetConnectionId)]));
              end
              else
              break;
         end;
       Writeln;
     end
     else
     Break;
   end;
end;

begin
 try
   //Check is Windows Vista at least
   if TOSVersion.Check(6) then
   begin
      CoInitialize(nil);
      try
        GetNetworks;
      finally
        CoUninitialize;
      end;
   end
   else
   Writeln('This windows version doesn''t support the NLM API');
 except
    on E:EOleException do
        Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
    on E:Exception do
        Writeln(E.Classname, ':', E.Message);
 end;
 Writeln('Press Enter to exit');
 Readln;
end.

Events

The NML API exposes several events (notifications) that you Application must implements to get network related events. These callback functions that are called automatically when the respective events are raised.

These are the notifications interfaces available on the NLM API

Note : The next sample shows how subscribe to the INetworkEvents only. I will leave it as reader’s exercise the implementation of the another events.

The INetworkEvents interface can inform when a Network was added, deleted or modified. To receive the notifications related to these events you must inherit a class from this interface and implement the next methods.

  INetworkEvents = interface(IUnknown)
    ['{DCB00004-570F-4A9B-8D69-199FDBA5723B}']
    function NetworkAdded(networkId: TGUID): HResult; stdcall;
    function NetworkDeleted(networkId: TGUID): HResult; stdcall;
    function NetworkConnectivityChanged(networkId: TGUID; newConnectivity: NLM_CONNECTIVITY): HResult; stdcall;
    function NetworkPropertyChanged(networkId: TGUID; Flags: NLM_NETWORK_PROPERTY_CHANGE): HResult; stdcall;
  end;

then you need get an instance to the IConnectionPointContainer interface, after using the IConnectionPointContainer.FindConnectionPoint return a connection point for the interface and finally call the IConnectionPoint.Advise method to establish the connection with the event.

   NetworkListManager := CoNetworkListManager.Create;
    if Succeeded(NetworkListManager.QueryInterface(IID_IConnectionPointContainer, LConnectionPointContainer)) then
      if Succeeded(LConnectionPointContainer.FindConnectionPoint(IID_INetworkEvents, LConnectionPoint)) then
        LConnectionPoint.Advise(Self as IUnknown, dwCookie);

When you not longer need to use the event, you must to terminate the advisory connection previously established with the connection point using the IConnectionPoint.Unadvise method.

  if Succeeded(NetworkListManager.QueryInterface(IID_IConnectionPointContainer, LConnectionPointContainer)) then
    if Succeeded(LConnectionPointContainer.FindConnectionPoint(IID_INetworkEvents, LConnectionPoint)) then
    begin
      LConnectionPoint.Unadvise(dwCookie);
      LConnectionPoint := nil;
    end;

Check the next sample console application which implements the INetworkEvents interface.

{$APPTYPE CONSOLE}

uses
  Winapi.Windows,
  {$IF CompilerVersion > 18.5}
  Vcl.Forms,
  {$IFEND }
  System.SysUtils,
  Winapi.ActiveX,
  System.Win.ComObj,
  NETWORKLIST_TLB in 'NETWORKLIST_TLB.pas';

 type
  TNetworkEvents = class(TInterfacedObject, INetworkEvents)
  private
   NetworkListManager :  INetworkListManager;
   dwCookie : Integer;
  public
    function NetworkAdded(networkId: TGUID): HResult; stdcall;
    function NetworkDeleted(networkId: TGUID): HResult; stdcall;
    function NetworkConnectivityChanged(networkId: TGUID; newConnectivity: NLM_CONNECTIVITY): HResult; stdcall;
    function NetworkPropertyChanged(networkId: TGUID; Flags: NLM_NETWORK_PROPERTY_CHANGE): HResult; stdcall;
    constructor Create;
    procedure Start;
    procedure Stop;
  end;

//Detect when a key was pressed in the console window
function KeyPressed:Boolean;
var
  lpNumberOfEvents     : DWORD;
  lpBuffer             : TInputRecord;
  lpNumberOfEventsRead : DWORD;
  nStdHandle           : THandle;
begin
  Result:=false;
  nStdHandle := GetStdHandle(STD_INPUT_HANDLE);
  lpNumberOfEvents:=0;
  GetNumberOfConsoleInputEvents(nStdHandle, lpNumberOfEvents);
  if (lpNumberOfEvents<> 0) then
  begin
    PeekConsoleInput(nStdHandle, lpBuffer, 1, lpNumberOfEventsRead);
    if lpNumberOfEventsRead <> 0 then
    begin
      if lpBuffer.EventType = KEY_EVENT then
      begin
        if lpBuffer.Event.KeyEvent.bKeyDown then
          Result:=true
        else
          FlushConsoleInputBuffer(nStdHandle);
      end
      else
      FlushConsoleInputBuffer(nStdHandle);
    end;
  end;
end;

//https://msdn.microsoft.com/en-us/library/windows/desktop/aa370795(v=vs.85).aspx
function GetNetworkConnectivity(Connectivity : NLM_CONNECTIVITY) : string;
begin
 Result:='';
    if NLM_CONNECTIVITY_DISCONNECTED and Connectivity <> 0 then  Result := Result+ 'Disconnected, ';
    if NLM_CONNECTIVITY_IPV4_NOTRAFFIC and Connectivity <> 0 then  Result := Result+ 'Connected but not ipv4 traffic, ';
    if NLM_CONNECTIVITY_IPV6_NOTRAFFIC  and Connectivity <> 0 then  Result := Result+  'Connected but not ipv6 traffic, ';
    if NLM_CONNECTIVITY_IPV4_SUBNET  and Connectivity <> 0 then  Result := Result+  'Subnet ipv4, ';
    if NLM_CONNECTIVITY_IPV4_LOCALNETWORK  and Connectivity <> 0 then  Result := Result+  'LocalNetwork ipv4, ';
    if NLM_CONNECTIVITY_IPV4_INTERNET  and Connectivity <> 0 then  Result := Result+  'Internet ipv4, ';
    if NLM_CONNECTIVITY_IPV6_SUBNET  and Connectivity <> 0 then  Result := Result+  'Subnet ipv6, ';
    if NLM_CONNECTIVITY_IPV6_LOCALNETWORK  and Connectivity <> 0 then  Result := Result+ 'LocalNetwork ipv6, ';
    if NLM_CONNECTIVITY_IPV6_INTERNET  and Connectivity <> 0 then  Result := Result+'Internet ipv6, ';

    Result:= StringReplace('['+Result+']', ', ]', ']', [rfReplaceAll]);
end;

//https://msdn.microsoft.com/en-us/library/windows/desktop/aa370801(v=vs.85).aspx
function GetNetworkPropertyChange(PropertyChange : NLM_NETWORK_PROPERTY_CHANGE) : string;
begin
 Result:='';
    if NLM_NETWORK_PROPERTY_CHANGE_CONNECTION and PropertyChange <> 0 then  Result := Result+ 'Connection, ';
    if NLM_NETWORK_PROPERTY_CHANGE_DESCRIPTION and PropertyChange <> 0 then  Result := Result+ 'Description, ';
    if NLM_NETWORK_PROPERTY_CHANGE_NAME  and PropertyChange <> 0 then  Result := Result+  'Name, ';
    if NLM_NETWORK_PROPERTY_CHANGE_ICON  and PropertyChange <> 0 then  Result := Result+  'Icon, ';
    if NLM_NETWORK_PROPERTY_CHANGE_CATEGORY_VALUE  and PropertyChange <> 0 then  Result := Result+  'Category value, ';

    Result:= StringReplace('['+Result+']', ', ]', ']', [rfReplaceAll]);

end;

{ TNetworkEvents }
const
  IID_IConnectionPointContainer: TGUID = (
    D1:$B196B284;D2:$BAB4;D3:$101A;D4:($B6,$9C,$00,$AA,$00,$34,$1D,$07));

constructor TNetworkEvents.Create;
begin
  dwCookie := 0;
end;

function TNetworkEvents.NetworkAdded(networkId: TGUID): HResult;
begin
  Writeln(Format('Network Added : %s', [GuidToString(networkId)]));
  Result := S_OK;
end;

function TNetworkEvents.NetworkConnectivityChanged(networkId: TGUID;
  NewConnectivity: NLM_CONNECTIVITY): HResult;
begin
  Writeln(Format('Network Connectivity Changed : %s - %s', [GuidToString(networkId), GetNetworkConnectivity(NewConnectivity)]));
  Result := S_OK;
end;

function TNetworkEvents.NetworkDeleted(networkId: TGUID): HResult;
begin
  Writeln(Format('Network Deleted : %s', [GuidToString(networkId)]));
  Result := S_OK;
end;

function TNetworkEvents.NetworkPropertyChanged(networkId: TGUID; Flags: NLM_NETWORK_PROPERTY_CHANGE): HResult;
begin
  Writeln(Format('Network Property Changed : %s - %s', [GuidToString(networkId), GetNetworkPropertyChange(Flags)]));
  Result := S_OK;
end;

procedure TNetworkEvents.Start;
var
  LConnectionPointContainer: IConnectionPointContainer;
  LConnectionPoint: IConnectionPoint;
begin
  if dwCookie > 0 then exit;
   NetworkListManager := CoNetworkListManager.Create;
    if Succeeded(NetworkListManager.QueryInterface(IID_IConnectionPointContainer, LConnectionPointContainer)) then
    begin
      if Succeeded(LConnectionPointContainer.FindConnectionPoint(IID_INetworkEvents, LConnectionPoint)) then
      begin
        LConnectionPoint.Advise(Self as IUnknown, dwCookie);
        LConnectionPoint := nil;
      end;
    end;
end;

procedure TNetworkEvents.Stop;
var
  LConnectionPointContainer: IConnectionPointContainer;
  LConnectionPoint: IConnectionPoint;
begin
  if dwCookie = 0 then exit;
  if Succeeded(NetworkListManager.QueryInterface(IID_IConnectionPointContainer, LConnectionPointContainer)) then
    if Succeeded(LConnectionPointContainer.FindConnectionPoint(IID_INetworkEvents, LConnectionPoint)) then
    begin
      LConnectionPoint.Unadvise(dwCookie);
      LConnectionPoint := nil;
    end;
end;

var
   NLMEvents : TNetworkEvents;
begin
 try
    //Check is Windows Vista at least
   if TOSVersion.Check(6) then
   begin
    NLMEvents:=TNetworkEvents.Create;
    try
      NLMEvents.Start;
      Writeln('Listening NLM events - press any key to stop');
      //The next loop is only necessary on this sample console App
      //In VCL forms Apps you don't need use a loop
      while not KeyPressed do
      begin
          Sleep(100);
          Application.ProcessMessages;
      end;
    finally
      NLMEvents.Stop;
      Writeln('NLM events - Done');
    end;
   end
   else
   Writeln('This windows version doesn''t support the NLM API');
 except
    on E:EOleException do
        Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
    on E:Exception do
        Writeln(E.Classname, ':', E.Message);
 end;

 Readln;
end.

All the source code posted on this article is available on Github.

Rodrigo.

Author: Rodrigo

Just another Delphi guy.

4 thoughts on “Using the Network List Manager (NLM) API from Delphi

  1. Nice job, I was searching for that since a long time

  2. Reblogged this on burningrump.

  3. how i reading ip adress from adapter id?

    • Hi, you can use the WMI to get the ip address from the adapter id .

      Try this sample

      uses
        SysUtils,
        ActiveX,
        ComObj,
        Variants;
      
      
      function  GetAdaptarIpAddress(const AdapterID : string) : string;
      const
        WbemUser            ='';
        WbemPassword        ='';
        WbemComputer        ='localhost';
        wbemFlagForwardOnly = $00000020;
      var
        FSWbemLocator : OLEVariant;
        FWMIService   : OLEVariant;
        FWbemObjectSet: OLEVariant;
        FWbemObject   : OLEVariant;
        oEnum         : IEnumvariant;
        iValue     : LongWord;
      begin
        Result := '';
        FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
        FWMIService   := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword);
        FWbemObjectSet:= FWMIService.ExecQuery(format('SELECT * FROM Win32_NetworkAdapterConfiguration Where SettingID = "%s"', [AdapterID]),'WQL',wbemFlagForwardOnly);
        oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
        if oEnum.Next(1, FWbemObject, iValue) = 0 then
        begin
          if not VarIsClear(FWbemObject.IPAddress) then
           Result := FWbemObject.IPAddress[0];
        end;
      end;
      
      
      begin
       try
          CoInitialize(nil);
          try      
            Writeln(GetAdaptarIpAddress('{8F91C738-5579-4A46-A410-A8001B63A610}')); //¡¡¡¡ pass as parameter the proper adapter ID
          finally
            CoUninitialize;
          end;
       except
          on E:EOleException do
              Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
          on E:Exception do
              Writeln(E.Classname, ':', E.Message);
       end;
       Writeln('Press Enter to exit');
       Readln;
      end.
      
      

      Also try this article https://theroadtodelphi.com/2011/10/30/wmi-tasks-using-delphi-%E2%80%93-networking/

Leave a comment