Solved

Reset network card or how do I fully disable and re-enable (rlibby)

Posted on 2008-06-11
47
1,670 Views
Last Modified: 2012-08-14
I have several chunks of code that is supposed to reset the network card. One piece of code uses the hnetcfg.dll (ActiveX) and works great, BUT, it only works under Windows XP and higher. I need 2000 support as well.

The other chunk was obtained from code and a component by Russell Libby (rlibby) which keeps the network icon active yet disables any network traffic. Not like a manual disable - enable, which resets the card or like the XP code using the ActiveX.

Snippets are below.

Does anyone have any code that will fully reset a NIC in 2000 and above?

Thanks!

John
// The following is from rlibby using his netstate library.
 

unit Unit1;
 

interface
 

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;
 

end.
 

//The following uses the Windows XP firewall control ActiveX, hnetcfg.dll and works but ONLY under XP. You // have to import the as an Active X hnetcfg.dll as NETCONLib_TLB and the dll is under system32.
 

uses

 OleServer, NETCONLib_TLB, activeX, ComObj;
 

procedure TFPCClusterMain.ResetNIC(const aConnection: string);

var

  pEnum: IEnumVariant;

  vNetCon: OleVARIANT;

  dwRetrieved: Cardinal;

  pUser: NETCONLib_TLB.PUserType1;

begin

  //enabled := false;

  try

    pEnum := ( NetSharingManager.EnumEveryConnection._NewEnum as IEnumVariant);

    while (pEnum.Next(1, vNetCon, dwRetrieved) = S_OK) do

    begin

       (IUnknown(vNetCon) as INetConnection).GetProperties(pUser);

       if pUser.pszwName = aConnection then

       begin

         (IUnknown(vNetCon) as INetConnection).Disconnect;

         (IUnknown(vNetCon) as INetConnection).Connect;

         delay(2000);

         break;

       end;

    end;

  finally

    //enabled := true;

  end;

end;
 

procedure TFPCClusterMain.GetConnectionList(Strings : TStrings);

var

  pEnum: IEnumVariant;

  vNetCon: OleVARIANT;

  dwRetrieved: Cardinal;

  pUser: NETCONLib_TLB.PUserType1;

  NetCon : INetConnection;

begin

  Strings.Clear;

  pEnum := ( NetSharingManager.EnumEveryConnection._NewEnum as IEnumVariant);

  while (pEnum.Next(1, vNetCon, dwRetrieved) = S_OK) do

  begin

     (IUnknown(vNetCon) as INetConnection).GetProperties(pUser);

     NetCon := (IUnknown(vNetCon) as INetConnection); 
 

     if (pUser.Status in [NCS_CONNECTED,NCS_CONNECTING])//remove if you want disabled NIC cards also

     and (pUser.MediaType in [NCM_LAN,NCM_SHAREDACCESSHOST_LAN,NCM_ISDN] ) then

     begin

       //we only want valid network cards that are enabled

       Strings.Add(pUser.pszwName );

       //IdList.Add(GuidToString(pUser.guidId));

     end;

  end;

end;

Open in new window

0
Comment
Question by:Johnjces
  • 26
  • 20
47 Comments
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
Should have a solution for this in the next few hours.

Russell
0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
Russell,

THANKS!!!

John
0
 
LVL 26

Accepted Solution

by:
Russell Libby earned 500 total points
Comment Utility
Here is the alternative I have been working on. It uses the shell folder interface to access the connection items, and then invokes the Enable/Disable menu item command against the network connection. It still needs cleanup, as I am trying to determine the best way to ensure that the command has completed before returning back to the user (the InvokeCommand returns immediately, due to the shell code running on another thread).

Something to look at anyways...
Russell

---

example usage:

var  ncItem:        TNetConnection;
begin

  with TNetConnections.Create do
  begin
     ncItem:=Items[0];
     // Show name
     ShowMessage(ncItem.Name);
     // Disconnect
     ncItem.Disconnect;
     Free;
  end;

end;

unit NetConnections;
////////////////////////////////////////////////////////////////////////////////
//
//   Unit        :  NetConnections
//   Author      :  rllibby
//   Date        :  06.12.2007
//   Description :  Shell (COM) based mechanism for enabling / disabling the
//                  network connections on a PC.
//
////////////////////////////////////////////////////////////////////////////////
interface

////////////////////////////////////////////////////////////////////////////////
//   Include units
////////////////////////////////////////////////////////////////////////////////
uses
  Windows, SysUtils, Classes, Forms, ComObj, ActiveX, ShlObj;

////////////////////////////////////////////////////////////////////////////////
//   ShlObj constants
////////////////////////////////////////////////////////////////////////////////
const
  IID_IShellFolder2:TGUID =  (D1:$93F2F68C; D2:$1D1B; D3:$11D3; D4:($A3,$0E,$00,$C0,$4F,$79,$AB,$D1));
  SID_IShellFolder2       =  '{93F2F68C-1D1B-11D3-A30E-00C04F79ABD1}';
  SID_IEnumExtraSearch    =  '{0E700BE1-9DB6-11D1-A1CE-00C04FD75D13}';

const
  SHCOLSTATE_TYPE_STR     = $00000001;
  SHCOLSTATE_TYPE_INT     = $00000002;
  SHCOLSTATE_TYPE_DATE    = $00000003;
  SHCOLSTATE_TYPEMASK     = $0000000F;
  SHCOLSTATE_ONBYDEFAULT  = $00000010;
  SHCOLSTATE_SLOW         = $00000020;
  SHCOLSTATE_EXTENDED     = $00000040;
  SHCOLSTATE_SECONDARYUI  = $00000080;
  SHCOLSTATE_HIDDEN       = $00000100;

////////////////////////////////////////////////////////////////////////////////
//   ShlObj types
////////////////////////////////////////////////////////////////////////////////
type
  PSHColInfo        =  ^SHColInfo;
  SHColInfo         =  record
     justify:       Integer;
     width:         Integer;
     text:          STRRET;
  end;

  PShellDetails     =  ^TShellDetails;
  _SHELLDETAILS     =  record
     fmt:           Integer;
     cxChar:        Integer;
     str:           STRRET;
  end;
  TShellDetails     =  _SHELLDETAILS;
  SHELLDETAILS      =  _SHELLDETAILS;

  PExtraSearch      =  ^TExtraSearch;
  TExtraSearch      =  record
     guidSearch:    TGUID;
     wszFriendlyName,
     wszMenuText:   Array [0..79] of WideChar;
     wszHelpText:   Array [0..MAX_PATH] of WideChar;
     wszUrl:        Array [0..2047] of WideChar;
     wszIcon,
     wszGreyIcon,
     wszClrIcon:    Array [0..MAX_PATH + 10] of WideChar;
  end;

  PShColumnID       =  ^TShColumnID;
  SHCOLUMNID        = record
     fmtid:         TGUID;
     pid:           DWORD;
  end;
  TShColumnID       =  SHCOLUMNID;

////////////////////////////////////////////////////////////////////////////////
//   ShlObj interfaces
////////////////////////////////////////////////////////////////////////////////
type
  IEnumExtraSearch  =  interface(IUnknown)
     [SID_IEnumExtraSearch]
     function       Next(celt: ULONG; out rgelt: PExtraSearch; out pceltFetched: ULONG): HResult; stdcall;
     function       Skip(celt: ULONG): HResult; stdcall;
     function       Reset: HResult; stdcall;
     function       Clone(out ppEnum: IEnumExtraSearch): HResult; stdcall;
  end;

  IShellFolder2     =  interface(IShellFolder)
     [SID_IShellFolder2]
     function       GetDefaultSearchGUID(out pguid: TGUID): HResult; stdcall;
     function       EnumSearches(out ppEnum: IEnumExtraSearch): HResult; stdcall;
     function       GetDefaultColumn(dwRes: DWORD; var pSort: ULONG; var pDisplay: ULONG): HResult; stdcall;
     function       GetDefaultColumnState(iColumn: UINT; var pcsFlags: DWORD): HResult; stdcall;
     function       GetDetailsEx(pidl: PItemIDList; const pscid: SHCOLUMNID; pv: POleVariant): HResult; stdcall;
     function       GetDetailsOf(pidl: PItemIDList; iColumn: UINT; var psd: TShellDetails): HResult; stdcall;
     function       MapNameToSCID(pwszName: LPCWSTR; var pscid: TShColumnID): HResult; stdcall;
  end;

////////////////////////////////////////////////////////////////////////////////
//   Constants
////////////////////////////////////////////////////////////////////////////////
const
  NC_ROOT           =  'Network Connections';
  NC_ENABLE         =  16;
  NC_DISABLE        =  17;

////////////////////////////////////////////////////////////////////////////////
//   Types
////////////////////////////////////////////////////////////////////////////////
type
  ENetConnections   =  class(Exception);

////////////////////////////////////////////////////////////////////////////////
//   Resource strings
////////////////////////////////////////////////////////////////////////////////
resourcestring
  resAquire         =  'Failed to aquire the "Network Connections" shell folder interface';
  resLoaded         =  'The network collection item has not been loaded';

////////////////////////////////////////////////////////////////////////////////
//   TPidlList
////////////////////////////////////////////////////////////////////////////////
type
  TPidlList         =  class(TObject)
  private
     // Private declarations
     FColumns:      TStringList;
     FList:         TList;
  protected
     // Protected declarations
     function       GetCount: Integer;
     function       GetItems(Index: Integer): PItemIDList;
     procedure      LoadFolder(Folder: IShellFolder2);
     procedure      LoadColumns(Folder: IShellFolder2);
  public
     // Public declarations
     constructor    Create(Folder: IShellFolder2);
     destructor     Destroy; override;
     procedure      Clear;
  public
     // Public properties
     property       Count: Integer read GetCount;
     property       Columns: TStringList read FColumns;
     property       Items[Index: Integer]: PItemIDList read GetItems; default;
  end;

////////////////////////////////////////////////////////////////////////////////
//   TNetConnection
////////////////////////////////////////////////////////////////////////////////
type
  TNetConnection    =  class(TCollectionItem)
  private
     // Private declarations
     FColumns:      TStringList;
     FItem:         PItemIDList;
     function       ExecuteVerb(Verb: Word): HResult;
  protected
     // Protected declarations
     procedure      CheckLoaded;
     function       GetName: String;
     function       GetPropertyCount: Integer;
     function       GetPropertyNames(Index: Integer): String;
     function       GetPropertyValues(Index: Integer): String;
     procedure      Load(Item: PItemIDList; Columns: TStringList);
  public
     // Public declarations
     constructor    Create(Collection: TCollection); override;
     destructor     Destroy; override;
     function       Connect: HResult;
     function       Disconnect: HResult;
  public
     // Public properties
     property       Name: String read GetName;
     property       PropertyCount: Integer read GetPropertyCount;
     property       PropertyNames[Index: Integer]: String read GetPropertyNames;
     property       PropertyValues[Index: Integer]: String read GetPropertyValues;
  end;

////////////////////////////////////////////////////////////////////////////////
//   TNetConnections
////////////////////////////////////////////////////////////////////////////////
type
  TNetConnections   =  class(TCollection)
  private
     // Private declarations
     FConnections:  TPidlList;
     function       GetItem(Index: Integer): TNetConnection;
     procedure      SetItem(Index: Integer; Value: TNetConnection);
  protected
     // Protected declarations
     procedure      Load;
  public
     // Public declarations
     constructor    Create;
     destructor     Destroy; override;
  public
     // Public properties
     property       Items[Index: Integer]: TNetConnection read GetItem write SetItem; default;
  end;

////////////////////////////////////////////////////////////////////////////////
//   Utility functions
////////////////////////////////////////////////////////////////////////////////
function   GetNetworkFolder(out NetworkFolder: IShellFolder2): Boolean;
function   CopyPIDL(Item: PItemIDList): PItemIDList;
function   CreatePIDL(Size: Integer): PItemIDList;
function   GetNextPIDL(Item: PItemIDList): PItemIDList;
function   GetPIDLSize(Item: PItemIDList): Integer;
function   StrRetToStr(StrRet: TStrRet): String;
procedure  StrRetFree(StrRet: TStrRet);
function   StripAccel(Str: PChar): PChar;

implementation

//// TNetConnection ////////////////////////////////////////////////////////////
constructor TNetConnection.Create(Collection: TCollection);
begin

  // Perform inherited
  inherited Create(Collection);

  // Set starting defaults
  FColumns:=TStringList.Create;
  FItem:=nil;

end;

destructor TNetConnection.Destroy;
begin

  // Resource protection
  try
     // Free memory
     CoTaskMemFree(FItem);
     // Free the columns list
     FColumns.Free;
  finally
     // Perform inherited
     inherited Destroy;
  end;

end;

procedure TNetConnection.Load(Item: PItemIDList; Columns: TStringList);
begin

  // Persist the passed values
  FColumns.Assign(Columns);
  FItem:=CopyPidl(Item);

end;

procedure TNetConnection.CheckLoaded;
begin

  // Determine if we are in a loaded state, raise exception if not
  if (FItem = nil) then raise ENetConnections.CreateRes(@resLoaded);

end;

function TNetConnection.Connect: HResult;
begin

  // Perform the connect
  result:=ExecuteVerb(NC_ENABLE);

end;

function TNetConnection.Disconnect: HResult;
begin

  // Perform the disconnect
  result:=ExecuteVerb(NC_DISABLE);

end;

function TNetConnection.ExecuteVerb(Verb: Word): HResult;
var  lpCmd:         TCMInvokeCommandInfo;
     pvFolder:      IShellFolder2;
     pvCtxMenu:     IContextMenu;
     dwMark:        LongWord;
begin

  // Check loaded state
  CheckLoaded;

  // Get network folder
  if not(GetNetworkFolder(pvFolder)) then
     // Failed
     result:=S_FALSE
  else
  begin
     // Resource protection
     try
        // Query for the conext menu
        result:=pvFolder.GetUIObjectOf(Application.Handle, 1, FItem, IContextMenu, nil, pvCtxMenu);
        // Check for success
        if Succeeded(result) then
        begin
           // Resource protection
           try
              // Clear the struct
              FillChar(lpCmd, SizeOf(TCMInvokeCommandInfo), 0);
              // Setup the command info struct
              lpCmd.cbSize:=SizeOf(TCMInvokeCommandInfo);
              lpCmd.fMask:=CMIC_MASK_FLAG_NO_UI;
              lpCmd.hwnd:=Application.Handle;
              lpCmd.lpVerb:=MakeIntResource(Verb);
              lpCmd.nShow:=SW_SHOW;
              // Execute
              result:=pvCtxMenu.InvokeCommand(lpCmd);
           finally
              // Release the interface
              pvCtxMenu:=nil;
           end;
        end;
     finally
        // Release the interface
        pvFolder:=nil;
     end;
  end;

end;

function TNetConnection.GetName: String;
var  pvFolder:      IShellFolder2;
     lpName:        TStrRet;
begin

  // Check loaded state
  CheckLoaded;

  // Get the name for the current pidl item
  if GetNetworkFolder(pvFolder) then
  begin
     // Resource protection
     try
        if (pvFolder.GetDisplayNameOf(FItem, SHGDN_NORMAL or SHGDN_INFOLDER, lpName) = S_OK) then
        begin
           // Resource protection
           try
              // Return the name
              result:=StrRetToStr(lpName);
           finally
              // Free string memory
              StrRetFree(lpName);
           end;
        end
        else
           // Failed to get name
           SetLength(result, 0);
     finally
        // Release the interface
        pvFolder:=nil;
     end;
  end
  else
     // Failed to get the folder
     SetLength(result, 0);

end;

function TNetConnection.GetPropertyCount: Integer;
begin

  // Return the column count
  result:=FColumns.Count;

end;

function TNetConnection.GetPropertyNames(Index: Integer): String;
begin

  // Return the column name
  result:=FColumns[Index];

end;

function TNetConnection.GetPropertyValues(Index: Integer): String;
var  pvFolder:      IShellFolder2;
     lpDetails:     TShellDetails;
     lpName:        TStrRet;
begin

  // Check loaded state
  CheckLoaded;

  // Get the name for the current pidl item
  if GetNetworkFolder(pvFolder) then
  begin
     // Resource protection
     try
        // Get the column value
        if (pvFolder.GetDetailsOf(FItem, Index, lpDetails) = S_OK) then
        begin
           // Resource protection
           try
              // Return the column value
              result:=StrRetToStr(lpDetails.str);
           finally
              // Free allocated string
              StrRetFree(lpDetails.str);
           end;
        end
        else
           // Failed to get value
           SetLength(result, 0);
     finally
        // Release the interface
        pvFolder:=nil;
     end;
  end
  else
     // Failed to get value
     SetLength(result, 0);

end;

//// TNetConnections ///////////////////////////////////////////////////////////
constructor TNetConnections.Create;
var  pvNetwork:     IShellFolder2;
begin

  // Perform inherited
  inherited Create(TNetConnection);

  // Aquire the network connections folder
  if not(GetNetworkFolder(pvNetwork)) then
     // Raise exception
     raise ENetConnections.CreateRes(@resAquire)
  else
  begin
     // Resource protection
     try
        // Create pidl list from folder
        FConnections:=TPidlList.Create(pvNetwork);
        // Load the collection items
        Load;
     finally
        // Release the interface
        pvNetwork:=nil;
     end;
  end;

end;

destructor TNetConnections.Destroy;
begin

  // Resource protection
  try
     // Free connection list
     FConnections.Free;
  finally
     // Perform inherited
     inherited Destroy;
  end;

end;

function TNetConnections.GetItem(Index: Integer): TNetConnection;
begin

  // Get the item at index
  result:=TNetConnection(inherited GetItem(Index));

end;

procedure TNetConnections.SetItem(Index: Integer; Value: TNetConnection);
begin

  // Set the item at index
  inherited SetItem(Index, Value);

end;

procedure TNetConnections.Load;
var  dwIndex:       Integer;
begin

  // Perform inherited clear;
  inherited Clear;

  // Walk the connection list and add the collection items
  for dwIndex:=0 to Pred(FConnections.Count) do
  begin
     // Perform the add and load
     TNetConnection(inherited Add).Load(FConnections[dwIndex], FConnections.Columns);
  end;

end;

//// TPidlList /////////////////////////////////////////////////////////////////
constructor TPidlList.Create(Folder: IShellFolder2);
begin

  // Perform inherited
  inherited Create;

  // Initial defaults
  FList:=TList.Create;
  FColumns:=TStringList.Create;

  // Load the list from the folder
  LoadFolder(Folder);

end;

destructor TPidlList.Destroy;
begin

  // Resource protection
  try
     // Clear the list
     Clear;
     // Free the lists
     FList.Free;
     FColumns.Free;
  finally
     // Perform inherited
     inherited Destroy;
  end;

end;

function TPidlList.GetCount: Integer;
begin

  // Return count of pidls
  result:=FList.Count;

end;

function TPidlList.GetItems(Index: Integer): PItemIDList;
begin

  // Return the pidl at the specified index
  result:=PItemIDList(FList[Index]);

end;

procedure TPidlList.LoadColumns(Folder: IShellFolder2);
var  lpDetails:     TShellDetails;
     dwColumn:      Integer;
begin

  // Lock list
  FColumns.BeginUpdate;

  // Resource protection
  try
     // Clear the list
     FColumns.Clear;
     // Check folder interface
     if Assigned(Folder) then
     begin
        // Set column enumerator
        dwColumn:=0;
        // Loop columns
        while (Folder.GetDetailsOf(nil, dwColumn, lpDetails) = S_OK) do
        begin
           // Resource protection
           try
              // Update for next iteration
              Inc(dwColumn);
              // Get column name
              FColumns.Add(StrRetToStr(lpDetails.str));
           finally
              // Free allocated string
              StrRetFree(lpDetails.str);
           end;
        end;
     end;
  finally
     // Unlock the list
     FColumns.EndUpdate;
  end;

end;

procedure TPidlList.LoadFolder(Folder: IShellFolder2);
var  pvEnumList:       IEnumIDList;
     pidlItem:         PItemIDList;
     cbCount:          Cardinal;
begin

  // Clear the list
  Clear;

  // Check folder interface
  if Assigned(Folder) then
  begin
     // Load the columns names
     LoadColumns(Folder);
     // Get enumerator
     if (Folder.EnumObjects(Application.Handle, SHCONTF_NONFOLDERS or SHCONTF_INCLUDEHIDDEN, pvEnumList) = S_OK) then
     begin
        // Resource protection
        try
           // Enumerate items
           while (pvEnumList.Next(1, pidlItem, cbCount) = S_OK) do
           begin
              // Add item to the list
              FList.Add(pidlItem);
           end;
        finally
           // Release the interface
           pvEnumList:=nil;
        end;
     end;
  end;

end;

procedure TPidlList.Clear;
var  dwIndex:       Integer;
begin

  // Resource protection
  try
     // Walk the list and free the pidls
     for dwIndex:=Pred(FList.Count) downto 0 do CoTaskMemFree(FList[dwIndex]);
  finally
     // Clear the list
     FList.Clear;
  end;

end;

//// Utility functions /////////////////////////////////////////////////////////
function StripAccel(Str: PChar): PChar;
var  lpszParse:     PChar;
begin

  // Set result
  result:=Str;

  // Set parse point
  lpszParse:=Str;

  // Resource protection
  try
     // Strip & accel from the string
     while (Str^ > #0) do
     begin
        // Check char
        if (Str^ = '&') then
        begin
           // Check next char
           if (Str[1] = '&') then
           begin
              // Copy char
              lpszParse^:=Str^;
              // Push parse point
              Inc(lpszParse);
              // Increment the string
              Inc(Str);
           end;
        end
        else
        begin
           // Copy char
           lpszParse^:=Str^;
           // Push parse point
           Inc(lpszParse);
        end;
        // Increment string
        Inc(Str);
     end;
  finally
     // Null terminate
     lpszParse^:=#0;
  end;

end;

function GetNetworkFolder(out NetworkFolder: IShellFolder2): Boolean;
var  pvDesktop:        IShellFolder;
     pvFolder:         IShellFolder;
     pvEnumItems:      IEnumIDList;
     pidlCtrlPanel:    PItemIDList;
     pidlItem:         PItemIDList;
     cbCount:          Cardinal;
     lpValue:          TStrRet;
begin

  // Clear outbound interface
  NetworkFolder:=nil;

  // Resource protection
  try
     // Get desktop folder
     if (SHGetDesktopFolder(pvDesktop) = S_OK) then
     begin
        // Resource protection
        try
           // Get control panel pidl
           if (SHGetSpecialFolderLocation(Application.Handle, CSIDL_CONTROLS, pidlCtrlPanel) = S_OK) then
           begin
              // Resource protection
              try
                 // Bind to folder interface
                 if (pvDesktop.BindToObject(pidlCtrlPanel, nil, IID_IShellFolder, pvFolder) = S_OK) then
                 begin
                    // Resource protection
                    try
                       // Locate the folder for "Network Connections"
                       if (pvFolder.EnumObjects(0, SHCONTF_FOLDERS or SHCONTF_INCLUDEHIDDEN, pvEnumItems) = S_OK) then
                       begin
                          // Resource protection
                          try
                             // Enumerate items
                             while (pvEnumItems.Next(1, pidlItem, cbCount) = S_OK) do
                             begin
                                // Resource protection
                                try
                                   // Get display name of pidl
                                   if (pvFolder.GetDisplayNameOf(pidlItem, SHGDN_NORMAL or SHGDN_INFOLDER, lpValue) = S_OK) then
                                   begin
                                      // Resource protection
                                      try
                                         // Check for "Network Connections"
                                         if (CompareText(StrRetToStr(lpValue), NC_ROOT) = 0) then
                                         begin
                                            // Bind to folder interface
                                            if not(pvFolder.BindToObject(pidlItem, nil, IID_IShellFolder2, NetworkFolder) = S_OK) then
                                            begin
                                               // Make sure interface is cleared
                                               NetworkFolder:=nil;
                                            end;
                                            // Done processing either way
                                            break;
                                         end;
                                      finally
                                         // Free string memory
                                         StrRetFree(lpValue);
                                      end;
                                   end;
                                finally
                                   // Free the pidl
                                   CoTaskMemFree(pidlItem);
                                end;
                             end;
                          finally
                             // Release the interface
                             pvEnumItems:=nil;
                          end;
                       end;
                    finally
                       // Release the interface
                       pvFolder:=nil;
                    end;
                 end;
              finally
                 // Free the pidl
                 CoTaskMemFree(pidlCtrlPanel);
              end;
           end;
        finally
           // Release the interface
           pvDesktop:=nil;
        end;
     end;
  finally
     // Success if we obtained the folder interface
     result:=Assigned(NetworkFolder);
  end;

end;

procedure StrRetFree(StrRet: TStrRet);
begin

  // Check the type
  if (StrRet.uType = STRRET_WSTR) then
  begin
     // Free the string memory
     CoTaskMemFree(StrRet.pOleStr);
  end;

end;

function StrRetToStr(StrRet: TStrRet): String;
begin

  // Check the type
  case StrRet.uType of
     // C type string
     STRRET_CSTR    :  SetString(result, StrRet.cStr, lstrlen(StrRet.cStr));
     // String offset
     STRRET_OFFSET  :  SetLength(result, 0);
     // WideString
     STRRET_WSTR    :  result:=StrRet.pOleStr;
  else
     // Sanity check
     SetLength(result, 0);
  end;

end;

function CreatePIDL(Size: Integer): PItemIDList;
begin

  // Allocate memory
  result:=CoTaskMemAlloc(Size);

end;

function GetNextPIDL(Item: PItemIDList): PItemIDList;
begin

  // Check for valid item
  if Assigned(Item) then
  begin
     // Get the size of the specified item identifier.
     if (Item^.mkid.cb  = 0) then
        // No more items
        result:=nil
     else
     begin
        // Add cb to pidl (casting to increment by bytes).
        Inc(PChar(Item), Item^.mkid.cb);
        // Check for null
        if (Item^.mkid.cb = 0) then
           // No further items
           result:=nil
        else
           // Return next item
           result:=Item;
     end;
  end
  else
     // No item
     result:=nil;

end;

function GetPIDLSize(Item: PItemIDList): Integer;
begin

  // Default result
  result:=0;

  // Check item
  if Assigned(Item) then
  begin
     // Get base size (null terminator)
     Inc(result, SizeOf(Item^.mkid.cb));
     // While we have the pidl
     while Assigned(Item) do
     begin
        // Update by current pidl size
        Inc(result, Item^.mkid.cb);
        // Get next pidl
        Item:=GetNextPIDL(Item);
     end;
  end;

end;

function CopyPIDL(Item: PItemIDList): PItemIDList;
var  dwSize:        Integer;
begin

  // Get total pidl size
  dwSize:=GetPIDLSize(Item);

  // Create new pidl
  result:=CreatePIDL(dwSize);

  // Check result, move data into new pidl
  if Assigned(result) then Move(Item^, result^, dwSize);

end;

end.
0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
Russell,

Thanks! I will check it out. That is a heck of a lot of code to actually "Click" those menu items, eh? That was a lot of work and truly unexpected!

I was seeking and working on a much simpler alternative, but if this works in 2000 and up, I will be truly grateful!

John
0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
Maybe there still is a simpler way.... so some more info might be helpful.

I am assigning a non persistent virtual IP to my NIC. I can remove the virtual (secondary) IP without any problems and it is removed/disabled. However, if the network cable is unplugged and that event trapped, the IP cannot be removed. A Win32 error occurs. Even after plugging the cable back in, the IP cannot be removed. Something happens when the card is unplugged and even after plugging it back in. The only solution has been a reset of the NIC if I want to rid myself of this virtual IP.

If the cable is left alone, not unplugged, you can and delete all day long with no problems this virtual IP. SO when one disables and enables the NIC, the virtual IP, not being persistent, clears.

Tested on multiple PCs and hardware. This uses the IPHlp and all those units supplied through Jedi.

So, if you have any other ideas....

Thanks.  I'll get cracking on your code.

John
0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
Russell,

Works great on Windows XP but does not work on Windows 2000. I get your

'Failed to aquire the "Network Connections" shell folder interface'

error.

John
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
Ok, try changing the NC_ROOT to "Network and Dial-up Connections" and then run it again on a 2K box.

If this runs through ok (it should), then the code can be modded to check running OS version. Also, how are you adding this virtual IP and what api are you using to try and remove it?

Russell
0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
Using:

VVAddIPAddress(Address, Mask, IfIndex, NTEContext, NTEInstance); to add an IP (again non persistent)

and

VVDeleteIPAddress(NTEContext);

The API is the IPhelper stuff which includes:

IPExport,  IPHlpApi,  Iprtrmib,  IpTypes and  IpFunctions

I'll mess around with the NC_ROOT and get back with you.

John

PS. How in the world did you learn your way around the registry as well as you do?!



0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
Alrighty,

Changed

NC_ROOT   =  'Network Connections';

to

NC_ROOT   =  'Network and Dial-up Connections';

No Joy on 2000. And of course no joy on XP.

hmmm... I certainly do not know where to go!

John
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
Sorry John,
Don't have a Win2K box to test on, so all I can suggest is going to control panel and copying the exact text from the Network settings control panel item. If you can't debug / single step on the 2K box, you can also add a MessageBox in the GetNetworkFolder routine at:

                              // Check for "Network Connections"
                              MessageBox(0, PChar(StrRetToStr(lpValue)), nil, MB_OK); // <--
                              if (CompareText(StrRetToStr(lpValue), NC_ROOT) = 0) then
                              begin
                                   ...

this will tell you (a) if the code is at least enumerating the control panel items and (b) what names are getting parsed out of the shell items. As to the use of AddIpAddress/DeleteIPAddress routines, I can't find anything that specifically talks about the DeleteIPAddress failing if the cable is unplugged. The two suggestions I have:

- In this scenario, have you tried to re-AddIpAddress(...) on the address in question to see if that succeedes, which would allow you to call delete?
- You could call DisableMediaSense, which would eliminate the notifications.. problem is, it disables notification all adapters

Its a little tough as the netshell.dll and hnetcfg are not available on Win2K

Russell



0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
I know!

Yes, I have closely scrutinized 2K and the control panel to make sure I spelled it correctly.

When I get home I will be able to step through it on a 2K box. Here I can only compile on XP but can test on a bunch of different machines.

I never thought about trying to re-add the address, as it still exists, but might be worth a try!

I'll let you know!

I'll accept but we can keep going as open discussion if need be.

Thanks Russell!
0
 
LVL 18

Author Closing Comment

by:Johnjces
Comment Utility
Simply above and beyond the call! More than I expected and I thank-you!
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
Thanks, and I hope you didn't feel like you had to close this question. I will look at it more tomorrow to see if there is anything else I can offer.

Russell
0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
I know I entered Network and Dial-up Connections and spelled it right.

I stepped through and in WIndows 2000 and it comes up as Network and Dial-up Connections! Arghhhh! I will mess with it later this evening.

I did not feel I had to close the Q. With all the help you did it was the least I could do! I just need to figure how "Network and Dial-up Connections" does not equal "Network and Dial-up Connections"!

Thanks again!

John
0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
This AM I, (didn't do anything at home last night on it), I found that the unit is getting the network folder, but failing after that. Comparing "Network and Dial-up  Connections, with what I typed, (in case I changed something or fat fingered a key) comes up 0. All is OK.

It fails after that... just have to continue my debugging.

One thing however, is that 2000 does not have the following keys in its registry.

 '{93F2F68C-1D1B-11D3-A30E-00C04F79ABD1}';
 '{0E700BE1-9DB6-11D1-A1CE-00C04FD75D13}';

... and this could be the source of the error.

I do not know the registry with this granularity and no nothing of any work around.

Thanks!

John
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
One last shot, removed the extra column info and dropped it down to just IShellFolder. Gives you the connect / disconnect only. Also, the parse name (GUID) is extracted and compared, which should be the same for Win2K/XP/Vista "::{7007ACC7-3202-11D1-AAD2-00805FC1270E}"

As I said, last shot...

unit NetConnections;
////////////////////////////////////////////////////////////////////////////////
//
//   Unit        :  NetConnections
//   Author      :  rllibby
//   Date        :  06.12.2007
//   Description :  Shell (COM) based mechanism for enabling / disabling the
//                  network connections on a PC.
//
////////////////////////////////////////////////////////////////////////////////
interface

////////////////////////////////////////////////////////////////////////////////
//   Include units
////////////////////////////////////////////////////////////////////////////////
uses
  Windows, SysUtils, Classes, Forms, ComObj, ActiveX, ShlObj;

////////////////////////////////////////////////////////////////////////////////
//   Constants
////////////////////////////////////////////////////////////////////////////////
const
  NC_ROOT           =  '::{7007ACC7-3202-11D1-AAD2-00805FC1270E}';
  NC_ENABLE         =  16;
  NC_DISABLE        =  17;

////////////////////////////////////////////////////////////////////////////////
//   Types
////////////////////////////////////////////////////////////////////////////////
type
  ENetConnections   =  class(Exception);

////////////////////////////////////////////////////////////////////////////////
//   Resource strings
////////////////////////////////////////////////////////////////////////////////
resourcestring
  resAquire         =  'Failed to aquire the "Network Connections" shell folder interface';
  resLoaded         =  'The network collection item has not been loaded';

////////////////////////////////////////////////////////////////////////////////
//   TPidlList
////////////////////////////////////////////////////////////////////////////////
type
  TPidlList         =  class(TObject)
  private
     // Private declarations
     FList:         TList;
  protected
     // Protected declarations
     function       GetCount: Integer;
     function       GetItems(Index: Integer): PItemIDList;
     procedure      LoadFolder(Folder: IShellFolder);
  public
     // Public declarations
     constructor    Create(Folder: IShellFolder);
     destructor     Destroy; override;
     procedure      Clear;
  public
     // Public properties
     property       Count: Integer read GetCount;
     property       Items[Index: Integer]: PItemIDList read GetItems; default;
  end;

////////////////////////////////////////////////////////////////////////////////
//   TNetConnection
////////////////////////////////////////////////////////////////////////////////
type
  TNetConnection    =  class(TCollectionItem)
  private
     // Private declarations
     FFolder:       IShellFolder;
     FItem:         PItemIDList;
     function       ExecuteVerb(Verb: Word): HResult;
  protected
     // Protected declarations
     procedure      CheckLoaded;
     function       GetName: String;
     procedure      Load(Folder: IShellFolder; Item: PItemIDList);
  public
     // Public declarations
     constructor    Create(Collection: TCollection); override;
     destructor     Destroy; override;
     function       Connect: HResult;
     function       Disconnect: HResult;
  public
     // Public properties
     property       Name: String read GetName;
  end;

////////////////////////////////////////////////////////////////////////////////
//   TNetConnections
////////////////////////////////////////////////////////////////////////////////
type
  TNetConnections   =  class(TCollection)
  private
     // Private declarations
     FConnections:  TPidlList;
     FFolder:       IShellFolder;
     function       GetItem(Index: Integer): TNetConnection;
     procedure      SetItem(Index: Integer; Value: TNetConnection);
  protected
     // Protected declarations
     procedure      Load;
  public
     // Public declarations
     constructor    Create;
     destructor     Destroy; override;
  public
     // Public properties
     property       Items[Index: Integer]: TNetConnection read GetItem write SetItem; default;
  end;

////////////////////////////////////////////////////////////////////////////////
//   Utility functions
////////////////////////////////////////////////////////////////////////////////
function   GetNetworkFolder(out NetworkFolder: IShellFolder): Boolean;
function   CopyPIDL(Item: PItemIDList): PItemIDList;
function   CreatePIDL(Size: Integer): PItemIDList;
function   GetNextPIDL(Item: PItemIDList): PItemIDList;
function   GetPIDLSize(Item: PItemIDList): Integer;
function   StrRetToStr(StrRet: TStrRet): String;
procedure  StrRetFree(StrRet: TStrRet);

implementation

//// TNetConnection ////////////////////////////////////////////////////////////
constructor TNetConnection.Create(Collection: TCollection);
begin

  // Perform inherited
  inherited Create(Collection);

  // Set starting defaults
  FFolder:=nil;
  FItem:=nil;

end;

destructor TNetConnection.Destroy;
begin

  // Resource protection
  try
     // Free memory
     CoTaskMemFree(FItem);
     // Release the interface
     FFolder:=nil;
  finally
     // Perform inherited
     inherited Destroy;
  end;

end;

procedure TNetConnection.Load(Folder: IShellFolder; Item: PItemIDList);
begin

  // Persist the passed values
  FFolder:=Folder;
  FItem:=CopyPidl(Item);

end;

procedure TNetConnection.CheckLoaded;
begin

  // Determine if we are in a loaded state, raise exception if not
  if (FFolder = nil) or (FItem = nil) then raise ENetConnections.CreateRes(@resLoaded);

end;

function TNetConnection.Connect: HResult;
begin

  // Perform the connect
  result:=ExecuteVerb(NC_ENABLE);

end;

function TNetConnection.Disconnect: HResult;
begin

  // Perform the disconnect
  result:=ExecuteVerb(NC_DISABLE);

end;

function TNetConnection.ExecuteVerb(Verb: Word): HResult;
var  lpCmd:         TCMInvokeCommandInfo;
     pvCtxMenu:     IContextMenu;
     dwMark:        LongWord;
begin

  // Check loaded state
  CheckLoaded;

  // Query for the conext menu
  result:=FFolder.GetUIObjectOf(Application.Handle, 1, FItem, IContextMenu, nil, pvCtxMenu);

  // Check for success
  if Succeeded(result) then
  begin
     // Resource protection
     try
        // Clear the struct
        FillChar(lpCmd, SizeOf(TCMInvokeCommandInfo), 0);
        // Setup the command info struct
        lpCmd.cbSize:=SizeOf(TCMInvokeCommandInfo);
        lpCmd.hwnd:=Application.Handle;
        lpCmd.lpVerb:=MakeIntResource(Verb);
        lpCmd.nShow:=SW_SHOW;
        // Execute
        if (pvCtxMenu.InvokeCommand(lpCmd) = S_OK) then
        begin
           // Determine time to wait
           dwMark:=GetTickCount + 5000;
           // Spin message loop
           while (dwMark > GetTickCount) do
           begin
              // Process messages
              Application.ProcessMessages;
           end;
        end;
     finally
        // Release the interface
        pvCtxMenu:=nil;
     end;
  end;

end;

function TNetConnection.GetName: String;
var  lpName:        TStrRet;
begin

  // Check loaded state
  CheckLoaded;

  // Get display name
  if (FFolder.GetDisplayNameOf(FItem, SHGDN_NORMAL or SHGDN_INFOLDER, lpName) = S_OK) then
  begin
     // Resource protection
     try
        // Return the name
        result:=StrRetToStr(lpName);
     finally
        // Free string memory
        StrRetFree(lpName);
     end;
  end
  else
     // Failed to get name
     SetLength(result, 0);

end;

//// TNetConnections ///////////////////////////////////////////////////////////
constructor TNetConnections.Create;
begin

  // Perform inherited
  inherited Create(TNetConnection);

  // Aquire the network connections folder
  if not(GetNetworkFolder(FFolder)) then
     // Raise exception
     raise ENetConnections.CreateRes(@resAquire)
  else
  begin
     // Create pidl list from folder
     FConnections:=TPidlList.Create(FFolder);
     // Load network connections from pidl
     Load;
  end;

end;

destructor TNetConnections.Destroy;
begin

  // Resource protection
  try
     // Release the interface
     FFolder:=nil;
     // Free connection list
     FConnections.Free;
  finally
     // Perform inherited
     inherited Destroy;
  end;

end;

function TNetConnections.GetItem(Index: Integer): TNetConnection;
begin

  // Get the item at index
  result:=TNetConnection(inherited GetItem(Index));

end;

procedure TNetConnections.SetItem(Index: Integer; Value: TNetConnection);
begin

  // Set the item at index
  inherited SetItem(Index, Value);

end;

procedure TNetConnections.Load;
var  dwIndex:       Integer;
begin

  // Perform inherited clear;
  inherited Clear;

  // Walk the connection list and add the collection items
  for dwIndex:=0 to Pred(FConnections.Count) do
  begin
     // Perform the add and load
     TNetConnection(inherited Add).Load(FFolder, FConnections[dwIndex]);
  end;

end;

//// TPidlList /////////////////////////////////////////////////////////////////
constructor TPidlList.Create(Folder: IShellFolder);
begin

  // Perform inherited
  inherited Create;

  // Initial defaults
  FList:=TList.Create;

  // Load the list from the folder
  LoadFolder(Folder);

end;

destructor TPidlList.Destroy;
begin

  // Resource protection
  try
     // Clear the list
     Clear;
     // Free the lists
     FList.Free;
  finally
     // Perform inherited
     inherited Destroy;
  end;

end;

function TPidlList.GetCount: Integer;
begin

  // Return count of pidls
  result:=FList.Count;

end;

function TPidlList.GetItems(Index: Integer): PItemIDList;
begin

  // Return the pidl at the specified index
  result:=PItemIDList(FList[Index]);

end;

procedure TPidlList.LoadFolder(Folder: IShellFolder);
var  pvEnumList:       IEnumIDList;
     pidlItem:         PItemIDList;
     cbCount:          Cardinal;
begin

  // Clear the list
  Clear;

  // Check folder interface
  if Assigned(Folder) then
  begin
     // Get enumerator
     if (Folder.EnumObjects(Application.Handle, SHCONTF_NONFOLDERS or SHCONTF_INCLUDEHIDDEN, pvEnumList) = S_OK) then
     begin
        // Resource protection
        try
           // Enumerate items
           while (pvEnumList.Next(1, pidlItem, cbCount) = S_OK) do
           begin
              // Add item to the list
              FList.Add(pidlItem);
           end;
        finally
           // Release the interface
           pvEnumList:=nil;
        end;
     end;
  end;

end;

procedure TPidlList.Clear;
var  dwIndex:       Integer;
begin

  // Resource protection
  try
     // Walk the list and free the pidls
     for dwIndex:=Pred(FList.Count) downto 0 do CoTaskMemFree(FList[dwIndex]);
  finally
     // Clear the list
     FList.Clear;
  end;

end;

//// Utility functions /////////////////////////////////////////////////////////
function GetNetworkFolder(out NetworkFolder: IShellFolder): Boolean;
var  pvDesktop:        IShellFolder;
     pvFolder:         IShellFolder;
     pvEnumItems:      IEnumIDList;
     pidlCtrlPanel:    PItemIDList;
     pidlItem:         PItemIDList;
     cbCount:          Cardinal;
     lpValue:          TStrRet;
begin

  // Clear outbound interface
  NetworkFolder:=nil;

  // Resource protection
  try
     // Get desktop folder
     if (SHGetDesktopFolder(pvDesktop) = S_OK) then
     begin
        // Resource protection
        try
           // Get control panel pidl
           if (SHGetSpecialFolderLocation(Application.Handle, CSIDL_CONTROLS, pidlCtrlPanel) = S_OK) then
           begin
              // Resource protection
              try
                 // Bind to folder interface
                 if (pvDesktop.BindToObject(pidlCtrlPanel, nil, IID_IShellFolder, pvFolder) = S_OK) then
                 begin
                    // Resource protection
                    try
                       // Locate the folder for "Network Connections"
                       if (pvFolder.EnumObjects(0, SHCONTF_FOLDERS or SHCONTF_INCLUDEHIDDEN, pvEnumItems) = S_OK) then
                       begin
                          // Resource protection
                          try
                             // Enumerate items
                             while (pvEnumItems.Next(1, pidlItem, cbCount) = S_OK) do
                             begin
                                // Resource protection
                                try
                                   // Get parse name of pidl
                                   if (pvFolder.GetDisplayNameOf(pidlItem, SHGDN_FORPARSING or SHGDN_INFOLDER, lpValue) = S_OK) then
                                   begin
                                      // Resource protection
                                      try
                                         // Check for ::{7007ACC7-3202-11D1-AAD2-00805FC1270E}
                                         if (CompareText(StrRetToStr(lpValue), NC_ROOT) = 0) then
                                         begin
                                            // Bind to folder interface
                                            if not(pvFolder.BindToObject(pidlItem, nil, IShellFolder, NetworkFolder) = S_OK) then
                                            begin
                                               // Make sure interface is cleared
                                               NetworkFolder:=nil;
                                            end;
                                            // Done processing either way
                                            break;
                                         end;
                                      finally
                                         // Free string memory
                                         StrRetFree(lpValue);
                                      end;
                                   end;
                                finally
                                   // Free the pidl
                                   CoTaskMemFree(pidlItem);
                                end;
                             end;
                          finally
                             // Release the interface
                             pvEnumItems:=nil;
                          end;
                       end;
                    finally
                       // Release the interface
                       pvFolder:=nil;
                    end;
                 end;
              finally
                 // Free the pidl
                 CoTaskMemFree(pidlCtrlPanel);
              end;
           end;
        finally
           // Release the interface
           pvDesktop:=nil;
        end;
     end;
  finally
     // Success if we obtained the folder interface
     result:=Assigned(NetworkFolder);
  end;

end;

procedure StrRetFree(StrRet: TStrRet);
begin

  // Check the type
  if (StrRet.uType = STRRET_WSTR) then
  begin
     // Free the string memory
     CoTaskMemFree(StrRet.pOleStr);
  end;

end;

function StrRetToStr(StrRet: TStrRet): String;
begin

  // Check the type
  case StrRet.uType of
     // C type string
     STRRET_CSTR    :  SetString(result, StrRet.cStr, lstrlen(StrRet.cStr));
     // String offset
     STRRET_OFFSET  :  SetLength(result, 0);
     // WideString
     STRRET_WSTR    :  result:=StrRet.pOleStr;
  else
     // Sanity check
     SetLength(result, 0);
  end;

end;

function CreatePIDL(Size: Integer): PItemIDList;
begin

  // Allocate memory
  result:=CoTaskMemAlloc(Size);

end;

function GetNextPIDL(Item: PItemIDList): PItemIDList;
begin

  // Check for valid item
  if Assigned(Item) then
  begin
     // Get the size of the specified item identifier.
     if (Item^.mkid.cb  = 0) then
        // No more items
        result:=nil
     else
     begin
        // Add cb to pidl (casting to increment by bytes).
        Inc(PChar(Item), Item^.mkid.cb);
        // Check for null
        if (Item^.mkid.cb = 0) then
           // No further items
           result:=nil
        else
           // Return next item
           result:=Item;
     end;
  end
  else
     // No item
     result:=nil;

end;

function GetPIDLSize(Item: PItemIDList): Integer;
begin

  // Default result
  result:=0;

  // Check item
  if Assigned(Item) then
  begin
     // Get base size (null terminator)
     Inc(result, SizeOf(Item^.mkid.cb));
     // While we have the pidl
     while Assigned(Item) do
     begin
        // Update by current pidl size
        Inc(result, Item^.mkid.cb);
        // Get next pidl
        Item:=GetNextPIDL(Item);
     end;
  end;

end;

function CopyPIDL(Item: PItemIDList): PItemIDList;
var  dwSize:        Integer;
begin

  // Get total pidl size
  dwSize:=GetPIDLSize(Item);

  // Create new pidl
  result:=CreatePIDL(dwSize);

  // Check result, move data into new pidl
  if Assigned(result) then Move(Item^, result^, dwSize);

end;

end.
0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
Russell,

That is more than I could hope for!!

I'll give it a last shot!

John
0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
Russell,

Damn!  Excuse my language.  :(

Worked just fine again on Windows XP (pro) but did not work on Windows 2000.

Thanks for all of your hard work.

I wonder... should I repost with your code and see if anyone has any thoughts?

Thx!

John
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
Can you pin point *where* it is failing? That would help narrow things down alot.

0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
No error, just runs through like it was clicked, but no disable.... or enable.

I did some research on the folder ID {7007ACC7-3202-11D1-AAD2-00805FC1270E} for win 2K and all "should' work....

I did read something about user permissions but I am an admin on the hardware I am testing on.

Also, it was interesting to note that the following when run on XP brings up the run as box but no network connections but does both under Win 2K.

%SystemRoot%\explorer.exe ::{7007ACC7-3202-11D1-AAD2-00805FC1270E}

hmmm... I am baffled.

Can you provide any hints on how best to debug or step through the code since it seems to 'run' just fine. No action.

John
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
Hmm, it may be a case where the Enable/Diable aren't 16 and 17 on Win2K. The only good way to find out is to create a popup menu and have the IContextMenu fill it in with a call to QueryContextMenu. (which is what I originally did to get the values).

Will have a chance to look at it more later.
0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
Cool!

Let me know what you would like me to do...

Most of this is pretty far out of my league.. but I am learning!!! Thanks!

John
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
John,

Just verify that (A) the network folder is being obtained, (B) that you can enumerate the connection items (loop the collection and showmessage the Items[index].Name) and that (C) the ExecuteVerb is getting called.

I will post up code either tonight or tomorrow for extracting the context menu items in order to obtain the ID's.

Russell
0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 
LVL 18

Author Comment

by:Johnjces
Comment Utility
Alrighty!

It does all the enumeration but under XP it only returns the network cards, and in my XP box it shows:

Primary Gigabit
Secondary

On the Windows 2000 box (3 nics) it shows:

Make New Connection
OpenNIC
Digi
PCI Card

Could the problem be related to "Make New Connection".

John
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
Issuing an enable/disable to the first 2 (under 2K) aren't goint to do anything, but it should work for the 3rd and 4th as long as the command ID's are the same as XPs (16/17).

0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
Ok... but the command IDs  I do not know.

Thx
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
As promised.

unit NetConnections;
////////////////////////////////////////////////////////////////////////////////
//
//   Unit        :  NetConnections
//   Author      :  rllibby
//   Date        :  06.12.2007
//   Description :  Shell (COM) based mechanism for enabling / disabling the
//                  network connections on a PC.
//
////////////////////////////////////////////////////////////////////////////////
interface

////////////////////////////////////////////////////////////////////////////////
//   Conditionals for testing
////////////////////////////////////////////////////////////////////////////////
{$DEFINE DEBUG}

////////////////////////////////////////////////////////////////////////////////
//   Include units
////////////////////////////////////////////////////////////////////////////////
uses
  Windows, SysUtils, Classes, Forms, ComObj, ActiveX, ShlObj;

////////////////////////////////////////////////////////////////////////////////
//   Constants
////////////////////////////////////////////////////////////////////////////////
const
  NC_ROOT           =  '::{7007ACC7-3202-11D1-AAD2-00805FC1270E}';
  NC_ENABLE         =  'enable';
  NC_DISABLE        =  'disable';

////////////////////////////////////////////////////////////////////////////////
//   Types
////////////////////////////////////////////////////////////////////////////////
type
  ENetConnections   =  class(Exception);

////////////////////////////////////////////////////////////////////////////////
//   Resource strings
////////////////////////////////////////////////////////////////////////////////
resourcestring
  resAquire         =  'Failed to aquire the "Network Connections" shell folder interface';
  resLoaded         =  'The network collection item has not been loaded';

////////////////////////////////////////////////////////////////////////////////
//   TPidlList
////////////////////////////////////////////////////////////////////////////////
type
  TPidlList         =  class(TObject)
  private
     // Private declarations
     FList:         TList;
  protected
     // Protected declarations
     function       GetCount: Integer;
     function       GetItems(Index: Integer): PItemIDList;
     procedure      LoadFolder(Folder: IShellFolder);
  public
     // Public declarations
     constructor    Create(Folder: IShellFolder);
     destructor     Destroy; override;
     procedure      Clear;
  public
     // Public properties
     property       Count: Integer read GetCount;
     property       Items[Index: Integer]: PItemIDList read GetItems; default;
  end;

////////////////////////////////////////////////////////////////////////////////
//   TNetConnection
////////////////////////////////////////////////////////////////////////////////
type
  TNetConnection    =  class(TCollectionItem)
  private
     // Private declarations
     FFolder:       IShellFolder;
     FItem:         PItemIDList;
     function       ExecuteVerb(Verb: Word): HResult;
     function       GetVerbID(Verb: String; out ID: Integer): Boolean;
  protected
     // Protected declarations
     procedure      CheckLoaded;
     function       GetName: String;
     procedure      Load(Folder: IShellFolder; Item: PItemIDList);
  public
     // Public declarations
     constructor    Create(Collection: TCollection); override;
     destructor     Destroy; override;
     function       Connect: HResult;
     function       Disconnect: HResult;
  public
     // Public properties
     property       Name: String read GetName;
  end;

////////////////////////////////////////////////////////////////////////////////
//   TNetConnections
////////////////////////////////////////////////////////////////////////////////
type
  TNetConnections   =  class(TCollection)
  private
     // Private declarations
     FConnections:  TPidlList;
     FFolder:       IShellFolder;
     function       GetItem(Index: Integer): TNetConnection;
     procedure      SetItem(Index: Integer; Value: TNetConnection);
  protected
     // Protected declarations
     procedure      Load;
  public
     // Public declarations
     constructor    Create;
     destructor     Destroy; override;
  public
     // Public properties
     property       Items[Index: Integer]: TNetConnection read GetItem write SetItem; default;
  end;

////////////////////////////////////////////////////////////////////////////////
//   Utility functions
////////////////////////////////////////////////////////////////////////////////
function   GetNetworkFolder(out NetworkFolder: IShellFolder): Boolean;
function   CopyPIDL(Item: PItemIDList): PItemIDList;
function   CreatePIDL(Size: Integer): PItemIDList;
function   GetNextPIDL(Item: PItemIDList): PItemIDList;
function   GetPIDLSize(Item: PItemIDList): Integer;
function   StrRetToStr(StrRet: TStrRet): String;
procedure  StrRetFree(StrRet: TStrRet);
function   StripAccel(Str: PChar): PChar;

implementation

//// TNetConnection ////////////////////////////////////////////////////////////
constructor TNetConnection.Create(Collection: TCollection);
begin

  // Perform inherited
  inherited Create(Collection);

  // Set starting defaults
  FFolder:=nil;
  FItem:=nil;

end;

destructor TNetConnection.Destroy;
begin

  // Resource protection
  try
     // Free memory
     CoTaskMemFree(FItem);
     // Release the interface
     FFolder:=nil;
  finally
     // Perform inherited
     inherited Destroy;
  end;

end;

procedure TNetConnection.Load(Folder: IShellFolder; Item: PItemIDList);
begin

  // Persist the passed values
  FFolder:=Folder;
  FItem:=CopyPidl(Item);

end;

procedure TNetConnection.CheckLoaded;
begin

  // Determine if we are in a loaded state, raise exception if not
  if (FFolder = nil) or (FItem = nil) then raise ENetConnections.CreateRes(@resLoaded);

end;

function TNetConnection.Connect: HResult;
var  dwEnable:      Integer;
begin

  // Get the enable id
  if GetVerbID(NC_ENABLE, dwEnable) then
     // Perform the connect
     result:=ExecuteVerb(dwEnable)
  else
  begin
     {$IFDEF DEBUG}
     MessageBox(0, 'Failed to get the ID for the Enable verb', nil, MB_OK);
     {$ENDIF}
     // Failed to get the id
     result:=S_FALSE;
  end;

end;

function TNetConnection.Disconnect: HResult;
var  dwDisable:     Integer;
begin

  // Get the disable id
  if GetVerbID(NC_DISABLE, dwDisable) then
     // Perform the connect
     result:=ExecuteVerb(dwDisable)
  else
  begin
     {$IFDEF DEBUG}
     MessageBox(0, 'Failed to get the ID for the Disable verb', nil, MB_OK);
     {$ENDIF}
     // Failed to get the id
     result:=S_FALSE;
  end;

end;

function TNetConnection.GetVerbID(Verb: String; out ID: Integer): Boolean;
var  pvCtxMenu:     IContextMenu;
     lpszVerb:      Array [0..MAX_PATH] of Char;
     hPopup:        HMENU;
     dwIndex:       Integer;
begin

  // Set default result
  result:=False;

  // Check loaded state
  CheckLoaded;

  // Query for the conext menu
  if (FFolder.GetUIObjectOf(Application.Handle, 1, FItem, IContextMenu, nil, pvCtxMenu) = S_OK) then
  begin
     // Resource protection
     try
        // Create popup menu
        hPopup:=CreatePopupMenu;
        // Resource protection
        try
           // Fill in the popup menu from the context menu
           if Succeeded(pvCtxMenu.QueryContextMenu(hPopup, 0, 0, MaxInt, CMF_VERBSONLY)) then
           begin
              // Walk the menu
              for dwIndex:=0 to Pred(GetMenuItemCount(hPopup)) do
              begin
                 // Get the menu item string
                 lpszVerb[GetMenuString(hPopup, dwIndex, @lpszVerb, MAX_PATH, MF_BYPOSITION)]:=#0;
                 // Check string
                 if (lpszVerb[0] > #0) then
                 begin
                    // Strip the accel chars
                    StripAccel(@lpszVerb);
                    // Check against passed verb
                    if (StrIComp(Pointer(Verb), @lpszVerb) = 0) then
                    begin
                       // Found a match, the the id
                       ID:=GetMenuItemID(hPopup, dwIndex);
                       // Success
                       result:=True;
                       // Done processing
                       break;
                    end;
                 end;
              end;
           end;
        finally
           // Destroy the menu
           DestroyMenu(hPopup);
        end;
     finally
        // Release the interface
        pvCtxMenu:=nil;
     end;
  end;

end;

function TNetConnection.ExecuteVerb(Verb: Word): HResult;
var  lpCmd:         TCMInvokeCommandInfo;
     pvCtxMenu:     IContextMenu;
     dwMark:        LongWord;
begin

  {$IFDEF DEBUG}
  MessageBox(0, PCHar(Format('ID to execute: %d', [Verb])), nil, MB_OK);
  {$ENDIF}

  // Check loaded state
  CheckLoaded;

  // Query for the conext menu
  result:=FFolder.GetUIObjectOf(Application.Handle, 1, FItem, IContextMenu, nil, pvCtxMenu);

  // Check for success
  if Succeeded(result) then
  begin
     // Resource protection
     try
        // Clear the struct
        FillChar(lpCmd, SizeOf(TCMInvokeCommandInfo), 0);
        // Setup the command info struct
        lpCmd.cbSize:=SizeOf(TCMInvokeCommandInfo);
        lpCmd.hwnd:=Application.Handle;
        lpCmd.lpVerb:=MakeIntResource(Verb);
        lpCmd.nShow:=SW_SHOW;
        // Execute
        if (pvCtxMenu.InvokeCommand(lpCmd) = S_OK) then
        begin
           // Determine time to wait
           dwMark:=GetTickCount + 5000;
           // Spin message loop
           while (dwMark > GetTickCount) do
           begin
              // Process messages
              Application.ProcessMessages;
           end;
        end;
     finally
        // Release the interface
        pvCtxMenu:=nil;
     end;
  end;

end;

function TNetConnection.GetName: String;
var  lpName:        TStrRet;
begin

  // Check loaded state
  CheckLoaded;

  // Get display name
  if (FFolder.GetDisplayNameOf(FItem, SHGDN_NORMAL or SHGDN_INFOLDER, lpName) = S_OK) then
  begin
     // Resource protection
     try
        // Return the name
        result:=StrRetToStr(lpName);
     finally
        // Free string memory
        StrRetFree(lpName);
     end;
  end
  else
     // Failed to get name
     SetLength(result, 0);

end;

//// TNetConnections ///////////////////////////////////////////////////////////
constructor TNetConnections.Create;
begin

  // Perform inherited
  inherited Create(TNetConnection);

  // Aquire the network connections folder
  if not(GetNetworkFolder(FFolder)) then
     // Raise exception
     raise ENetConnections.CreateRes(@resAquire)
  else
  begin
     // Create pidl list from folder
     FConnections:=TPidlList.Create(FFolder);
     // Load network connections from pidl
     Load;
  end;

end;

destructor TNetConnections.Destroy;
begin

  // Resource protection
  try
     // Release the interface
     FFolder:=nil;
     // Free connection list
     FConnections.Free;
  finally
     // Perform inherited
     inherited Destroy;
  end;

end;

function TNetConnections.GetItem(Index: Integer): TNetConnection;
begin

  // Get the item at index
  result:=TNetConnection(inherited GetItem(Index));

end;

procedure TNetConnections.SetItem(Index: Integer; Value: TNetConnection);
begin

  // Set the item at index
  inherited SetItem(Index, Value);

end;

procedure TNetConnections.Load;
var  dwIndex:       Integer;
begin

  // Perform inherited clear;
  inherited Clear;

  // Walk the connection list and add the collection items
  for dwIndex:=0 to Pred(FConnections.Count) do
  begin
     // Perform the add and load
     TNetConnection(inherited Add).Load(FFolder, FConnections[dwIndex]);
  end;

end;

//// TPidlList /////////////////////////////////////////////////////////////////
constructor TPidlList.Create(Folder: IShellFolder);
begin

  // Perform inherited
  inherited Create;

  // Initial defaults
  FList:=TList.Create;

  // Load the list from the folder
  LoadFolder(Folder);

end;

destructor TPidlList.Destroy;
begin

  // Resource protection
  try
     // Clear the list
     Clear;
     // Free the lists
     FList.Free;
  finally
     // Perform inherited
     inherited Destroy;
  end;

end;

function TPidlList.GetCount: Integer;
begin

  // Return count of pidls
  result:=FList.Count;

end;

function TPidlList.GetItems(Index: Integer): PItemIDList;
begin

  // Return the pidl at the specified index
  result:=PItemIDList(FList[Index]);

end;

procedure TPidlList.LoadFolder(Folder: IShellFolder);
var  pvEnumList:       IEnumIDList;
     pidlItem:         PItemIDList;
     cbCount:          Cardinal;
begin

  // Clear the list
  Clear;

  // Check folder interface
  if Assigned(Folder) then
  begin
     // Get enumerator
     if (Folder.EnumObjects(Application.Handle, SHCONTF_NONFOLDERS or SHCONTF_INCLUDEHIDDEN, pvEnumList) = S_OK) then
     begin
        // Resource protection
        try
           // Enumerate items
           while (pvEnumList.Next(1, pidlItem, cbCount) = S_OK) do
           begin
              // Add item to the list
              FList.Add(pidlItem);
           end;
        finally
           // Release the interface
           pvEnumList:=nil;
        end;
     end;
  end;

end;

procedure TPidlList.Clear;
var  dwIndex:       Integer;
begin

  // Resource protection
  try
     // Walk the list and free the pidls
     for dwIndex:=Pred(FList.Count) downto 0 do CoTaskMemFree(FList[dwIndex]);
  finally
     // Clear the list
     FList.Clear;
  end;

end;

//// Utility functions /////////////////////////////////////////////////////////
function StripAccel(Str: PChar): PChar;
var  lpszParse:     PChar;
begin

  // Set result
  result:=Str;

  // Set parse point
  lpszParse:=Str;

  // Resource protection
  try
     // Strip & accel from the string
     while (Str^ > #0) do
     begin
        // Check char
        if (Str^ = '&') then
        begin
           // Check next char
           if (Str[1] = '&') then
           begin
              // Copy char
              lpszParse^:=Str^;
              // Push parse point
              Inc(lpszParse);
              // Increment the string
              Inc(Str);
           end;
        end
        else
        begin
           // Copy char
           lpszParse^:=Str^;
           // Push parse point
           Inc(lpszParse);
        end;
        // Increment string
        Inc(Str);
     end;
  finally
     // Null terminate
     lpszParse^:=#0;
  end;

end;

function GetNetworkFolder(out NetworkFolder: IShellFolder): Boolean;
var  pvDesktop:        IShellFolder;
     pvFolder:         IShellFolder;
     pvEnumItems:      IEnumIDList;
     pidlCtrlPanel:    PItemIDList;
     pidlItem:         PItemIDList;
     cbCount:          Cardinal;
     lpValue:          TStrRet;
begin

  // Clear outbound interface
  NetworkFolder:=nil;

  // Resource protection
  try
     // Get desktop folder
     if (SHGetDesktopFolder(pvDesktop) = S_OK) then
     begin
        // Resource protection
        try
           // Get control panel pidl
           if (SHGetSpecialFolderLocation(Application.Handle, CSIDL_CONTROLS, pidlCtrlPanel) = S_OK) then
           begin
              // Resource protection
              try
                 // Bind to folder interface
                 if (pvDesktop.BindToObject(pidlCtrlPanel, nil, IID_IShellFolder, pvFolder) = S_OK) then
                 begin
                    // Resource protection
                    try
                       // Locate the folder for "Network Connections"
                       if (pvFolder.EnumObjects(0, SHCONTF_FOLDERS or SHCONTF_INCLUDEHIDDEN, pvEnumItems) = S_OK) then
                       begin
                          // Resource protection
                          try
                             // Enumerate items
                             while (pvEnumItems.Next(1, pidlItem, cbCount) = S_OK) do
                             begin
                                // Resource protection
                                try
                                   // Get parse name of pidl
                                   if (pvFolder.GetDisplayNameOf(pidlItem, SHGDN_FORPARSING or SHGDN_INFOLDER, lpValue) = S_OK) then
                                   begin
                                      // Resource protection
                                      try
                                         // Check for ::{7007ACC7-3202-11D1-AAD2-00805FC1270E}
                                         if (CompareText(StrRetToStr(lpValue), NC_ROOT) = 0) then
                                         begin
                                            // Bind to folder interface
                                            if not(pvFolder.BindToObject(pidlItem, nil, IShellFolder, NetworkFolder) = S_OK) then
                                            begin
                                               // Make sure interface is cleared
                                               NetworkFolder:=nil;
                                            end;
                                            // Done processing either way
                                            break;
                                         end;
                                      finally
                                         // Free string memory
                                         StrRetFree(lpValue);
                                      end;
                                   end;
                                finally
                                   // Free the pidl
                                   CoTaskMemFree(pidlItem);
                                end;
                             end;
                          finally
                             // Release the interface
                             pvEnumItems:=nil;
                          end;
                       end;
                    finally
                       // Release the interface
                       pvFolder:=nil;
                    end;
                 end;
              finally
                 // Free the pidl
                 CoTaskMemFree(pidlCtrlPanel);
              end;
           end;
        finally
           // Release the interface
           pvDesktop:=nil;
        end;
     end;
  finally
     // Success if we obtained the folder interface
     result:=Assigned(NetworkFolder);
  end;

end;

procedure StrRetFree(StrRet: TStrRet);
begin

  // Check the type
  if (StrRet.uType = STRRET_WSTR) then
  begin
     // Free the string memory
     CoTaskMemFree(StrRet.pOleStr);
  end;

end;

function StrRetToStr(StrRet: TStrRet): String;
begin

  // Check the type
  case StrRet.uType of
     // C type string
     STRRET_CSTR    :  SetString(result, StrRet.cStr, lstrlen(StrRet.cStr));
     // String offset
     STRRET_OFFSET  :  SetLength(result, 0);
     // WideString
     STRRET_WSTR    :  result:=StrRet.pOleStr;
  else
     // Sanity check
     SetLength(result, 0);
  end;

end;

function CreatePIDL(Size: Integer): PItemIDList;
begin

  // Allocate memory
  result:=CoTaskMemAlloc(Size);

end;

function GetNextPIDL(Item: PItemIDList): PItemIDList;
begin

  // Check for valid item
  if Assigned(Item) then
  begin
     // Get the size of the specified item identifier.
     if (Item^.mkid.cb  = 0) then
        // No more items
        result:=nil
     else
     begin
        // Add cb to pidl (casting to increment by bytes).
        Inc(PChar(Item), Item^.mkid.cb);
        // Check for null
        if (Item^.mkid.cb = 0) then
           // No further items
           result:=nil
        else
           // Return next item
           result:=Item;
     end;
  end
  else
     // No item
     result:=nil;

end;

function GetPIDLSize(Item: PItemIDList): Integer;
begin

  // Default result
  result:=0;

  // Check item
  if Assigned(Item) then
  begin
     // Get base size (null terminator)
     Inc(result, SizeOf(Item^.mkid.cb));
     // While we have the pidl
     while Assigned(Item) do
     begin
        // Update by current pidl size
        Inc(result, Item^.mkid.cb);
        // Get next pidl
        Item:=GetNextPIDL(Item);
     end;
  end;

end;

function CopyPIDL(Item: PItemIDList): PItemIDList;
var  dwSize:        Integer;
begin

  // Get total pidl size
  dwSize:=GetPIDLSize(Item);

  // Create new pidl
  result:=CreatePIDL(dwSize);

  // Check result, move data into new pidl
  if Assigned(result) then Move(Item^, result^, dwSize);

end;

end.
0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
Russell,

Thanks a bunch! I will check it later tonight as I have been pulling fence and fence posts today.

I will also start another thread with another 500 points for you as that is the least I can do for your efforts in any event, later this evening.

I would have never thought enable/disable would be the key here in looking over it briefly.

You too are the man!

John
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
John,

Your very welcome, and I hope you have some success with it. I'm out of ideas otherwise <lol>. As to the points, don't post another question because (a) its not allowed and (b) it really isn't necessary. I could care less about the points, and I only maintain enough to keep my "free" status (3K/Month). Plus, I enjoy questions such as these, as it is a good learning experience for both involved.

Let me know how it goes.
Russell
0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
Russell,

A bummer, but... no joy at all on 2K! Works fine on XP. The latest on 2K is 'Failed to acquire the "Network Connections" shell folder interface'

This popped up a time or two on XP as well but would work after a second click.

I really appreciate your work and assistance! At least I have a good method for XP and above. I'll test it on Vista when I get a chance too.

Thank-you Russell!

John
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
Sorry to hear that its not working. Did you have any luck with the other option? (Re-adding and attempt delete after the first attempt at Delete fails)

Russell
0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
I did enable the NIC manually then tried disabling through code if that is what you are speaking of, and tried the inverse as well. No joy....

I need to research why 2K is so different.... I can't image that being the case, but I have gone over what I am doing a million times and it is fine. I even tried a shotgun approach with a "for do" for all connections.

Interesting.

John
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
No, I was talking about calling AddIpAddress then DeleteIPAddress if the call to DeleteIPAddress (or whatever your unit has declared the function as) fails.
0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
Oh... no I have not tried that yet as the address still exists after a disconnect and it just does not sound "logical" to me BUT, I will try that today!

0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
I know some of the scripting sites mention the use of Shell.Application (exposed out of Shell32) in order to do the enabling/disabling. Below I  provided a small piece of code that uses this, and can be used to load a litsbox/memo etc with connection item names. Seems like it is just a wrapper over the IShellFolder interfaces, but you never know. Try calling GetConnections(...) passing it a TMemo.Lines / TListBox.Items / etc to see what you get.

Also, you are running the latest svc packs on these 2K boxes right?

---- start of code ----
interface

uses
  Windows, SysUtils, Classes, Forms, ComObj, ActiveX;

type
  IEnumerator       =  interface
     function       ForEach(out Obj: OleVariant): Boolean;
     function       ForEachObject(const IID: TGUID; out Obj): Boolean;
     function       Reset: Boolean;
     function       Skip(Count: LongWord): Boolean;
     function       Clone: IEnumerator;
  end;

  TEnumerator       =  class(TInterfacedObject, IEnumerator)
  private
     // Private declarations
     FEnumVariant:  IEnumVariant;
     procedure      GetEnumVariant(Dispatch: IDispatch);
  protected
     // Protected declarations
     function       ForEach(out Obj: OleVariant): Boolean;
     function       ForEachObject(const IID: TGUID; out Obj): Boolean;
     function       Reset: Boolean;
     function       Skip(Count: LongWord): Boolean;
     function       Clone: IEnumerator;
  public
     // Public declarations
     constructor    Create(Dispatch: IDispatch);
     constructor    CreateWrapper(EnumVariant: IEnumVariant);
     destructor     Destroy; override;
  end;

function   GetOSFolderName: String;
function   GetConnections(List: TStrings): Integer;

implementation

function GetConnections(List: TStrings): Integer;
var  oShellApp:     OleVariant;
     oFolder:       OleVariant;
     pvItems:       IEnumerator;
     pvConnections: IEnumerator;
     szFolder:      String;
begin

  // Check list
  if not(Assigned(List)) then
     // No list
     result:=(-1)
  else
  begin
     // Lock the list
     List.BeginUpdate;
     // Resource protection
     try
        // Clear the list
        List.Clear;
        // Create shell object
        oShellApp:=CreateOleObject('Shell.Application');
        // Resource protection
        try
           // Get desired folder name
           szFolder:=GetOSFolderName;
           // Get enumerator for the control panel folder
           pvItems:=TEnumerator.Create(oShellApp.NameSpace(3).Items);
           // Resource protection
           try
              // Iterate the items
              while pvItems.ForEach(oFolder) do
              begin
                 // Debugging
                 MessageBox(0, PChar(String(oFolder.Name)), nil, MB_OK);
                 // Check folder name against desired folder name
                 if (CompareText(oFolder.Name, szFolder) = 0) then
                 begin
                    // Get the network folder items
                    pvConnections:=TEnumerator.Create(oFolder.GetFolder.Items);
                    // Resource protection
                    try
                       // Iterate the connections
                       while pvConnections.ForEach(oFolder) do
                       begin
                          // Add name to list
                          List.Add(oFolder.Name);
                       end;
                    finally
                       // Release the interface
                       pvConnections:=nil;
                    end;
                    // Done processing
                    break;
                 end;
              end;
           finally
              // Release the interface
              pvItems:=nil;
           end;
        finally
           // Clear variant
           oShellApp:=Unassigned;
        end;
     finally
        // Unlock list
        List.EndUpdate;
     end;
     // Return the count of items
     result:=List.Count;
  end;

end;

function GetOSFolderName: String;
var  lpVer:         TOSVersionInfo;
begin

  // Set default result
  SetLength(result, 0);

  // Set size
  lpVer.dwOSVersionInfoSize:=SizeOf(lpVer);

  // Get OS version
  if GetVersionEx(lpVer) then
  begin
     // Check major and minor
     if (lpVer.dwMajorVersion = 5) then
     begin
        // Check minor version
        if (lpVer.dwMinorVersion = 0) then
           // Win 2000
           result:='Network and Dial-up Connections'
        else
           // Win XP or up
           result:='Network Connections';
     end;
  end;

end;

//// TEnumerator ///////////////////////////////////////////////////////////////
procedure TEnumerator.GetEnumVariant(Dispatch: IDispatch);
var  pdParams:      TDispParams;
     ovEnum:        OleVariant;
begin

  // Check interface
  if Assigned(Dispatch) then
  begin
     // Clear disp params
     FillChar(pdParams, SizeOf(TDispParams), 0);
     // Get enumerator
     OleCheck(Dispatch.Invoke(DISPID_NEWENUM, GUID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET or DISPATCH_METHOD, pdParams, @ovEnum, nil, nil));
     // Resource protection
     try
        // Check returned interface
        if (TVariantArg(ovEnum).vt = VT_UNKNOWN) then
           // Query interface for the IEnumVariant
           OleCheck(IUnknown(ovEnum).QueryInterface(IEnumVariant, FEnumVariant))
        else
           // Throw error
           OleError(E_NOINTERFACE);
     finally
        // Clear interface
        ovEnum:=Unassigned;
     end;
  end
  else
     // Throw error
     OleError(E_NOINTERFACE);

end;

function TEnumerator.ForEach(out Obj: OleVariant): Boolean;
var  dwFetch:       Cardinal;
begin

  // Get the next item
  result:=(FEnumVariant.Next(1, Obj, dwFetch) = S_OK) and (dwFetch = 1);

end;

function TEnumerator.ForEachObject(const IID: TGUID; out Obj): Boolean;
var  ovItem:        OleVariant;
begin

  // Get next item as OleVariant
  if ForEach(ovItem) then
  begin
     // Resource protection
     try
        // Check interface for IUknown
        if (TVariantArg(ovItem).vt = VT_UNKNOWN) then
           // Query interface for the desired interface
           result:=(IUnknown(ovItem).QueryInterface(IID, Obj) = S_OK)
        // Check interface for IDispatch
        else if (TVariantArg(ovItem).vt = VT_DISPATCH) then
           // Query interface for the desired interface
           result:=(IDispatch(ovItem).QueryInterface(IID, Obj) = S_OK)
        else
        begin
           // Pacify the compiler
           result:=False;
           // Throw error
           OleError(E_NOINTERFACE);
        end;
     finally
        // Clear obtained item
        ovItem:=Unassigned;
     end;
  end
  else
     // Failed to get item
     result:=False;

end;

function TEnumerator.Reset: Boolean;
begin

  // Reset enumerator
  result:=(FEnumVariant.Reset = S_OK);

end;

function TEnumerator.Skip(Count: LongWord): Boolean;
begin

  // Skip items in enumerator
  result:=(FEnumVariant.Skip(Count) = S_OK);

end;

function TEnumerator.Clone: IEnumerator;
var  pvEnum:        IEnumVariant;
begin

  // Clone
  if (FEnumVariant.Clone(pvEnum) = S_OK) then
  begin
     // Resource protection
     try
        // Return wrapper
        result:=TEnumerator.CreateWrapper(pvEnum);
     finally
        // Release interface
        pvEnum:=nil;
     end
  end
  else
     // Return nil
     result:=nil;

end;

constructor TEnumerator.CreateWrapper(EnumVariant: IEnumVariant);
begin

  // Perform inherited
  inherited Create;

  // Check interface pointer
  if Assigned(EnumVariant) then
     // Bind to the passed interface
     FEnumVariant:=EnumVariant
  else
     // Throw error
     OleError(E_NOINTERFACE);

end;

constructor TEnumerator.Create(Dispatch: IDispatch);
begin

  // Perform inherited
  inherited Create;

  // Get enumerator interface
  GetEnumVariant(Dispatch);

end;

destructor TEnumerator.Destroy;
begin

  // Resource protection
  try
     // Release the interface
     FEnumVariant:=nil;
  finally
     // Perform inherited
     inherited Destroy;
  end;

end;

end.
0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
I get an error box three times, first has printer and the second something else and the third network connections and then the list box populates with all three network adapters. All 2K PCs have SP 4.

Clicking through the error messages gets me the info. Does the same on XP. I didn't see where any messagesboxes were written into the code, but I didn't look hard!
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
So, just to clarify, this is loading the list of connections for Win2k boxes? And yes, there is a MessagBox call to display each enumerated item until the network is found.

If this is correct, then this method can be followed to what will hopefully be a solution for 2K and XP systems.

Russell
0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
Yes. It is showing up for the Win 2K boxes...

It, the 2K boxes, have three NICS and each is listed!

It showed up in a prior test as well.


John

0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
Example usage:

procedure TForm1.Button1Click(Sender: TObject);
var  dwIndex:          Integer;
begin

  GetNetworkNames(ListBox1.Items);
  for dwIndex:=0 to Pred(ListBox1.Items.Count) do
     NetworkDisable(ListBox1.Items[dwIndex]);

end;

procedure TForm1.Button2Click(Sender: TObject);
var  dwIndex:          Integer;
begin

  GetNetworkNames(ListBox1.Items);
  for dwIndex:=0 to Pred(ListBox1.Items.Count) do
     NetworkEnable(ListBox1.Items[dwIndex]);

end;

-- dfm --
object Form1: TForm1
  Left = 251
  Top = 166
  Width = 386
  Height = 319
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object ListBox1: TListBox
    Left = 140
    Top = 28
    Width = 185
    Height = 225
    ItemHeight = 13
    TabOrder = 0
  end
  object Button1: TButton
    Left = 32
    Top = 32
    Width = 75
    Height = 25
    Caption = 'Disable'
    TabOrder = 1
    OnClick = Button1Click
  end
  object Button2: TButton
    Left = 32
    Top = 68
    Width = 75
    Height = 25
    Caption = 'Enable'
    TabOrder = 2
    OnClick = Button2Click
  end
end

-- Source --
unit NetConnections;
////////////////////////////////////////////////////////////////////////////////
//
//   Unit        :  NetConnections
//   Author      :  rllibby
//   Date        :  06.16.2007
//   Description :  OLE scripting based mechanism for enabling / disabling the
//                  network connections on a PC.
//
////////////////////////////////////////////////////////////////////////////////
interface

////////////////////////////////////////////////////////////////////////////////
//   Include units
////////////////////////////////////////////////////////////////////////////////
uses
  Windows, SysUtils, Classes, Forms, ComObj, ActiveX, ComUtils;

////////////////////////////////////////////////////////////////////////////////
//   Constants
////////////////////////////////////////////////////////////////////////////////
const
  SHELL_APPLICATION =  'Shell.Application';
  NETWORK_2K        =  'Network and Dial-up Connections';
  NETWORK_XP        =  'Network Connections';
  VERB_ENABLE1      =  'En&able';
  VERB_ENABLE2      =  'Enable';
  VERB_DISABLE1     =  'Disa&ble';
  VERB_DISABLE2     =  'Disable';

////////////////////////////////////////////////////////////////////////////////
//   IEnumVariant interface and implementation
////////////////////////////////////////////////////////////////////////////////
type
  IEnumerator       =  interface
     function       ForEach(out Obj: OleVariant): Boolean;
     function       ForEachObject(const IID: TGUID; out Obj): Boolean;
     function       Reset: Boolean;
     function       Skip(Count: LongWord): Boolean;
     function       Clone: IEnumerator;
  end;

  TEnumerator       =  class(TInterfacedObject, IEnumerator)
  private
     // Private declarations
     FEnumVariant:  IEnumVariant;
     procedure      GetEnumVariant(Dispatch: IDispatch);
  protected
     // Protected declarations
     function       ForEach(out Obj: OleVariant): Boolean;
     function       ForEachObject(const IID: TGUID; out Obj): Boolean;
     function       Reset: Boolean;
     function       Skip(Count: LongWord): Boolean;
     function       Clone: IEnumerator;
  public
     // Public declarations
     constructor    Create(Dispatch: IDispatch);
     constructor    CreateWrapper(EnumVariant: IEnumVariant);
     destructor     Destroy; override;
  end;

////////////////////////////////////////////////////////////////////////////////
//   Utility functions
////////////////////////////////////////////////////////////////////////////////
function   NetworkDisable(Name: String): Boolean;
function   NetworkEnable(Name: String): Boolean;
function   GetNetworkNames(List: TStrings): Integer;
function   GetNetworkFolderItems(out Enumerator: IEnumerator): HResult;
function   IsWin2000: Boolean;

implementation

function NetworkDisable(Name: String): Boolean;
var  pvConnections: IEnumerator;
     pvVerbs:       IEnumerator;
     oItem:         OleVariant;
     oVerb:         OleVariant;
begin

  // Set default result
  result:=False;

  // Get the network folder items
  OleCheck(GetNetworkFolderItems(pvConnections));

  // Resuorce protection
  try
     // Iterate the items to find the match
     while pvConnections.ForEach(oItem) do
     begin
        // Check name
        if (CompareText(oItem.Name, Name) = 0) then
        begin
           // Found the item, get the verbs
           pvVerbs:=TEnumerator.Create(oItem.Verbs);
           // Resource protection
           try
              // Iterate the vebs
              while pvVerbs.ForEach(oVerb) do
              begin
                 // Resource protection
                 try
                    // Check verb name
                    if (CompareText(oVerb.Name, VERB_DISABLE1) = 0) or (CompareText(oVerb.Name, VERB_DISABLE2) = 0) then
                    begin
                       // Found the enable verb, fire it
                       oVerb.DoIt;
                       // Success
                       result:=True;
                       // Wait
                       Sleep(1000);
                       // Done processing
                       break;
                    end;
                 finally
                    // Clear the variant
                    oVerb:=Unassigned;
                 end;
              end;
           finally
              // Release the interface
              pvVerbs:=nil;
           end;
        end;
     end;
  finally
     // Release the interface
     pvConnections:=nil;
  end;

end;

function NetworkEnable(Name: String): Boolean;
var  pvConnections: IEnumerator;
     pvVerbs:       IEnumerator;
     oItem:         OleVariant;
     oVerb:         OleVariant;
begin

  // Set default result
  result:=False;

  // Get the network folder items
  OleCheck(GetNetworkFolderItems(pvConnections));

  // Resuorce protection
  try
     // Iterate the items to find the match
     while pvConnections.ForEach(oItem) do
     begin
        // Check name
        if (CompareText(oItem.Name, Name) = 0) then
        begin
           // Found the item, get the verbs
           pvVerbs:=TEnumerator.Create(oItem.Verbs);
           // Resource protection
           try
              // Iterate the vebs
              while pvVerbs.ForEach(oVerb) do
              begin
                 // Resource protection
                 try
                    // Check verb name
                    if (CompareText(oVerb.Name, VERB_ENABLE1) = 0) or (CompareText(oVerb.Name, VERB_ENABLE2) = 0) then
                    begin
                       // Found the enable verb, fire it
                       oVerb.DoIt;
                       // Success
                       result:=True;
                       // Wait
                       Sleep(1000);
                       // Done processing
                       break;
                    end;
                 finally
                    // Clear the variant
                    oVerb:=Unassigned;
                 end;
              end;
           finally
              // Release the interface
              pvVerbs:=nil;
           end;
        end;
     end;
  finally
     // Release the interface
     pvConnections:=nil;
  end;

end;

function GetNetworkNames(List: TStrings): Integer;
var  pvConnections: IEnumerator;
     oItem:         OleVariant;
begin

  // Get the network folder items
  OleCheck(GetNetworkFolderItems(pvConnections));

  // Resuorce protection
  try
     // Lock list
     List.BeginUpdate;
     // Rsource protection
     try
        // Clear the list
        List.Clear;
        // Add the items to the list
        while pvConnections.ForEach(oItem) do
        begin
           // Resource protection
           try
              // Add item name
              List.Add(oItem.Name);
           finally
              // Clear the variant
              oItem:=Unassigned;
           end;
        end;
     finally
        // Unlock the list
        List.EndUpdate;
     end;
  finally
     // Release the interface
     pvConnections:=nil;
     // Return list count
     result:=List.Count;
  end;

end;

function GetNetworkFolderItems(out Enumerator: IEnumerator): HResult;
var  pvItems:       IEnumerator;
     oShellApp:     OleVariant;
     oFolder:       OleVariant;
     szFolder:      String;
begin

  // Clear out bound interface
  Enumerator:=nil;

  // Resource protection
  try
     // Create shell object
     oShellApp:=CreateOleObject('Shell.Application');
     // Resource protection
     try
        // Get desired folder name
        if IsWin2000 then
           szFolder:=NETWORK_2K
        else
           szFolder:=NETWORK_XP;
        // Get enumerator for the control panel folder
        pvItems:=TEnumerator.Create(oShellApp.NameSpace(3).Items);
        // Resource protection
        try
           // Iterate the items
           while pvItems.ForEach(oFolder) do
           begin
              // Resource protection
              try
                 // Check folder name against desired folder name
                 if (CompareText(oFolder.Name, szFolder) = 0) then
                 begin
                    // Found the network folder, get items collection
                    Enumerator:=TEnumerator.Create(oFolder.GetFolder.Items);
                    // Done processing
                    break;
                 end;
              finally
                 // Clear variant
                 oFolder:=Unassigned;
              end;
           end;
        finally
           // Release the interface
           pvItems:=nil;
        end;
     finally
        // Clear variant
        oShellApp:=Unassigned;
     end;
  finally
     // Success if we have the interface
     if Assigned(Enumerator) then
        // Success
        result:=S_OK
     else
        // No interface
        result:=E_NOINTERFACE;
  end;

end;

//// Utility functions /////////////////////////////////////////////////////////
function IsWin2000: Boolean;
var  lpVer:         TOSVersionInfo;
begin

  // Set size
  lpVer.dwOSVersionInfoSize:=SizeOf(lpVer);

  // Get OS version
  if GetVersionEx(lpVer) then
     // Check major and minor
     result:=(lpVer.dwMajorVersion = 5) and (lpVer.dwMinorVersion = 0)
  else
     // Failed, who knows...
     result:=False;

end;

//// TEnumerator ///////////////////////////////////////////////////////////////
procedure TEnumerator.GetEnumVariant(Dispatch: IDispatch);
var  pdParams:      TDispParams;
     ovEnum:        OleVariant;
begin

  // Check interface
  if Assigned(Dispatch) then
  begin
     // Clear disp params
     FillChar(pdParams, SizeOf(TDispParams), 0);
     // Get enumerator
     OleCheck(Dispatch.Invoke(DISPID_NEWENUM, GUID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET or DISPATCH_METHOD, pdParams, @ovEnum, nil, nil));
     // Resource protection
     try
        // Check returned interface
        if (TVariantArg(ovEnum).vt = VT_UNKNOWN) then
           // Query interface for the IEnumVariant
           OleCheck(IUnknown(ovEnum).QueryInterface(IEnumVariant, FEnumVariant))
        else
           // Throw error
           OleError(E_NOINTERFACE);
     finally
        // Clear interface
        ovEnum:=Unassigned;
     end;
  end
  else
     // Throw error
     OleError(E_NOINTERFACE);

end;

function TEnumerator.ForEach(out Obj: OleVariant): Boolean;
var  dwFetch:       Cardinal;
begin

  // Get the next item
  result:=(FEnumVariant.Next(1, Obj, dwFetch) = S_OK) and (dwFetch = 1);

end;

function TEnumerator.ForEachObject(const IID: TGUID; out Obj): Boolean;
var  ovItem:        OleVariant;
begin

  // Get next item as OleVariant
  if ForEach(ovItem) then
  begin
     // Resource protection
     try
        // Check interface for IUknown
        if (TVariantArg(ovItem).vt = VT_UNKNOWN) then
           // Query interface for the desired interface
           result:=(IUnknown(ovItem).QueryInterface(IID, Obj) = S_OK)
        // Check interface for IDispatch
        else if (TVariantArg(ovItem).vt = VT_DISPATCH) then
           // Query interface for the desired interface
           result:=(IDispatch(ovItem).QueryInterface(IID, Obj) = S_OK)
        else
        begin
           // Pacify the compiler
           result:=False;
           // Throw error
           OleError(E_NOINTERFACE);
        end;
     finally
        // Clear obtained item
        ovItem:=Unassigned;
     end;
  end
  else
     // Failed to get item
     result:=False;

end;

function TEnumerator.Reset: Boolean;
begin

  // Reset enumerator
  result:=(FEnumVariant.Reset = S_OK);

end;

function TEnumerator.Skip(Count: LongWord): Boolean;
begin

  // Skip items in enumerator
  result:=(FEnumVariant.Skip(Count) = S_OK);

end;

function TEnumerator.Clone: IEnumerator;
var  pvEnum:        IEnumVariant;
begin

  // Clone
  if (FEnumVariant.Clone(pvEnum) = S_OK) then
  begin
     // Resource protection
     try
        // Return wrapper
        result:=TEnumerator.CreateWrapper(pvEnum);
     finally
        // Release interface
        pvEnum:=nil;
     end
  end
  else
     // Return nil
     result:=nil;

end;

constructor TEnumerator.CreateWrapper(EnumVariant: IEnumVariant);
begin

  // Perform inherited
  inherited Create;

  // Check interface pointer
  if Assigned(EnumVariant) then
     // Bind to the passed interface
     FEnumVariant:=EnumVariant
  else
     // Throw error
     OleError(E_NOINTERFACE);

end;

constructor TEnumerator.Create(Dispatch: IDispatch);
begin

  // Perform inherited
  inherited Create;

  // Get enumerator interface
  GetEnumVariant(Dispatch);

end;

destructor TEnumerator.Destroy;
begin

  // Resource protection
  try
     // Release the interface
     FEnumVariant:=nil;
  finally
     // Perform inherited
     inherited Destroy;
  end;

end;

end.




0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
Russell,

ComUtils.pas is a unit you wrote some time ago, correct?

John
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
Oops, yep. You don't need it in the includes though, as I ripped the enumerator stuff from it already.

Russell

0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
ALL RIGHT!!!!!

It werks! In XP and 2K! However...

It tries to enable the card(s) multiple times. In XP it was once (had two nics) and in 2000 it was three times (had 3 nics) after you do a NetworkEnable.

John!
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
Cool, glad it works in both cases. Also, you can individually enable/disable the desired card as well (the demo code was just that... demo code). Its going to be up to you to determine which connection you wish to disable then re-enable.

Russell
0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
Ya know... one can overlook the most obvious stuff. And several times.

Man, I was stepping through your code starting from the middle working my way out and it dawned on me...

It was my button code causing it to loop and try to enable it again causing windows to let me know that it was already enabling the connection!

Oh Me!

Thanks Russell. It works great!!!!!!!

John
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
No problem John.
Glad we were able to finally kick out some code that worked on both OS's. It does make me curious as to what the Shell COM interfaces are doing internally though, as my original code using IShellFolder should have been doing the same thing (but at the lowest level of interfaces). Moot point, as you have a solution that works.

Russell
0
 
LVL 18

Author Comment

by:Johnjces
Comment Utility
Well, me too!

I have learned a BUNCH and will dig deeper as time permits...

Thanks again.

John
0
 
LVL 14

Expert Comment

by:systan
Comment Utility
rllibby;
is the Best guy for Delphi networking
0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now