//+--------------------------------------------------------------------------- // // 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(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(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(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 *pHNCfgMgrChild; *ppv = NULL; hr = CComObject::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(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; }