Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

4646 lines
94 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997 - 2000
//
// File: H N C U T I L . C P P
//
// Contents: Home Networking Configuration Utility Routines
//
// Notes:
//
// Author: jonburs 27 June 2000
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
//
// MPRAPI.DLL import prototypes
//
typedef DWORD
(APIENTRY* PMPRCONFIGBUFFERFREE)(
LPVOID
);
typedef DWORD
(APIENTRY* PMPRCONFIGSERVERCONNECT)(
LPWSTR,
PHANDLE
);
typedef VOID
(APIENTRY* PMPRCONFIGSERVERDISCONNECT)(
HANDLE
);
typedef DWORD
(APIENTRY* PMPRCONFIGTRANSPORTGETHANDLE)(
HANDLE,
DWORD,
PHANDLE
);
typedef DWORD
(APIENTRY* PMPRCONFIGTRANSPORTGETINFO)(
HANDLE,
HANDLE,
LPBYTE*,
LPDWORD,
LPBYTE*,
LPDWORD,
LPWSTR*
);
typedef DWORD
(APIENTRY* PMPRINFOBLOCKFIND)(
LPVOID,
DWORD,
LPDWORD,
LPDWORD,
LPBYTE*
);
//
// The size of the stack buffer to use for building queries. If the
// query exceeeds this length, the working buffer will be allocated from
// the heap
//
const ULONG c_cchQueryBuffer = 256;
HRESULT
HrFromLastWin32Error ()
//+---------------------------------------------------------------------------
//
// Function: HrFromLastWin32Error
//
// Purpose: Converts the GetLastError() Win32 call into a proper HRESULT.
//
// Arguments:
// (none)
//
// Returns: Converted HRESULT value.
//
// Author: danielwe 24 Mar 1997
//
// Notes: This is not inline as it actually generates quite a bit of
// code.
// If GetLastError returns an error that looks like a SetupApi
// error, this function will convert the error to an HRESULT
// with FACILITY_SETUP instead of FACILITY_WIN32
//
{
DWORD dwError = GetLastError();
HRESULT hr;
// This test is testing SetupApi errors only (this is
// temporary because the new HRESULT_FROM_SETUPAPI macro will
// do the entire conversion)
if (dwError & (APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR))
{
hr = HRESULT_FROM_SETUPAPI(dwError);
}
else
{
hr = HRESULT_FROM_WIN32(dwError);
}
return hr;
}
BOOLEAN
ApplicationProtocolExists(
IWbemServices *piwsNamespace,
BSTR bstrWQL,
USHORT usOutgoingPort,
UCHAR ucOutgoingIPProtocol
)
/*++
Routine Description:
Checks if an application protocol already exists that has the
specified outgoing protocol and port.
Arguments:
piwsNamespace - the namespace to use
bstrWQL - a BSTR containing "WQL"
ucOutgoingProtocol - the protocol number to check for
usOutgoingPort - the port to check for
Return Value:
BOOLEAN -- TRUE if the application protocol exists; FALSE otherwise
--*/
{
BSTR bstr;
BOOLEAN fDuplicate = FALSE;
HRESULT hr = S_OK;
int iBytes;
IEnumWbemClassObject *pwcoEnum;
IWbemClassObject *pwcoInstance;
ULONG ulObjs;
OLECHAR wszWhereClause[c_cchQueryBuffer + 1];
_ASSERT(NULL != piwsNamespace);
_ASSERT(NULL != bstrWQL);
_ASSERT(0 == wcscmp(bstrWQL, L"WQL"));
//
// Build the query string
//
iBytes = _snwprintf(
wszWhereClause,
c_cchQueryBuffer,
c_wszApplicationProtocolQueryFormat,
usOutgoingPort,
ucOutgoingIPProtocol
);
if (iBytes >= 0)
{
//
// String fit into buffer; make sure it's null terminated
//
wszWhereClause[c_cchQueryBuffer] = L'\0';
}
else
{
//
// For some reason the string didn't fit into the buffer...
//
hr = E_UNEXPECTED;
_ASSERT(FALSE);
}
if (S_OK == hr)
{
hr = BuildSelectQueryBstr(
&bstr,
c_wszStar,
c_wszHnetApplicationProtocol,
wszWhereClause
);
}
if (S_OK == hr)
{
//
// Execute the query
//
pwcoEnum = NULL;
hr = piwsNamespace->ExecQuery(
bstrWQL,
bstr,
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pwcoEnum
);
SysFreeString(bstr);
}
if (S_OK == hr)
{
//
// Attempt to retrieve an item from the enum. If we're successful,
// this is a duplicate protocol.
//
pwcoInstance = NULL;
hr = pwcoEnum->Next(
WBEM_INFINITE,
1,
&pwcoInstance,
&ulObjs
);
if (SUCCEEDED(hr) && 1 == ulObjs)
{
//
// It's a duplicate
//
fDuplicate = TRUE;
pwcoInstance->Release();
}
pwcoEnum->Release();
}
return fDuplicate;
} // ApplicationProtocolExists
HRESULT
BuildAndString(
LPWSTR *ppwsz,
LPCWSTR pwszLeft,
LPCWSTR pwszRight
)
/*++
Routine Description:
Builds the following string:
pwszLeft AND pwszRight
Arguments:
ppwsz - receives the built string. The caller is responsible for calling
delete[] on this variable. Receives NULL on failure.
pwszLeft - left side of the AND clause
pwszRight - right side of the AND clause
Return Value:
Standard HRESULT
--*/
{
HRESULT hr = S_OK;
ULONG cch;
_ASSERT(NULL != ppwsz);
_ASSERT(NULL != pwszLeft);
_ASSERT(NULL != pwszRight);
//
// length(left) + space + AND + space + length(right) + null
//
cch = wcslen(pwszLeft) + wcslen(pwszRight) + 6;
*ppwsz = new OLECHAR[cch];
if (NULL != *ppwsz)
{
swprintf(
*ppwsz,
L"%s AND %s",
pwszLeft,
pwszRight
);
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
HRESULT
BuildAssociatorsQueryBstr(
BSTR *pBstr,
LPCWSTR pwszObjectPath,
LPCWSTR pwszAssocClass
)
/*++
Routine Description:
Builds a WQL references query and places it into a BSTR. The returned
query is
ASSOCIATORS OF {wszProperties} WHERE AssocClass = pwszAssocClass
Arguments:
pBstr - receives the built query. The caller is responsible for calling
SysFreeString on this variable. Receives NULL on failure.
pwszObjectPath - path of the object to find the references of
pwszAssocClass - the associator class
Return Value:
Standard HRESULT
--*/
{
HRESULT hr = S_OK;
OLECHAR wszBuffer[c_cchQueryBuffer + 1];
OLECHAR *pwszQuery = NULL;
//
// On debug builds, verify that our precomputed string lengths
// match the actual lengths
//
_ASSERT(wcslen(c_wszAssociatorsOf) == c_cchAssociatorsOf);
_ASSERT(wcslen(c_wszWhereAssocClass) == c_cchWhereAssocClass);
//
// All necessary spaces are embedded in the string constants
//
ULONG cchLength = c_cchAssociatorsOf + c_cchWhereAssocClass;
_ASSERT(pwszObjectPath);
_ASSERT(pwszAssocClass);
_ASSERT(pBstr);
*pBstr = NULL;
//
// Determine the length of the query string
//
cchLength += wcslen(pwszObjectPath);
cchLength += wcslen(pwszAssocClass);
//
// If the query string is longer than our stack buffer, we need
// to allocate a buffer off of the heap.
//
if (cchLength <= c_cchQueryBuffer)
{
//
// The buffer is large enough. (Note that since the buffer on the
// stack is one greater than the constant, the terminator is accounted
// for.) Point our working pointer to the stack buffer.
//
pwszQuery = wszBuffer;
}
else
{
//
// Allocate a sufficient buffer from the heap. The +1 is for the
// terminating nul
//
pwszQuery = new OLECHAR[cchLength + 1];
if (NULL == pwszQuery)
{
hr = E_OUTOFMEMORY;
pwszQuery = wszBuffer;
}
}
if (S_OK == hr)
{
//
// Build the actual query string
//
swprintf(
pwszQuery,
L"%s%s%s%s",
c_wszAssociatorsOf,
pwszObjectPath,
c_wszWhereAssocClass,
pwszAssocClass
);
*pBstr = SysAllocString(pwszQuery);
if (NULL == *pBstr)
{
hr = E_OUTOFMEMORY;
}
}
//
// Free the query buffer, if necessary
//
if (wszBuffer != pwszQuery)
{
delete [] pwszQuery;
}
return hr;
}
HRESULT
BuildEqualsString(
LPWSTR *ppwsz,
LPCWSTR pwszLeft,
LPCWSTR pwszRight
)
/*++
Routine Description:
Builds the following string:
pwszLeft = pwszRight
Arguments:
ppwsz - receives the built string. The caller is responsible for calling
delete[] on this variable. Receives NULL on failure.
pwszLeft - left side of the equals clause
pwszRight - right side of the equals clause
Return Value:
Standard HRESULT
--*/
{
HRESULT hr = S_OK;
ULONG cch;
_ASSERT(NULL != ppwsz);
_ASSERT(NULL != pwszLeft);
_ASSERT(NULL != pwszRight);
//
// length(left) + space + = + space + length(right) + null
//
cch = wcslen(pwszLeft) + wcslen(pwszRight) + 4;
*ppwsz = new OLECHAR[cch];
if (NULL != *ppwsz)
{
swprintf(
*ppwsz,
L"%s = %s",
pwszLeft,
pwszRight
);
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
HRESULT
BuildEscapedQuotedEqualsString(
LPWSTR *ppwsz,
LPCWSTR pwszLeft,
LPCWSTR pwszRight
)
/*++
Routine Description:
Builds the following string:
pwszLeft = "pwszRight"
after escaping pwszRight -- replace \ w/ \\ and " with \"
Arguments:
ppwsz - receives the built string. The caller is responsible for calling
delete[] on this variable. Receives NULL on failure.
pwszLeft - left side of the equals clause
pwszRight - right side of the equals clause. This will be escaped, and then
wrapped in quotes
Return Value:
Standard HRESULT
--*/
{
HRESULT hr = S_OK;
ULONG cch;
LPWSTR wszEscaped;
_ASSERT(NULL != ppwsz);
_ASSERT(NULL != pwszLeft);
_ASSERT(NULL != pwszRight);
//
// Escape string
//
wszEscaped = EscapeString(pwszRight);
if (NULL == wszEscaped)
{
return E_OUTOFMEMORY;
}
//
// length(left) + space + = + space + " + length(right) + " + null
//
cch = wcslen(pwszLeft) + wcslen(wszEscaped) + 6;
*ppwsz = new OLECHAR[cch];
if (NULL != *ppwsz)
{
swprintf(
*ppwsz,
L"%s = \"%s\"",
pwszLeft,
wszEscaped
);
delete [] wszEscaped;
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
HRESULT
BuildQuotedEqualsString(
LPWSTR *ppwsz,
LPCWSTR pwszLeft,
LPCWSTR pwszRight
)
/*++
Routine Description:
Builds the following string:
pwszLeft = "pwszRight"
Arguments:
ppwsz - receives the built string. The caller is responsible for calling
delete[] on this variable. Receives NULL on failure.
pwszLeft - left side of the equals clause
pwszRight - right side of the equals clause. This will be wrapped in
quotes
Return Value:
Standard HRESULT
--*/
{
HRESULT hr = S_OK;
ULONG cch;
LPWSTR wsz;
_ASSERT(NULL != ppwsz);
_ASSERT(NULL != pwszLeft);
_ASSERT(NULL != pwszRight);
//
// length(left) + space + = + space + " + length(right) + " + null
//
cch = wcslen(pwszLeft) + wcslen(pwszRight) + 6;
*ppwsz = new OLECHAR[cch];
if (NULL != *ppwsz)
{
swprintf(
*ppwsz,
L"%s = \"%s\"",
pwszLeft,
pwszRight
);
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
HRESULT
BuildReferencesQueryBstr(
BSTR *pBstr,
LPCWSTR pwszObjectPath,
LPCWSTR pwszTargetClass
)
/*++
Routine Description:
Builds a WQL references query and places it into a BSTR. The returned
query is
REFERENCES OF {pwszObjectPath} WHERE ResultClass = pwszTargetClass
if pwszTargetClass is not NULL, and
REFERENCES OF {pwszObjectPath}
otherwise
Arguments:
pBstr - receives the built query. The caller is responsible for calling
SysFreeString on this variable. Receives NULL on failure.
pwszObjectPath - path of the object to find the references of
pwszTargetClass - the class of references desired. May be NULL.
Return Value:
Standard HRESULT
--*/
{
HRESULT hr = S_OK;
OLECHAR wszBuffer[c_cchQueryBuffer + 1];
OLECHAR *pwszQuery = NULL;
//
// On debug builds, verify that our precomputed string lengths
// match the actual lengths
//
_ASSERT(wcslen(c_wszReferencesOf) == c_cchReferencesOf);
_ASSERT(wcslen(c_wszWhereResultClass) == c_cchWhereResultClass);
//
// All necessary spaces are embedded in the string constants
//
ULONG cchLength = c_cchReferencesOf + c_cchWhereResultClass;
_ASSERT(pwszObjectPath);
_ASSERT(pBstr);
*pBstr = NULL;
//
// Determine the length of the query string
//
cchLength += wcslen(pwszObjectPath);
if (NULL != pwszTargetClass)
{
cchLength += wcslen(pwszTargetClass);
}
//
// If the query string is longer than our stack buffer, we need
// to allocate a buffer off of the heap.
//
if (cchLength <= c_cchQueryBuffer)
{
//
// The buffer is large enough. (Note that since the buffer on the
// stack is one greater than the constant, the terminator is accounted
// for.) Point our working pointer to the stack buffer.
//
pwszQuery = wszBuffer;
}
else
{
//
// Allocate a sufficient buffer from the heap. The +1 is for the
// terminating nul
//
pwszQuery = new OLECHAR[cchLength + 1];
if (NULL == pwszQuery)
{
hr = E_OUTOFMEMORY;
pwszQuery = wszBuffer;
}
}
if (S_OK == hr)
{
//
// Build the actual query string
//
if (NULL != pwszTargetClass)
{
swprintf(
pwszQuery,
L"%s%s%s%s",
c_wszReferencesOf,
pwszObjectPath,
c_wszWhereResultClass,
pwszTargetClass
);
}
else
{
swprintf(
pwszQuery,
L"%s%s}",
c_wszReferencesOf,
pwszObjectPath
);
}
*pBstr = SysAllocString(pwszQuery);
if (NULL == *pBstr)
{
hr = E_OUTOFMEMORY;
}
}
//
// Free the query buffer, if necessary
//
if (wszBuffer != pwszQuery)
{
delete [] pwszQuery;
}
return hr;
}
HRESULT
BuildSelectQueryBstr(
BSTR *pBstr,
LPCWSTR pwszProperties,
LPCWSTR pwszFromClause,
LPCWSTR pwszWhereClause
)
/*++
Routine Description:
Builds a WQL select query and places it into a BSTR. The returned
query is
SELECT wszProperties FROM wszFromClause [WHERE wszWhereClause]
Arguments:
pBstr - receives the built query. The caller is responsible for calling
SysFreeString on this variable. Receives NULL on failure.
pwszProperties - the properties the query should return
pwszFromClause - the class the returned objects should be from
pwszWhereClause - the constraints that the returned object must meet. If
NULL, the query will not have a where clause.
Return Value:
Standard HRESULT
--*/
{
HRESULT hr = S_OK;
OLECHAR wszBuffer[c_cchQueryBuffer + 1];
OLECHAR *pwszQuery = NULL;
//
// On debug builds, verify that our precomputed string lengths
// match the actual lengths
//
_ASSERT(wcslen(c_wszSelect) == c_cchSelect);
_ASSERT(wcslen(c_wszFrom) == c_cchFrom);
_ASSERT(wcslen(c_wszWhere) == c_cchWhere);
//
// SELECT + 2 spaces (around properties) + FROM + space
//
ULONG cchLength = c_cchSelect + 2 + c_cchFrom + 1;
_ASSERT(pwszProperties);
_ASSERT(pwszFromClause);
_ASSERT(pBstr);
*pBstr = NULL;
//
// Determine the length of the query string
//
cchLength += wcslen(pwszProperties);
cchLength += wcslen(pwszFromClause);
if (pwszWhereClause)
{
//
// space + WHERE + space
//
cchLength += 2 + c_cchWhere;
cchLength += wcslen(pwszWhereClause);
}
//
// If the query string is longer than our stack buffer, we need
// to allocate a buffer off of the heap.
//
if (cchLength <= c_cchQueryBuffer)
{
//
// The buffer is large enough. (Note that since the buffer on the
// stack is one greater than the constant, the terminator is accounted
// for.) Point our working pointer to the stack buffer.
//
pwszQuery = wszBuffer;
}
else
{
//
// Allocate a sufficient buffer from the heap. The +1 is for the
// terminating nul
//
pwszQuery = new OLECHAR[cchLength + 1];
if (NULL == pwszQuery)
{
hr = E_OUTOFMEMORY;
pwszQuery = wszBuffer;
}
}
if (S_OK == hr)
{
//
// Build the actual query string
//
if (pwszWhereClause)
{
swprintf(
pwszQuery,
L"%s %s %s %s %s %s",
c_wszSelect,
pwszProperties,
c_wszFrom,
pwszFromClause,
c_wszWhere,
pwszWhereClause
);
}
else
{
swprintf(
pwszQuery,
L"%s %s %s %s",
c_wszSelect,
pwszProperties,
c_wszFrom,
pwszFromClause
);
}
*pBstr = SysAllocString(pwszQuery);
if (NULL == *pBstr)
{
hr = E_OUTOFMEMORY;
}
}
//
// Free the query buffer, if necessary
//
if (wszBuffer != pwszQuery)
{
delete [] pwszQuery;
}
return hr;
}
BOOLEAN
ConnectionIsBoundToTcp(
PIP_INTERFACE_INFO pIpInfoTable,
GUID *pConnectionGuid
)
/*++
Routine Description:
Determines if a LAN connection is bound to TCP/IP. For the purposes of
this routine, "bound to TCP/IP" is defines as there exists an IP
adapter index for the connection.
Arguments:
pIpInfoTable - the IP interface table, obtained from a call to
GetInterfaceInfo
pConnectionGuid - a pointer to the guid for the connection
Return Value:
BOOLEAN - TRUE if the connection is bound to TCP/IP; FALSE otherwise.
FALSE will be returned if an error occurs
--*/
{
BOOLEAN fIsBound = FALSE;
LPOLESTR pszGuid;
HRESULT hr;
ULONG cchGuid;
ULONG cchName;
PWCHAR pwchName;
LONG l;
_ASSERT(NULL != pIpInfoTable);
_ASSERT(NULL != pConnectionGuid);
//
// Convert the guid to a string
//
hr = StringFromCLSID(*pConnectionGuid, &pszGuid);
if (SUCCEEDED(hr))
{
cchGuid = wcslen(pszGuid);
//
// Walk the table, searching for the corresponding adapter
//
for (l = 0; l < pIpInfoTable->NumAdapters; l++)
{
cchName = wcslen(pIpInfoTable->Adapter[l].Name);
if (cchName < cchGuid) { continue; }
pwchName = pIpInfoTable->Adapter[l].Name + (cchName - cchGuid);
if (0 == _wcsicmp(pszGuid, pwchName))
{
fIsBound = TRUE;
break;
}
}
CoTaskMemFree(pszGuid);
}
return fIsBound;
} // ConnectionIsBoundToTcp
HRESULT
ConvertResponseRangeArrayToInstanceSafearray(
IWbemServices *piwsNamespace,
USHORT uscResponses,
HNET_RESPONSE_RANGE rgResponses[],
SAFEARRAY **ppsa
)
/*++
Routine Description:
Converts an array of HNET_RESPONSE_RANGE structures into a
safearray of IUnknows that represent WMI instances of
those response ranges.
Arguments:
piwsNamespace - the namespace to use
uscResponses - the count of responses
rgResponses - the response range structures
ppsa - receives a pointer to the safearrays
Return Value:
Standard HRESULT
--*/
{
HRESULT hr = S_OK;
SAFEARRAY *psa;
BSTR bstrPath;
SAFEARRAYBOUND rgsabound[1];
IWbemClassObject *pwcoClass = NULL;
IWbemClassObject *pwcoInstance;
IUnknown *pUnk;
_ASSERT(NULL != piwsNamespace);
_ASSERT(0 != uscResponses);
_ASSERT(NULL != rgResponses);
_ASSERT(NULL != ppsa);
bstrPath = SysAllocString(c_wszHnetResponseRange);
if (NULL == bstrPath)
{
hr = E_OUTOFMEMORY;
}
if (S_OK == hr)
{
//
// Get the class for HNet_ResponseRange
//
pwcoClass = NULL;
hr = piwsNamespace->GetObject(
bstrPath,
WBEM_FLAG_RETURN_WBEM_COMPLETE,
NULL,
&pwcoClass,
NULL
);
SysFreeString(bstrPath);
}
if (S_OK == hr)
{
//
// Create the array to hold the response range instances
//
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = uscResponses;
psa = SafeArrayCreate(VT_UNKNOWN, 1, rgsabound);
if (NULL == psa)
{
hr = E_OUTOFMEMORY;
}
}
if (S_OK == hr)
{
//
// Process the passed in response ranges
//
for (USHORT i = 0; i < uscResponses; i++)
{
//
// First, create an HNet_ResponseRange instance
// for the entry
//
pwcoInstance = NULL;
hr = pwcoClass->SpawnInstance(0, &pwcoInstance);
if (WBEM_S_NO_ERROR != hr)
{
break;
}
//
// Populate that instance
//
hr = CopyStructToResponseInstance(
&rgResponses[i],
pwcoInstance
);
if (FAILED(hr))
{
pwcoInstance->Release();
break;
}
//
// Get the IUnknown for the instance and put it
// in the array
//
hr = pwcoInstance->QueryInterface(
IID_PPV_ARG(IUnknown, &pUnk)
);
_ASSERT(S_OK == hr);
LONG lIndex = i;
hr = SafeArrayPutElement(
psa,
&lIndex,
pUnk
);
pUnk->Release();
pwcoInstance->Release();
if (FAILED(hr))
{
SafeArrayDestroy(psa);
break;
}
}
}
if (SUCCEEDED(hr))
{
*ppsa = psa;
hr = S_OK;
}
if (pwcoClass) pwcoClass->Release();
return hr;
}
HRESULT
CopyResponseInstanceToStruct(
IWbemClassObject *pwcoInstance,
HNET_RESPONSE_RANGE *pResponse
)
/*++
Routine Description:
Converts an instance of an HNet_ResponseRange into the
corresponding HNET_RESPONSE_RANGE
Arguments:
pwcoInstance - the HNet_ResponseRange instance
pResponse - the HNET_RESPONSE_RANGE to fill
Return Value:
Standard HRESULT
--*/
{
HRESULT hr = S_OK;
VARIANT vt;
_ASSERT(NULL != pwcoInstance);
_ASSERT(NULL != pResponse);
hr = pwcoInstance->Get(
c_wszIPProtocol,
0,
&vt,
NULL,
NULL
);
if (WBEM_S_NO_ERROR == hr)
{
_ASSERT(VT_UI1 == V_VT(&vt));
pResponse->ucIPProtocol = V_UI1(&vt);
VariantClear(&vt);
}
if (WBEM_S_NO_ERROR == hr)
{
hr = pwcoInstance->Get(
c_wszStartPort,
0,
&vt,
NULL,
NULL
);
if (WBEM_S_NO_ERROR == hr)
{
//
// WMI returns uint16 properties as VT_I4
//
_ASSERT(VT_I4 == V_VT(&vt));
pResponse->usStartPort = static_cast<USHORT>(V_I4(&vt));
VariantClear(&vt);
}
}
if (WBEM_S_NO_ERROR == hr)
{
hr = pwcoInstance->Get(
c_wszEndPort,
0,
&vt,
NULL,
NULL
);
if (WBEM_S_NO_ERROR == hr)
{
//
// WMI returns uint16 properties as VT_I4
//
_ASSERT(VT_I4 == V_VT(&vt));
pResponse->usEndPort = static_cast<USHORT>(V_I4(&vt));
VariantClear(&vt);
}
}
return hr;
}
HRESULT
CopyStructToResponseInstance(
HNET_RESPONSE_RANGE *pResponse,
IWbemClassObject *pwcoInstance
)
/*++
Routine Description:
Converts an instance of an HNet_ResponseRange into the
corresponding HNET_RESPONSE_RANGE
Arguments:
pResponse - the HNET_RESPONSE_RANGE to fill
pwcoInstance - the HNet_ResponseRange instance to create
Return Value:
Standard HRESULT
--*/
{
HRESULT hr = S_OK;
VARIANT vt;
_ASSERT(NULL != pResponse);
_ASSERT(NULL != pwcoInstance);
VariantInit(&vt);
V_VT(&vt) = VT_UI1;
V_UI1(&vt) = pResponse->ucIPProtocol;
hr = pwcoInstance->Put(
c_wszIPProtocol,
0,
&vt,
NULL
);
if (WBEM_S_NO_ERROR == hr)
{
V_VT(&vt) = VT_I4;
V_I4(&vt) = pResponse->usStartPort;
hr = pwcoInstance->Put(
c_wszStartPort,
0,
&vt,
NULL
);
}
if (WBEM_S_NO_ERROR == hr)
{
V_I4(&vt) = pResponse->usEndPort;
hr = pwcoInstance->Put(
c_wszEndPort,
0,
&vt,
NULL
);
}
return hr;
}
HRESULT
DeleteWmiInstance(
IWbemServices *piwsNamespace,
IWbemClassObject *pwcoInstance
)
/*++
Routine Description:
Deletes an object instance from the WMI repository.
Arguments:
piwsNamespace - the namespace the object is in
pwcoInstance - the class object interface for the instance
Return Value:
Standard HRESULT
--*/
{
HRESULT hr = S_OK;
BSTR bstr;
_ASSERT(piwsNamespace);
_ASSERT(pwcoInstance);
hr = GetWmiPathFromObject(pwcoInstance, &bstr);
if (WBEM_S_NO_ERROR == hr)
{
hr = piwsNamespace->DeleteInstance(
bstr,
0,
NULL,
NULL
);
SysFreeString(bstr);
}
return hr;
}
LPWSTR
EscapeString(
LPCWSTR pwsz
)
{
ULONG ulCount = 0;
LPWSTR wsz;
LPWSTR wszReturn;
wsz = const_cast<LPWSTR>(pwsz);
while (NULL != *wsz)
{
if (L'\\' == *wsz || L'\"' == *wsz)
{
//
// Need an extra character
//
ulCount += 1;
}
wsz += 1;
ulCount += 1;
}
//
// Allocate new string buffer
//
wszReturn = new OLECHAR[ulCount + 1];
if (NULL == wszReturn)
{
return wszReturn;
}
//
// Copy string over
//
wsz = wszReturn;
while (NULL != *pwsz)
{
if (L'\\' == *pwsz || L'\"' == *pwsz)
{
*wsz++ = L'\\';
}
*wsz++ = *pwsz++;
}
//
// Make sure everything is properly null terminated
//
*wsz = L'';
return wszReturn;
}
HRESULT
InitializeNetCfgForWrite(
OUT INetCfg **ppnetcfg,
OUT INetCfgLock **ppncfglock
)
/*++
Routine Description:
Initializes NetCfg for writing. If this function succeeds, the
caller must call UninitializeNetCfgForWrite() with the two
returned interface pointers when done.
Arguments:
ppnetcfg Receives an initialized INetCfg interface.
ppnetcfglock Receives an acquires INetCfgLock interface.
Return Value:
Status of the operation
--*/
{
HRESULT hr = S_OK;
*ppnetcfg = NULL;
*ppncfglock = NULL;
// Open our own NetCfg context
hr = CoCreateInstance(
CLSID_CNetCfg,
NULL,
CLSCTX_SERVER,
IID_PPV_ARG(INetCfg, ppnetcfg)
);
if ( SUCCEEDED(hr) )
{
//
// Get the lock interface
//
hr = (*ppnetcfg)->QueryInterface(
IID_PPV_ARG(INetCfgLock, ppncfglock)
);
if ( SUCCEEDED(hr) )
{
//
// Get the NetCfg lock
//
hr = (*ppncfglock)->AcquireWriteLock(
5,
L"HNetCfg",
NULL
);
//
// S_FALSE is actually failure; it means NetCfg timed out
// trying to acquire the write lock
//
if( S_FALSE == hr )
{
// Turn into an error that will make sense up the call chain
hr = NETCFG_E_NO_WRITE_LOCK;
}
if ( SUCCEEDED(hr) )
{
//
// Must initialize NetCfg inside the lock
//
hr = (*ppnetcfg)->Initialize( NULL );
if( FAILED(hr) )
{
(*ppncfglock)->ReleaseWriteLock();
}
}
if( FAILED(hr) )
{
(*ppncfglock)->Release();
*ppncfglock = NULL;
}
}
if( FAILED(hr) )
{
(*ppnetcfg)->Release();
*ppnetcfg = NULL;
}
}
return hr;
}
void
UninitializeNetCfgForWrite(
IN INetCfg *pnetcfg,
IN INetCfgLock *pncfglock
)
/*++
Routine Description:
Uninitializes a NetCfg context created with InitializeNetCfgForWrite()
Arguments:
pnetcfg An INetCfg instance created by InitializeNetCfgForWrite()
pncfglock An INetCfgLock instance created by InitializeNetCfgForWrite()
Return Value:
Status of the operation
--*/
{
_ASSERT( (NULL != pnetcfg) && (NULL != pncfglock) );
pnetcfg->Uninitialize();
pncfglock->ReleaseWriteLock();
pncfglock->Release();
pnetcfg->Release();
}
HRESULT
FindAdapterByGUID(
IN INetCfg *pnetcfg,
IN GUID *pguid,
OUT INetCfgComponent **ppncfgcomp
)
/*++
Routine Description:
Retrieves an INetCfgComponent interface, if any, that corresponds
to the given device GUID. The GUID must correspond to a networking
component of class NET (i.e., a miniport).
E_FAIL is returned if the given GUID is not located.
Arguments:
pnetcfg An instance of INetCfg which has already had
its Initialize() method called
pguid The GUID to search for
ppncfgcomp Receives the resulting INetCfgComponent interface
pointer.
Return Value:
Status of the operation
--*/
{
HRESULT hr = S_OK;
GUID guidDevClass = GUID_DEVCLASS_NET;
IEnumNetCfgComponent *penumncfgcomp;
INetCfgComponent *pnetcfgcomp;
ULONG ulCount;
BOOLEAN fFound = FALSE;
//
// Get the list of NET (adapter) devices
//
hr = pnetcfg->EnumComponents( &guidDevClass, &penumncfgcomp );
if (S_OK == hr)
{
//
// Search for the designated adapter by GUID
//
while ( (FALSE == fFound) &&
(S_OK == penumncfgcomp->Next(1, &pnetcfgcomp, &ulCount) ) )
{
GUID guidThis;
hr = pnetcfgcomp->GetInstanceGuid( &guidThis );
if ( (S_OK == hr) && (InlineIsEqualGUID(guidThis,*pguid)) )
{
fFound = TRUE;
}
else
{
pnetcfgcomp->Release();
}
}
penumncfgcomp->Release();
}
if (fFound)
{
*ppncfgcomp = pnetcfgcomp;
}
else
{
hr = E_FAIL;
}
return hr;
}
HRESULT
FindINetConnectionByGuid(
GUID *pGuid,
INetConnection **ppNetCon
)
/*++
Routine Description:
Retrieves the INetConnection that corresponds to the given GUID.
Arguments:
pGuid - the guid of the connection
ppNetCon - receives the interface
Return Value:
standard HRESULT
--*/
{
HRESULT hr;
INetConnectionManager *pManager;
IEnumNetConnection *pEnum;
INetConnection *pConn;
_ASSERT(NULL != pGuid);
_ASSERT(NULL != ppNetCon);
//
// Get the net connections manager
//
hr = CoCreateInstance(
CLSID_ConnectionManager,
NULL,
CLSCTX_ALL,
IID_PPV_ARG(INetConnectionManager, &pManager)
);
if (S_OK == hr)
{
//
// Get the enumeration of connections
//
SetProxyBlanket(pManager);
hr = pManager->EnumConnections(NCME_DEFAULT, &pEnum);
pManager->Release();
}
if (S_OK == hr)
{
//
// Search for the connection with the correct guid
//
ULONG ulCount;
BOOLEAN fFound = FALSE;
SetProxyBlanket(pEnum);
do
{
NETCON_PROPERTIES *pProps;
hr = pEnum->Next(1, &pConn, &ulCount);
if (SUCCEEDED(hr) && 1 == ulCount)
{
SetProxyBlanket(pConn);
hr = pConn->GetProperties(&pProps);
if (S_OK == hr)
{
if (IsEqualGUID(pProps->guidId, *pGuid))
{
fFound = TRUE;
*ppNetCon = pConn;
(*ppNetCon)->AddRef();
}
NcFreeNetconProperties(pProps);
}
pConn->Release();
}
}
while (FALSE == fFound && SUCCEEDED(hr) && 1 == ulCount);
//
// Normalize hr
//
hr = (fFound ? S_OK : E_FAIL);
pEnum->Release();
}
return hr;
}
HRESULT
GetBridgeConnection(
IN IWbemServices *piwsHomenet,
OUT IHNetBridge **pphnetBridge
)
{
INetCfg *pnetcfg;
HRESULT hr;
if( NULL != pphnetBridge )
{
*pphnetBridge = NULL;
hr = CoCreateInstance(
CLSID_CNetCfg,
NULL,
CLSCTX_SERVER,
IID_PPV_ARG(INetCfg, &pnetcfg));
if( S_OK == hr )
{
hr = pnetcfg->Initialize( NULL );
if( S_OK == hr )
{
INetCfgComponent *pnetcfgcompBridge;
hr = pnetcfg->FindComponent( c_wszSBridgeMPID, &pnetcfgcompBridge );
if( S_OK == hr )
{
hr = GetIHNetConnectionForNetCfgComponent(
piwsHomenet,
pnetcfgcompBridge,
TRUE,
IID_PPV_ARG(IHNetBridge, pphnetBridge)
);
pnetcfgcompBridge->Release();
}
pnetcfg->Uninitialize();
}
pnetcfg->Release();
}
}
else
{
hr = E_POINTER;
}
// S_FALSE tends to get mishandled; return E_FAIL to signal the absence of a bridge.
if( S_FALSE == hr )
{
return E_FAIL;
}
return hr;
}
HRESULT
GetIHNetConnectionForNetCfgComponent(
IN IWbemServices *piwsHomenet,
IN INetCfgComponent *pnetcfgcomp,
IN BOOLEAN fLanConnection,
IN REFIID iid,
OUT PVOID *ppv
)
{
HRESULT hr;
if( NULL != ppv )
{
CComObject<CHNetCfgMgrChild> *pHNCfgMgrChild;
*ppv = NULL;
hr = CComObject<CHNetCfgMgrChild>::CreateInstance(&pHNCfgMgrChild);
if (SUCCEEDED(hr))
{
pHNCfgMgrChild->AddRef();
hr = pHNCfgMgrChild->Initialize(piwsHomenet);
if (SUCCEEDED(hr))
{
GUID guid;
hr = pnetcfgcomp->GetInstanceGuid( &guid );
if( S_OK == hr )
{
IHNetConnection *phnetcon;
hr = pHNCfgMgrChild->GetIHNetConnectionForGuid( &guid, fLanConnection, TRUE, &phnetcon );
if( S_OK == hr )
{
hr = phnetcon->GetControlInterface( iid, ppv );
phnetcon->Release();
}
}
}
pHNCfgMgrChild->Release();
}
}
else
{
hr = E_POINTER;
}
return hr;
}
HRESULT
BindOnlyToBridge(
IN INetCfgComponent *pnetcfgcomp
)
/*++
Routine Description:
Alters the bindings for the given INetCfgComponent so it is bound only
to the bridge protocol
c_pwszBridgeBindExceptions is a list of exceptions; if a binding path
involves a component listed in c_pwszBridgeBindExceptions, the path
will not be altered.
Arguments:
pnetcfgcomp The component whose bindings we wish to alter
Return Value:
standard HRESULT
--*/
{
HRESULT hr = S_OK;
INetCfgComponentBindings *pnetcfgBindings;
//
// Retrieve the ComponentBindings interface
//
hr = pnetcfgcomp->QueryInterface(
IID_PPV_ARG(INetCfgComponentBindings, &pnetcfgBindings)
);
if (S_OK == hr)
{
IEnumNetCfgBindingPath *penumPaths;
//
// Get the list of binding paths for this component
//
hr = pnetcfgBindings->EnumBindingPaths(
EBP_ABOVE,
&penumPaths
);
if (S_OK == hr)
{
ULONG ulCount1, ulCount2;
INetCfgBindingPath *pnetcfgPath;
while( (S_OK == penumPaths->Next(1, &pnetcfgPath, &ulCount1) ) )
{
INetCfgComponent *pnetcfgOwner;
//
// Get the owner of this path
//
hr = pnetcfgPath->GetOwner( &pnetcfgOwner );
if (S_OK == hr)
{
INetCfgComponentBindings *pnetcfgOwnerBindings;
hr = pnetcfgOwner->QueryInterface(
IID_PPV_ARG(INetCfgComponentBindings, &pnetcfgOwnerBindings)
);
if (S_OK == hr)
{
LPWSTR lpwstrId;
hr = pnetcfgOwner->GetId( &lpwstrId );
if (S_OK == hr)
{
BOOLEAN bIsBridge;
bIsBridge = ( _wcsicmp(lpwstrId, c_wszSBridgeSID) == 0 );
if( bIsBridge )
{
// This is the bridge component. Activate this binding path
hr = pnetcfgOwnerBindings->BindTo(pnetcfgcomp);
}
else
{
// Check if this is one of the bind exceptions
BOOLEAN bIsException = FALSE;
const WCHAR **ppwszException = c_pwszBridgeBindExceptions;
while( NULL != *ppwszException )
{
bIsException = ( _wcsicmp(lpwstrId, *ppwszException) == 0 );
if( bIsException )
{
break;
}
ppwszException++;
}
if( !bIsException )
{
hr = pnetcfgOwnerBindings->UnbindFrom(pnetcfgcomp);
}
// else this is an exception; leave the bind path as-is.
}
CoTaskMemFree(lpwstrId);
}
pnetcfgOwnerBindings->Release();
}
pnetcfgOwner->Release();
}
pnetcfgPath->Release();
}
penumPaths->Release();
}
pnetcfgBindings->Release();
}
return hr;
}
HRESULT
GetBooleanValue(
IWbemClassObject *pwcoInstance,
LPCWSTR pwszProperty,
BOOLEAN *pfBoolean
)
/*++
Routine Description:
Retrieves a boolean property from a Wbem object.
Arguments:
pwcoInstance - the object to get the property from
pwszProperty - the property to retrieve
pfBoolean - received the property value
Return Value:
standard HRESULT
--*/
{
HRESULT hr = S_OK;
VARIANT vt;
_ASSERT(NULL != pwcoInstance);
_ASSERT(NULL != pwszProperty);
_ASSERT(NULL != pfBoolean);
hr = pwcoInstance->Get(
pwszProperty,
0,
&vt,
NULL,
NULL
);
if (WBEM_S_NO_ERROR == hr)
{
_ASSERT(VT_BOOL == V_VT(&vt) || VT_NULL == V_VT(&vt));
if (VT_BOOL == V_VT(&vt))
{
*pfBoolean = VARIANT_TRUE == V_BOOL(&vt);
}
else
{
//
// No value for this member was ever written to the store.
// Return FALSE, and set that value in the store. We don't
// pass along the error, if one occurs
//
*pfBoolean = FALSE;
SetBooleanValue(
pwcoInstance,
pwszProperty,
FALSE
);
}
VariantClear(&vt);
}
return hr;
}
HRESULT
GetConnectionInstanceByGuid(
IWbemServices *piwsNamespace,
BSTR bstrWQL,
GUID *pGuid,
IWbemClassObject **ppwcoConnection
)
/*++
Routine Description:
Retrieves the HNet_Connection instance for a INetConnection guid
Arguments:
piwsNamespace - WMI namespace
bstrWQL - a BSTR that corresponds to "WQL"
pGuid - the guid of the INetConnection (i.e., guidId in its properties)
ppwcoConnection - receives the HNet_Connection instance
Return Value:
standard HRESULT
--*/
{
HRESULT hr;
LPWSTR wsz;
BSTR bstrQuery;
LPOLESTR wszGuid;
IEnumWbemClassObject *pwcoEnum;
//
// Convert the guid to a string
//
hr = StringFromCLSID(*pGuid, &wszGuid);
if (S_OK == hr)
{
//
// Find the connection w/ name equal to that string
//
hr = BuildQuotedEqualsString(
&wsz,
c_wszGuid,
wszGuid
);
CoTaskMemFree(wszGuid);
if (S_OK == hr)
{
hr = BuildSelectQueryBstr(
&bstrQuery,
c_wszStar,
c_wszHnetConnection,
wsz
);
delete [] wsz;
}
if (S_OK == hr)
{
pwcoEnum = NULL;
hr = piwsNamespace->ExecQuery(
bstrWQL,
bstrQuery,
WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
NULL,
&pwcoEnum
);
SysFreeString(bstrQuery);
}
}
if (WBEM_S_NO_ERROR == hr)
{
ULONG ulCount;
//
// Get the instance out of the enum
//
*ppwcoConnection = NULL;
hr = pwcoEnum->Next(
WBEM_INFINITE,
1,
ppwcoConnection,
&ulCount
);
if (SUCCEEDED(hr) && 1 != ulCount)
{
hr = E_FAIL;
}
ValidateFinishedWCOEnum(piwsNamespace, pwcoEnum);
pwcoEnum->Release();
}
return hr;
}
HRESULT
GetConnAndPropInstancesByGuid(
IWbemServices *piwsNamespace,
GUID *pGuid,
IWbemClassObject **ppwcoConnection,
IWbemClassObject **ppwcoProperties
)
/*++
Routine Description:
Retrieves the HNet_Connection and HNet_ConnectionProperties instances
for a INetConnection guid
Arguments:
piwsNamespace - WMI namespace
pGuid - the guid of the INetConnection (i.e., guidId in its properties)
ppwcoConnection - receives the HNet_Connection instance
ppwcoProperties - receives the HNet_ConnectionProperties instance
Return Value:
standard HRESULT
--*/
{
HRESULT hr = S_OK;
BSTR bstrWQL = NULL;
_ASSERT(NULL != piwsNamespace);
_ASSERT(NULL != pGuid);
_ASSERT(NULL != ppwcoConnection);
_ASSERT(NULL != ppwcoProperties);
bstrWQL = SysAllocString(c_wszWQL);
if (NULL != bstrWQL)
{
hr = GetConnectionInstanceByGuid(
piwsNamespace,
bstrWQL,
pGuid,
ppwcoConnection
);
}
else
{
hr = E_OUTOFMEMORY;
}
if (SUCCEEDED(hr))
{
hr = GetPropInstanceFromConnInstance(
piwsNamespace,
*ppwcoConnection,
ppwcoProperties
);
if (FAILED(hr))
{
(*ppwcoConnection)->Release();
*ppwcoConnection = NULL;
}
}
if (NULL != bstrWQL)
{
SysFreeString(bstrWQL);
}
return hr;
}
HRESULT
GetConnAndPropInstancesForHNC(
IWbemServices *piwsNamespace,
IHNetConnection *pConn,
IWbemClassObject **ppwcoConnection,
IWbemClassObject **ppwcoProperties
)
/*++
Routine Description:
Retrieves the HNet_Connection and HNet_ConnectionProperties instances
for an IHNetConnection.
Arguments:
piwsNamespace - WMI namespace
pConn - the IHNetConnection
ppwcoConnection - receives the HNet_Connection instance
ppwcoProperties - receives the HNet_ConnectionProperties instance
Return Value:
standard HRESULT
--*/
{
HRESULT hr;
GUID *pGuid;
_ASSERT(NULL != piwsNamespace);
_ASSERT(NULL != pConn);
_ASSERT(NULL != ppwcoConnection);
_ASSERT(NULL != ppwcoProperties);
//
// Find the items by GUID
//
hr = pConn->GetGuid(&pGuid);
if (S_OK == hr)
{
hr = GetConnAndPropInstancesByGuid(
piwsNamespace,
pGuid,
ppwcoConnection,
ppwcoProperties
);
CoTaskMemFree(pGuid);
}
return hr;
}
HRESULT
GetPhonebookPathFromRasNetcon(
INetConnection *pConn,
LPWSTR *ppwstr
)
/*++
Routine Description:
Retrieves the phonebook path for an INetConnection that represents
a RAS connection
Arguments:
INetConnection - the RAS connection
ppwstr - receives the phonebook path. The caller must call CoTaskMemFree for
this pointer on success. On failure, the pointer receives NULL.
Return Value:
standard HRESULT
--*/
{
HRESULT hr;
INetRasConnection *pRasConn;
RASCON_INFO RasConInfo;
_ASSERT(NULL != pConn);
_ASSERT(NULL != ppwstr);
*ppwstr = NULL;
//
// QI for the INetRasConnection
//
hr = pConn->QueryInterface(
IID_PPV_ARG(INetRasConnection, &pRasConn)
);
if (SUCCEEDED(hr))
{
//
// Get the connection information
//
hr = pRasConn->GetRasConnectionInfo(&RasConInfo);
if (SUCCEEDED(hr))
{
*ppwstr = RasConInfo.pszwPbkFile;
//
// Free the name pointer. The caller is responsible for
// freeing the path pointer
//
CoTaskMemFree(RasConInfo.pszwEntryName);
}
pRasConn->Release();
}
return hr;
}
HRESULT
GetPortMappingBindingInstance(
IWbemServices *piwsNamespace,
BSTR bstrWQL,
BSTR bstrConnectionPath,
BSTR bstrProtocolPath,
USHORT usPublicPort,
IWbemClassObject **ppInstance
)
/*++
Routine Description:
Given the path to an HNet_Connection instance and and
HNet_PortMappingProtocol instance, checks to see if a
corresponding HNet_ConnectionPortMapping exists. If it
doesn't, the instance is created. The HNet_ConnectionPortMapping
instance -- existing or newly created -- is returned and must
be released by the caller.
Arguments:
piwsNamespace - the namespace to use
bstrWQL - a BSTR containing the string "WQL"
bstrConnectionPath - path to the HNet_Connection instance
bstrProtocolPath - path to the HNet_PortMappingProtocol instance
usPublicPort - the port of the port mapping protocol
ppInstance - receives the HNet_ConnectionPortMapping instance
Return Value:
Standard HRESULT
--*/
{
HRESULT hr;
IEnumWbemClassObject *pwcoEnum;
IWbemClassObject *pwcoInstance;
BSTR bstrQuery;
BSTR bstr;
LPWSTR wsz;
LPWSTR wszConClause;
LPWSTR wszProtClause;
_ASSERT(NULL != piwsNamespace);
_ASSERT(NULL != bstrWQL);
_ASSERT(NULL != bstrConnectionPath);
_ASSERT(NULL != bstrProtocolPath);
_ASSERT(NULL != ppInstance);
//
// Connection = "bstrConnectionPath" AND Protocol = "bstrProtocolPath"
//
hr = BuildEscapedQuotedEqualsString(
&wszConClause,
c_wszConnection,
bstrConnectionPath
);
if (S_OK == hr)
{
hr = BuildEscapedQuotedEqualsString(
&wszProtClause,
c_wszProtocol,
bstrProtocolPath
);
if (S_OK == hr)
{
hr = BuildAndString(
&wsz,
wszConClause,
wszProtClause
);
delete [] wszProtClause;
}
delete [] wszConClause;
}
if (S_OK == hr)
{
hr = BuildSelectQueryBstr(
&bstrQuery,
c_wszStar,
c_wszHnetConnectionPortMapping,
wsz
);
delete [] wsz;
}
if (S_OK == hr)
{
pwcoEnum = NULL;
hr = piwsNamespace->ExecQuery(
bstrWQL,
bstrQuery,
WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
NULL,
&pwcoEnum
);
SysFreeString(bstrQuery);
}
if (WBEM_S_NO_ERROR == hr)
{
ULONG ulCount;
*ppInstance = NULL;
hr = pwcoEnum->Next(WBEM_INFINITE, 1, ppInstance, &ulCount);
if (FAILED(hr) || 1 != ulCount)
{
//
// Instance does not exist -- create now. However, first make
// sure that the protocol instance bstrProtocolPath refers to
// actually exists.
//
hr = GetWmiObjectFromPath(
piwsNamespace,
bstrProtocolPath,
ppInstance
);
if (WBEM_S_NO_ERROR == hr)
{
//
// The protocol object exists -- release it and
// continue with creating the new binding object.
//
(*ppInstance)->Release();
*ppInstance = NULL;
hr = SpawnNewInstance(
piwsNamespace,
c_wszHnetConnectionPortMapping,
ppInstance
);
}
if (WBEM_S_NO_ERROR == hr)
{
VARIANT vt;
//
// Fill out new instance information
//
V_VT(&vt) = VT_BSTR;
V_BSTR(&vt) = bstrConnectionPath;
hr = (*ppInstance)->Put(
c_wszConnection,
0,
&vt,
NULL
);
if (WBEM_S_NO_ERROR == hr)
{
V_BSTR(&vt) = bstrProtocolPath;
hr = (*ppInstance)->Put(
c_wszProtocol,
0,
&vt,
NULL
);
}
if (WBEM_S_NO_ERROR == hr)
{
hr = SetBooleanValue(
*ppInstance,
c_wszEnabled,
FALSE
);
}
if (WBEM_S_NO_ERROR == hr)
{
hr = SetBooleanValue(
*ppInstance,
c_wszNameActive,
FALSE
);
}
if (WBEM_S_NO_ERROR == hr)
{
V_VT(&vt) = VT_I4;
V_I4(&vt) = 0;
hr = (*ppInstance)->Put(
c_wszTargetIPAddress,
0,
&vt,
NULL
);
}
if (WBEM_S_NO_ERROR == hr)
{
V_VT(&vt) = VT_BSTR;
V_BSTR(&vt) = SysAllocString(L" ");
if (NULL != V_BSTR(&vt))
{
hr = (*ppInstance)->Put(
c_wszTargetName,
0,
&vt,
NULL
);
VariantClear(&vt);
}
else
{
hr = E_OUTOFMEMORY;
}
}
if (WBEM_S_NO_ERROR == hr)
{
V_VT(&vt) = VT_I4;
V_I4(&vt) = usPublicPort;
hr = (*ppInstance)->Put(
c_wszTargetPort,
0,
&vt,
NULL
);
}
if (WBEM_S_NO_ERROR == hr)
{
IWbemCallResult *pResult;
//
// Write new instance to the store
//
pResult = NULL;
hr = piwsNamespace->PutInstance(
*ppInstance,
WBEM_FLAG_CREATE_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pResult
);
if (WBEM_S_NO_ERROR == hr)
{
//
// Release the object, get the path from the result,
// and re-retrieve the object from the path
//
(*ppInstance)->Release();
*ppInstance = NULL;
hr = pResult->GetResultString(WBEM_INFINITE, &bstr);
if (WBEM_S_NO_ERROR == hr)
{
hr = GetWmiObjectFromPath(
piwsNamespace,
bstr,
ppInstance
);
SysFreeString(bstr);
}
pResult->Release();
}
}
}
}
else
{
//
// Normalize enum hresult
//
hr = S_OK;
}
ValidateFinishedWCOEnum(piwsNamespace, pwcoEnum);
pwcoEnum->Release();
}
return hr;
}
HRESULT
GetPropInstanceFromConnInstance(
IWbemServices *piwsNamespace,
IWbemClassObject *pwcoConnection,
IWbemClassObject **ppwcoProperties
)
/*++
Routine Description:
Retrieves the HNet_ConnectionProperties instance associated with
an HNet_Connection.
Arguments:
piwsNamespace - WMI namespace
bstrWQL - a BSTR that corresponds to "WQL"
pwcoConnection - the HNet_Connection instance
ppwcoProperties - receives the HNet_ConnectionProperties instance
Return Value:
standard HRESULT
--*/
{
HRESULT hr = S_OK;
OLECHAR wszBuffer[c_cchQueryBuffer + 1];
OLECHAR *pwszPath = NULL;
BSTR bstrPath;
VARIANT vt;
_ASSERT(NULL != piwsNamespace);
_ASSERT(NULL != pwcoConnection);
_ASSERT(NULL != ppwcoProperties);
//
// On debug builds, verify that our precomputed string lengths
// match the actual lengths
//
_ASSERT(wcslen(c_wszConnectionPropertiesPathFormat) == c_cchConnectionPropertiesPathFormat);
//
// Get the guid for the connection
//
hr = pwcoConnection->Get(
c_wszGuid,
0,
&vt,
NULL,
NULL
);
if (WBEM_S_NO_ERROR == hr)
{
_ASSERT(VT_BSTR == V_VT(&vt));
//
// Determine how much space we need for the path and decide
// if we need to allocate a heap buffer.
//
ULONG cchLength =
c_cchConnectionPropertiesPathFormat + SysStringLen(V_BSTR(&vt)) + 1;
if (cchLength <= c_cchQueryBuffer)
{
//
// The buffer is large enough. (Note that since the buffer on the
// stack is one greater than the constant, the terminator is accounted
// for.) Point our working pointer to the stack buffer.
//
pwszPath = wszBuffer;
}
else
{
//
// Allocate a sufficient buffer from the heap. The +1 is for the
// terminating nul
//
pwszPath = new OLECHAR[cchLength + 1];
if (NULL == pwszPath)
{
hr = E_OUTOFMEMORY;
pwszPath = wszBuffer;
}
}
if (WBEM_S_NO_ERROR == hr)
{
//
// Build the path string
//
int iBytes =
_snwprintf(
pwszPath,
cchLength,
c_wszConnectionPropertiesPathFormat,
V_BSTR(&vt)
);
_ASSERT(iBytes >= 0);
//
// Convert that to a BSTR
//
bstrPath = SysAllocString(pwszPath);
if (NULL != bstrPath)
{
hr = GetWmiObjectFromPath(
piwsNamespace,
bstrPath,
ppwcoProperties
);
SysFreeString(bstrPath);
}
else
{
hr = E_OUTOFMEMORY;
}
}
VariantClear(&vt);
}
//
// Free the query buffer, if necessary
//
if (wszBuffer != pwszPath)
{
delete [] pwszPath;
}
return hr;
}
HRESULT
GetWmiObjectFromPath(
IWbemServices *piwsNamespace,
BSTR bstrPath,
IWbemClassObject **ppwcoInstance
)
/*++
Routine Description:
Retrieves the IWbemClassObject corresponding to an object path.
Arguments:
piwsNamespace - the WMI namespace the object lives in
bstrPath - the path to the object
ppwcoInstance - receives the object instance
Return Value:
standard HRESULT
--*/
{
HRESULT hr;
_ASSERT(NULL != piwsNamespace);
_ASSERT(NULL != bstrPath);
_ASSERT(NULL != ppwcoInstance);
*ppwcoInstance = NULL;
hr = piwsNamespace->GetObject(
bstrPath,
WBEM_FLAG_RETURN_WBEM_COMPLETE,
NULL,
ppwcoInstance,
NULL
);
return hr;
}
HRESULT
GetWmiPathFromObject(
IWbemClassObject *pwcoInstance,
BSTR *pbstrPath
)
/*++
Routine Description:
Retrieves the object path corresponding to an IWbemClassObject instance.
Arguments:
pwcoInstance - the object instance to retrieve the path of
pbstrPath - receives the path to the object
Return Value:
standard HRESULT
--*/
{
HRESULT hr;
VARIANT vt;
_ASSERT(NULL != pwcoInstance);
_ASSERT(NULL != pbstrPath);
hr = pwcoInstance->Get(
c_wsz__Path,
0,
&vt,
NULL,
NULL
);
if (WBEM_S_NO_ERROR == hr)
{
_ASSERT(VT_BSTR == V_VT(&vt));
*pbstrPath = V_BSTR(&vt);
//
// BSTR ownership transferred to caller
//
}
return hr;
}
HRESULT
HostAddrToIpPsz(
DWORD dwAddress,
LPWSTR* ppszwNewStr
)
// Converts IP Address from host by order to string
{
HRESULT hr = S_OK;
LPWSTR pszwStr;
*ppszwNewStr = NULL;
pszwStr = reinterpret_cast<LPWSTR>(CoTaskMemAlloc(sizeof(WCHAR) * 16));
if ( NULL == pszwStr )
{
hr = E_OUTOFMEMORY;
}
else
{
swprintf( pszwStr,
TEXT("%u.%u.%u.%u"),
(dwAddress&0xff),
((dwAddress>>8)&0x0ff),
((dwAddress>>16)&0x0ff),
((dwAddress>>24)&0x0ff) );
*ppszwNewStr = pszwStr;
}
return hr;
}
DWORD
IpPszToHostAddr(
LPCWSTR cp
)
// Converts an IP address represented as a string to
// host byte order.
//
{
DWORD val, base, n;
TCHAR c;
DWORD parts[4], *pp = parts;
again:
// Collect number up to ``.''.
// Values are specified as for C:
// 0x=hex, 0=octal, other=decimal.
//
val = 0; base = 10;
if (*cp == TEXT('0'))
base = 8, cp++;
if (*cp == TEXT('x') || *cp == TEXT('X'))
base = 16, cp++;
while (c = *cp)
{
if ((c >= TEXT('0')) && (c <= TEXT('9')))
{
val = (val * base) + (c - TEXT('0'));
cp++;
continue;
}
if ((base == 16) &&
( ((c >= TEXT('0')) && (c <= TEXT('9'))) ||
((c >= TEXT('A')) && (c <= TEXT('F'))) ||
((c >= TEXT('a')) && (c <= TEXT('f'))) ))
{
val = (val << 4) + (c + 10 - (
((c >= TEXT('a')) && (c <= TEXT('f')))
? TEXT('a')
: TEXT('A') ) );
cp++;
continue;
}
break;
}
if (*cp == TEXT('.'))
{
// Internet format:
// a.b.c.d
// a.b.c (with c treated as 16-bits)
// a.b (with b treated as 24 bits)
//
if (pp >= parts + 3)
return (DWORD) -1;
*pp++ = val, cp++;
goto again;
}
// Check for trailing characters.
//
if (*cp && (*cp != TEXT(' ')))
return 0xffffffff;
*pp++ = val;
// Concoct the address according to
// the number of parts specified.
//
n = (DWORD) (pp - parts);
switch (n)
{
case 1: // a -- 32 bits
val = parts[0];
break;
case 2: // a.b -- 8.24 bits
val = (parts[0] << 24) | (parts[1] & 0xffffff);
break;
case 3: // a.b.c -- 8.8.16 bits
val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
(parts[2] & 0xffff);
break;
case 4: // a.b.c.d -- 8.8.8.8 bits
val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
((parts[2] & 0xff) << 8) | (parts[3] & 0xff);
break;
default:
return 0xffffffff;
}
return val;
}
BOOLEAN
IsRoutingProtocolInstalled(
ULONG ulProtocolId
)
/*++
Routine Description:
This routine is invoked to determine whether the routing protocol
with the given protocol-ID is installed for Routing and Remote Access.
This is determined by examining the configuration for the service.
Arguments:
ulProtocolId - identifies the protocol to be found
Return Value:
TRUE if the protocol is installed, FALSE otherwise.
--*/
{
PUCHAR Buffer;
ULONG BufferLength;
HINSTANCE Hinstance;
PMPRCONFIGBUFFERFREE MprConfigBufferFree;
PMPRCONFIGSERVERCONNECT MprConfigServerConnect;
PMPRCONFIGSERVERDISCONNECT MprConfigServerDisconnect;
PMPRCONFIGTRANSPORTGETHANDLE MprConfigTransportGetHandle;
PMPRCONFIGTRANSPORTGETINFO MprConfigTransportGetInfo;
PMPRINFOBLOCKFIND MprInfoBlockFind;
HANDLE ServerHandle;
HANDLE TransportHandle;
//
// Load the MPRAPI.DLL module and retrieve the entrypoints
// to be used for examining the RRAS configuration.
//
if (!(Hinstance = LoadLibraryW(c_wszMprapiDll)) ||
!(MprConfigBufferFree =
(PMPRCONFIGBUFFERFREE)
GetProcAddress(Hinstance, c_szMprConfigBufferFree)) ||
!(MprConfigServerConnect =
(PMPRCONFIGSERVERCONNECT)
GetProcAddress(Hinstance, c_szMprConfigServerConnect)) ||
!(MprConfigServerDisconnect =
(PMPRCONFIGSERVERDISCONNECT)
GetProcAddress(Hinstance, c_szMprConfigServerDisconnect)) ||
!(MprConfigTransportGetHandle =
(PMPRCONFIGTRANSPORTGETHANDLE)
GetProcAddress(Hinstance, c_szMprConfigTransportGetHandle)) ||
!(MprConfigTransportGetInfo =
(PMPRCONFIGTRANSPORTGETINFO)
GetProcAddress(Hinstance, c_szMprConfigTransportGetInfo)) ||
!(MprInfoBlockFind =
(PMPRINFOBLOCKFIND)
GetProcAddress(Hinstance, c_szMprInfoBlockFind))) {
if (Hinstance) { FreeLibrary(Hinstance); }
return FALSE;
}
//
// Connect to the RRAS configuration, and retrieve the configuration
// for the IP transport-layer routing protocols. This should include
// the configuration for the routing-protocol in 'ProtocolId',
// if installed.
//
ServerHandle = NULL;
if (MprConfigServerConnect(NULL, &ServerHandle) != NO_ERROR ||
MprConfigTransportGetHandle(ServerHandle, PID_IP, &TransportHandle)
!= NO_ERROR ||
MprConfigTransportGetInfo(
ServerHandle,
TransportHandle,
&Buffer,
&BufferLength,
NULL,
NULL,
NULL
) != NO_ERROR) {
if (ServerHandle) { MprConfigServerDisconnect(ServerHandle); }
FreeLibrary(Hinstance);
return FALSE;
}
MprConfigServerDisconnect(ServerHandle);
//
// Look for the requested protocol's configuration,
// and return TRUE if it is found; otherwise, return FALSE.
//
if (MprInfoBlockFind(Buffer, ulProtocolId, NULL, NULL, NULL) == NO_ERROR) {
MprConfigBufferFree(Buffer);
FreeLibrary(Hinstance);
return TRUE;
}
MprConfigBufferFree(Buffer);
FreeLibrary(Hinstance);
return FALSE;
} // IsRoutingProtocolInstalled
BOOLEAN
IsServiceRunning(
LPCWSTR pwszServiceName
)
/*++
Routine Description:
Determines if a service is in a running state.
Arguments:
pwszServiceName - the service to check
Return Value:
TRUE if the service is in the running or start_pending state,
FALSE otherwise
--*/
{
BOOLEAN fServiceRunning = FALSE;
SC_HANDLE hScm;
SC_HANDLE hService;
SERVICE_STATUS Status;
hScm = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, GENERIC_READ);
if (NULL != hScm)
{
hService = OpenService(hScm, pwszServiceName, GENERIC_READ);
if (NULL != hService)
{
if (QueryServiceStatus(hService, &Status))
{
fServiceRunning =
(SERVICE_RUNNING == Status.dwCurrentState
|| SERVICE_START_PENDING == Status.dwCurrentState);
}
CloseServiceHandle(hService);
}
CloseServiceHandle(hScm);
}
return fServiceRunning;
} // IsServiceRunning
HRESULT
MapGuidStringToAdapterIndex(
LPCWSTR pwszGuid,
ULONG *pulIndex
)
/*++
Routine Description:
This routine is called to match the GUID in the given string to
an adapter in the list returned by calling GetInterfaceInfo.
Arguments:
pwszGuid - identifies the GUID of the adapter to be found. The GUID string
must be in the format returned by RtlGuidToUnicodeString
pulIndex - receives the index of the adapter
Return Value:
standard HRESULT
--*/
{
HRESULT hr = S_OK;
ULONG ulError;
ULONG i;
ULONG GuidLength;
PIP_INTERFACE_INFO Info;
PWCHAR Name;
ULONG NameLength;
ULONG Size;
_ASSERT(NULL != pwszGuid);
_ASSERT(NULL != pulIndex);
Size = 0;
GuidLength = wcslen(pwszGuid);
ulError = GetInterfaceInfo(NULL, &Size);
if (ERROR_INSUFFICIENT_BUFFER == ulError)
{
Info = new IP_INTERFACE_INFO[Size];
if (NULL != Info)
{
ulError = GetInterfaceInfo(Info, &Size);
if (NO_ERROR == ulError)
{
for (i = 0; i < (ULONG)Info->NumAdapters; i++)
{
NameLength = wcslen(Info->Adapter[i].Name);
if (NameLength < GuidLength) { continue; }
Name = Info->Adapter[i].Name + (NameLength - GuidLength);
if (_wcsicmp(pwszGuid, Name) == 0)
{
*pulIndex = Info->Adapter[i].Index;
break;
}
}
}
else
{
hr = HRESULT_FROM_WIN32(ulError);
}
delete [] Info;
}
else
{
hr = E_OUTOFMEMORY;
}
}
else
{
hr = HRESULT_FROM_WIN32(ulError);
}
return hr;
}
HRESULT
OpenRegKey(
PHANDLE Key,
ACCESS_MASK DesiredAccess,
PCWSTR Name
)
/*++
Routine Description:
This routine is invoked to open a given registry key.
Arguments:
Key - receives the opened key
DesiredAccess - specifies the requested access
Name - specifies the key to be opened
Return Value:
HRESULT - NT status code.
--*/
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING UnicodeString;
RtlInitUnicodeString(&UnicodeString, Name);
InitializeObjectAttributes(
&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
return NtOpenKey(Key, DesiredAccess, &ObjectAttributes);
} // OpenRegKey
BOOLEAN
PortMappingProtocolExists(
IWbemServices *piwsNamespace,
BSTR bstrWQL,
USHORT usPort,
UCHAR ucIPProtocol
)
/*++
Routine Description:
Checks if an port mapping protocol already exists that has the
specified protocol and port.
Arguments:
piwsNamespace - the namespace to use
bstrWQL - a BSTR containing "WQL"
ucProtocol - the protocol number to check for
usPort - the port to check for
Return Value:
BOOLEAN -- TRUE if the port mapping protocol exists; FALSE otherwise
--*/
{
BSTR bstr;
BOOLEAN fDuplicate = FALSE;
HRESULT hr = S_OK;
int iBytes;
IEnumWbemClassObject *pwcoEnum;
IWbemClassObject *pwcoInstance;
ULONG ulObjs;
OLECHAR wszWhereClause[c_cchQueryBuffer + 1];
_ASSERT(NULL != piwsNamespace);
_ASSERT(NULL != bstrWQL);
_ASSERT(0 == wcscmp(bstrWQL, L"WQL"));
//
// Build the query string
//
iBytes = _snwprintf(
wszWhereClause,
c_cchQueryBuffer,
c_wszPortMappingProtocolQueryFormat,
usPort,
ucIPProtocol
);
if (iBytes >= 0)
{
//
// String fit into buffer; make sure it's null terminated
//
wszWhereClause[c_cchQueryBuffer] = L'\0';
}
else
{
//
// For some reason the string didn't fit into the buffer...
//
hr = E_UNEXPECTED;
_ASSERT(FALSE);
}
if (S_OK == hr)
{
hr = BuildSelectQueryBstr(
&bstr,
c_wszStar,
c_wszHnetPortMappingProtocol,
wszWhereClause
);
}
if (S_OK == hr)
{
//
// Execute the query
//
pwcoEnum = NULL;
hr = piwsNamespace->ExecQuery(
bstrWQL,
bstr,
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pwcoEnum
);
SysFreeString(bstr);
}
if (S_OK == hr)
{
//
// Attempt to retrieve an item from the enum. If we're successful,
// this is a duplicate protocol.
//
pwcoInstance = NULL;
hr = pwcoEnum->Next(
WBEM_INFINITE,
1,
&pwcoInstance,
&ulObjs
);
if (SUCCEEDED(hr) && 1 == ulObjs)
{
//
// It's a duplicate
//
fDuplicate = TRUE;
pwcoInstance->Release();
}
pwcoEnum->Release();
}
return fDuplicate;
} // PortMappingProtocolExists
HRESULT
QueryRegValueKey(
HANDLE Key,
const WCHAR ValueName[],
PKEY_VALUE_PARTIAL_INFORMATION* Information
)
/*++
Routine Description:
This routine is called to obtain the value of a registry key.
Arguments:
Key - the key to be queried
ValueName - the value to be queried
Information - receives a pointer to the information read. On success,
the caller must HeapFree this pointer
Return Value:
HRESULT - NT status code.
--*/
{
UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
ULONG InformationLength;
NTSTATUS status;
UNICODE_STRING UnicodeString;
RtlInitUnicodeString(&UnicodeString, ValueName);
*Information = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer;
InformationLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION);
//
// Read the value's size
//
status =
NtQueryValueKey(
Key,
&UnicodeString,
KeyValuePartialInformation,
*Information,
InformationLength,
&InformationLength
);
if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW &&
status != STATUS_BUFFER_TOO_SMALL) {
*Information = NULL;
return status;
}
//
// Allocate space for the value's size
//
*Information = (PKEY_VALUE_PARTIAL_INFORMATION) HeapAlloc(
GetProcessHeap(),
0,
InformationLength+2
);
if (!*Information) { return STATUS_NO_MEMORY; }
//
// Read the value's data
//
status =
NtQueryValueKey(
Key,
&UnicodeString,
KeyValuePartialInformation,
*Information,
InformationLength,
&InformationLength
);
if (!NT_SUCCESS(status))
{
HeapFree(GetProcessHeap(), 0, *Information);
*Information = NULL;
}
return status;
} // QueryRegValueKey
HRESULT
ReadDhcpScopeSettings(
DWORD *pdwScopeAddress,
DWORD *pdwScopeMask
)
{
_ASSERT(NULL != pdwScopeAddress);
_ASSERT(NULL != pdwScopeMask);
//
// This routine never fails. Set default address/mask
// (192.168.0.1/255.255.255.255, in network order)
//
*pdwScopeAddress = 0x0100a8c0;
*pdwScopeMask = 0x00ffffff;
//
// $$TODO: Check to see if these values are overiddent
// through a registry entry
//
return S_OK;
}
HRESULT
RetrieveSingleInstance(
IWbemServices *piwsNamespace,
const OLECHAR *pwszClass,
BOOLEAN fCreate,
IWbemClassObject **ppwcoInstance
)
/*++
Routine Description:
Retrieves a single instance of a class from the WMI store. If there
are more than one instance, every instance after the first is deleted,
and an assertion is raised. If there are no instances, one is optionally
created.
Arguments:
piwsNamespace - WMI namespace
pwszClass - the class to retrieve the instance of
fCreate - create an instance if one does not already exist
ppwcoInstance - receive the instance
Return Value:
standard HRESULT
--*/
{
HRESULT hr = S_OK;
IEnumWbemClassObject *pwcoEnum = NULL;
BSTR bstrClass = NULL;
ULONG ulCount = 0;
_ASSERT(NULL != piwsNamespace);
_ASSERT(NULL != pwszClass);
_ASSERT(NULL != ppwcoInstance);
//
// Allocate the BSTR for the class name
//
bstrClass = SysAllocString(pwszClass);
if (NULL == bstrClass)
{
hr = E_OUTOFMEMORY;
}
//
// Query the WMI store for instances of the class
//
if (S_OK == hr)
{
pwcoEnum = NULL;
hr = piwsNamespace->CreateInstanceEnum(
bstrClass,
WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
NULL,
&pwcoEnum
);
SysFreeString(bstrClass);
}
if (WBEM_S_NO_ERROR == hr)
{
//
// Attempt to retrieve an actual instance from the enumeration.
// Even if there are zero instances, WMI considers returning a
// zero-element enumerator success.
//
*ppwcoInstance = NULL;
hr = pwcoEnum->Next(
WBEM_INFINITE,
1,
ppwcoInstance,
&ulCount
);
if (SUCCEEDED(hr) && 1 == ulCount)
{
//
// Normalize return value
//
hr = S_OK;
//
// Validate that enumeration is now empty
//
ValidateFinishedWCOEnum(piwsNamespace, pwcoEnum);
}
else
{
if (WBEM_S_FALSE == hr)
{
//
// No items in enumeration.
//
if (fCreate)
{
//
// Create a new object instance
//
hr = SpawnNewInstance(
piwsNamespace,
pwszClass,
ppwcoInstance
);
}
else
{
//
// Change this to an error code. This
// is deliberately not a WBEM error code.
//
hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND);
}
}
}
pwcoEnum->Release();
}
return hr;
}
HRESULT
SetBooleanValue(
IWbemClassObject *pwcoInstance,
LPCWSTR pwszProperty,
BOOLEAN fBoolean
)
/*++
Routine Description:
Retrieves a boolean property from a Wbem object.
Arguments:
pwcoInstance - the object to get the property from
pwszProperty - the property to retrieve
pfBoolean - received the property value
Return Value:
standard HRESULT
--*/
{
HRESULT hr = S_OK;
VARIANT vt;
_ASSERT(NULL != pwcoInstance);
_ASSERT(NULL != pwszProperty);
VariantInit(&vt);
V_VT(&vt) = VT_BOOL;
V_BOOL(&vt) = (fBoolean ? VARIANT_TRUE : VARIANT_FALSE);
hr = pwcoInstance->Put(
pwszProperty,
0,
&vt,
NULL
);
return hr;
}
VOID
SetProxyBlanket(
IUnknown *pUnk
)
/*++
Routine Description:
Sets the standard COM security settings on the proxy for an
object.
Arguments:
pUnk - the object to set the proxy blanket on
Return Value:
None. Even if the CoSetProxyBlanket calls fail, pUnk remains
in a usable state. Failure is expected in certain contexts, such
as when, for example, we're being called w/in the netman process --
in this case, we have direct pointers to the netman objects, instead
of going through a proxy.
--*/
{
HRESULT hr;
_ASSERT(pUnk);
hr = CoSetProxyBlanket(
pUnk,
RPC_C_AUTHN_WINNT, // use NT default security
RPC_C_AUTHZ_NONE, // use NT default authentication
NULL, // must be null if default
RPC_C_AUTHN_LEVEL_CALL, // call
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL, // use process token
EOAC_NONE
);
if (SUCCEEDED(hr))
{
IUnknown * pUnkSet = NULL;
hr = pUnk->QueryInterface(&pUnkSet);
if (SUCCEEDED(hr))
{
hr = CoSetProxyBlanket(
pUnkSet,
RPC_C_AUTHN_WINNT, // use NT default security
RPC_C_AUTHZ_NONE, // use NT default authentication
NULL, // must be null if default
RPC_C_AUTHN_LEVEL_CALL, // call
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL, // use process token
EOAC_NONE
);
pUnkSet->Release();
}
}
}
HRESULT
SpawnNewInstance(
IWbemServices *piwsNamespace,
LPCWSTR wszClass,
IWbemClassObject **ppwcoInstance
)
/*++
Routine Description:
Creates a new instance of a class
Arguments:
piwsNamespace - the namespace the class is in
wszClass - the class to create the instance of
ppwcoInstance -- receives the created instance
Return Value:
standard HRESULT
--*/
{
HRESULT hr;
BSTR bstr;
IWbemClassObject *pwcoClass;
_ASSERT(NULL != piwsNamespace);
_ASSERT(NULL != wszClass);
_ASSERT(NULL != ppwcoInstance);
*ppwcoInstance = NULL;
bstr = SysAllocString(wszClass);
if (NULL != bstr)
{
pwcoClass = NULL;
hr = piwsNamespace->GetObject(
bstr,
WBEM_FLAG_RETURN_WBEM_COMPLETE,
NULL,
&pwcoClass,
NULL
);
SysFreeString(bstr);
}
else
{
hr = E_OUTOFMEMORY;
}
if (WBEM_S_NO_ERROR == hr)
{
hr = pwcoClass->SpawnInstance(0, ppwcoInstance);
pwcoClass->Release();
}
return hr;
}
DWORD
StartOrUpdateService(
VOID
)
/*++
Routine Description:
This routine is invoked to start the SharedAccess service. It will
also mark the service as auto-start. If the service is already running,
it will send a IPNATHLP_CONTROL_UPDATE_CONNECTION notification
Arguments:
none.
Return Value:
ULONG - Win32 status code.
--*/
{
ULONG Error;
SC_HANDLE ScmHandle;
SC_HANDLE ServiceHandle;
SERVICE_STATUS ServiceStatus;
ULONG Timeout;
//
// Connect to the service control manager
//
ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!ScmHandle) { return GetLastError(); }
do {
//
// Open the shared access service
//
ServiceHandle =
OpenService(ScmHandle, c_wszSharedAccess, SERVICE_ALL_ACCESS);
if (!ServiceHandle) { Error = GetLastError(); break; }
//
// Mark it as auto-start
//
ChangeServiceConfig(
ServiceHandle,
SERVICE_NO_CHANGE,
SERVICE_AUTO_START,
SERVICE_NO_CHANGE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
);
// if we are in ICS Upgrade, don't start the SharedAccess service because the
// service may have problem in starting up during GUI Mode Setup.
HANDLE hIcsUpgradeEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, c_wszIcsUpgradeEventName);
if (NULL != hIcsUpgradeEvent)
{
CloseHandle(hIcsUpgradeEvent);
Error = NO_ERROR;
break;
}
//
// Attempt to start the service
//
if (!StartService(ServiceHandle, 0, NULL)) {
Error = GetLastError();
if (Error == ERROR_SERVICE_ALREADY_RUNNING)
{
//
// Send control notification
//
Error = NO_ERROR;
if (!ControlService(
ServiceHandle,
IPNATHLP_CONTROL_UPDATE_CONNECTION,
&ServiceStatus
))
{
Error = GetLastError();
}
}
break;
}
//
// Wait for the service to start
//
Timeout = 30;
Error = ERROR_CAN_NOT_COMPLETE;
do {
//
// Query the service's state
//
if (!QueryServiceStatus(ServiceHandle, &ServiceStatus)) {
Error = GetLastError(); break;
}
//
// See if the service has started
//
if (ServiceStatus.dwCurrentState == SERVICE_RUNNING) {
Error = NO_ERROR; break;
} else if (ServiceStatus.dwCurrentState == SERVICE_STOPPED ||
ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING) {
break;
}
//
// Wait a little longer
//
Sleep(1000);
} while(Timeout--);
} while(FALSE);
if (ServiceHandle) { CloseServiceHandle(ServiceHandle); }
CloseServiceHandle(ScmHandle);
return Error;
}
VOID
StopService(
VOID
)
/*++
Routine Description:
Stops the SharedAccess service, and marks it as demand start.
Arguments:
none.
Return Value:
none.
--*/
{
ULONG Error;
SC_HANDLE ScmHandle;
SC_HANDLE ServiceHandle;
SERVICE_STATUS ServiceStatus;
//
// Connect to the service control manager
//
ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!ScmHandle) { return; }
do {
//
// Open the shared access service
//
ServiceHandle =
OpenService(ScmHandle, c_wszSharedAccess, SERVICE_ALL_ACCESS);
if (!ServiceHandle) { Error = GetLastError(); break; }
//
// Mark it as demand-start
//
ChangeServiceConfig(
ServiceHandle,
SERVICE_NO_CHANGE,
SERVICE_DEMAND_START,
SERVICE_NO_CHANGE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
);
//
// Attempt to stop the service
//
ControlService(ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus);
} while(FALSE);
if (ServiceHandle) { CloseServiceHandle(ServiceHandle); }
CloseServiceHandle(ScmHandle);
}
HRESULT
UpdateOrStopService(
IWbemServices *piwsNamespace,
BSTR bstrWQL,
DWORD dwControlCode
)
/*++
Routine Description:
Checks to see if there are any firewalled or ICS connections. If so,
an update request is sent to the SharedAccess service; if not, the
service is stopped
Arguments:
piwsNamespace - WMI namespace
bstrWQL - a BSTR that corresponds to "WQL"
dwControlCode - the kind of update to send
Return Value:
standard HRESULT
--*/
{
HRESULT hr = S_OK;
IEnumWbemClassObject *pwcoEnum;
BSTR bstrQuery;
_ASSERT(NULL != piwsNamespace);
_ASSERT(NULL != bstrWQL);
//
// See if we have any connections that are marked as
// * ICS public
// * ICS private
// * firewalled
//
// (We don't care about bridged connections, as the SharedAccess service
// doesn't have anything to do with the bridge.)
//
bstrQuery = SysAllocString(c_wszServiceCheckQuery);
if (NULL != bstrQuery)
{
pwcoEnum = NULL;
hr = piwsNamespace->ExecQuery(
bstrWQL,
bstrQuery,
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pwcoEnum
);
SysFreeString(bstrQuery);
}
else
{
hr = E_OUTOFMEMORY;
}
if (WBEM_S_NO_ERROR == hr)
{
ULONG ulCount;
IWbemClassObject *pwcoObj;
//
// Check to see if the query returned anything
//
pwcoObj = NULL;
hr = pwcoEnum->Next(WBEM_INFINITE, 1, &pwcoObj, &ulCount);
if (SUCCEEDED(hr))
{
if (1 == ulCount)
{
//
// Object retrieved -- need to update service
//
pwcoObj->Release();
UpdateService(dwControlCode);
}
else
{
//
// No object retrieved -- stop service
//
StopService();
}
}
pwcoEnum->Release();
}
return hr;
}
VOID
UpdateService(
DWORD dwControlCode
)
/*++
Routine Description:
Sends a control code to the SharedAccess service
Arguments:
dwControlCode - the code to send
Return Value:
none.
--*/
{
ULONG Error;
SC_HANDLE ScmHandle;
SC_HANDLE ServiceHandle;
SERVICE_STATUS ServiceStatus;
//
// Connect to the service control manager
//
ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!ScmHandle) { return; }
do {
//
// Open the shared access service
//
ServiceHandle =
OpenService(ScmHandle, c_wszSharedAccess, SERVICE_ALL_ACCESS);
if (!ServiceHandle) { Error = GetLastError(); break; }
//
// Send the control notification
//
ControlService(ServiceHandle, dwControlCode, &ServiceStatus);
} while(FALSE);
if (ServiceHandle) { CloseServiceHandle(ServiceHandle); }
CloseServiceHandle(ScmHandle);
}
VOID
ValidateFinishedWCOEnum(
IWbemServices *piwsNamespace,
IEnumWbemClassObject *pwcoEnum
)
/*++
Routine Description:
Checks to see that a WCO enumerator is finished (i.e., all objects
have been retrieved). If the enumerator is not finished, any object
instances that are retrieved will be deleted, and an assertion will
be raised on checked builds.
Arguments:
piwsNamespace - the namespace the enumeration is from
pwcoEnum - the enumeration to validate
Return Value:
None.
--*/
{
HRESULT hr;
IWbemClassObject *pwcoInstance = NULL;
ULONG ulCount = 0;
_ASSERT(piwsNamespace);
_ASSERT(pwcoEnum);
do
{
pwcoInstance = NULL;
hr = pwcoEnum->Next(
WBEM_INFINITE,
1,
&pwcoInstance,
&ulCount
);
if (SUCCEEDED(hr) && 1 == ulCount)
{
//
// We got an unexpected instance.
//
_ASSERT(FALSE);
//
// Delete the instance. Don't care about return value.
//
DeleteWmiInstance(
piwsNamespace,
pwcoInstance
);
pwcoInstance->Release();
}
}
while (SUCCEEDED(hr) && 1 == ulCount);
}
HRESULT
SendPortMappingListChangeNotification()
{
HRESULT hr = S_OK;
ISharedAccessUpdate* pUpdate = NULL;
if ( IsServiceRunning(c_wszSharedAccess) )
{
hr = CoCreateInstance(
CLSID_SAUpdate,
NULL,
CLSCTX_SERVER,
IID_PPV_ARG( ISharedAccessUpdate, &pUpdate )
);
if ( SUCCEEDED(hr) )
{
hr = pUpdate->PortMappingListChanged();
pUpdate->Release();
}
}
return hr;
}
HRESULT
SignalModifiedConnection(
GUID *pGUID
)
/*++
Routine Description:
Signals a modification to a network connection (refreshes the UI)
Arguments:
pGUID The GUID of the modified connection
Return Value:
Result of the operation
--*/
{
HRESULT hr;
INetConnection *pConn;
hr = FindINetConnectionByGuid( pGUID, &pConn );
if( SUCCEEDED(hr) )
{
INetConnectionRefresh *pNetConRefresh;
hr = CoCreateInstance(
CLSID_ConnectionManager,
NULL,
CLSCTX_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
IID_PPV_ARG(INetConnectionRefresh, &pNetConRefresh)
);
if( SUCCEEDED(hr) )
{
SetProxyBlanket(pNetConRefresh);
hr = pNetConRefresh->ConnectionModified(pConn);
pNetConRefresh->Release();
}
pConn->Release();
}
return hr;
}
HRESULT
SignalNewConnection(
GUID *pGUID
)
/*++
Routine Description:
Signals that a new network connection has been created (refreshes the UI)
Arguments:
pGUID The GUID of the new connection
Return Value:
Result of the operation
--*/
{
HRESULT hr;
INetConnection *pConn;
hr = FindINetConnectionByGuid( pGUID, &pConn );
if( SUCCEEDED(hr) )
{
INetConnectionRefresh *pNetConRefresh;
hr = CoCreateInstance(
CLSID_ConnectionManager,
NULL,
CLSCTX_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
IID_PPV_ARG(INetConnectionRefresh, &pNetConRefresh)
);
if( SUCCEEDED(hr) )
{
SetProxyBlanket(pNetConRefresh);
hr = pNetConRefresh->ConnectionAdded(pConn);
pNetConRefresh->Release();
}
pConn->Release();
}
return hr;
}
HRESULT
SignalDeletedConnection(
GUID *pGUID
)
/*++
Routine Description:
Signals that a network connection has been deleted (refreshes the UI)
Arguments:
pGUID The GUID of the deleted connection
Return Value:
Result of the operation
--*/
{
HRESULT hr;
INetConnectionRefresh *pNetConRefresh;
hr = CoCreateInstance(
CLSID_ConnectionManager,
NULL,
CLSCTX_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
IID_PPV_ARG(INetConnectionRefresh, &pNetConRefresh)
);
if( SUCCEEDED(hr) )
{
hr = pNetConRefresh->ConnectionDeleted(pGUID);
pNetConRefresh->Release();
}
return hr;
}