mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4646 lines
94 KiB
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;
|
|
}
|