windows-nt/Source/XPSP1/NT/net/wlbs/nlbmgr/provider/cfgutils.cpp
2020-09-26 16:20:57 +08:00

4415 lines
106 KiB
C++

//***************************************************************************
//
// CFGUTILS.CPP
//
// Module: WMI Framework Instance provider
//
// Purpose: Low-level utilities to configure NICs -- bind/unbind,
// get/set IP address lists, and get/set NLB cluster params.
//
// Copyright (c)2001 Microsoft Corporation, All Rights Reserved
//
// History:
//
// 04/05/01 JosephJ Created
//
//***************************************************************************
#include "private.h"
#include <netcfgx.h>
#include <devguid.h>
#include <cfg.h>
#include "..\..\..\inc\wlbsiocl.h"
#include "..\..\..\api\control.h"
#include "cfgutils.tmh"
//
// This magic has the side effect defining "smart pointers"
// IWbemServicesPtr
// IWbemLocatorPtr
// IWbemClassObjectPtr
// IEnumWbemClassObjectPtr
// IWbemCallResultPtr
// IWbemStatusCodeTextPtr
//
// These types automatically call the COM Release function when the
// objects go out of scope.
//
_COM_SMARTPTR_TYPEDEF(IWbemServices, __uuidof(IWbemServices));
_COM_SMARTPTR_TYPEDEF(IWbemLocator, __uuidof(IWbemLocator));
_COM_SMARTPTR_TYPEDEF(IEnumWbemClassObject, __uuidof(IEnumWbemClassObject));
_COM_SMARTPTR_TYPEDEF(IWbemCallResult, __uuidof(IWbemCallResult));
_COM_SMARTPTR_TYPEDEF(IWbemStatusCodeText, __uuidof(IWbemStatusCodeText));
WBEMSTATUS
CfgUtilGetWmiAdapterObjFromAdapterConfigurationObj(
IN IWbemClassObjectPtr spObj, // smart pointer
OUT IWbemClassObjectPtr &spAdapterObj // smart pointer, by reference
);
WBEMSTATUS
get_string_parameter(
IN IWbemClassObjectPtr spObj,
IN LPCWSTR szParameterName,
OUT LPWSTR *ppStringValue
);
WBEMSTATUS
get_nic_instance(
IN IWbemServicesPtr spWbemServiceIF,
IN LPCWSTR szNicGuid,
OUT IWbemClassObjectPtr &sprefObj
);
WBEMSTATUS
get_multi_string_parameter(
IN IWbemClassObjectPtr spObj,
IN LPCWSTR szParameterName,
IN UINT MaxStringLen, // in wchars, INCLUDING space for trailing zeros.
OUT UINT *pNumItems,
OUT LPCWSTR *ppStringValue
);
WBEMSTATUS
set_string_parameter(
IN IWbemClassObjectPtr spObj,
IN LPCWSTR szParameterName,
IN LPCWSTR szValue
);
WBEMSTATUS
set_multi_string_parameter(
IN IWbemClassObjectPtr spObj,
IN LPCWSTR szParameterName,
IN UINT MaxStringLen, // in wchars, INCLUDING space for trailing zeros.
IN UINT NumItems,
IN LPCWSTR pStringValue
);
//
// This locally-defined class implements interfaces to WMI, NetConfig,
// and low-level NLB APIs.
//
class CfgUtils
{
public:
//
// Initialization function -- call before using any other functions
//
WBEMSTATUS
Initialize(
VOID
);
//
// Deinitialization function -- call after using any other functions
//
VOID
Deinitialize(
VOID
);
//
// Constructor and distructor.
//
CfgUtils(VOID)
{
//
// WARNING: We do a blanked zero memory initialization of our entire
// structure. Any other initialization should go into the
// Initialize() function.
//
ZeroMemory(this, sizeof(*this));
InitializeCriticalSection(&m_Crit);
}
~CfgUtils()
{
DeleteCriticalSection(&m_Crit);
}
//
// Check if we're initialized
//
BOOL
IsInitalized(VOID)
{
return m_ComInitialized && m_WmiInitialized && m_NLBApisInitialized;
}
IWbemStatusCodeTextPtr m_spWbemStatusIF; // Smart pointer
IWbemServicesPtr m_spWbemServiceIF; // Smart pointer
CWlbsControl *m_pWlbsControl;
WBEMSTATUS
GetClusterFromGuid(
IN LPCWSTR szGuid,
OUT CWlbsCluster **pCluster
);
private:
//
// A single lock serialzes all access.
// Use mfn_Lock and mfn_Unlock.
//
CRITICAL_SECTION m_Crit;
BOOL m_ComInitialized;
BOOL m_WmiInitialized;
BOOL m_NLBApisInitialized;
VOID
mfn_Lock(
VOID
)
{
EnterCriticalSection(&m_Crit);
}
VOID
mfn_Unlock(
VOID
)
{
LeaveCriticalSection(&m_Crit);
}
};
//
// This class manages NetCfg interfaces
//
class MyNetCfg
{
public:
MyNetCfg(VOID)
{
m_pINetCfg = NULL;
m_pLock = NULL;
}
~MyNetCfg()
{
ASSERT(m_pINetCfg==NULL);
ASSERT(m_pLock==NULL);
}
WBEMSTATUS
Initialize(
BOOL fWriteLock
);
VOID
Deinitialize(
VOID
);
WBEMSTATUS
GetNlbCompatibleNics(
OUT LPWSTR **ppszNics,
OUT UINT *pNumNics,
OUT UINT *pNumBoundToNlb // OPTIONAL
);
WBEMSTATUS
GetNicIF(
IN LPCWSTR szNicGuid,
OUT INetCfgComponent **ppINic
);
WBEMSTATUS
GetBindingIF(
IN LPCWSTR szComponent,
OUT INetCfgComponentBindings **ppIBinding
);
typedef enum
{
NOOP,
BIND,
UNBIND
} UPDATE_OP;
WBEMSTATUS
UpdateBindingState(
IN LPCWSTR szNic,
IN LPCWSTR szComponent,
IN UPDATE_OP Op,
OUT BOOL *pfBound
);
private:
INetCfg *m_pINetCfg;
INetCfgLock *m_pLock;
}; // Class MyNetCfg
//
// We keep a single global instance of this class around currently...
//
CfgUtils g_CfgUtils;
WBEMSTATUS
CfgUtilInitialize(VOID)
{
return g_CfgUtils.Initialize();
}
VOID
CfgUtilDeitialize(VOID)
{
return g_CfgUtils.Deinitialize();
}
WBEMSTATUS
CfgUtils::Initialize(
VOID
)
{
WBEMSTATUS Status = WBEM_E_INITIALIZATION_FAILURE;
HRESULT hr;
TRACE_INFO(L"-> CfgUtils::Initialize");
mfn_Lock();
//
// Initialize COM
//
{
HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED);
if ( FAILED(hr) )
{
TRACE_CRIT(L"CfgUtils: Failed to initialize COM library (hr=0x%08lx)", hr);
goto end;
}
m_ComInitialized = TRUE;
}
//
// WMI Initialization
//
{
IWbemLocatorPtr spWbemLocatorIF = NULL; // Smart pointer
//
// Get error text generator interface
//
SCODE sc = CoCreateInstance(
CLSID_WbemStatusCodeText,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemStatusCodeText,
(LPVOID *) &m_spWbemStatusIF
);
if( sc != S_OK )
{
ASSERT(m_spWbemStatusIF == NULL); // smart pointer
TRACE_CRIT(L"CfgUtils: CoCreateInstance IWbemStatusCodeText failure\n");
goto end;
}
TRACE_INFO(L"CfgUtils: m_spIWbemStatusIF=0x%p\n", (PVOID) m_spWbemStatusIF);
//
// Get "locator" interface
//
hr = CoCreateInstance(
CLSID_WbemLocator, 0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator,
(LPVOID *) &spWbemLocatorIF
);
if (FAILED(hr))
{
ASSERT(spWbemLocatorIF == NULL); // smart pointer
TRACE_CRIT(L"CoCreateInstance IWebmLocator failed 0x%08lx", (UINT)hr);
goto end;
}
//
// Get interface to provider for NetworkAdapter class objects
// on the local machine
//
_bstr_t serverPath = L"root\\cimv2";
hr = spWbemLocatorIF->ConnectServer(
serverPath,
NULL, // strUser,
NULL, // strPassword,
NULL,
0,
NULL,
NULL,
&m_spWbemServiceIF
);
if (FAILED(hr))
{
ASSERT(m_spWbemServiceIF == NULL); // smart pointer
TRACE_CRIT(L"ConnectServer to cimv2 failed 0x%08lx", (UINT)hr);
goto end;
}
TRACE_INFO(L"CfgUtils: m_spIWbemServiceIF=0x%p\n", (PVOID) m_spWbemServiceIF);
hr = CoSetProxyBlanket(
m_spWbemServiceIF,
RPC_C_AUTHN_WINNT,
RPC_C_AUTHZ_DEFAULT, // RPC_C_AUTHZ_NAME,
COLE_DEFAULT_PRINCIPAL, // NULL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
COLE_DEFAULT_AUTHINFO, // NULL,
EOAC_DEFAULT // EOAC_NONE
);
if (FAILED(hr))
{
TRACE_INFO(L"Error 0x%08lx setting proxy blanket", (UINT) hr);
goto end;
}
//
// Release locator interface.
//
// <NO need to do this explicitly, because this is a smart pointer>
//
spWbemLocatorIF = NULL;
m_WmiInitialized = TRUE;
}
//
// Netconfig Initialization
//
{
// Nothing to do here...
}
//
// WLBS API Initialization
//
{
CWlbsControl *pWlbsControl = NULL;
pWlbsControl = new CWlbsControl;
if (pWlbsControl == NULL)
{
TRACE_CRIT("Could not initialize wlbs control!");
goto end;
}
DWORD dwRet = pWlbsControl->Initialize();
if (dwRet == WLBS_INIT_ERROR)
{
TRACE_CRIT("Error initializing WLBS Control!");
delete pWlbsControl;
pWlbsControl = NULL;
goto end;
}
else
{
TRACE_INFO("WlbsControl (0x%p) Initialize returns 0x%08lx",
(PVOID) pWlbsControl, dwRet);
}
m_pWlbsControl = pWlbsControl;
m_NLBApisInitialized = TRUE;
}
Status = WBEM_NO_ERROR;
end:
mfn_Unlock();
if (FAILED(Status))
{
TRACE_CRIT("CfgUtil -- FAILING INITIALIZATION! Status=0x%08lx",
(UINT) Status);
CfgUtils::Deinitialize();
}
TRACE_INFO(L"<- CfgUtils::Initialize(Status=0x%08lx)", (UINT) Status);
return Status;
}
VOID
CfgUtils::Deinitialize(
VOID
)
//
// NOTE: can be called in the context of a failed initialization.
//
{
TRACE_INFO(L"-> CfgUtils::Deinitialize");
mfn_Lock();
//
// De-initialize WLBS API
//
if (m_NLBApisInitialized)
{
delete m_pWlbsControl;
m_pWlbsControl = NULL;
m_NLBApisInitialized = FALSE;
}
//
// Deinitialize Netconfig
//
//
// Deinitialize WMI
//
{
//
// Release interface to NetworkAdapter provider
//
if (m_spWbemStatusIF!= NULL)
{
// Smart pointer.
m_spWbemStatusIF= NULL;
}
if (m_spWbemServiceIF!= NULL)
{
// Smart pointer.
m_spWbemServiceIF= NULL;
}
m_WmiInitialized = FALSE;
}
//
// Deinitialize COM.
//
if (m_ComInitialized)
{
TRACE_CRIT(L"CfgUtils: Deinitializing COM");
CoUninitialize();
m_ComInitialized = FALSE;
}
mfn_Unlock();
TRACE_INFO(L"<- CfgUtils::Deinitialize");
}
WBEMSTATUS
CfgUtils::GetClusterFromGuid(
IN LPCWSTR szGuid,
OUT CWlbsCluster **ppCluster
)
{
GUID Guid;
WBEMSTATUS Status = WBEM_NO_ERROR;
CWlbsCluster *pCluster = NULL;
GUID AdapterGuid;
HRESULT hr;
hr = CLSIDFromString((LPWSTR)szGuid, &Guid);
if (FAILED(hr))
{
TRACE_CRIT(
"CWlbsControl::Initialize failed at CLSIDFromString %ws",
szGuid
);
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
mfn_Lock(); // TODO: This is not really that effective because we still
// refer to pCluster outside this function.
g_CfgUtils.m_pWlbsControl->ReInitialize();
pCluster = m_pWlbsControl->GetClusterFromAdapter(Guid);
mfn_Unlock();
if (pCluster == NULL)
{
TRACE_CRIT("ERROR: Couldn't find cluster with Nic GUID %ws", szGuid);
Status = WBEM_E_NOT_FOUND;
goto end;
}
Status = WBEM_NO_ERROR;
end:
*ppCluster = pCluster;
return Status;
}
//
// Gets the list of statically-bound IP addresses for the NIC.
// Sets *pNumIpAddresses to 0 if DHCP
//
WBEMSTATUS
CfgUtilGetIpAddressesAndFriendlyName(
IN LPCWSTR szNic,
OUT UINT *pNumIpAddresses,
OUT NLB_IP_ADDRESS_INFO **ppIpInfo, // Free using c++ delete operator.
OUT LPWSTR *pszFriendlyName // Optional, Free using c++ delete
)
{
WBEMSTATUS Status = WBEM_NO_ERROR;
IWbemClassObjectPtr spObj = NULL; // smart pointer
HRESULT hr;
LPCWSTR pAddrs = NULL;
LPCWSTR pSubnets = NULL;
UINT AddrCount = 0;
NLB_IP_ADDRESS_INFO *pIpInfo = NULL;
TRACE_INFO(L"-> %!FUNC!(Nic=%ws)", szNic);
*pNumIpAddresses = NULL;
*ppIpInfo = NULL;
if (pszFriendlyName!=NULL)
{
*pszFriendlyName = NULL;
}
//
// If not initialized, fail...
//
if (!g_CfgUtils.IsInitalized())
{
TRACE_CRIT(L"%!FUNC!(Nic=%ws) FAILING because uninitialized", szNic);
Status = WBEM_E_INITIALIZATION_FAILURE;
goto end;
}
//
// Get WMI instance to specific NIC
//
Status = get_nic_instance(
g_CfgUtils.m_spWbemServiceIF,
szNic,
spObj // pass by reference
);
if (FAILED(Status))
{
ASSERT(spObj == NULL);
goto end;
}
//
// Extract IP addresses and subnets.
//
{
//
// This gets the ip addresses in a 2D WCHAR array -- inner dimension
// is WLBS_MAX_CLI_IP_ADDR.
//
Status = get_multi_string_parameter(
spObj,
L"IPAddress", // szParameterName,
WLBS_MAX_CL_IP_ADDR, // MaxStringLen - in wchars, incl null
&AddrCount,
&pAddrs
);
if (FAILED(Status))
{
pAddrs = NULL;
goto end;
}
else
{
TRACE_INFO("GOT %lu IP ADDRESSES!", AddrCount);
}
UINT SubnetCount;
Status = get_multi_string_parameter(
spObj,
L"IPSubnet", // szParameterName,
WLBS_MAX_CL_NET_MASK, // MaxStringLen - in wchars, incl null
&SubnetCount,
&pSubnets
);
if (FAILED(Status))
{
pSubnets = NULL;
goto end;
}
else if (SubnetCount != AddrCount)
{
TRACE_CRIT("FAILING SubnetCount!=AddressCount!");
goto end;
}
}
//
// Convert IP addresses to our internal form.
//
if (AddrCount != 0)
{
pIpInfo = new NLB_IP_ADDRESS_INFO[AddrCount];
if (pIpInfo == NULL)
{
TRACE_CRIT("get_multi_str_parm: Alloc failure!");
Status = WBEM_E_OUT_OF_MEMORY;
goto end;
}
ZeroMemory(pIpInfo, AddrCount*sizeof(*pIpInfo));
for (UINT u=0;u<AddrCount; u++)
{
//
// We extrace each IP address and it's corresponding subnet mask
// from the 2 2D arrays and insert it into a NLB_IP_ADDRESS_INFO
// structure.
//
LPCWSTR pIp = pAddrs+u*WLBS_MAX_CL_IP_ADDR;
LPCWSTR pSub = pSubnets+u*WLBS_MAX_CL_NET_MASK;
TRACE_INFO("IPaddress: %ws; SubnetMask:%ws", pIp, pSub);
UINT len = wcslen(pIp);
UINT len1 = wcslen(pSub);
if ( (len < WLBS_MAX_CL_IP_ADDR) && (len1 < WLBS_MAX_CL_NET_MASK))
{
CopyMemory(pIpInfo[u].IpAddress, pIp, (len+1)*sizeof(WCHAR));
CopyMemory(pIpInfo[u].SubnetMask, pSub, (len1+1)*sizeof(WCHAR));
}
else
{
//
// This would be an implementation error in get_multi_string_...
//
ASSERT(FALSE);
Status = WBEM_E_CRITICAL_ERROR;
goto end;
}
}
}
//
// If requested, get friendly name.
// We don't fail if there's an error, just return the empty "" string.
//
if (pszFriendlyName != NULL)
{
IWbemClassObjectPtr spAdapterObj = NULL; // smart pointer
LPWSTR szFriendlyName = NULL;
WBEMSTATUS TmpStatus;
do
{
TmpStatus = CfgUtilGetWmiAdapterObjFromAdapterConfigurationObj(
spObj,
spAdapterObj // passed by ref
);
if (FAILED(TmpStatus))
{
break;
}
TmpStatus = CfgUtilGetWmiStringParam(
spAdapterObj,
L"NetConnectionID",
&szFriendlyName
);
if (FAILED(TmpStatus))
{
TRACE_CRIT("%!FUNC! Get NetConnectionID failed error=0x%08lx\n",
(UINT) TmpStatus);
}
} while (FALSE);
if (szFriendlyName == NULL)
{
//
// Try to put an empty string.
//
szFriendlyName = new WCHAR[1];
if (szFriendlyName == NULL)
{
Status = WBEM_E_OUT_OF_MEMORY;
TRACE_CRIT("%!FUNC! Alloc failure!");
goto end;
}
*szFriendlyName = 0; // Empty string
}
*pszFriendlyName = szFriendlyName;
szFriendlyName = NULL;
}
end:
if (pAddrs != NULL)
{
delete pAddrs;
}
if (pSubnets != NULL)
{
delete pSubnets;
}
if (FAILED(Status))
{
if (pIpInfo != NULL)
{
delete pIpInfo;
pIpInfo = NULL;
}
AddrCount = 0;
}
*pNumIpAddresses = AddrCount;
*ppIpInfo = pIpInfo;
spObj = NULL; // smart pointer
TRACE_INFO(L"<- %!FUNC!(Nic=%ws) returns 0x%08lx", szNic, (UINT) Status);
return Status;
}
#if OBSOLETE
//
// Sets the list of statically-bound IP addresses for the NIC.
// if NumIpAddresses is 0, the NIC is configured for DHCP.
//
WBEMSTATUS
CfgUtilSetStaticIpAddressesOld(
IN LPCWSTR szNic,
IN UINT NumIpAddresses,
IN NLB_IP_ADDRESS_INFO *pIpInfo
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
IWbemClassObjectPtr spNicClassObj = NULL; // smart pointer
IWbemClassObjectPtr spWbemInputInstance = NULL; // smart pointer
HRESULT hr;
WCHAR *rgIpAddresses = NULL;
WCHAR *rgIpSubnets = NULL;
LPWSTR pRelPath = NULL;
TRACE_INFO(L"-> %!FUNC!(Nic=%ws)", szNic);
//
// If not initialized, fail...
//
if (!g_CfgUtils.IsInitalized())
{
TRACE_CRIT(L"%!FUNC!(Nic=%ws) FAILING because uninitialized", szNic);
Status = WBEM_E_INITIALIZATION_FAILURE;
goto end;
}
if (NumIpAddresses != 0)
{
//
// Convert IP addresses from our internal form into 2D arrays.
//
rgIpAddresses = new WCHAR[NumIpAddresses * WLBS_MAX_CL_IP_ADDR];
rgIpSubnets = new WCHAR[NumIpAddresses * WLBS_MAX_CL_NET_MASK];
if (rgIpAddresses == NULL || rgIpSubnets == NULL)
{
TRACE_CRIT("SetStaticIpAddresses: Alloc failure!");
Status = WBEM_E_OUT_OF_MEMORY;
goto end;
}
for (UINT u=0;u<NumIpAddresses; u++)
{
//
// We extrace each IP address and it's corresponding subnet mask
// from the 2 2D arrays and insert it into a NLB_IP_ADDRESS_INFO
// structure.
//
LPWSTR pIpDest = rgIpAddresses+u*WLBS_MAX_CL_IP_ADDR;
LPWSTR pSubDest = rgIpSubnets+u*WLBS_MAX_CL_NET_MASK;
LPCWSTR pIpSrc = pIpInfo[u].IpAddress;
LPCWSTR pSubSrc = pIpInfo[u].SubnetMask;
UINT len = wcslen(pIpSrc);
UINT len1 = wcslen(pSubSrc);
if ( (len < WLBS_MAX_CL_IP_ADDR) && (len1 < WLBS_MAX_CL_NET_MASK))
{
CopyMemory(pIpDest, pIpSrc, (len+1)*sizeof(WCHAR));
CopyMemory(pSubDest, pSubSrc, (len1+1)*sizeof(WCHAR));
}
else
{
//
// This would be an implementation error in get_multi_string_...
//
ASSERT(FALSE);
goto end;
}
}
}
//
// Get WMI path to specific NIC
//
{
IWbemClassObjectPtr spNicObj = NULL; // smart pointer
pRelPath = NULL;
Status = get_nic_instance(
g_CfgUtils.m_spWbemServiceIF,
szNic,
spNicObj // pass by reference
);
if (FAILED(Status))
{
ASSERT(spObj == NULL);
goto end;
}
//
// Extract the relative path, needed for ExecMethod.
//
Status = get_string_parameter(
spNicObj,
L"__RELPATH", // szParameterName
&pRelPath // Delete when done.
);
if (FAILED(Status))
{
TRACE_CRIT("Couldn't get rel path");
pRelPath = NULL;
goto end;
}
else
{
if (pRelPath==NULL)
{
ASSERT(FALSE); // we don't expect this!
goto end;
}
TRACE_CRIT("GOT RELATIVE PATH for %ws: %ws", szNic, pRelPath);
}
}
//
// Get NIC CLASS object
//
{
hr = g_CfgUtils.m_spWbemServiceIF->GetObject(
_bstr_t(L"Win32_NetworkAdapterConfiguration"),
0,
NULL,
&spNicClassObj,
NULL
);
if (FAILED(hr))
{
TRACE_CRIT("Couldn't get nic class object pointer");
goto end;
}
}
//
// Set up input parameters to the call to Enable static.
//
{
IWbemClassObjectPtr spWbemInput = NULL; // smart pointer
// check if any input parameters specified.
hr = spNicClassObj->GetMethod(
L"EnableStatic",
0,
&spWbemInput,
NULL
);
if( FAILED( hr) )
{
TRACE_CRIT("IWbemClassObject::GetMethod failure");
goto end;
}
hr = spWbemInput->SpawnInstance( 0, &spWbemInputInstance );
if( FAILED( hr) )
{
TRACE_CRIT("IWbemClassObject::SpawnInstance failure. Unable to spawn instance." );
goto end;
}
//
// This gets the ip addresses in a 2D WCHAR array -- inner dimension
// is WLBS_MAX_CLI_IP_ADDR.
//
Status = set_multi_string_parameter(
spWbemInputInstance,
L"IPAddress", // szParameterName,
WLBS_MAX_CL_IP_ADDR, // MaxStringLen - in wchars, incl null
NumIpAddresses,
rgIpAddresses
);
if (FAILED(Status))
{
goto end;
}
else
{
TRACE_INFO("SET %lu IP ADDRESSES!", NumIpAddresses);
}
Status = set_multi_string_parameter(
spWbemInputInstance,
L"SubnetMask", // szParameterName,
WLBS_MAX_CL_NET_MASK, // MaxStringLen - in wchars, incl null
NumIpAddresses,
rgIpSubnets
);
if (FAILED(Status))
{
goto end;
}
}
//
// execute method and get the output result
// WARNING: we try this a few times because the wmi call apperears to
// suffer from a recoverable error. TODO: Need to get to the bottom of
// this.
//
for (UINT NumTries=10; NumTries--;)
{
IWbemClassObjectPtr spWbemOutput = NULL; // smart pointer.
_variant_t v_retVal;
TRACE_CRIT("Going to call EnableStatic");
hr = g_CfgUtils.m_spWbemServiceIF->ExecMethod(
_bstr_t(pRelPath),
L"EnableStatic",
0,
NULL,
spWbemInputInstance,
&spWbemOutput,
NULL
);
TRACE_CRIT("EnableStatic returns");
if( FAILED( hr) )
{
TRACE_CRIT("IWbemServices::ExecMethod failure 0x%08lx", (UINT) hr);
goto end;
}
hr = spWbemOutput->Get(
L"ReturnValue",
0,
&v_retVal,
NULL,
NULL
);
if( FAILED( hr) )
{
TRACE_CRIT("IWbemClassObject::Get failure");
goto end;
}
LONG lRet = (LONG) v_retVal;
v_retVal.Clear();
if (lRet == 0)
{
TRACE_INFO("EnableStatic returns SUCCESS!");
Status = WBEM_NO_ERROR;
break;
}
else if (lRet == 0x51) // This appears to be a recoverable error
{
TRACE_INFO(
"EnableStatic on NIC %ws returns recoverable FAILURE:0x%08lx!",
szNic,
lRet
);
Sleep(1000);
Status = WBEM_E_CRITICAL_ERROR;
}
else
{
TRACE_INFO(
"EnableStatic on NIC %ws returns FAILURE:0x%08lx!",
szNic,
lRet
);
Status = WBEM_E_CRITICAL_ERROR;
}
}
end:
if (rgIpAddresses != NULL)
{
delete rgIpAddresses;
}
if (rgIpSubnets != NULL)
{
delete rgIpSubnets;
}
if (pRelPath != NULL)
{
delete pRelPath;
}
spNicClassObj = NULL; // smart pointer
spWbemInputInstance = NULL;
TRACE_INFO(L"<- %!FUNC!(Nic=%ws) returns 0x%08lx", szNic, (UINT) Status);
return Status;
}
#endif // OBSOLETE
//
// Sets the list of statically-bound IP addresses for the NIC.
// if NumIpAddresses is 0, the NIC is configured for DHCP.
//
WBEMSTATUS
CfgUtilSetStaticIpAddresses(
IN LPCWSTR szNic,
IN UINT NumIpAddresses,
IN NLB_IP_ADDRESS_INFO *pIpInfo
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
IWbemClassObjectPtr spWbemInputInstance = NULL; // smart pointer
WCHAR *rgIpAddresses = NULL;
WCHAR *rgIpSubnets = NULL;
LPWSTR pRelPath = NULL;
TRACE_INFO(L"-> %!FUNC!(Nic=%ws)", szNic);
//
// If not initialized, fail...
//
if (!g_CfgUtils.IsInitalized())
{
TRACE_CRIT(L"%!FUNC!(Nic=%ws) FAILING because uninitialized", szNic);
Status = WBEM_E_INITIALIZATION_FAILURE;
goto end;
}
if (NumIpAddresses != 0)
{
//
// Convert IP addresses from our internal form into 2D arrays.
//
rgIpAddresses = new WCHAR[NumIpAddresses * WLBS_MAX_CL_IP_ADDR];
rgIpSubnets = new WCHAR[NumIpAddresses * WLBS_MAX_CL_NET_MASK];
if (rgIpAddresses == NULL || rgIpSubnets == NULL)
{
TRACE_CRIT("SetStaticIpAddresses: Alloc failure!");
Status = WBEM_E_OUT_OF_MEMORY;
goto end;
}
for (UINT u=0;u<NumIpAddresses; u++)
{
//
// We extrace each IP address and it's corresponding subnet mask
// from the 2 2D arrays and insert it into a NLB_IP_ADDRESS_INFO
// structure.
//
LPWSTR pIpDest = rgIpAddresses+u*WLBS_MAX_CL_IP_ADDR;
LPWSTR pSubDest = rgIpSubnets+u*WLBS_MAX_CL_NET_MASK;
LPCWSTR pIpSrc = pIpInfo[u].IpAddress;
LPCWSTR pSubSrc = pIpInfo[u].SubnetMask;
UINT len = wcslen(pIpSrc);
UINT len1 = wcslen(pSubSrc);
if ( (len < WLBS_MAX_CL_IP_ADDR) && (len1 < WLBS_MAX_CL_NET_MASK))
{
CopyMemory(pIpDest, pIpSrc, (len+1)*sizeof(WCHAR));
CopyMemory(pSubDest, pSubSrc, (len1+1)*sizeof(WCHAR));
}
else
{
//
// This would be an implementation error in get_multi_string_...
//
ASSERT(FALSE);
goto end;
}
}
}
//
// Get input instance and relpath...
//
Status = CfgUtilGetWmiInputInstanceAndRelPath(
g_CfgUtils.m_spWbemServiceIF,
L"Win32_NetworkAdapterConfiguration", // szClassName
L"SettingID", // szPropertyName
szNic, // szPropertyValue
L"EnableStatic", // szMethodName,
spWbemInputInstance, // smart pointer
&pRelPath // free using delete
);
if (FAILED(Status))
{
goto end;
}
//
// Set up input parameters to the call to Enable static.
//
{
//
// This gets the ip addresses in a 2D WCHAR array -- inner dimension
// is WLBS_MAX_CLI_IP_ADDR.
//
Status = set_multi_string_parameter(
spWbemInputInstance,
L"IPAddress", // szParameterName,
WLBS_MAX_CL_IP_ADDR, // MaxStringLen - in wchars, incl null
NumIpAddresses,
rgIpAddresses
);
if (FAILED(Status))
{
goto end;
}
else
{
TRACE_INFO("SET %lu IP ADDRESSES!", NumIpAddresses);
}
Status = set_multi_string_parameter(
spWbemInputInstance,
L"SubnetMask", // szParameterName,
WLBS_MAX_CL_NET_MASK, // MaxStringLen - in wchars, incl null
NumIpAddresses,
rgIpSubnets
);
if (FAILED(Status))
{
goto end;
}
}
//
// execute method and get the output result
// WARNING: we try this a few times because the wmi call apperears to
// suffer from a recoverable error. TODO: Need to get to the bottom of
// this.
//
for (UINT NumTries=10; NumTries--;)
{
HRESULT hr;
IWbemClassObjectPtr spWbemOutput = NULL; // smart pointer.
_variant_t v_retVal;
TRACE_CRIT("Going to call EnableStatic");
hr = g_CfgUtils.m_spWbemServiceIF->ExecMethod(
_bstr_t(pRelPath),
L"EnableStatic",
0,
NULL,
spWbemInputInstance,
&spWbemOutput,
NULL
);
TRACE_CRIT("EnableStatic returns");
if( FAILED( hr) )
{
TRACE_CRIT("IWbemServices::ExecMethod failure 0x%08lx", (UINT) hr);
goto end;
}
hr = spWbemOutput->Get(
L"ReturnValue",
0,
&v_retVal,
NULL,
NULL
);
if( FAILED( hr) )
{
TRACE_CRIT("IWbemClassObject::Get failure");
goto end;
}
LONG lRet = (LONG) v_retVal;
v_retVal.Clear();
if (lRet == 0)
{
TRACE_INFO("EnableStatic returns SUCCESS!");
Status = WBEM_NO_ERROR;
break;
}
else if (lRet == 0x51) // This appears to be a recoverable error
{
TRACE_INFO(
"EnableStatic on NIC %ws returns recoverable FAILURE:0x%08lx!",
szNic,
lRet
);
Sleep(1000);
Status = WBEM_E_CRITICAL_ERROR;
}
else
{
TRACE_INFO(
"EnableStatic on NIC %ws returns FAILURE:0x%08lx!",
szNic,
lRet
);
Status = WBEM_E_CRITICAL_ERROR;
}
}
end:
if (rgIpAddresses != NULL)
{
delete rgIpAddresses;
}
if (rgIpSubnets != NULL)
{
delete rgIpSubnets;
}
if (pRelPath != NULL)
{
delete pRelPath;
}
spWbemInputInstance = NULL;
TRACE_INFO(L"<- %!FUNC!(Nic=%ws) returns 0x%08lx", szNic, (UINT) Status);
return Status;
}
//
// Determines whether NLB is bound to the specified NIC.
//
WBEMSTATUS
CfgUtilCheckIfNlbBound(
IN LPCWSTR szNic,
OUT BOOL *pfBound
)
{
WBEMSTATUS Status = WBEM_NO_ERROR;
BOOL fNetCfgInitialized = FALSE;
MyNetCfg NetCfg;
BOOL fBound = FALSE;
//
// Get and initialize interface to netcfg
//
Status = NetCfg.Initialize(FALSE); // FALSE == don't get write lock.
if (FAILED(Status))
{
goto end;
}
fNetCfgInitialized = TRUE;
//
//
//
Status = NetCfg.UpdateBindingState(
szNic,
L"ms_wlbs",
MyNetCfg::NOOP,
&fBound
);
end:
if (fNetCfgInitialized)
{
NetCfg.Deinitialize();
}
*pfBound = fBound;
return Status;
}
//
// Binds/unbinds NLB to the specified NIC.
//
WBEMSTATUS
CfgUtilChangeNlbBindState(
IN LPCWSTR szNic,
IN BOOL fBind
)
{
WBEMSTATUS Status = WBEM_NO_ERROR;
BOOL fNetCfgInitialized = FALSE;
MyNetCfg NetCfg;
BOOL fBound = FALSE;
//
// Get and initialize interface to netcfg
//
Status = NetCfg.Initialize(TRUE); // TRUE == get write lock.
if (FAILED(Status))
{
goto end;
}
fNetCfgInitialized = TRUE;
//
//
//
Status = NetCfg.UpdateBindingState(
szNic,
L"ms_wlbs",
fBind ? MyNetCfg::BIND : MyNetCfg::UNBIND,
&fBound
);
end:
if (fNetCfgInitialized)
{
NetCfg.Deinitialize();
}
return Status;
}
//
// Gets the current NLB configuration for the specified NIC
//
WBEMSTATUS
CfgUtilGetNlbConfig(
IN LPCWSTR szNic,
OUT WLBS_REG_PARAMS *pParams
)
{
GUID Guid;
WBEMSTATUS Status = WBEM_NO_ERROR;
CWlbsCluster *pCluster = NULL;
// g_CfgUtils.mfn_Lock(); // Because pCluster is not protected...
Status = g_CfgUtils.GetClusterFromGuid(
szNic,
&pCluster
);
if (FAILED(Status))
{
goto end;
}
//
// Read the configuration.
//
DWORD dwRet = pCluster->ReadConfig(pParams);
if (dwRet != WLBS_OK)
{
TRACE_CRIT("Could not read NLB configuration for %wsz", szNic);
Status = WBEM_E_CRITICAL_ERROR;
goto end;
}
Status = WBEM_NO_ERROR;
end:
// g_CfgUtils.mfn_Unlock();
return Status;
}
//
// Sets the current NLB configuration for the specified NIC. This
// includes notifying the driver if required.
//
WBEMSTATUS
CfgUtilSetNlbConfig(
IN LPCWSTR szNic,
IN WLBS_REG_PARAMS *pParams
)
{
GUID Guid;
WBEMSTATUS Status = WBEM_NO_ERROR;
CWlbsCluster *pCluster = NULL;
DWORD dwRet = 0;
// NOTE: we assume pCluster won't go away -- i.e. no one is trying
// to unbind in this process' context.
// someone else remove it say fron netconfig UI?
Status = g_CfgUtils.GetClusterFromGuid(
szNic,
&pCluster
);
if (FAILED(Status))
{
goto end;
}
//
// Write the configuration.
//
dwRet = pCluster->WriteConfig(pParams);
if (dwRet != WLBS_OK)
{
TRACE_CRIT("Could not write NLB configuration for %wsz. Err=0x%08lx",
szNic, dwRet);
Status = WBEM_E_CRITICAL_ERROR;
goto end;
}
//
// Commit the changes.
//
dwRet = pCluster->CommitChanges(g_CfgUtils.m_pWlbsControl);
if (dwRet != WLBS_OK)
{
TRACE_CRIT("Could not commit changes to NLB configuration for %wsz. Err=0x%08lx",
szNic, dwRet);
Status = WBEM_E_CRITICAL_ERROR;
goto end;
}
Status = WBEM_NO_ERROR;
end:
return Status;
}
WBEMSTATUS
CfgUtilsAnalyzeNlbUpdate(
IN WLBS_REG_PARAMS *pCurrentParams, OPTIONAL
IN WLBS_REG_PARAMS *pNewParams,
OUT BOOL *pfConnectivityChange
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
BOOL fConnectivityChange = FALSE;
//
// If not initialized, fail...
//
if (!g_CfgUtils.IsInitalized())
{
TRACE_CRIT(L"%!FUNC! FAILING because uninitialized");
Status = WBEM_E_INITIALIZATION_FAILURE;
goto end;
}
if (pCurrentParams != NULL)
{
//
// If the structures have identical content, we return S_FALSE.
// We do this check before we call ValidateParm below, because
// ValidateParam has the side effect of filling out / modifying
// certain fields.
//
if (memcmp(pCurrentParams, pNewParams, sizeof(*pCurrentParams))==0)
{
Status = WBEM_S_FALSE;
goto end;
}
}
//
// Validate pNewParams -- this may also modify pNewParams slightly, by
// re-formatting ip addresses into canonical format.
//
BOOL fRet = g_CfgUtils.m_pWlbsControl->ValidateParam(pNewParams);
if (!fRet)
{
TRACE_CRIT(L"%!FUNC!FAILING because New params are invalid");
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
Status = WBEM_NO_ERROR;
if (pCurrentParams == NULL)
{
//
// NLB was not previously bound.
//
fConnectivityChange = TRUE;
goto end;
}
//
// Change in multicast modes or mac address.
//
if ( (pCurrentParams->mcast_support != pNewParams->mcast_support)
|| _wcsicmp(pCurrentParams->cl_mac_addr, pNewParams->cl_mac_addr)!=0)
{
fConnectivityChange = TRUE;
}
//
// Change in primary cluster ip or subnet mask
//
if ( _wcsicmp(pCurrentParams->cl_ip_addr,pNewParams->cl_ip_addr)!=0
|| _wcsicmp(pCurrentParams->cl_net_mask,pNewParams->cl_net_mask)!=0)
{
fConnectivityChange = TRUE;
}
end:
*pfConnectivityChange = fConnectivityChange;
return Status;
}
WBEMSTATUS
CfgUtilsValidateNicGuid(
IN LPCWSTR szGuid
)
//
//
{
//
// Sample GUID: {EBE09517-07B4-4E88-AAF1-E06F5540608B}
//
WBEMSTATUS Status = WBEM_E_INVALID_PARAMETER;
UINT Length = wcslen(szGuid);
if (Length != NLB_GUID_LEN)
{
TRACE_CRIT("Length != %d", NLB_GUID_LEN);
goto end;
}
//
// Open tcpip's registry key and look for guid there -- if not found,
// we'll return WBEM_E_NOT_FOUND
//
{
WCHAR szKey[128]; // This is enough for the tcpip+guid key
wcscpy(szKey,
L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\"
);
wcscat(szKey, szGuid);
HKEY hKey = NULL;
LONG lRet;
lRet = RegOpenKeyEx(
HKEY_LOCAL_MACHINE, // handle to an open key
szKey, // address of subkey name
0, // reserved
KEY_QUERY_VALUE, // desired security access
&hKey // address of buffer for opened handle
);
if (lRet != ERROR_SUCCESS)
{
TRACE_CRIT("Guid %ws doesn't exist under tcpip", szGuid);
Status = WBEM_E_NOT_FOUND;
goto end;
}
RegCloseKey(hKey);
}
Status = WBEM_NO_ERROR;
end:
return Status;
}
WBEMSTATUS
get_string_parameter(
IN IWbemClassObjectPtr spObj,
IN LPCWSTR szParameterName,
OUT LPWSTR *ppStringValue
)
{
WBEMSTATUS Status = WBEM_E_NOT_FOUND;
WCHAR *pStringValue = NULL;
_variant_t v_value;
CIMTYPE v_type;
HRESULT hr;
hr = spObj->Get(
_bstr_t(szParameterName), // Name
0, // Reserved, must be 0
&v_value, // Place to store value
&v_type, // Type of value
NULL // Flavor (unused)
);
if (FAILED(hr))
{
// Couldn't read the Setting ID field!
//
TRACE_CRIT(
"get_str_parm:Couldn't retrieve %ws from 0x%p",
szParameterName,
(PVOID) spObj
);
goto end;
}
else
{
if (v_type != VT_BSTR)
{
TRACE_CRIT(
"get_str_parm: Parm value not of string type %ws from 0x%p",
szParameterName,
(PVOID) spObj
);
Status = WBEM_E_INVALID_PARAMETER;
}
else
{
_bstr_t bstrNicGuid(v_value);
LPCWSTR sz = bstrNicGuid; // Pointer to internal buffer.
if (sz==NULL)
{
// hmm.. null value
Status = WBEM_NO_ERROR;
}
else
{
UINT len = wcslen(sz);
pStringValue = new WCHAR[len+1];
if (pStringValue == NULL)
{
TRACE_CRIT("get_str_parm: Alloc failure!");
Status = WBEM_E_OUT_OF_MEMORY;
}
else
{
CopyMemory(pStringValue, sz, (len+1)*sizeof(WCHAR));
Status = WBEM_NO_ERROR;
}
}
TRACE_VERB(
"get_str_parm: String parm %ws of 0x%p is %ws",
szParameterName,
(PVOID) spObj,
(sz==NULL) ? L"<null>" : sz
);
}
v_value.Clear(); // Must be cleared after each call to Get.
}
end:
*ppStringValue = pStringValue;
return Status;
}
WBEMSTATUS
get_nic_instance(
IN IWbemServicesPtr spWbemServiceIF,
IN LPCWSTR szNicGuid,
OUT IWbemClassObjectPtr &sprefObj
)
{
WBEMSTATUS Status = WBEM_E_NOT_FOUND;
IWbemClassObjectPtr spObj = NULL; // smart pointer.
Status = CfgUtilGetWmiObjectInstance(
spWbemServiceIF,
L"Win32_NetworkAdapterConfiguration", // szClassName
L"SettingID", // szParameterName
szNicGuid, // ParameterValue
spObj // smart pointer, passed by ref
);
if (FAILED(Status))
{
ASSERT(spObj == NULL);
goto end;
}
end:
if (FAILED(Status))
{
sprefObj = NULL;
}
else
{
sprefObj = spObj; // smart pointer.
}
return Status;
}
WBEMSTATUS
get_multi_string_parameter(
IN IWbemClassObjectPtr spObj,
IN LPCWSTR szParameterName,
IN UINT MaxStringLen, // in wchars, INCLUDING space for trailing zeros.
OUT UINT *pNumItems,
OUT LPCWSTR *ppStringValue
)
{
WBEMSTATUS Status = WBEM_E_NOT_FOUND;
WCHAR *pStringValue = NULL;
_variant_t v_value;
CIMTYPE v_type;
HRESULT hr;
LONG count = 0;
*ppStringValue = NULL;
*pNumItems = 0;
hr = spObj->Get(
_bstr_t(szParameterName),
0, // Reserved, must be 0
&v_value, // Place to store value
&v_type, // Type of value
NULL // Flavor (unused)
);
if (FAILED(hr))
{
// Couldn't read the requested parameter.
//
TRACE_CRIT(
"get_multi_str_parm:Couldn't retrieve %ws from 0x%p",
szParameterName,
(PVOID) spObj
);
goto end;
}
{
VARIANT ipsV = v_value.Detach();
do // while false
{
BSTR* pbstr;
if (ipsV.vt == VT_NULL)
{
//
// NULL string -- this is ok
//
count = 0;
}
else
{
count = ipsV.parray->rgsabound[0].cElements;
}
if (count==0)
{
Status = WBEM_NO_ERROR;
break;
}
pStringValue = new WCHAR[count*MaxStringLen];
if (pStringValue == NULL)
{
TRACE_CRIT("get_multi_str_parm: Alloc failure!");
Status = WBEM_E_OUT_OF_MEMORY;
break;
}
ZeroMemory(pStringValue, sizeof(WCHAR)*count*MaxStringLen);
hr = SafeArrayAccessData(ipsV.parray, ( void **) &pbstr);
if(FAILED(hr))
{
Status = WBEM_E_INVALID_PARAMETER; // TODO: pick better error
break;
}
Status = WBEM_NO_ERROR;
for( LONG x = 0; x < count; x++ )
{
LPCWSTR sz = pbstr[x]; // Pointer to internal buffer.
if (sz==NULL)
{
// hmm.. null value
continue;
}
else
{
UINT len = wcslen(sz);
if ((len+1) > MaxStringLen)
{
TRACE_CRIT("get_str_parm: string size too long!");
Status = WBEM_E_INVALID_PARAMETER;
break;
}
else
{
WCHAR *pDest = pStringValue+x*MaxStringLen;
CopyMemory(pDest, sz, (len+1)*sizeof(WCHAR));
}
}
}
(VOID) SafeArrayUnaccessData( ipsV.parray );
} while (FALSE);
VariantClear( &ipsV );
}
if (FAILED(Status))
{
if (pStringValue!=NULL)
{
delete pStringValue;
*pStringValue = NULL;
}
}
else
{
*ppStringValue = pStringValue;
*pNumItems = count;
}
end:
return Status;
}
WBEMSTATUS
MyNetCfg::Initialize(
BOOL fWriteLock
)
{
HRESULT hr;
INetCfg *pnc = NULL;
INetCfgLock *pncl = NULL;
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
BOOL fLocked = FALSE;
BOOL fInitialized=FALSE;
if (m_pINetCfg != NULL || m_pLock != NULL)
{
ASSERT(FALSE);
goto end;
}
hr = CoCreateInstance( CLSID_CNetCfg,
NULL,
CLSCTX_SERVER,
IID_INetCfg,
(void **) &pnc);
if( !SUCCEEDED( hr ) )
{
// failure to create instance.
TRACE_CRIT("ERROR: could not get interface to Net Config");
goto end;
}
//
// If require, get the write lock
//
if (fWriteLock)
{
WCHAR *szLockedBy = NULL;
hr = pnc->QueryInterface( IID_INetCfgLock, ( void **) &pncl );
if( !SUCCEEDED( hr ) )
{
TRACE_CRIT("ERROR: could not get interface to NetCfg Lock");
goto end;
}
hr = pncl->AcquireWriteLock( 1, // One Second
L"NLBManager",
&szLockedBy);
if( hr != S_OK )
{
TRACE_CRIT("Could not get write lock. Lock held by %ws",
(szLockedBy!=NULL) ? szLockedBy : L"<null>");
goto end;
}
}
// Initializes network configuration by loading into
// memory all basic networking information
//
hr = pnc->Initialize( NULL );
if( !SUCCEEDED( hr ) )
{
// failure to Initialize
TRACE_CRIT("INetCfg::Initialize failure ");
goto end;
}
Status = WBEM_NO_ERROR;
end:
if (FAILED(Status))
{
if (pncl!=NULL)
{
if (fLocked)
{
pncl->ReleaseWriteLock();
}
pncl->Release();
pncl=NULL;
}
if( pnc != NULL)
{
if (fInitialized)
{
pnc->Uninitialize();
}
pnc->Release();
pnc= NULL;
}
}
else
{
m_pINetCfg = pnc;
m_pLock = pncl;
}
return Status;
}
VOID
MyNetCfg::Deinitialize(
VOID
)
{
if (m_pLock!=NULL)
{
m_pLock->ReleaseWriteLock();
m_pLock->Release();
m_pLock=NULL;
}
if( m_pINetCfg != NULL)
{
m_pINetCfg->Uninitialize();
m_pINetCfg->Release();
m_pINetCfg= NULL;
}
}
WBEMSTATUS
MyNetCfg::GetNicIF(
IN LPCWSTR szNicGuid,
OUT INetCfgComponent **ppINic
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
INetCfgComponent *pncc = NULL;
HRESULT hr;
IEnumNetCfgComponent* pencc = NULL;
ULONG countToFetch = 1;
ULONG countFetched;
DWORD characteristics;
if (m_pINetCfg == NULL)
{
//
// This means we're not initialized
//
ASSERT(FALSE);
goto end;
}
hr = m_pINetCfg->EnumComponents( &GUID_DEVCLASS_NET, &pencc );
if( !SUCCEEDED( hr ) )
{
// failure to Enumerate net components
TRACE_CRIT("Could not enum netcfg adapters");
pencc = NULL;
goto end;
}
while( ( hr = pencc->Next( countToFetch, &pncc, &countFetched ) )== S_OK )
{
LPWSTR szName = NULL;
hr = pncc->GetBindName( &szName );
if (!SUCCEEDED(hr))
{
TRACE_CRIT("WARNING: couldn't get bind name for 0x%p, ignoring",
(PVOID) pncc);
continue;
}
if(!_wcsicmp(szName, szNicGuid))
{
//
// Got this one!
//
CoTaskMemFree( szName );
break;
}
CoTaskMemFree( szName );
pncc->Release();
pncc=NULL;
}
if (pncc == NULL)
{
TRACE_CRIT("Could not find NIC %ws", szNicGuid);
Status = WBEM_E_NOT_FOUND;
}
else
{
Status = WBEM_NO_ERROR;
}
end:
if (pencc != NULL)
{
pencc->Release();
}
*ppINic = pncc;
return Status;
}
LPWSTR *
CfgUtilsAllocateStringArray(
UINT NumStrings,
UINT MaxStringLen // excluding ending NULL
)
/*
Allocate a single chunk of memory using the new LPWSTR[] operator.
The first NumStrings LPWSTR values of this operator contain an array
of pointers to WCHAR strings. Each of these strings
is of size (MaxStringLen+1) WCHARS.
The rest of the memory contains the strings themselve.
Return NULL if NumStrings==0 or on allocation failure.
Each of the strings are initialized to be empty strings (first char is 0).
*/
{
LPWSTR *pStrings = NULL;
UINT TotalSize = 0;
if (NumStrings == 0)
{
goto end;
}
//
// Note - even if MaxStringLen is 0 we will allocate space for NumStrings
// pointers and NumStrings empty (first char is 0) strings.
//
//
// Calculate space for the array of pointers to strings...
//
TotalSize = NumStrings*sizeof(LPWSTR);
//
// Calculate space for the strings themselves...
// Remember to add +1 for each ending 0 character.
//
TotalSize += NumStrings*(MaxStringLen+1)*sizeof(WCHAR);
//
// Allocate space for *both* the array of pointers and the strings
// in one shot -- we're doing a new of type LPWSTR[] for the whole
// lot, so need to specify the size in units of LPWSTR (with an
// additional +1 in case there's roundoff.
//
pStrings = new LPWSTR[(TotalSize/sizeof(LPWSTR))+1];
if (pStrings == NULL)
{
goto end;
}
//
// Make sz point to the start of the place where we'll be placing
// the string data.
//
LPWSTR sz = (LPWSTR) (pStrings+NumStrings);
for (UINT u=0; u<NumStrings; u++)
{
*sz=NULL;
pStrings[u] = sz;
sz+=(MaxStringLen+1); // +1 for ending NULL
}
end:
return pStrings;
}
WBEMSTATUS
MyNetCfg::GetNlbCompatibleNics(
OUT LPWSTR **ppszNics,
OUT UINT *pNumNics,
OUT UINT *pNumBoundToNlb // OPTIONAL
)
/*
Returns an array of pointers to string-version of GUIDS
that represent the set of alive and healthy NICS that are
suitable for NLB to bind to -- basically alive ethernet NICs.
Delete ppNics using the delete WCHAR[] operator. Do not
delete the individual strings.
*/
{
#define MY_GUID_LENGTH 38
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
HRESULT hr;
IEnumNetCfgComponent* pencc = NULL;
INetCfgComponent *pncc = NULL;
ULONG countToFetch = 1;
ULONG countFetched;
DWORD characteristics;
UINT NumNics = 0;
LPWSTR *pszNics = NULL;
INetCfgComponentBindings *pINlbBinding=NULL;
UINT NumNlbBoundNics = 0;
typedef struct _MYNICNODE MYNICNODE;
typedef struct _MYNICNODE
{
LPWSTR szNicGuid;
MYNICNODE *pNext;
} MYNICNODE;
MYNICNODE *pNicNodeList = NULL;
MYNICNODE *pNicNode = NULL;
*ppszNics = NULL;
*pNumNics = 0;
if (pNumBoundToNlb != NULL)
{
*pNumBoundToNlb = 0;
}
if (m_pINetCfg == NULL)
{
//
// This means we're not initialized
//
ASSERT(FALSE);
goto end;
}
hr = m_pINetCfg->EnumComponents( &GUID_DEVCLASS_NET, &pencc );
if( !SUCCEEDED( hr ) )
{
// failure to Enumerate net components
TRACE_CRIT("%!FUNC! Could not enum netcfg adapters");
pencc = NULL;
goto end;
}
//
// Check if nlb is bound to the nlb component.
//
//
// If we need to count of NLB-bound nics, get instance of the nlb component
//
if (pNumBoundToNlb != NULL)
{
Status = GetBindingIF(L"ms_wlbs", &pINlbBinding);
if (FAILED(Status))
{
TRACE_CRIT("%!FUNC! WARNING: NLB doesn't appear to be installed on this machine");
pINlbBinding = NULL;
}
}
while( ( hr = pencc->Next( countToFetch, &pncc, &countFetched ) )== S_OK )
{
LPWSTR szName = NULL;
hr = pncc->GetBindName( &szName );
if (!SUCCEEDED(hr))
{
TRACE_CRIT("%!FUNC! WARNING: couldn't get bind name for 0x%p, ignoring",
(PVOID) pncc);
continue;
}
do // while FALSE -- just to allow breaking out
{
UINT Len = wcslen(szName);
if (Len != MY_GUID_LENGTH)
{
TRACE_CRIT("%!FUNC! WARNING: GUID %ws has unexpected length %ul",
szName, Len);
break;
}
DWORD characteristics = 0;
hr = pncc->GetCharacteristics( &characteristics );
if(!SUCCEEDED(hr))
{
TRACE_CRIT("%!FUNC! WARNING: couldn't get characteristics for %ws, ignoring",
szName);
break;
}
if(characteristics & NCF_PHYSICAL)
{
ULONG devstat = 0;
// This is a physical network card.
// we are only interested in such devices
// check if the nic is enabled, we are only
// interested in enabled nics.
//
hr = pncc->GetDeviceStatus( &devstat );
if(!SUCCEEDED(hr))
{
TRACE_CRIT(
"%!FUNC! WARNING: couldn't get dev status for %ws, ignoring",
szName
);
break;
}
// if any of the nics has any of the problem codes
// then it cannot be used.
if( devstat != CM_PROB_NOT_CONFIGURED
&&
devstat != CM_PROB_FAILED_START
&&
devstat != CM_PROB_NORMAL_CONFLICT
&&
devstat != CM_PROB_NEED_RESTART
&&
devstat != CM_PROB_REINSTALL
&&
devstat != CM_PROB_WILL_BE_REMOVED
&&
devstat != CM_PROB_DISABLED
&&
devstat != CM_PROB_FAILED_INSTALL
&&
devstat != CM_PROB_FAILED_ADD
)
{
//
// No problem with this nic and also
// physical device
// thus we want it.
//
if (pINlbBinding != NULL)
{
BOOL fBound = FALSE;
hr = pINlbBinding->IsBoundTo(pncc);
if( !SUCCEEDED( hr ) )
{
TRACE_CRIT("IsBoundTo method failed for Nic %ws", szName);
goto end;
}
if( hr == S_OK )
{
TRACE_VERB("BOUND: %ws\n", szName);
NumNlbBoundNics++;
fBound = TRUE;
}
else if (hr == S_FALSE )
{
TRACE_VERB("NOT BOUND: %ws\n", szName);
fBound = FALSE;
}
}
// We allocate a little node to keep this string
// temporarily and add it to our list of nodes.
//
pNicNode = new MYNICNODE;
if (pNicNode == NULL)
{
Status = WBEM_E_OUT_OF_MEMORY;
goto end;
}
ZeroMemory(pNicNode, sizeof(*pNicNode));
pNicNode->szNicGuid = szName;
szName = NULL; // so we don't delete inside the lopp.
pNicNode->pNext = pNicNodeList;
pNicNodeList = pNicNode;
NumNics++;
}
else
{
// There is a problem...
TRACE_CRIT(
"%!FUNC! WARNING: Skipping %ws because DeviceStatus=0x%08lx",
szName, devstat
);
break;
}
}
else
{
TRACE_VERB("%!FUNC! Ignoring non-physical device %ws", szName);
}
} while (FALSE);
if (szName != NULL)
{
CoTaskMemFree( szName );
}
pncc->Release();
pncc=NULL;
}
if (pINlbBinding!=NULL)
{
pINlbBinding->Release();
pINlbBinding = NULL;
}
if (NumNics==0)
{
Status = WBEM_NO_ERROR;
goto end;
}
//
// Now let's allocate space for all the nic strings and:w
// copy them over..
//
#define MY_GUID_LENGTH 38
pszNics = CfgUtilsAllocateStringArray(NumNics, MY_GUID_LENGTH);
if (pszNics == NULL)
{
Status = WBEM_E_OUT_OF_MEMORY;
goto end;
}
pNicNode= pNicNodeList;
for (UINT u=0; u<NumNics; u++, pNicNode=pNicNode->pNext)
{
ASSERT(pNicNode != NULL); // because we just counted NumNics of em.
UINT Len = wcslen(pNicNode->szNicGuid);
if (Len != MY_GUID_LENGTH)
{
//
// We should never get here beause we checked the length earlier.
//
TRACE_CRIT("%!FUNC! ERROR: GUID %ws has unexpected length %ul",
pNicNode->szNicGuid, Len);
ASSERT(FALSE);
Status = WBEM_E_CRITICAL_ERROR;
goto end;
}
CopyMemory(
pszNics[u],
pNicNode->szNicGuid,
(MY_GUID_LENGTH+1)*sizeof(WCHAR));
ASSERT(pszNics[u][MY_GUID_LENGTH]==0);
}
Status = WBEM_NO_ERROR;
end:
//
// Now release the temporarly allocated memory.
//
pNicNode= pNicNodeList;
while (pNicNode!=NULL)
{
MYNICNODE *pTmp = pNicNode->pNext;
CoTaskMemFree(pNicNode->szNicGuid);
pNicNode->szNicGuid = NULL;
delete pNicNode;
pNicNode = pTmp;
}
if (FAILED(Status))
{
TRACE_CRIT("%!FUNC! fails with status 0x%08lx", (UINT) Status);
NumNics = 0;
if (pszNics!=NULL)
{
delete pszNics;
pszNics = NULL;
}
}
else
{
if (pNumBoundToNlb != NULL)
{
*pNumBoundToNlb = NumNlbBoundNics;
}
*ppszNics = pszNics;
*pNumNics = NumNics;
}
if (pencc != NULL)
{
pencc->Release();
}
return Status;
}
WBEMSTATUS
MyNetCfg::GetBindingIF(
IN LPCWSTR szComponent,
OUT INetCfgComponentBindings **ppIBinding
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
INetCfgComponent *pncc = NULL;
INetCfgComponentBindings *pnccb = NULL;
HRESULT hr;
if (m_pINetCfg == NULL)
{
//
// This means we're not initialized
//
ASSERT(FALSE);
goto end;
}
hr = m_pINetCfg->FindComponent(szComponent, &pncc);
if (FAILED(hr))
{
TRACE_CRIT("Error checking if component %ws does not exist\n", szComponent);
pncc = NULL;
goto end;
}
else if (hr == S_FALSE)
{
Status = WBEM_E_NOT_FOUND;
TRACE_CRIT("Component %ws does not exist\n", szComponent);
goto end;
}
hr = pncc->QueryInterface( IID_INetCfgComponentBindings, (void **) &pnccb );
if( !SUCCEEDED( hr ) )
{
TRACE_CRIT("INetCfgComponent::QueryInterface failed ");
pnccb = NULL;
goto end;
}
Status = WBEM_NO_ERROR;
end:
if (pncc)
{
pncc->Release();
pncc=NULL;
}
*ppIBinding = pnccb;
return Status;
}
WBEMSTATUS
set_string_parameter(
IN IWbemClassObjectPtr spObj,
IN LPCWSTR szParameterName,
IN LPCWSTR szValue
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
HRESULT hr;
{
_bstr_t bstrName = szParameterName;
_variant_t v_value = (LPWSTR) szValue; // Allocates.
hr = spObj->Put(
bstrName, // Parameter Name
0, // Must be 0
&v_value,
0 // Must be 0
);
v_value.Clear();
if (FAILED(hr))
{
TRACE_CRIT("Unable to put parameter %ws", szParameterName);
goto end;
}
Status = WBEM_NO_ERROR;
//
// I think bstrName releases the internally allocated string
// on exiting this block.
//
}
end:
return Status;
}
WBEMSTATUS
set_multi_string_parameter(
IN IWbemClassObjectPtr spObj,
IN LPCWSTR szParameterName,
IN UINT MaxStringLen, // in wchars, INCLUDING space for trailing zeros.
IN UINT NumItems,
IN LPCWSTR pStringValue
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
SAFEARRAY *pSA = NULL;
HRESULT hr;
LONG Index = 0;
//
// Create safe array for the parameter values
//
pSA = SafeArrayCreateVector(
VT_BSTR,
0, // lower bound
NumItems // size of the fixed-sized vector.
);
if (pSA == NULL)
{
TRACE_CRIT("Could not create safe array");
Status = WBEM_E_OUT_OF_MEMORY;
goto end;
}
//
// Place the strings into the safe array
//
{
for (Index = 0; Index<NumItems; Index++)
{
LPCWSTR sz = pStringValue + Index*MaxStringLen;
//
// SafeArrayPutElement expects the string passed in to
// be of type BSTR, which is of type wchar *, except, that
// the first 2 wchars contains length and other(?)
// information. This is why you can't simply pass in sz.
//
// So to get this we initalize an object of type _bstr_t
// based on sz. On initializaton, bstrValue allocates memory
// and copies the string.
//
_bstr_t bstrValue = sz;
wchar_t *pwchar = (wchar_t *) bstrValue; // returns internal pointer.
// bpStr[Index] = sz; // may work as well.
//
// SafeArrayPutElement internally allocates space for pwchar and
// copies over the string.
// So pSA doesn't contain a direct reference to pwchar.
//
hr = SafeArrayPutElement(pSA, &Index, pwchar);
if (FAILED(hr))
{
TRACE_CRIT("Unable to put element %wsz", sz);
(VOID) SafeArrayUnaccessData(pSA);
goto end;
}
//
// I think that bstrValue's contents are deallocated on exit of
// this block.
//
}
}
#if DBG
//
// Just check ...
//
{
BSTR *pbStr=NULL;
hr = SafeArrayAccessData(pSA, ( void **) &pbStr);
if (FAILED(hr))
{
TRACE_CRIT("Could not access data of safe array");
goto end;
}
for (UINT u = 0; u<NumItems; u++)
{
LPCWSTR sz = pbStr[u];
if (_wcsicmp(sz, (pStringValue + u*MaxStringLen)))
{
TRACE_CRIT("!!!MISMATCH!!!!");
}
else
{
TRACE_CRIT("!!!MATCH!!!!");
}
}
(VOID) SafeArrayUnaccessData(pSA);
pbStr=NULL;
}
#endif // DBG
//
// Put the parameter.
//
{
VARIANT V;
_bstr_t bstrName = szParameterName;
VariantInit(&V);
V.vt = VT_ARRAY | VT_BSTR;
V.parray = pSA;
_variant_t v_value;
v_value.Attach(V); // Takes owhership of V. V now becomes empty.
ASSERT(V.vt == VT_EMPTY);
pSA = NULL; // should be no need to delete this explicitly now.
// v_value.Clear() should delete it, I think.
hr = spObj->Put(
bstrName, // Parameter Name
0, // Must be 0
&v_value,
0 // Must be 0
);
v_value.Clear();
if (FAILED(hr))
{
TRACE_CRIT("Unable to put parameter %ws", szParameterName);
goto end;
}
Status = WBEM_NO_ERROR;
}
//
// ?Destroy the data?
//
if (FAILED(Status))
{
if (pSA!=NULL)
{
SafeArrayDestroy(pSA);
pSA = NULL;
}
}
end:
return Status;
}
WBEMSTATUS
MyNetCfg::UpdateBindingState(
IN LPCWSTR szNic,
IN LPCWSTR szComponent,
IN UPDATE_OP Op,
OUT BOOL *pfBound
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
INetCfgComponent *pINic = NULL;
INetCfgComponentBindings *pIBinding=NULL;
BOOL fBound = FALSE;
HRESULT hr;
//
// Get instance to the NIC
//
Status = GetNicIF(szNic, &pINic);
if (FAILED(Status))
{
pINic = NULL;
goto end;
}
//
// Get instance of the nlb component
//
Status = GetBindingIF(szComponent, &pIBinding);
if (FAILED(Status))
{
pIBinding = NULL;
goto end;
}
//
// Check if nlb is bound to the nlb component.
//
hr = pIBinding->IsBoundTo(pINic);
if( !SUCCEEDED( hr ) )
{
TRACE_CRIT("IsBoundTo method failed for Nic %ws", szNic);
goto end;
}
if( hr == S_OK )
{
fBound = TRUE;
}
else if (hr == S_FALSE )
{
fBound = FALSE;
}
if ( (Op == MyNetCfg::NOOP)
|| (Op == MyNetCfg::BIND && fBound)
|| (Op == MyNetCfg::UNBIND && !fBound))
{
Status = WBEM_NO_ERROR;
goto end;
}
if (Op == MyNetCfg::BIND)
{
hr = pIBinding->BindTo( pINic );
}
else if (Op == MyNetCfg::UNBIND)
{
hr = pIBinding->UnbindFrom( pINic );
}
else
{
ASSERT(FALSE);
goto end;
}
if (FAILED(hr))
{
TRACE_CRIT("Error 0x%08lx %ws %ws on %ws",
(UINT) hr,
((Op==MyNetCfg::BIND) ? L"binding" : L"unbinding"),
szComponent,
szNic
);
goto end;
}
//
// apply the binding change made.
//
hr = m_pINetCfg->Apply();
if( !SUCCEEDED( hr ) )
{
TRACE_CRIT("INetCfg::Apply failed with 0x%08lx", (UINT) hr);
goto end;
}
//
// We're done. Our state should now be toggled.
//
fBound = !fBound;
Status = WBEM_NO_ERROR;
end:
if (pINic!=NULL)
{
pINic->Release();
pINic = NULL;
}
if (pIBinding!=NULL)
{
pIBinding->Release();
pIBinding = NULL;
}
*pfBound = fBound;
return Status;
}
WBEMSTATUS
CfgUtilControlCluster(
IN LPCWSTR szNic,
IN LONG ioctl
)
{
HRESULT hr;
GUID Guid;
WBEMSTATUS Status;
if (!g_CfgUtils.IsInitalized())
{
TRACE_CRIT(L"%!FUNC!(Nic=%ws) FAILING because uninitialized", szNic);
Status = WBEM_E_INITIALIZATION_FAILURE;
goto end;
}
hr = CLSIDFromString((LPWSTR)szNic, &Guid);
if (FAILED(hr))
{
TRACE_CRIT(
"CWlbsControl::Initialize failed at CLSIDFromString %ws",
szNic
);
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
TRACE_INFO("Going to stop cluster on NIC %ws...", szNic);
DWORD dwRet = g_CfgUtils.m_pWlbsControl->LocalClusterControl(
Guid,
ioctl
);
TRACE_INFO("Stop cluster returned with wlbs error 0x%08lx", dwRet);
Status = WBEM_NO_ERROR;
switch(dwRet)
{
case WLBS_ALREADY: break;
case WLBS_CONVERGED: break;
case WLBS_CONVERGING: break;
case WLBS_DEFAULT: break;
case WLBS_DRAIN_STOP: break;
case WLBS_DRAINING: break;
case WLBS_OK: break;
case WLBS_STOPPED: break;
case WLBS_SUSPENDED: break;
case WLBS_BAD_PARAMS: Status = WBEM_E_INVALID_PARAMETER; break;
default: Status = WBEM_E_CRITICAL_ERROR; break;
}
end:
return Status;
}
//
// Initializes pParams using default values.
//
VOID
CfgUtilInitializeParams(
OUT WLBS_REG_PARAMS *pParams
)
{
//
// We don't expect WlbsSetDefaults to fail (it should have been
// defined returning VOID.
//
DWORD dwRet;
dwRet = WlbsSetDefaults(pParams);
if (dwRet != WLBS_OK)
{
ZeroMemory(pParams, sizeof(*pParams));
TRACE_CRIT("Internal error: WlbsSetDefaults failed");
ASSERT(FALSE);
}
}
WBEMSTATUS
CfgUtilSafeArrayFromStrings(
IN LPCWSTR *pStrings,
IN UINT NumStrings,
OUT SAFEARRAY **ppSA
)
/*
Allocates and returns a SAFEARRAY of strings -- strings are copies of
the passed in values.
Call SafeArrayDestroy when done with the array.
*/
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
SAFEARRAY *pSA = NULL;
HRESULT hr;
LONG Index = 0;
*ppSA = NULL;
//
// Create safe array for the parameter values
//
pSA = SafeArrayCreateVector(
VT_BSTR,
0, // lower bound
NumStrings // size of the fixed-sized vector.
);
if (pSA == NULL)
{
TRACE_CRIT("Could not create safe array");
Status = WBEM_E_OUT_OF_MEMORY;
goto end;
}
//
// Place the strings into the safe array
//
{
for (Index = 0; Index<NumStrings; Index++)
{
LPCWSTR sz = pStrings[Index];
//
// SafeArrayPutElement expects the string passed in to
// be of type BSTR, which is of type wchar *, except, that
// the first 2 wchars contains length and other(?)
// information. This is why you can't simply pass in sz.
//
// So to get this we initalize an object of type _bstr_t
// based on sz. On initializaton, bstrValue allocates memory
// and copies the string.
//
_bstr_t bstrValue = sz;
wchar_t *pwchar = (wchar_t *) bstrValue; // returns internal pointer.
// bpStr[Index] = sz; // may work as well.
//
// SafeArrayPutElement internally allocates space for pwchar and
// copies over the string.
// So pSA doesn't contain a direct reference to pwchar.
//
hr = SafeArrayPutElement(pSA, &Index, pwchar);
if (FAILED(hr))
{
TRACE_CRIT("Unable to put element %wsz", sz);
(VOID) SafeArrayUnaccessData(pSA);
goto end;
}
//
// I think that bstrValue's contents are deallocated on exit of
// this block.
//
}
}
Status = WBEM_NO_ERROR;
end:
if (FAILED(Status))
{
if (pSA!=NULL)
{
SafeArrayDestroy(pSA);
pSA = NULL;
}
}
*ppSA = pSA;
return Status;
}
WBEMSTATUS
CfgUtilStringsFromSafeArray(
IN SAFEARRAY *pSA,
OUT LPWSTR **ppStrings,
OUT UINT *pNumStrings
)
/*
Extracts copies of the strings in the passed-in safe array.
Free *pStrings using the delete operator when done.
NOTE: Do NOT delete the individual strings -- they are
stored in the memory allocated for pStrings.
*/
{
WBEMSTATUS Status = WBEM_E_OUT_OF_MEMORY;
LPWSTR *pStrings = NULL;
LPCWSTR csz;
LPWSTR sz;
UINT NumStrings = 0;
UINT u;
HRESULT hr;
BSTR *pbStr =NULL;
UINT TotalSize =0;
LONG UBound = 0;
*ppStrings = NULL;
*pNumStrings = 0;
hr = SafeArrayGetUBound(pSA, 1, &UBound);
if (FAILED(hr))
{
TRACE_CRIT("Could not get upper bound of safe array");
goto end;
}
NumStrings = (UINT) (UBound+1); // Convert from UpperBound to NumStrings.
if (NumStrings == 0)
{
// nothing in array -- we're done.
Status = WBEM_NO_ERROR;
goto end;
}
hr = SafeArrayAccessData(pSA, ( void **) &pbStr);
if (FAILED(hr))
{
TRACE_CRIT("Could not access data of safe array");
goto end;
}
//
// Calculate space for the array of pointers to strings...
//
TotalSize = NumStrings*sizeof(LPWSTR);
//
// Calculate space for the strings themselves...
//
for (u=0; u<NumStrings; u++)
{
csz = pbStr[u];
TotalSize += (wcslen(csz)+1)*sizeof(WCHAR);
}
//
// Allocate space for *both* the array of pointers and the strings
// in one shot -- we're doing a new of type LPWSTR[] for the whole
// lot, so need to specify the size in units of LPWSTR (with an
// additional +1 in case there's roundoff.
//
pStrings = new LPWSTR[(TotalSize/sizeof(LPWSTR))+1];
if (pStrings == NULL)
{
Status = WBEM_E_OUT_OF_MEMORY;
(VOID) SafeArrayUnaccessData(pSA);
goto end;
}
//
// Make sz point to the start of the place where we'll be placing
// the string data.
//
sz = (LPWSTR) (pStrings+NumStrings);
for (u=0; u<NumStrings; u++)
{
csz = pbStr[u];
UINT len = wcslen(csz)+1;
CopyMemory(sz, csz, len*sizeof(WCHAR));
pStrings[u] = sz;
sz+=len;
}
(VOID) SafeArrayUnaccessData(pSA);
Status = WBEM_NO_ERROR;
end:
pbStr=NULL;
if (FAILED(Status))
{
if (pStrings!=NULL)
{
delete pStrings;
pStrings = NULL;
}
NumStrings = 0;
}
*ppStrings = pStrings;
*pNumStrings = NumStrings;
return Status;
}
WBEMSTATUS
CfgUtilGetWmiObjectInstance(
IN IWbemServicesPtr spWbemServiceIF,
IN LPCWSTR szClassName,
IN LPCWSTR szPropertyName,
IN LPCWSTR szPropertyValue,
OUT IWbemClassObjectPtr &sprefObj // smart pointer
)
{
WBEMSTATUS Status = WBEM_E_NOT_FOUND;
HRESULT hr;
//
// TODO: consider using IWbemServices::ExecQuery
//
IEnumWbemClassObjectPtr spEnum=NULL; // smart pointer
IWbemClassObjectPtr spObj = NULL; // smart pointer.
_bstr_t bstrClassName = szClassName;
//
// get all instances of object
//
hr = spWbemServiceIF->CreateInstanceEnum(
bstrClassName,
WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&spEnum
);
if (FAILED(hr))
{
TRACE_CRIT("IWbemServices::CreateInstanceEnum failure\n" );
spEnum = NULL;
goto end;
}
//
// Look for the object with the matching property.
//
do
{
ULONG count = 1;
hr = spEnum->Next(
INFINITE,
1,
&spObj,
&count
);
//
// Note -- Next() returns S_OK if number asked == number returned.
// and S_FALSE if number asked < than number requested.
// Since we're asking for only ...
//
if (hr == S_OK)
{
LPWSTR szEnumValue = NULL;
Status = get_string_parameter(
spObj,
szPropertyName,
&szEnumValue // Delete when done.
);
if (FAILED(Status))
{
//
// Ignore this failure here.
//
}
else if (szEnumValue!=NULL)
{
BOOL fFound = FALSE;
if (!_wcsicmp(szEnumValue, szPropertyValue))
{
fFound = TRUE;
}
delete szEnumValue;
if (fFound)
{
break; // BREAK BREAK BREAK BREAK
}
}
}
else
{
TRACE_INFO(
"====0x%p->Next() returns Error 0x%lx; count=0x%lu", (PVOID) spObj,
(UINT) hr, count);
}
//
// Since I don't fully trust smart pointers, I'm specifically
// setting spObj to NULL here...
//
spObj = NULL; // smart pointer
} while (hr == S_OK);
if (spObj == NULL)
{
//
// We couldn't find a NIC which matches the one asked for...
//
Status = WBEM_E_NOT_FOUND;
goto end;
}
end:
if (FAILED(Status))
{
sprefObj = NULL;
}
else
{
sprefObj = spObj; // smart pointer.
}
return Status;
}
WBEMSTATUS
CfgUtilGetWmiRelPath(
IN IWbemClassObjectPtr spObj,
OUT LPWSTR * pszRelPath // free using delete
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
LPWSTR pRelPath = NULL;
//
// Extract the relative path, needed for ExecMethod.
//
Status = get_string_parameter(
spObj,
L"__RELPATH", // szParameterName
&pRelPath // Delete when done.
);
if (FAILED(Status))
{
TRACE_CRIT("Couldn't get rel path");
pRelPath = NULL;
goto end;
}
else
{
if (pRelPath==NULL)
{
ASSERT(FALSE); // we don't expect this!
goto end;
}
TRACE_CRIT("GOT RELATIVE PATH %ws", pRelPath);
}
end:
*pszRelPath = pRelPath;
return Status;
}
WBEMSTATUS
CfgUtilGetWmiInputInstanceAndRelPath(
IN IWbemServicesPtr spWbemServiceIF,
IN LPCWSTR szClassName,
IN LPCWSTR szPropertyName, // NULL: return Class rel path
IN LPCWSTR szPropertyValue,
IN LPCWSTR szMethodName,
OUT IWbemClassObjectPtr &spWbemInputInstance, // smart pointer
OUT LPWSTR * pszRelPath // free using delete
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
IWbemClassObjectPtr spClassObj = NULL; // smart pointer
HRESULT hr;
LPWSTR pRelPath = NULL;
TRACE_INFO(L"-> %!FUNC!(PropertyValue=%ws)", szPropertyValue);
//
// Get CLASS object
//
{
hr = spWbemServiceIF->GetObject(
_bstr_t(szClassName),
0,
NULL,
&spClassObj,
NULL
);
if (FAILED(hr))
{
TRACE_CRIT("Couldn't get nic class object pointer");
Status = (WBEMSTATUS)hr;
goto end;
}
}
//
// Get WMI path to specific object
//
if (szPropertyName == NULL)
{
// Get WMI path to the class
Status = CfgUtilGetWmiRelPath(
spClassObj,
&pRelPath
);
if (FAILED(Status))
{
goto end;
}
}
else
{
IWbemClassObjectPtr spObj = NULL; // smart pointer
pRelPath = NULL;
Status = CfgUtilGetWmiObjectInstance(
spWbemServiceIF,
szClassName,
szPropertyName,
szPropertyValue,
spObj // smart pointer, passed by ref
);
if (FAILED(Status))
{
ASSERT(spObj == NULL);
goto end;
}
Status = CfgUtilGetWmiRelPath(
spObj,
&pRelPath
);
spObj = NULL; // smart pointer
if (FAILED(Status))
{
goto end;
}
}
//
// Get the input parameters to the call to the method
//
{
IWbemClassObjectPtr spWbemInput = NULL; // smart pointer
// check if any input parameters specified.
hr = spClassObj->GetMethod(
szMethodName,
0,
&spWbemInput,
NULL
);
if(FAILED(hr))
{
TRACE_CRIT("IWbemClassObject::GetMethod failure");
Status = (WBEMSTATUS) hr;
goto end;
}
if (spWbemInput != NULL)
{
hr = spWbemInput->SpawnInstance( 0, &spWbemInputInstance );
if( FAILED( hr) )
{
TRACE_CRIT("IWbemClassObject::SpawnInstance failure. Unable to spawn instance." );
Status = (WBEMSTATUS) hr;
goto end;
}
}
else
{
//
// This method has no input arguments!
//
spWbemInputInstance = NULL;
}
}
Status = WBEM_NO_ERROR;
end:
if (FAILED(Status))
{
if (pRelPath != NULL)
{
delete pRelPath;
pRelPath = NULL;
}
}
*pszRelPath = pRelPath;
TRACE_INFO(L"<- %!FUNC!(Obj=%ws) returns 0x%08lx", szPropertyValue, (UINT) Status);
return Status;
}
WBEMSTATUS
CfgUtilGetWmiStringParam(
IN IWbemClassObjectPtr spObj,
IN LPCWSTR szParameterName,
OUT LPWSTR *ppStringValue
)
{
WBEMSTATUS Status = WBEM_E_NOT_FOUND;
WCHAR *pStringValue = NULL;
try
{
_variant_t v_value;
CIMTYPE v_type;
HRESULT hr;
hr = spObj->Get(
_bstr_t(szParameterName), // Name
0, // Reserved, must be 0
&v_value, // Place to store value
&v_type, // Type of value
NULL // Flavor (unused)
);
if (FAILED(hr))
{
// Couldn't read the Setting ID field!
//
TRACE_CRIT(
"get_str_parm:Couldn't retrieve %ws from 0x%p. Hr=0x%08lx",
szParameterName,
(PVOID) spObj,
hr
);
goto end;
}
else if (v_type == VT_NULL)
{
pStringValue = NULL;
Status = WBEM_NO_ERROR;
goto end;
}
else
{
if (v_type != VT_BSTR)
{
TRACE_CRIT(
"get_str_parm: Parm value not of string type %ws from 0x%p",
szParameterName,
(PVOID) spObj
);
Status = WBEM_E_INVALID_PARAMETER;
}
else
{
_bstr_t bstrNicGuid(v_value);
LPCWSTR sz = bstrNicGuid; // Pointer to internal buffer.
if (sz==NULL)
{
// hmm.. null value
pStringValue = NULL;
Status = WBEM_NO_ERROR;
}
else
{
UINT len = wcslen(sz);
pStringValue = new WCHAR[len+1];
if (pStringValue == NULL)
{
TRACE_CRIT("get_str_parm: Alloc failure!");
Status = WBEM_E_OUT_OF_MEMORY;
}
else
{
CopyMemory(pStringValue, sz, (len+1)*sizeof(WCHAR));
Status = WBEM_NO_ERROR;
}
}
TRACE_VERB(
"get_str_parm: String parm %ws of 0x%p is %ws",
szParameterName,
(PVOID) spObj,
(sz==NULL) ? L"<null>" : sz
);
}
v_value.Clear(); // Must be cleared after each call to Get.
}
}
catch( _com_error e )
{
TRACE_INFO(L"%!FUNC! -- com exception");
WBEMSTATUS Status = WBEM_E_NOT_FOUND;
}
end:
if (!FAILED(Status) && pStringValue == NULL)
{
//
// We convert a NULL value to an empty, not NULL string.
//
pStringValue = new WCHAR[1];
if (pStringValue == NULL)
{
Status = WBEM_E_OUT_OF_MEMORY;
}
else
{
*pStringValue = 0;
Status = WBEM_NO_ERROR;
}
}
*ppStringValue = pStringValue;
return Status;
}
WBEMSTATUS
CfgUtilSetWmiStringParam(
IN IWbemClassObjectPtr spObj,
IN LPCWSTR szParameterName,
IN LPCWSTR szValue
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
try
{
HRESULT hr;
_bstr_t bstrName = szParameterName;
_variant_t v_value = (LPWSTR) szValue; // Allocates.
hr = spObj->Put(
bstrName, // Parameter Name
0, // Must be 0
&v_value,
0 // Must be 0
);
v_value.Clear();
if (FAILED(hr))
{
TRACE_CRIT("Unable to put parameter %ws", szParameterName);
goto end;
}
Status = WBEM_NO_ERROR;
//
// I think bstrName releases the internally allocated string
// on exiting this block.
//
}
catch( _com_error e )
{
TRACE_INFO(L"%!FUNC! -- com exception");
Status = WBEM_E_INVALID_PARAMETER;
}
end:
return Status;
}
WBEMSTATUS
CfgUtilGetWmiStringArrayParam(
IN IWbemClassObjectPtr spObj,
IN LPCWSTR szParameterName,
OUT LPWSTR **ppStrings,
OUT UINT *pNumStrings
)
{
WBEMSTATUS Status = WBEM_E_NOT_FOUND;
try
{
_variant_t v_value;
CIMTYPE v_type;
HRESULT hr;
LONG count = 0;
*ppStrings = NULL;
*pNumStrings = 0;
hr = spObj->Get(
_bstr_t(szParameterName),
0, // Reserved, must be 0
&v_value, // Place to store value
&v_type, // Type of value
NULL // Flavor (unused)
);
if (FAILED(hr))
{
// Couldn't read the requested parameter.
//
TRACE_CRIT(
"get_multi_str_parm:Couldn't retrieve %ws from 0x%p",
szParameterName,
(PVOID) spObj
);
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
if (v_type != (VT_ARRAY | VT_BSTR))
{
if (v_type == VT_NULL)
{
//
// We convert a NULL value to zero strings
//
Status = WBEM_NO_ERROR;
goto end;
}
TRACE_CRIT("vt is not of type string!");
goto end;
}
else
{
VARIANT ipsV = v_value.Detach();
SAFEARRAY *pSA = ipsV.parray;
Status = CfgUtilStringsFromSafeArray(
pSA,
ppStrings,
pNumStrings
);
VariantClear( &ipsV );
}
}
catch( _com_error e )
{
TRACE_INFO(L"%!FUNC! -- com exception");
Status = WBEM_E_NOT_FOUND;
}
end:
return Status;
}
WBEMSTATUS
CfgUtilSetWmiStringArrayParam(
IN IWbemClassObjectPtr spObj,
IN LPCWSTR szParameterName,
IN LPCWSTR *ppStrings,
IN UINT NumStrings
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
SAFEARRAY *pSA = NULL;
try
{
HRESULT hr;
LONG Index = 0;
Status = CfgUtilSafeArrayFromStrings(
ppStrings,
NumStrings,
&pSA
);
if (FAILED(Status))
{
pSA = NULL;
goto end;
}
//
// Put the parameter.
//
{
VARIANT V;
_bstr_t bstrName = szParameterName;
VariantInit(&V);
V.vt = VT_ARRAY | VT_BSTR;
V.parray = pSA;
_variant_t v_value;
v_value.Attach(V); // Takes owhership of V. V now becomes empty.
ASSERT(V.vt == VT_EMPTY);
pSA = NULL; // should be no need to delete this explicitly now.
// v_value.Clear() should delete it, I think.
hr = spObj->Put(
bstrName, // Parameter Name
0, // Must be 0
&v_value,
0 // Must be 0
);
v_value.Clear();
if (FAILED(hr))
{
Status = (WBEMSTATUS) hr;
TRACE_CRIT("Unable to put parameter %ws", szParameterName);
goto end;
}
Status = WBEM_NO_ERROR;
}
}
catch( _com_error e )
{
TRACE_INFO(L"%!FUNC! -- com exception");
Status = WBEM_E_INVALID_PARAMETER;
}
end:
if (pSA!=NULL)
{
SafeArrayDestroy(pSA);
pSA = NULL;
}
return Status;
}
WBEMSTATUS
CfgUtilGetWmiDWORDParam(
IN IWbemClassObjectPtr spObj,
IN LPCWSTR szParameterName,
OUT DWORD *pValue
)
{
WBEMSTATUS Status = WBEM_E_NOT_FOUND;
DWORD Value=0;
try
{
_variant_t v_value;
CIMTYPE v_type;
HRESULT hr;
hr = spObj->Get(
_bstr_t(szParameterName), // Name
0, // Reserved, must be 0
&v_value, // Place to store value
&v_type, // Type of value
NULL // Flavor (unused)
);
if (FAILED(hr))
{
// Couldn't read the parameter
//
TRACE_CRIT(
"GetDWORDParm:Couldn't retrieve %ws from 0x%p",
szParameterName,
(PVOID) spObj
);
goto end;
}
else
{
Value = (DWORD) (long) v_value;
v_value.Clear(); // Must be cleared after each call to Get.
Status = WBEM_NO_ERROR;
}
}
catch( _com_error e )
{
TRACE_INFO(L"%!FUNC! -- com exception");
Status = WBEM_E_NOT_FOUND;
}
end:
*pValue = Value;
return Status;
}
WBEMSTATUS
CfgUtilSetWmiDWORDParam(
IN IWbemClassObjectPtr spObj,
IN LPCWSTR szParameterName,
IN DWORD Value
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
try
{
HRESULT hr;
_bstr_t bstrName = szParameterName;
_variant_t v_value = (long) Value;
hr = spObj->Put(
bstrName, // Parameter Name
0, // Must be 0
&v_value,
0 // Must be 0
);
v_value.Clear();
if (FAILED(hr))
{
TRACE_CRIT("Unable to put parameter %ws", szParameterName);
goto end;
}
Status = WBEM_NO_ERROR;
}
catch( _com_error e )
{
TRACE_INFO(L"%!FUNC! -- com exception");
Status = WBEM_E_INVALID_PARAMETER;
}
end:
return Status;
}
WBEMSTATUS
CfgUtilGetWmiBoolParam(
IN IWbemClassObjectPtr spObj,
IN LPCWSTR szParameterName,
OUT BOOL *pValue
)
{
WBEMSTATUS Status = WBEM_E_NOT_FOUND;
BOOL Value=0;
try
{
_variant_t v_value;
CIMTYPE v_type;
HRESULT hr;
hr = spObj->Get(
_bstr_t(szParameterName), // Name
0, // Reserved, must be 0
&v_value, // Place to store value
&v_type, // Type of value
NULL // Flavor (unused)
);
if (FAILED(hr))
{
// Couldn't read the parameter
//
TRACE_CRIT(
"GetDWORDParm:Couldn't retrieve %ws from 0x%p",
szParameterName,
(PVOID) spObj
);
goto end;
}
else
{
Value = ((bool) v_value)!=0;
v_value.Clear(); // Must be cleared after each call to Get.
Status = WBEM_NO_ERROR;
}
}
catch( _com_error e )
{
TRACE_INFO(L"%!FUNC! -- com exception");
Status = WBEM_E_NOT_FOUND;
}
end:
*pValue = Value;
return Status;
}
WBEMSTATUS
CfgUtilSetWmiBoolParam(
IN IWbemClassObjectPtr spObj,
IN LPCWSTR szParameterName,
IN BOOL Value
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
try
{
HRESULT hr;
_bstr_t bstrName = szParameterName;
_variant_t v_value = (long) Value;
hr = spObj->Put(
bstrName, // Parameter Name
0, // Must be 0
&v_value,
0 // Must be 0
);
v_value.Clear();
if (FAILED(hr))
{
TRACE_CRIT("Unable to put parameter %ws", szParameterName);
goto end;
}
Status = WBEM_NO_ERROR;
}
catch( _com_error e )
{
TRACE_INFO(L"%!FUNC! -- com exception");
Status = WBEM_E_INVALID_PARAMETER;
}
end:
return Status;
}
WBEMSTATUS
CfgUtilConnectToServer(
IN LPCWSTR szNetworkResource, // \\machinename\root\microsoftnlb \root\...
IN LPCWSTR szUser,
IN LPCWSTR szPassword,
IN LPCWSTR szAuthority,
OUT IWbemServices **ppWbemService // deref when done.
)
{
HRESULT hr = WBEM_E_CRITICAL_ERROR;
IWbemLocatorPtr spLocator=NULL; // Smart pointer
IWbemServices *pService=NULL;
try
{
_bstr_t serverPath(szNetworkResource);
*ppWbemService = NULL;
hr = CoCreateInstance(CLSID_WbemLocator, 0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator,
(LPVOID *) &spLocator);
if (FAILED(hr))
{
TRACE_CRIT(L"CoCreateInstance IWebmLocator failed 0x%08lx ", (UINT)hr);
goto end;
}
for (int timesToRetry=0; timesToRetry<10; timesToRetry++)
{
hr = spLocator->ConnectServer(
serverPath,
// (szUser!=NULL) ? (_bstr_t(szUser)) : NULL,
_bstr_t(szUser),
// (szPassword==NULL) ? NULL : _bstr_t(szPassword),
_bstr_t(szPassword),
NULL, // Locale
0, // Security flags
//(szAuthority==NULL) ? NULL : _bstr_t(szAuthority),
_bstr_t(szAuthority),
NULL,
&pService
);
if( !FAILED( hr) )
{
break;
}
//
// these have been found to be special cases where retrying may
// help. The errors below are not in any header file, and I searched
// the index2a sources for these constants -- no hits.
// TODO: file bug against WMI.
//
if( ( hr == 0x800706bf ) || ( hr == 0x80070767 ) || ( hr == 0x80070005 ) )
{
TRACE_CRIT(L"connectserver recoverable failure, retrying.");
Sleep(500);
}
}
if (FAILED(hr))
{
TRACE_CRIT(L"Error 0x%08lx connecting to server", (UINT) hr);
goto end;
}
else
{
TRACE_INFO(L"Successfully connected to server %s", serverPath);
}
// Set the proxy so that impersonation of the client occurs.
//
hr = CoSetProxyBlanket(
pService,
RPC_C_AUTHN_WINNT,
RPC_C_AUTHZ_DEFAULT, // RPC_C_AUTHZ_NAME,
COLE_DEFAULT_PRINCIPAL, // NULL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
COLE_DEFAULT_AUTHINFO, // NULL,
EOAC_DEFAULT // EOAC_NONE
);
if (FAILED(hr))
{
TRACE_CRIT(L"Error 0x%08lx setting proxy blanket", (UINT) hr);
goto end;
}
hr = WBEM_NO_ERROR;
}
catch( _com_error e )
{
TRACE_INFO(L"%!FUNC! -- com exception");
hr = WBEM_E_INVALID_PARAMETER;
}
end:
spLocator = NULL; // smart pointer.
if (FAILED(hr))
{
if (pService != NULL)
{
pService->Release();
pService=NULL;
}
}
*ppWbemService = pService;
return (WBEMSTATUS) hr;
}
WBEMSTATUS
CfgUtilsGetNlbCompatibleNics(
OUT LPWSTR **ppszNics,
OUT UINT *pNumNics,
OUT UINT *pNumBoundToNlb // OPTIONAL
)
{
WBEMSTATUS Status = WBEM_NO_ERROR;
BOOL fNetCfgInitialized = FALSE;
MyNetCfg NetCfg;
BOOL fBound = FALSE;
//
// Get and initialize interface to netcfg
//
Status = NetCfg.Initialize(FALSE); // TRUE == get write lock.
if (FAILED(Status))
{
goto end;
}
fNetCfgInitialized = TRUE;
//
//
//
Status = NetCfg.GetNlbCompatibleNics(
ppszNics,
pNumNics,
pNumBoundToNlb // OPTIONAL
);
end:
if (fNetCfgInitialized)
{
NetCfg.Deinitialize();
}
return Status;
}
WBEMSTATUS
CfgUtilGetWmiAdapterObjFromAdapterConfigurationObj(
IN IWbemClassObjectPtr spObj, // smart pointer
OUT IWbemClassObjectPtr &spAdapterObj // smart pointer, by reference
)
/*
We need to return the "Win32_NetworkAdapter" object associated with
the "Win32_NetworkAdapterConfiguration" object.
We use the "Win32_NetworkAdapterSetting" object for this.
*/
{
spAdapterObj = spObj;
return WBEM_NO_ERROR;
}
#if 0
HRESULT
Test(
IWbemClassObject * pNetworkAdapterIn)
//
// FROM: nt\base\cluster\mgmt\cluscfg\server\cenumcluscfgipaddresses.cpp
//
{
#define ARRAYSIZE(_arr) (sizeof(_arr)/sizeof(_arr[0]))
#define TraceSysAllocString(_str) (NULL)
#define TraceSysFreeString( bstrQuery ) (0)
#define THR(_exp) S_OK
#define STHR(_exp) S_OK
#define STATUS_REPORT_STRING(_a, _b, _c, _d, _e) (0)
#define STATUS_REPORT( _a, _b, _c, _d) (0)
#define Assert ASSERT
#define HRETURN( hr ) return hr
HRESULT hr = S_OK;
BSTR bstrQuery = NULL;
BSTR bstrWQL = NULL;
VARIANT var;
WCHAR sz[ 256 ];
IEnumWbemClassObject * pConfigurations = NULL;
ULONG ulReturned;
IWbemClassObject * pConfiguration = NULL;
int cFound = 0;
BSTR bstrAdapterName = NULL;
int idx;
VariantInit( &var );
bstrWQL = TraceSysAllocString( L"WQL" );
if ( bstrWQL == NULL )
{
goto OutOfMemory;
} // if:
hr = THR( HrGetWMIProperty( pNetworkAdapterIn, L"DeviceID", VT_BSTR, &var ) );
if ( FAILED( hr ) )
{
goto Cleanup;
} // if:
_snwprintf( sz, ARRAYSIZE( sz ), L"Associators of {Win32_NetworkAdapter.DeviceID='%s'} where AssocClass=Win32_NetworkAdapterSetting", var.bstrVal );
bstrQuery = TraceSysAllocString( sz );
if ( bstrQuery == NULL )
{
goto OutOfMemory;
} // if:
VariantClear( &var );
hr = THR( HrGetWMIProperty( pNetworkAdapterIn, L"NetConnectionID", VT_BSTR, &var ) );
if ( FAILED( hr ) )
{
goto Cleanup;
} // if:
bstrAdapterName = TraceSysAllocString( var.bstrVal );
if ( bstrAdapterName == NULL )
{
goto OutOfMemory;
} // if:
hr = THR( m_pIWbemServices->ExecQuery( bstrWQL, bstrQuery, WBEM_FLAG_FORWARD_ONLY, NULL, &pConfigurations ) );
if ( FAILED( hr ) )
{
STATUS_REPORT_STRING(
TASKID_Major_Find_Devices,
TASKID_Minor_WMI_NetworkAdapterSetting_Qry_Failed,
IDS_ERROR_WMI_NETWORKADAPTERSETTINGS_QRY_FAILED,
bstrAdapterName,
hr
);
goto Cleanup;
} // if:
for ( idx = 0; ; idx++ )
{
hr = pConfigurations->Next( WBEM_INFINITE, 1, &pConfiguration, &ulReturned );
if ( ( hr == S_OK ) && ( ulReturned == 1 ) )
{
//
// KB: 25-AUG-2000 GalenB
//
// WMI only supports one configuration per adapter!
//
Assert( idx < 1 );
VariantClear( &var );
hr = THR( HrGetWMIProperty( pConfiguration, L"IPEnabled", VT_BOOL, &var ) );
if ( FAILED( hr ) )
{
goto Cleanup;
} // if:
//
// If this configuration is not for TCP/IP then skip it.
//
if ( ( var.vt != VT_BOOL ) || ( var.boolVal != VARIANT_TRUE ) )
{
hr = S_FALSE;
STATUS_REPORT_STRING( TASKID_Major_Find_Devices, TASKID_Minor_Non_Tcp_Config, IDS_WARNING__NON_TCP_CONFIG, bstrAdapterName, hr );
continue;
} // if:
hr = STHR( HrSaveIPAddresses( bstrAdapterName, pConfiguration ) );
if ( FAILED( hr ) )
{
goto Cleanup;
} // if:
//
// KB: 24-AUG-2000 GalenB
//
// If any configuration returns S_FALSE then we skip.
//
if ( hr == S_FALSE )
{
pConfiguration->Release();
pConfiguration = NULL;
continue;
} // if:
cFound++;
pConfiguration->Release();
pConfiguration = NULL;
} // if:
else if ( ( hr == S_FALSE ) && ( ulReturned == 0 ) )
{
hr = S_OK;
break;
} // else if:
else
{
STATUS_REPORT_STRING( TASKID_Major_Find_Devices, TASKID_Minor_WQL_Qry_Next_Failed, IDS_ERROR_WQL_QRY_NEXT_FAILED, bstrQuery, hr );
goto Cleanup;
} // else:
} // for:
//
// If we didn't find any valid configurations then we should return S_FALSE
// to tell the caller to ingore that adpater.
//
if ( cFound == 0 )
{
hr = S_FALSE;
STATUS_REPORT_STRING( TASKID_Major_Find_Devices, TASKID_Minor_No_Valid_TCP_Configs, IDS_WARNING_NO_VALID_TCP_CONFIGS, bstrAdapterName, hr );
} // if:
goto Cleanup;
OutOfMemory:
hr = THR( E_OUTOFMEMORY );
STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_HrGetAdapterConfiguration, IDS_ERROR_OUTOFMEMORY, hr );
Cleanup:
VariantClear( &var );
TraceSysFreeString( bstrQuery );
TraceSysFreeString( bstrWQL );
TraceSysFreeString( bstrAdapterName );
if ( pConfiguration != NULL )
{
pConfiguration->Release();
} // if:
if ( pConfigurations != NULL )
{
pConfigurations->Release();
} // if:
HRETURN( hr );
} //*** CEnumClusCfgIPAddresses::HrGetAdapterConfiguration
#endif // 0