|
|
/****************************************************************************
* * 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) { int iRetVal = 0;
if (OS_NT51) { iRetVal = CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, szLowerRange, -1, TEXT("isdn"), -1); } else { DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); iRetVal = CompareString(lcid, NORM_IGNORECASE, szLowerRange, -1, TEXT("isdn"), -1); } if (CSTR_EQUAL == iRetVal) { *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); }
|