You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1068 lines
30 KiB
1068 lines
30 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1997.
|
|
//
|
|
// File: S N E T C F G . C P P
|
|
//
|
|
// Contents: Sample code that demonstrates how to:
|
|
// - find out if a component is installed
|
|
// - install a net component
|
|
// - install an OEM net component
|
|
// - uninstall a net component
|
|
// - enumerate net components
|
|
// - enumerate net adapters using Setup API
|
|
// - enumerate binding paths of a component
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "pch.h"
|
|
#pragma hdrstop
|
|
#include "snetcfg.h"
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Globals
|
|
//
|
|
static const GUID* c_aguidClass[] =
|
|
{
|
|
&GUID_DEVCLASS_NET,
|
|
&GUID_DEVCLASS_NETTRANS,
|
|
&GUID_DEVCLASS_NETSERVICE,
|
|
&GUID_DEVCLASS_NETCLIENT
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Prototypes of helper functions
|
|
//
|
|
HRESULT HrInstallNetComponent(IN INetCfg* pnc, IN PCWSTR szComponentId,
|
|
IN const GUID* pguidClass);
|
|
HRESULT HrUninstallNetComponent(IN INetCfg* pnc, IN PCWSTR szComponentId);
|
|
HRESULT HrGetINetCfg(IN BOOL fGetWriteLock, INetCfg** ppnc);
|
|
HRESULT HrReleaseINetCfg(BOOL fHasWriteLock, INetCfg* pnc);
|
|
void ShowMessage(IN PCWSTR szMsg, ...);
|
|
void ShowHrMessage(IN HRESULT hr);
|
|
inline ULONG ReleaseObj(IUnknown* punk)
|
|
{
|
|
return (punk) ? punk->Release () : 0;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HrIsComponentInstalled
|
|
//
|
|
// Purpose: Find out if a component is installed
|
|
//
|
|
// Arguments:
|
|
// szComponentId [in] id of component to search
|
|
//
|
|
// Returns: S_OK if installed,
|
|
// S_FALSE if not installed,
|
|
// otherwise an error code
|
|
//
|
|
// Author: kumarp 11-February-99
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT HrIsComponentInstalled(IN PCWSTR szComponentId)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
INetCfg* pnc;
|
|
INetCfgComponent* pncc;
|
|
|
|
hr = HrGetINetCfg(FALSE, &pnc);
|
|
if (S_OK == hr)
|
|
{
|
|
hr = pnc->FindComponent(szComponentId, &pncc);
|
|
if (S_OK == hr)
|
|
{
|
|
ReleaseObj(pncc);
|
|
}
|
|
(void) HrReleaseINetCfg(FALSE, pnc);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: FindIfComponentInstalled
|
|
//
|
|
// Purpose: Find out if a component is installed
|
|
//
|
|
// Arguments:
|
|
// szComponentId [in] id of component to locate
|
|
//
|
|
// Returns: None
|
|
//
|
|
// Author: kumarp 11-February-99
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT FindIfComponentInstalled(IN PCWSTR szComponentId)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
|
|
hr = HrIsComponentInstalled(szComponentId);
|
|
if (S_OK == hr)
|
|
{
|
|
_tprintf(L"'%s' is installed\n", szComponentId);
|
|
}
|
|
else if (S_FALSE == hr)
|
|
{
|
|
_tprintf(L"'%s' is not installed\n", szComponentId);
|
|
}
|
|
else
|
|
{
|
|
_tprintf(L"Could not find if '%s' is installed. error code: 0x%x\n",
|
|
szComponentId, hr);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HrInstallNetComponent
|
|
//
|
|
// Purpose: Install the specified net component
|
|
//
|
|
// Arguments:
|
|
// szComponentId [in] component to install
|
|
// nc [in] class of the component
|
|
// szInfFullPath [in] full path to primary INF file
|
|
// required if the primary INF and other
|
|
// associated files are not pre-copied to
|
|
// the right destination dirs.
|
|
// Not required when installing MS components
|
|
// since the files are pre-copied by
|
|
// Windows NT Setup.
|
|
//
|
|
// Returns: S_OK or NETCFG_S_REBOOT on success, otherwise an error code
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT HrInstallNetComponent(IN PCWSTR szComponentId,
|
|
IN enum NetClass nc,
|
|
IN PCWSTR szInfFullPath)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
INetCfg* pnc;
|
|
|
|
// cannot install net adapters this way. they have to be
|
|
// enumerated/detected and installed by PnP
|
|
|
|
if ((nc == NC_NetProtocol) ||
|
|
(nc == NC_NetService) ||
|
|
(nc == NC_NetClient))
|
|
{
|
|
ShowMessage(L"Trying to install '%s'...", szComponentId);
|
|
|
|
// if full path to INF has been specified, the INF
|
|
// needs to be copied using Setup API to ensure that any other files
|
|
// that the primary INF copies will be correctly found by Setup API
|
|
//
|
|
if (szInfFullPath && wcslen(szInfFullPath))
|
|
{
|
|
WCHAR szInfNameAfterCopy[MAX_PATH+1];
|
|
if (SetupCopyOEMInf(
|
|
szInfFullPath,
|
|
NULL, // other files are in the
|
|
// same dir. as primary INF
|
|
SPOST_PATH, // first param. contains path to INF
|
|
0, // default copy style
|
|
szInfNameAfterCopy, // receives the name of the INF
|
|
// after it is copied to %windir%\inf
|
|
MAX_PATH, // max buf. size for the above
|
|
NULL, // receives required size if non-null
|
|
NULL)) // optionally retrieves filename
|
|
// component of szInfNameAfterCopy
|
|
{
|
|
ShowMessage(L"...%s was copied to %s",
|
|
szInfFullPath,
|
|
szInfNameAfterCopy);
|
|
}
|
|
else
|
|
{
|
|
DWORD dwError = GetLastError();
|
|
hr = HRESULT_FROM_WIN32(dwError);
|
|
}
|
|
}
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
// get INetCfg interface
|
|
hr = HrGetINetCfg(TRUE, &pnc);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// install szComponentId
|
|
hr = HrInstallNetComponent(pnc, szComponentId,
|
|
c_aguidClass[nc]);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Apply the changes
|
|
hr = pnc->Apply();
|
|
}
|
|
|
|
// release INetCfg
|
|
(void) HrReleaseINetCfg(TRUE, pnc);
|
|
}
|
|
}
|
|
// show success/failure message
|
|
ShowHrMessage(hr);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HrInstallNetComponent
|
|
//
|
|
// Purpose: Install the specified net component
|
|
//
|
|
// Arguments:
|
|
// pnc [in] pointer to INetCfg object
|
|
// szComponentId [in] component to install
|
|
// pguidClass [in] class guid of the component
|
|
//
|
|
// Returns: S_OK or NETCFG_S_REBOOT on success, otherwise an error code
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT HrInstallNetComponent(IN INetCfg* pnc,
|
|
IN PCWSTR szComponentId,
|
|
IN const GUID* pguidClass)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
OBO_TOKEN OboToken;
|
|
INetCfgClassSetup* pncClassSetup;
|
|
INetCfgComponent* pncc;
|
|
|
|
// OBO_TOKEN specifies the entity on whose behalf this
|
|
// component is being installed
|
|
|
|
// set it to OBO_USER so that szComponentId will be installed
|
|
// On-Behalf-Of "user"
|
|
ZeroMemory (&OboToken, sizeof(OboToken));
|
|
OboToken.Type = OBO_USER;
|
|
|
|
hr = pnc->QueryNetCfgClass (pguidClass, IID_INetCfgClassSetup,
|
|
(void**)&pncClassSetup);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pncClassSetup->Install(szComponentId,
|
|
&OboToken,
|
|
NSF_POSTSYSINSTALL,
|
|
0, // <upgrade-from-build-num>
|
|
NULL, // answerfile name
|
|
NULL, // answerfile section name
|
|
&pncc);
|
|
if (S_OK == hr)
|
|
{
|
|
// we dont want to use pncc (INetCfgComponent), release it
|
|
ReleaseObj(pncc);
|
|
}
|
|
|
|
ReleaseObj(pncClassSetup);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HrUninstallNetComponent
|
|
//
|
|
// Purpose: Initialize INetCfg and uninstall a component
|
|
//
|
|
// Arguments:
|
|
// szComponentId [in] InfId of component to uninstall (e.g. MS_TCPIP)
|
|
//
|
|
// Returns: S_OK or NETCFG_S_REBOOT on success, otherwise an error code
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT HrUninstallNetComponent(IN PCWSTR szComponentId)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
INetCfg* pnc;
|
|
|
|
ShowMessage(L"Trying to uninstall '%s'...", szComponentId);
|
|
|
|
// get INetCfg interface
|
|
hr = HrGetINetCfg(TRUE, &pnc);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// uninstall szComponentId
|
|
hr = HrUninstallNetComponent(pnc, szComponentId);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
// Apply the changes
|
|
hr = pnc->Apply();
|
|
}
|
|
else if (S_FALSE == hr)
|
|
{
|
|
ShowMessage(L"...'%s' is not installed", szComponentId);
|
|
}
|
|
|
|
// release INetCfg
|
|
(void) HrReleaseINetCfg(TRUE, pnc);
|
|
}
|
|
|
|
// show success/failure message
|
|
ShowHrMessage(hr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HrUninstallNetComponent
|
|
//
|
|
// Purpose: Uninstall the specified component.
|
|
//
|
|
// Arguments:
|
|
// pnc [in] pointer to INetCfg object
|
|
// szComponentId [in] component to uninstall
|
|
//
|
|
// Returns: S_OK or NETCFG_S_REBOOT on success, otherwise an error code
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT HrUninstallNetComponent(IN INetCfg* pnc, IN PCWSTR szComponentId)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
OBO_TOKEN OboToken;
|
|
INetCfgComponent* pncc;
|
|
GUID guidClass;
|
|
INetCfgClass* pncClass;
|
|
INetCfgClassSetup* pncClassSetup;
|
|
|
|
// OBO_TOKEN specifies the entity on whose behalf this
|
|
// component is being uninstalld
|
|
|
|
// set it to OBO_USER so that szComponentId will be uninstalld
|
|
// On-Behalf-Of "user"
|
|
ZeroMemory (&OboToken, sizeof(OboToken));
|
|
OboToken.Type = OBO_USER;
|
|
|
|
// see if the component is really installed
|
|
hr = pnc->FindComponent(szComponentId, &pncc);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
// yes, it is installed. obtain INetCfgClassSetup and DeInstall
|
|
|
|
hr = pncc->GetClassGuid(&guidClass);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
hr = pnc->QueryNetCfgClass(&guidClass, IID_INetCfgClass,
|
|
(void**)&pncClass);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pncClass->QueryInterface(IID_INetCfgClassSetup,
|
|
(void**)&pncClassSetup);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pncClassSetup->DeInstall (pncc, &OboToken, NULL);
|
|
|
|
ReleaseObj (pncClassSetup);
|
|
}
|
|
ReleaseObj(pncClass);
|
|
}
|
|
}
|
|
ReleaseObj(pncc);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HrShowNetAdapters
|
|
//
|
|
// Purpose: Display all installed net class devices using Setup API
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: S_OK on success, otherwise an error code
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT HrShowNetAdapters()
|
|
{
|
|
#define MAX_COMP_INSTID 4096
|
|
#define MAX_COMP_DESC 4096
|
|
|
|
HRESULT hr=S_OK;
|
|
HDEVINFO hdi;
|
|
DWORD dwIndex=0;
|
|
SP_DEVINFO_DATA deid;
|
|
BOOL fSuccess=FALSE;
|
|
DWORD cchRequiredSize;
|
|
WCHAR szCompInstanceId[MAX_COMP_INSTID];
|
|
WCHAR szCompDescription[MAX_COMP_DESC];
|
|
DWORD dwRegType;
|
|
BOOL fFound=FALSE;
|
|
|
|
// get a list of all devices of class 'GUID_DEVCLASS_NET'
|
|
hdi = SetupDiGetClassDevs(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT);
|
|
|
|
if (INVALID_HANDLE_VALUE != hdi)
|
|
{
|
|
// enumerate over each device
|
|
while (deid.cbSize = sizeof(SP_DEVINFO_DATA),
|
|
SetupDiEnumDeviceInfo(hdi, dwIndex, &deid))
|
|
{
|
|
dwIndex++;
|
|
|
|
// the right thing to do here would be to call this function
|
|
// to get the size required to hold the instance ID and then
|
|
// to call it second time with a buffer large enough for that size.
|
|
// However, that would tend to obscure the control flow in
|
|
// the sample code. Lets keep things simple by keeping the
|
|
// buffer large enough.
|
|
|
|
// get the device instance ID
|
|
fSuccess = SetupDiGetDeviceInstanceId(hdi, &deid,
|
|
szCompInstanceId,
|
|
MAX_COMP_INSTID, NULL);
|
|
if (fSuccess)
|
|
{
|
|
// get the description for this instance
|
|
fSuccess =
|
|
SetupDiGetDeviceRegistryProperty(hdi, &deid,
|
|
SPDRP_DEVICEDESC,
|
|
&dwRegType,
|
|
(BYTE*) szCompDescription,
|
|
MAX_COMP_DESC,
|
|
NULL);
|
|
if (fSuccess)
|
|
{
|
|
if (!fFound)
|
|
{
|
|
fFound = TRUE;
|
|
_tprintf(L"Instance ID\tDescription\n");
|
|
_tprintf(L"-----------\t-----------\n");
|
|
}
|
|
_tprintf(L"%s\t%s\n",
|
|
szCompInstanceId, szCompDescription);
|
|
}
|
|
}
|
|
}
|
|
|
|
// release the device info list
|
|
SetupDiDestroyDeviceInfoList(hdi);
|
|
}
|
|
|
|
if (!fSuccess)
|
|
{
|
|
DWORD dwError = GetLastError();
|
|
hr = HRESULT_FROM_WIN32(dwError);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HrShowNetComponents
|
|
//
|
|
// Purpose: Display the list of installed components of the
|
|
// specified class.
|
|
//
|
|
// Arguments:
|
|
// pnc [in] pointer to INetCfg object
|
|
// pguidClass [in] pointer to class GUID
|
|
//
|
|
// Returns: S_OK on success, otherwise an error code
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT HrShowNetComponents(IN INetCfg* pnc,
|
|
IN const GUID* pguidClass)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
PWSTR szInfId;
|
|
PWSTR szDisplayName;
|
|
DWORD dwcc;
|
|
INetCfgComponent* pncc;
|
|
INetCfgClass* pncclass;
|
|
IEnumNetCfgComponent* pencc;
|
|
ULONG celtFetched;
|
|
|
|
hr = pnc->QueryNetCfgClass(pguidClass, IID_INetCfgClass,
|
|
(void**)&pncclass);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// get IEnumNetCfgComponent so that we can enumerate
|
|
hr = pncclass->EnumComponents(&pencc);
|
|
|
|
ReleaseObj(pncclass);
|
|
|
|
while (SUCCEEDED(hr) &&
|
|
(S_OK == (hr = pencc->Next(1, &pncc, &celtFetched))))
|
|
{
|
|
if (pguidClass == &GUID_DEVCLASS_NET)
|
|
{
|
|
// we are interested only in physical netcards
|
|
//
|
|
hr = pncc->GetCharacteristics(&dwcc);
|
|
|
|
if (FAILED(hr) || !(dwcc & NCF_PHYSICAL))
|
|
{
|
|
hr = S_OK;
|
|
ReleaseObj(pncc);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
hr = pncc->GetId(&szInfId);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
hr = pncc->GetDisplayName(&szDisplayName);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
_tprintf(L"%-26s %s\n", szInfId, szDisplayName);
|
|
|
|
CoTaskMemFree(szDisplayName);
|
|
}
|
|
CoTaskMemFree(szInfId);
|
|
}
|
|
// we dont want to stop enumeration just because 1 component
|
|
// failed either GetId or GetDisplayName, therefore reset hr to S_OK
|
|
hr = S_OK;
|
|
|
|
ReleaseObj(pncc);
|
|
}
|
|
ReleaseObj(pencc);
|
|
}
|
|
|
|
|
|
if (S_FALSE == hr)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HrShowNetComponents
|
|
//
|
|
// Purpose: Display installed net components.
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: S_OK on success, otherwise an error code
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT HrShowNetComponents()
|
|
{
|
|
HRESULT hr=S_OK;
|
|
PCWSTR szClassName;
|
|
|
|
static const PCWSTR c_aszClassNames[] =
|
|
{
|
|
L"Network Adapters",
|
|
L"Network Protocols",
|
|
L"Network Services",
|
|
L"Network Clients"
|
|
};
|
|
|
|
INetCfg* pnc;
|
|
|
|
// get INetCfg interface
|
|
hr = HrGetINetCfg(FALSE, &pnc);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
for (int i=0; i<4; i++)
|
|
{
|
|
_tprintf(L"\n%s\n-----------------\n", c_aszClassNames[i]);
|
|
|
|
(void) HrShowNetComponents(pnc, c_aguidClass[i]);
|
|
}
|
|
|
|
// release INetCfg
|
|
hr = HrReleaseINetCfg(FALSE, pnc);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HrGetNextBindingInterface
|
|
//
|
|
// Purpose: Enumerate over binding interfaces that constitute
|
|
// the given binding path
|
|
//
|
|
// Arguments:
|
|
// pncbp [in] pointer to INetCfgBindingPath object
|
|
// ppncbi [out] pointer to pointer to INetCfgBindingInterface object
|
|
//
|
|
// Returns: S_OK on success, otherwise an error code
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT HrGetNextBindingInterface(IN INetCfgBindingPath* pncbp,
|
|
OUT INetCfgBindingInterface** ppncbi)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
INetCfgBindingInterface* pncbi=NULL;
|
|
|
|
static IEnumNetCfgBindingInterface* pencbi=NULL;
|
|
|
|
*ppncbi = NULL;
|
|
|
|
// if this is the first call in the enumeration, obtain
|
|
// the IEnumNetCfgBindingInterface interface
|
|
//
|
|
if (!pencbi)
|
|
{
|
|
hr = pncbp->EnumBindingInterfaces(&pencbi);
|
|
}
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
ULONG celtFetched;
|
|
|
|
// get next binding interface
|
|
hr = pencbi->Next(1, &pncbi, &celtFetched);
|
|
}
|
|
|
|
// on the last call (hr == S_FALSE) or on error, release resources
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
*ppncbi = pncbi;
|
|
}
|
|
else
|
|
{
|
|
ReleaseObj(pencbi);
|
|
pencbi = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HrGetNextBindingPath
|
|
//
|
|
// Purpose: Enumerate over binding paths that start with
|
|
// the specified component
|
|
//
|
|
// Arguments:
|
|
// pncc [in] pointer to INetCfgComponent object
|
|
// dwBindingPathType [in] type of binding path to retrieve
|
|
// ppncbp [out] pointer to INetCfgBindingPath interface
|
|
//
|
|
// Returns: S_OK on success, otherwise an error code
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT HrGetNextBindingPath(IN INetCfgComponent* pncc,
|
|
IN DWORD dwBindingPathType,
|
|
OUT INetCfgBindingPath** ppncbp)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
INetCfgBindingPath* pncbp=NULL;
|
|
|
|
static IEnumNetCfgBindingPath* pebp=NULL;
|
|
|
|
*ppncbp = NULL;
|
|
|
|
// if this is the first call in the enumeration, obtain
|
|
// the IEnumNetCfgBindingPath interface
|
|
if (!pebp)
|
|
{
|
|
INetCfgComponentBindings* pnccb=NULL;
|
|
|
|
hr = pncc->QueryInterface(IID_INetCfgComponentBindings,
|
|
(void**) &pnccb);
|
|
if (S_OK == hr)
|
|
{
|
|
hr = pnccb->EnumBindingPaths(dwBindingPathType, &pebp);
|
|
ReleaseObj(pnccb);
|
|
}
|
|
}
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
ULONG celtFetched;
|
|
|
|
// get next binding path
|
|
hr = pebp->Next(1, &pncbp, &celtFetched);
|
|
}
|
|
|
|
// on the last call (hr == S_FALSE) or on error, release resources
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
*ppncbp = pncbp;
|
|
}
|
|
else
|
|
{
|
|
ReleaseObj(pebp);
|
|
pebp = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HrShowBindingPath
|
|
//
|
|
// Purpose: Display components of a binding path in the format:
|
|
// foo -> bar -> adapter
|
|
//
|
|
// Arguments:
|
|
// pncbp [in] pointer to INetCfgBindingPath object
|
|
//
|
|
// Returns: S_OK on success, otherwise an error code
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT HrShowBindingPath(IN INetCfgBindingPath* pncbp)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
INetCfgBindingInterface* pncbi;
|
|
INetCfgComponent* pncc = NULL;
|
|
BOOL fFirstInterface=TRUE;
|
|
PWSTR szComponentId;
|
|
|
|
while (SUCCEEDED(hr) &&
|
|
(S_OK == (hr = HrGetNextBindingInterface(pncbp, &pncbi))))
|
|
{
|
|
// for the first (top) interface we need to get the upper as well as
|
|
// the lower component. for other interfaces we need to get
|
|
// only the lower component.
|
|
|
|
if (fFirstInterface)
|
|
{
|
|
fFirstInterface = FALSE;
|
|
hr = pncbi->GetUpperComponent(&pncc);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// get id so that we can display it
|
|
//
|
|
// for readability of the output, we have used the GetId
|
|
// function. For non net class components, this
|
|
// does not pose a problem. In case of net class components,
|
|
// there may be more than one net adapters of the same type
|
|
// in which case, GetId will return the same string. This will
|
|
// make it impossible to distinguish between two binding
|
|
// paths that end in two distinct identical cards. In such case,
|
|
// it may be better to use the GetInstanceGuid function because
|
|
// it will return unique GUID for each instance of an adapter.
|
|
//
|
|
hr = pncc->GetId(&szComponentId);
|
|
ReleaseObj(pncc);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
_tprintf(szComponentId);
|
|
CoTaskMemFree(szComponentId);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pncbi->GetLowerComponent(&pncc);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pncc->GetId(&szComponentId);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
_tprintf(L" -> %s", szComponentId);
|
|
CoTaskMemFree(szComponentId);
|
|
}
|
|
ReleaseObj(pncc);
|
|
}
|
|
}
|
|
ReleaseObj(pncbi);
|
|
}
|
|
|
|
_tprintf(L"\n");
|
|
|
|
if (hr == S_FALSE)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HrShowBindingPathsBelowComponent
|
|
//
|
|
// Purpose: Display all binding paths that start with
|
|
// the specified component
|
|
//
|
|
// Arguments:
|
|
// szComponentId [in] id of given component (e.g. MS_TCPIP)
|
|
//
|
|
// Returns: S_OK on success, otherwise an error code
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT HrShowBindingPathsOfComponent(IN PCWSTR szComponentId)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
INetCfg* pnc=NULL;
|
|
INetCfgComponent* pncc=NULL;
|
|
INetCfgBindingPath* pncbp=NULL;
|
|
|
|
// get INetCfg interface
|
|
hr = HrGetINetCfg(FALSE, &pnc);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// get INetCfgComponent for szComponentId
|
|
hr = pnc->FindComponent(szComponentId, &pncc);
|
|
if (S_OK == hr)
|
|
{
|
|
_tprintf(L"Binding paths starting with '%s'\n\n",
|
|
szComponentId);
|
|
|
|
while (S_OK == (hr = HrGetNextBindingPath(pncc, EBP_BELOW,
|
|
&pncbp)))
|
|
{
|
|
// display the binding path
|
|
hr = HrShowBindingPath(pncbp);
|
|
ReleaseObj(pncbp);
|
|
}
|
|
|
|
_tprintf(L"Binding paths ending with '%s'\n\n",
|
|
szComponentId);
|
|
|
|
while (S_OK == (hr = HrGetNextBindingPath(pncc, EBP_ABOVE,
|
|
&pncbp)))
|
|
{
|
|
// display the binding path
|
|
hr = HrShowBindingPath(pncbp);
|
|
ReleaseObj(pncbp);
|
|
}
|
|
|
|
ReleaseObj(pncc);
|
|
}
|
|
// release INetCfg
|
|
hr = HrReleaseINetCfg(FALSE, pnc);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HrGetINetCfg
|
|
//
|
|
// Purpose: Initialize COM, create and initialize INetCfg.
|
|
// Obtain write lock if indicated.
|
|
//
|
|
// Arguments:
|
|
// fGetWriteLock [in] whether to get write lock
|
|
// ppnc [in] pointer to pointer to INetCfg object
|
|
//
|
|
// Returns: S_OK on success, otherwise an error code
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT HrGetINetCfg(IN BOOL fGetWriteLock,
|
|
INetCfg** ppnc)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
|
|
// Initialize the output parameters.
|
|
*ppnc = NULL;
|
|
|
|
// initialize COM
|
|
hr = CoInitializeEx(NULL,
|
|
COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED );
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Create the object implementing INetCfg.
|
|
//
|
|
INetCfg* pnc;
|
|
hr = CoCreateInstance(CLSID_CNetCfg, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_INetCfg, (void**)&pnc);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
INetCfgLock * pncLock = NULL;
|
|
if (fGetWriteLock)
|
|
{
|
|
// Get the locking interface
|
|
hr = pnc->QueryInterface(IID_INetCfgLock,
|
|
(LPVOID *)&pncLock);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Attempt to lock the INetCfg for read/write
|
|
static const ULONG c_cmsTimeout = 15000;
|
|
static const WCHAR c_szSampleNetcfgApp[] =
|
|
L"Sample Netcfg Application (netcfg.exe)";
|
|
PWSTR szLockedBy;
|
|
|
|
hr = pncLock->AcquireWriteLock(c_cmsTimeout,
|
|
c_szSampleNetcfgApp,
|
|
&szLockedBy);
|
|
if (S_FALSE == hr)
|
|
{
|
|
hr = NETCFG_E_NO_WRITE_LOCK;
|
|
_tprintf(L"Could not lock INetcfg, it is already locked by '%s'", szLockedBy);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Initialize the INetCfg object.
|
|
//
|
|
hr = pnc->Initialize(NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*ppnc = pnc;
|
|
pnc->AddRef();
|
|
}
|
|
else
|
|
{
|
|
// initialize failed, if obtained lock, release it
|
|
if (pncLock)
|
|
{
|
|
pncLock->ReleaseWriteLock();
|
|
}
|
|
}
|
|
}
|
|
ReleaseObj(pncLock);
|
|
ReleaseObj(pnc);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
CoUninitialize();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HrReleaseINetCfg
|
|
//
|
|
// Purpose: Uninitialize INetCfg, release write lock (if present)
|
|
// and uninitialize COM.
|
|
//
|
|
// Arguments:
|
|
// fHasWriteLock [in] whether write lock needs to be released.
|
|
// pnc [in] pointer to INetCfg object
|
|
//
|
|
// Returns: S_OK on success, otherwise an error code
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT HrReleaseINetCfg(BOOL fHasWriteLock, INetCfg* pnc)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// uninitialize INetCfg
|
|
hr = pnc->Uninitialize();
|
|
|
|
// if write lock is present, unlock it
|
|
if (SUCCEEDED(hr) && fHasWriteLock)
|
|
{
|
|
INetCfgLock* pncLock;
|
|
|
|
// Get the locking interface
|
|
hr = pnc->QueryInterface(IID_INetCfgLock,
|
|
(LPVOID *)&pncLock);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pncLock->ReleaseWriteLock();
|
|
ReleaseObj(pncLock);
|
|
}
|
|
}
|
|
|
|
ReleaseObj(pnc);
|
|
|
|
CoUninitialize();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: ShowMessage
|
|
//
|
|
// Purpose: Helper function to display a message in verbose mode.
|
|
// If not in verbose mode, do nothing.
|
|
//
|
|
// Arguments:
|
|
// szMsg [in] message to display
|
|
//
|
|
// Returns: None
|
|
//
|
|
// Notes:
|
|
//
|
|
void ShowMessage(IN PCWSTR szMsg, ...)
|
|
{
|
|
extern BOOL g_fVerbose;
|
|
|
|
if (g_fVerbose)
|
|
{
|
|
va_list arglist;
|
|
|
|
va_start(arglist, szMsg);
|
|
_vtprintf(szMsg, arglist);
|
|
_tprintf(L"\n");
|
|
fflush(stdout);
|
|
va_end(arglist);
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: ShowHrMessage
|
|
//
|
|
// Purpose: Helper function to display the status of the last action
|
|
// as indicated by the given HRESULT
|
|
//
|
|
// Arguments:
|
|
// hr [in] status code
|
|
//
|
|
// Returns: None
|
|
//
|
|
// Notes:
|
|
//
|
|
void ShowHrMessage(IN HRESULT hr)
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ShowMessage(L"...done");
|
|
if (NETCFG_S_REBOOT == hr)
|
|
{
|
|
ShowMessage(L"*** You need to reboot your computer for this change to take effect ***");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ShowMessage(L"..failed. Error code: 0x%lx", hr);
|
|
}
|
|
}
|