4647 lines
94 KiB
C++
4647 lines
94 KiB
C++
//+---------------------------------------------------------------------------
|
||
//
|
||
// 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;
|
||
}
|