mirror of https://github.com/tongzx/nt5src
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.
721 lines
20 KiB
721 lines
20 KiB
/****************************************************************************
|
|
*
|
|
* icfg32.cpp
|
|
*
|
|
* Microsoft Confidential
|
|
* Copyright (c) 1992-1999 Microsoft Corporation
|
|
* All rights reserved
|
|
*
|
|
* This module provides the implementation of the methods for
|
|
* the NT specific functionality of inetcfg
|
|
*
|
|
* 6/5/97 ChrisK Inherited from AmnonH
|
|
* 7/3/97 ShaunCo Modfied for NT5
|
|
*
|
|
***************************************************************************/
|
|
#define UNICODE
|
|
#define _UNICODE
|
|
|
|
#include <wtypes.h>
|
|
#include <cfgapi.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <tchar.h>
|
|
#include <setupapi.h>
|
|
#include <basetyps.h>
|
|
#include <devguid.h>
|
|
#include <lmsname.h>
|
|
#include "debug.h"
|
|
|
|
#include <netcfgx.h>
|
|
|
|
const LPTSTR gc_szIsdnSigature = TEXT("\\NET\\");
|
|
|
|
#define REG_DATA_EXTRA_SPACE 255
|
|
#define DEVICE_INSTANCE_SIZE 128
|
|
|
|
extern DWORD g_dwLastError;
|
|
|
|
|
|
typedef BOOL (WINAPI *PFNINSTALLNEWDEVICE) (HWND hwndParent,
|
|
LPGUID ClassGuid,
|
|
PDWORD pReboot);
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Exported Entry point from newdev.cpl. Installs a new device. A new Devnode is
|
|
created and the user is prompted to select the device. If the class guid
|
|
is not specified then then the user begins at class selection.
|
|
|
|
Arguments:
|
|
|
|
hwndParent - Window handle of the top-level window to use for any UI related
|
|
to installing the device.
|
|
|
|
LPGUID ClassGuid - Optional class of the new device to install.
|
|
If ClassGuid is NULL we start at detection choice page.
|
|
If ClassGuid == GUID_NULL or GUID_DEVCLASS_UNKNOWN
|
|
we start at class selection page.
|
|
|
|
pReboot - Optional address of variable to receive reboot flags (DI_NEEDRESTART,DI_NEEDREBOOT)
|
|
|
|
|
|
Return Value:
|
|
|
|
BOOL TRUE for success (does not mean device was installed or updated),
|
|
FALSE unexpected error. GetLastError returns the winerror code.
|
|
*/
|
|
|
|
|
|
// For the code that was copied from netcfg, make the TraceError stuff
|
|
// go away. Likewise for existing debug statements.
|
|
//
|
|
#define TraceError
|
|
#define Dprintf
|
|
|
|
ULONG
|
|
ReleaseObj (
|
|
IUnknown* punk)
|
|
{
|
|
return (punk) ? punk->Release () : 0;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HrCreateAndInitializeINetCfg
|
|
//
|
|
// Purpose: Cocreate and initialize the root INetCfg object. This will
|
|
// optionally initialize COM for the caller too.
|
|
//
|
|
// Arguments:
|
|
// pfInitCom [in,out] TRUE to call CoInitialize before creating.
|
|
// returns TRUE if COM was successfully
|
|
// initialized FALSE if not. If NULL, means
|
|
// don't initialize COM.
|
|
// ppnc [out] The returned INetCfg object.
|
|
// fGetWriteLock [in] TRUE if a writable INetCfg is needed
|
|
// cmsTimeout [in] See INetCfg::AcquireWriteLock
|
|
// szwClientDesc [in] See INetCfg::AcquireWriteLock
|
|
// pbstrClientDesc [in] See INetCfg::AcquireWriteLock
|
|
//
|
|
// Returns: S_OK or an error code.
|
|
//
|
|
// Author: shaunco 7 May 1997
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT
|
|
HrCreateAndInitializeINetCfg (
|
|
BOOL* pfInitCom,
|
|
INetCfg** ppnc,
|
|
BOOL fGetWriteLock,
|
|
DWORD cmsTimeout,
|
|
LPCWSTR szwClientDesc,
|
|
BSTR* pbstrClientDesc)
|
|
{
|
|
Assert (ppnc);
|
|
|
|
// Initialize the output parameter.
|
|
*ppnc = NULL;
|
|
|
|
// Initialize COM if the caller requested.
|
|
HRESULT hr = S_OK;
|
|
if (pfInitCom && *pfInitCom)
|
|
{
|
|
hr = CoInitializeEx( NULL,
|
|
COINIT_DISABLE_OLE1DDE | COINIT_MULTITHREADED );
|
|
if (RPC_E_CHANGED_MODE == hr)
|
|
{
|
|
hr = S_OK;
|
|
if (pfInitCom)
|
|
{
|
|
*pfInitCom = FALSE;
|
|
}
|
|
}
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Create the object implementing INetCfg.
|
|
//
|
|
INetCfg* pnc;
|
|
hr = CoCreateInstance(CLSID_CNetCfg, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_INetCfg, reinterpret_cast<void**>(&pnc));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
INetCfgLock * pnclock = NULL;
|
|
if (fGetWriteLock)
|
|
{
|
|
// Get the locking interface
|
|
hr = pnc->QueryInterface(IID_INetCfgLock,
|
|
reinterpret_cast<LPVOID *>(&pnclock));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Attempt to lock the INetCfg for read/write
|
|
hr = pnclock->AcquireWriteLock(cmsTimeout, szwClientDesc,
|
|
pbstrClientDesc);
|
|
if (S_FALSE == hr)
|
|
{
|
|
// Couldn't acquire the lock
|
|
hr = NETCFG_E_NO_WRITE_LOCK;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Initialize the INetCfg object.
|
|
//
|
|
hr = pnc->Initialize (NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*ppnc = pnc;
|
|
pnc->AddRef ();
|
|
}
|
|
else
|
|
{
|
|
if (pnclock)
|
|
{
|
|
pnclock->ReleaseWriteLock();
|
|
}
|
|
}
|
|
// Transfer reference to caller.
|
|
}
|
|
ReleaseObj(pnclock);
|
|
|
|
ReleaseObj(pnc);
|
|
}
|
|
|
|
// If we failed anything above, and we've initialized COM,
|
|
// be sure an uninitialize it.
|
|
//
|
|
if (FAILED(hr) && pfInitCom && *pfInitCom)
|
|
{
|
|
CoUninitialize ();
|
|
}
|
|
}
|
|
TraceError("HrCreateAndInitializeINetCfg", hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HrUninitializeAndUnlockINetCfg
|
|
//
|
|
// Purpose: Uninitializes and unlocks the INetCfg object
|
|
//
|
|
// Arguments:
|
|
// pnc [in] INetCfg to uninitialize and unlock
|
|
//
|
|
// Returns: S_OK if success, OLE or Win32 error otherwise
|
|
//
|
|
// Author: danielwe 13 Nov 1997
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT
|
|
HrUninitializeAndUnlockINetCfg (
|
|
INetCfg* pnc)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = pnc->Uninitialize();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
INetCfgLock * pnclock;
|
|
|
|
// Get the locking interface
|
|
hr = pnc->QueryInterface(IID_INetCfgLock,
|
|
reinterpret_cast<LPVOID *>(&pnclock));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Attempt to lock the INetCfg for read/write
|
|
hr = pnclock->ReleaseWriteLock();
|
|
|
|
ReleaseObj(pnclock);
|
|
}
|
|
}
|
|
|
|
TraceError("HrUninitializeAndUnlockINetCfg", hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HrUninitializeAndReleaseINetCfg
|
|
//
|
|
// Purpose: Unintialize and release an INetCfg object. This will
|
|
// optionally uninitialize COM for the caller too.
|
|
//
|
|
// Arguments:
|
|
// fUninitCom [in] TRUE to uninitialize COM after the INetCfg is
|
|
// uninitialized and released.
|
|
// pnc [in] The INetCfg object.
|
|
// fHasLock [in] TRUE if the INetCfg was locked for write and
|
|
// must be unlocked.
|
|
//
|
|
// Returns: S_OK or an error code.
|
|
//
|
|
// Author: shaunco 7 May 1997
|
|
//
|
|
// Notes: The return value is the value returned from
|
|
// INetCfg::Uninitialize. Even if this fails, the INetCfg
|
|
// is still released. Therefore, the return value is for
|
|
// informational purposes only. You can't touch the INetCfg
|
|
// object after this call returns.
|
|
//
|
|
HRESULT
|
|
HrUninitializeAndReleaseINetCfg (
|
|
BOOL fUninitCom,
|
|
INetCfg* pnc,
|
|
BOOL fHasLock)
|
|
{
|
|
Assert (pnc);
|
|
HRESULT hr = S_OK;
|
|
|
|
if (fHasLock)
|
|
{
|
|
hr = HrUninitializeAndUnlockINetCfg(pnc);
|
|
}
|
|
else
|
|
{
|
|
hr = pnc->Uninitialize ();
|
|
}
|
|
|
|
ReleaseObj (pnc);
|
|
|
|
if (fUninitCom)
|
|
{
|
|
CoUninitialize ();
|
|
}
|
|
TraceError("HrUninitializeAndReleaseINetCfg", hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HrInstallComponent
|
|
//
|
|
// Purpose: Install the component with a specified id.
|
|
//
|
|
// Arguments:
|
|
// pnc [in] INetCfg pointer.
|
|
// pguidClass [in] Class guid of the component to install.
|
|
// pszwComponentId [in] Component id to install.
|
|
// ppncc [out] (Optional) Returned component that was
|
|
// installed.
|
|
//
|
|
// Returns: S_OK or an error code.
|
|
//
|
|
// Author: shaunco 4 Jan 1998
|
|
//
|
|
// Notes: nickball 7 May 1999 - Removed unused pszwOboToken parameter
|
|
//
|
|
HRESULT
|
|
HrInstallComponent (
|
|
INetCfg* pnc,
|
|
const GUID* pguidClass,
|
|
LPCWSTR pszwComponentId,
|
|
INetCfgComponent** ppncc)
|
|
{
|
|
OBO_TOKEN oboToken;
|
|
|
|
Assert (pnc);
|
|
Assert (pszwComponentId);
|
|
|
|
// Initialize output parameter.
|
|
//
|
|
if (ppncc)
|
|
{
|
|
*ppncc = NULL;
|
|
}
|
|
|
|
// Get the class setup object.
|
|
//
|
|
INetCfgClassSetup* pncclasssetup;
|
|
|
|
ZeroMemory((PVOID)&oboToken, sizeof(oboToken));
|
|
oboToken.Type = OBO_USER;
|
|
|
|
//NT #330252
|
|
//oboToken.pncc = *ppncc;
|
|
//oboToken. fRegistered = TRUE;
|
|
|
|
HRESULT hr = pnc->QueryNetCfgClass (pguidClass, IID_INetCfgClassSetup,
|
|
reinterpret_cast<void**>(&pncclasssetup));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pncclasssetup->Install (pszwComponentId,
|
|
&oboToken, 0, 0, NULL, NULL, ppncc);
|
|
|
|
ReleaseObj (pncclasssetup);
|
|
}
|
|
TraceError("HrInstallComponent", hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CallModemInstallWizard
|
|
//
|
|
// Synopsis: Invoke modem install wizard via SetupDi interfaces
|
|
//
|
|
// Arguments: hwnd - handle to parent window
|
|
//
|
|
// Returns: TRUE - success, FALSE - failed
|
|
//
|
|
// History: 6/5/97 ChrisK Inherited
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// The following code was stolen from RAS
|
|
//
|
|
|
|
BOOL
|
|
CallModemInstallWizardNT5(HWND hwnd)
|
|
{
|
|
BOOL fReturn = FALSE;
|
|
PFNINSTALLNEWDEVICE pfn;
|
|
HINSTANCE hInst;
|
|
|
|
Dprintf("ICFGNT: CallModemInstallWizard\n");
|
|
|
|
//
|
|
// Load newdev.dll can call the InstallNewDevice method with Modem device class
|
|
//
|
|
hInst = LoadLibrary((LPCTSTR) L"newdev.dll");
|
|
if (NULL == hInst)
|
|
{
|
|
goto CleanupAndExit;
|
|
}
|
|
|
|
pfn = (PFNINSTALLNEWDEVICE) GetProcAddress(hInst, (LPCSTR)"InstallNewDevice");
|
|
if (NULL == pfn)
|
|
{
|
|
goto CleanupAndExit;
|
|
}
|
|
|
|
//
|
|
// Call the function - on NT5 modem installation should not require
|
|
// reboot; so that last parameter, which is used to return if restart/reboot
|
|
// is required can be NULL
|
|
//
|
|
fReturn = pfn(hwnd, (LPGUID) &GUID_DEVCLASS_MODEM, NULL);
|
|
|
|
|
|
CleanupAndExit:
|
|
|
|
if (NULL != hInst)
|
|
{
|
|
FreeLibrary(hInst);
|
|
}
|
|
return fReturn;
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: IcfgNeedModem
|
|
//
|
|
// Synopsis: Check system configuration to determine if there is at least
|
|
// one physical modem installed
|
|
//
|
|
// Arguments: dwfOptions - currently not used
|
|
//
|
|
// Returns: HRESULT - S_OK if successfull
|
|
// lpfNeedModem - TRUE if no modems are available
|
|
//
|
|
// History: 6/5/97 ChrisK Inherited
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT WINAPI
|
|
IcfgNeedModemNT5(DWORD dwfOptions, LPBOOL lpfNeedModem)
|
|
{
|
|
//
|
|
// Ras is installed, and ICW wants to know if it needs to
|
|
// install a modem.
|
|
//
|
|
*lpfNeedModem = TRUE;
|
|
|
|
// Get the device info set for modems.
|
|
//
|
|
HDEVINFO hdevinfo = SetupDiGetClassDevs((GUID*)&GUID_DEVCLASS_MODEM,
|
|
NULL,
|
|
NULL,
|
|
DIGCF_PRESENT);
|
|
if (hdevinfo)
|
|
{
|
|
SP_DEVINFO_DATA diData;
|
|
diData.cbSize = sizeof(diData);
|
|
|
|
// Look for at least one modem.
|
|
//
|
|
if (SetupDiEnumDeviceInfo(hdevinfo, 0, &diData))
|
|
{
|
|
*lpfNeedModem = FALSE;
|
|
}
|
|
|
|
SetupDiDestroyDeviceInfoList (hdevinfo);
|
|
}
|
|
|
|
if (*lpfNeedModem)
|
|
{
|
|
//
|
|
// check for ISDN adaptors
|
|
//
|
|
// Get the device info set for modems.
|
|
//
|
|
hdevinfo = SetupDiGetClassDevs((GUID*)&GUID_DEVCLASS_NET,
|
|
NULL,
|
|
NULL,
|
|
DIGCF_PRESENT);
|
|
if (hdevinfo)
|
|
{
|
|
TCHAR szDevInstanceId[DEVICE_INSTANCE_SIZE];
|
|
DWORD dwIndex = 0;
|
|
DWORD dwRequiredSize;
|
|
SP_DEVINFO_DATA diData;
|
|
diData.cbSize = sizeof(diData);
|
|
|
|
//
|
|
// look for an ISDN device
|
|
//
|
|
while (SetupDiEnumDeviceInfo(hdevinfo, dwIndex, &diData))
|
|
{
|
|
if (SetupDiGetDeviceInstanceId(hdevinfo,
|
|
&diData,
|
|
szDevInstanceId,
|
|
sizeof(szDevInstanceId) / sizeof(szDevInstanceId[0]),
|
|
&dwRequiredSize))
|
|
{
|
|
HKEY hReg, hInterface;
|
|
TCHAR szLowerRange[MAX_PATH + 1];
|
|
DWORD cb = sizeof(szLowerRange);
|
|
|
|
hReg = SetupDiOpenDevRegKey(hdevinfo, &diData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ);
|
|
if (hReg != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (RegOpenKey(hReg, TEXT("Ndi\\Interfaces"), &hInterface) == ERROR_SUCCESS)
|
|
{
|
|
if (RegQueryValueEx(hInterface, TEXT("LowerRange"), 0, NULL, (PBYTE) szLowerRange, &cb) == ERROR_SUCCESS)
|
|
{
|
|
if (lstrcmpi(szLowerRange, TEXT("isdn")) == 0)
|
|
{
|
|
*lpfNeedModem = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
RegCloseKey(hInterface);
|
|
}
|
|
RegCloseKey(hReg);
|
|
}
|
|
|
|
//
|
|
// ISDN adaptors are in the form XXX\NET\XXX
|
|
//
|
|
if (_tcsstr(szDevInstanceId, gc_szIsdnSigature))
|
|
{
|
|
*lpfNeedModem = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
dwIndex++;
|
|
}
|
|
|
|
SetupDiDestroyDeviceInfoList (hdevinfo);
|
|
}
|
|
}
|
|
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: IcfgInstallModem
|
|
//
|
|
// Synopsis:
|
|
// This function is called when ICW verified that RAS is installed,
|
|
// but no modems are avilable. It needs to make sure a modem is availble.
|
|
// There are two possible scenarios:
|
|
//
|
|
// a. There are no modems installed. This happens when someone deleted
|
|
// a modem after installing RAS. In this case we need to run the modem
|
|
// install wizard, and configure the newly installed modem to be a RAS
|
|
// dialout device.
|
|
//
|
|
// b. There are modems installed, but non of them is configured as a dial out
|
|
// device. In this case, we silently convert them to be DialInOut devices,
|
|
// so ICW can use them.
|
|
//
|
|
// Arguments: hwndParent - handle to parent window
|
|
// dwfOptions - not used
|
|
//
|
|
// Returns: lpfNeedsStart - not used
|
|
//
|
|
// History: 6/5/97 ChrisK Inherited
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT WINAPI
|
|
IcfgInstallModemNT5(HWND hwndParent, DWORD dwfOptions, LPBOOL lpfNeedsStart)
|
|
{
|
|
//
|
|
// Fire up the modem install wizard
|
|
//
|
|
if (!CallModemInstallWizardNT5(hwndParent))
|
|
{
|
|
return(g_dwLastError = GetLastError());
|
|
}
|
|
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: IcfgNeedInetComponets
|
|
//
|
|
// Synopsis: Check to see if the components marked in the options are
|
|
// installed on the system
|
|
//
|
|
// Arguements: dwfOptions - set of bit flag indicating which components to
|
|
// check for
|
|
//
|
|
// Returns; HRESULT - S_OK if successfull
|
|
// lpfNeedComponents - TRUE is some components are not installed
|
|
//
|
|
// History: 6/5/97 ChrisK Inherited
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT WINAPI
|
|
IcfgNeedInetComponentsNT5(DWORD dwfOptions, LPBOOL lpfNeedComponents)
|
|
{
|
|
Dprintf("ICFGNT: IcfgNeedInetComponents\n");
|
|
|
|
//
|
|
// Assume we have what we need.
|
|
//
|
|
*lpfNeedComponents = FALSE;
|
|
|
|
HRESULT hr = S_OK;
|
|
INetCfg* pnc = NULL;
|
|
BOOL fInitCom = TRUE;
|
|
|
|
// If the optiona are such that we need an INetCfg interface pointer,
|
|
// get one.
|
|
//
|
|
if ((dwfOptions & ICFG_INSTALLTCP) ||
|
|
(dwfOptions & ICFG_INSTALLRAS))
|
|
{
|
|
hr = HrCreateAndInitializeINetCfg (&fInitCom, &pnc,
|
|
FALSE, 0, NULL, NULL);
|
|
}
|
|
|
|
// Look for TCP/IP using the INetCfg interface.
|
|
//
|
|
if (SUCCEEDED(hr) && (dwfOptions & ICFG_INSTALLTCP))
|
|
{
|
|
Assert (pnc);
|
|
|
|
hr = pnc->FindComponent (NETCFG_TRANS_CID_MS_TCPIP, NULL);
|
|
if (S_FALSE == hr)
|
|
{
|
|
*lpfNeedComponents = TRUE;
|
|
}
|
|
}
|
|
|
|
// We no longer need the INetCfg interface pointer, so release it.
|
|
//
|
|
if (pnc)
|
|
{
|
|
(void) HrUninitializeAndReleaseINetCfg (fInitCom, pnc, FALSE);
|
|
}
|
|
|
|
// Normalize the HRESULT.
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: IcfgInstallInetComponentsNT5
|
|
//
|
|
// Synopsis: Install the components as specified by the dwfOptions values
|
|
//
|
|
// Arguments hwndParent - handle to parent window
|
|
// dwfOptions - set of bit flags indicating which components to
|
|
// install
|
|
//
|
|
// Returns: HRESULT - S_OK if success
|
|
// lpfNeedsReboot - TRUE if reboot is required
|
|
//
|
|
// History: 6/5/97 ChrisK Inherited
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT WINAPI
|
|
IcfgInstallInetComponentsNT5(HWND hwndParent, DWORD dwfOptions, LPBOOL lpfNeedsRestart)
|
|
{
|
|
Dprintf("ICFGNT: IcfgInstallInetComponents\n");
|
|
|
|
//
|
|
// Assume don't need restart
|
|
//
|
|
*lpfNeedsRestart = FALSE;
|
|
|
|
HRESULT hr = S_OK;
|
|
INetCfg* pnc = NULL;
|
|
BOOL fInitCom = TRUE;
|
|
|
|
// If the optiona are such that we need an INetCfg interface pointer,
|
|
// get one.
|
|
//
|
|
if ((dwfOptions & ICFG_INSTALLTCP) ||
|
|
(dwfOptions & ICFG_INSTALLRAS))
|
|
{
|
|
BSTR bstrClient;
|
|
hr = HrCreateAndInitializeINetCfg (&fInitCom, &pnc, TRUE,
|
|
0, L"", &bstrClient);
|
|
}
|
|
|
|
// Install TCP/IP on behalf of the user.
|
|
//
|
|
if (SUCCEEDED(hr) && (dwfOptions & ICFG_INSTALLTCP))
|
|
{
|
|
hr = HrInstallComponent (pnc, &GUID_DEVCLASS_NETTRANS,
|
|
NETCFG_TRANS_CID_MS_TCPIP, NULL);
|
|
}
|
|
|
|
// We no longer need the INetCfg interface pointer, so release it.
|
|
//
|
|
if (pnc)
|
|
{
|
|
// Apply the changes if everything was successful.
|
|
//
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pnc->Apply();
|
|
|
|
if (NETCFG_S_REBOOT == hr)
|
|
{
|
|
*lpfNeedsRestart = TRUE;
|
|
}
|
|
}
|
|
(void) HrUninitializeAndReleaseINetCfg (fInitCom, pnc, TRUE);
|
|
}
|
|
|
|
// Normalize the HRESULT.
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
return(hr);
|
|
}
|