//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1997 - 2000 // // File: H N P R T M A P . C P P // // Contents: CHNetPortMappingProtocol implementation // // Notes: // // Author: jonburs 22 June 2000 // //---------------------------------------------------------------------------- #include "pch.h" #pragma hdrstop // // Atl methods // HRESULT CHNetPortMappingProtocol::FinalConstruct() { HRESULT hr = S_OK; m_bstrWQL = SysAllocString(c_wszWQL); if (NULL == m_bstrWQL) { hr = E_OUTOFMEMORY; } return hr; } HRESULT CHNetPortMappingProtocol::FinalRelease() { if (m_piwsHomenet) m_piwsHomenet->Release(); if (m_bstrProtocol) SysFreeString(m_bstrProtocol); if (m_bstrWQL) SysFreeString(m_bstrWQL); return S_OK; } // // Object initialization // HRESULT CHNetPortMappingProtocol::Initialize( IWbemServices *piwsNamespace, IWbemClassObject *pwcoInstance ) { HRESULT hr = S_OK; _ASSERT(NULL == m_piwsHomenet); _ASSERT(NULL == m_bstrProtocol); _ASSERT(NULL != piwsNamespace); _ASSERT(NULL != pwcoInstance); // // Read and cache our builtin value // hr = GetBooleanValue( pwcoInstance, c_wszBuiltIn, &m_fBuiltIn ); if (WBEM_S_NO_ERROR == hr) { hr = GetWmiPathFromObject(pwcoInstance, &m_bstrProtocol); } if (WBEM_S_NO_ERROR == hr) { m_piwsHomenet = piwsNamespace; m_piwsHomenet->AddRef(); } return hr; } // // IHNetPortMappingProtocol methods // STDMETHODIMP CHNetPortMappingProtocol::GetName( OLECHAR **ppszwName ) { HRESULT hr = S_OK; IWbemClassObject *pwcoProtocol; VARIANT vt; if (NULL == ppszwName) { hr = E_POINTER; } else { *ppszwName = NULL; hr = GetProtocolObject(&pwcoProtocol); } if (S_OK == hr) { // // Read the name property from our instance // hr = pwcoProtocol->Get( c_wszName, NULL, &vt, NULL, NULL ); pwcoProtocol->Release(); } if (WBEM_S_NO_ERROR == hr) { _ASSERT(VT_BSTR == V_VT(&vt)); if (m_fBuiltIn) { UINT uiId; // // Attempt to convert the retrieved name to a resource // ID. (For localization purposes the names for builtin // protocols are stored as resources instead of directly // w/in the store.) // uiId = static_cast(_wtoi(V_BSTR(&vt))); if (0 != uiId) { WCHAR wszBuffer[256]; int iLength; iLength = LoadString( _Module.GetResourceInstance(), uiId, wszBuffer, sizeof(wszBuffer) / sizeof(WCHAR) ); if (0 != iLength) { // // We were able to map the name to a resource. Allocate // the output buffer and copy over the resource string. // *ppszwName = reinterpret_cast( CoTaskMemAlloc((iLength + 1) * sizeof(OLECHAR)) ); if (NULL != *ppszwName) { wcscpy(*ppszwName, wszBuffer); } else { hr = E_OUTOFMEMORY; } } } } if (WBEM_S_NO_ERROR == hr && NULL == *ppszwName) { // // This isn't a builtin protocol, or we weren't able to map // the stored "name" to a resource. Allocate the output // buffer and copy over the retrieved BSTR. // *ppszwName = reinterpret_cast( CoTaskMemAlloc((SysStringLen(V_BSTR(&vt)) + 1) * sizeof(OLECHAR)) ); if (NULL != *ppszwName) { wcscpy(*ppszwName, V_BSTR(&vt)); } else { hr = E_OUTOFMEMORY; } } VariantClear(&vt); } return hr; } STDMETHODIMP CHNetPortMappingProtocol::SetName( OLECHAR *pszwName ) { HRESULT hr = S_OK; IWbemClassObject *pwcoProtocol; VARIANT vt; if (TRUE == m_fBuiltIn) { // // Can't change values for builtin protocols // hr = E_ACCESSDENIED; } else if (NULL == pszwName) { hr = E_INVALIDARG; } else { hr = GetProtocolObject(&pwcoProtocol); } if (S_OK == hr) { // // Wrap the passed-in string in a BSTR and a variant // VariantInit(&vt); V_VT(&vt) = VT_BSTR; V_BSTR(&vt) = SysAllocString(pszwName); if (NULL == V_BSTR(&vt)) { hr = E_OUTOFMEMORY; } if (S_OK == hr) { // // Set the property on the instance // hr = pwcoProtocol->Put( c_wszName, 0, &vt, NULL ); VariantClear(&vt); } if (WBEM_S_NO_ERROR == hr) { // // Write the modified instance to the store // hr = m_piwsHomenet->PutInstance( pwcoProtocol, WBEM_FLAG_UPDATE_ONLY, NULL, NULL ); } pwcoProtocol->Release(); } return hr; } STDMETHODIMP CHNetPortMappingProtocol::GetIPProtocol( UCHAR *pucProtocol ) { HRESULT hr = S_OK; IWbemClassObject *pwcoProtocol; VARIANT vt; if (NULL == pucProtocol) { hr = E_POINTER; } else { hr = GetProtocolObject(&pwcoProtocol); } if (S_OK == hr) { hr = pwcoProtocol->Get( c_wszIPProtocol, 0, &vt, NULL, NULL ); pwcoProtocol->Release(); } if (WBEM_S_NO_ERROR == hr) { _ASSERT(VT_UI1 == V_VT(&vt)); *pucProtocol = V_UI1(&vt); VariantClear(&vt); } return hr; } STDMETHODIMP CHNetPortMappingProtocol::SetIPProtocol( UCHAR ucProtocol ) { BOOLEAN fProtocolChanged = TRUE; HRESULT hr = S_OK; IWbemClassObject *pwcoProtocol; VARIANT vt; if (TRUE == m_fBuiltIn) { // // Can't change values for builtin protocols // hr = E_ACCESSDENIED; } else if (0 == ucProtocol) { hr = E_INVALIDARG; } if (S_OK == hr) { UCHAR ucOldProtocol; hr = GetIPProtocol(&ucOldProtocol); if (S_OK == hr && ucProtocol == ucOldProtocol) { fProtocolChanged = FALSE; } } if (S_OK == hr && fProtocolChanged) { USHORT usPort; // // Make sure that this won't result in a duplicate // hr = GetPort(&usPort); if (S_OK == hr) { if (PortMappingProtocolExists( m_piwsHomenet, m_bstrWQL, usPort, ucProtocol )) { // // This change would result in a duplicate // hr = HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS); } } if (S_OK == hr) { hr = GetProtocolObject(&pwcoProtocol); } if (S_OK == hr) { VariantInit(&vt); V_VT(&vt) = VT_UI1; V_UI1(&vt) = ucProtocol; hr = pwcoProtocol->Put( c_wszIPProtocol, 0, &vt, NULL ); if (WBEM_S_NO_ERROR == hr) { // // Write the modified instance to the store // hr = m_piwsHomenet->PutInstance( pwcoProtocol, WBEM_FLAG_UPDATE_ONLY, NULL, NULL ); } pwcoProtocol->Release(); } if (S_OK == hr) { // // Update SharedAccess of the change // SendUpdateNotification(); } } return hr; } STDMETHODIMP CHNetPortMappingProtocol::GetPort( USHORT *pusPort ) { HRESULT hr = S_OK; IWbemClassObject *pwcoProtocol; VARIANT vt; if (NULL == pusPort) { hr = E_POINTER; } else { hr = GetProtocolObject(&pwcoProtocol); } if (S_OK == hr) { hr = pwcoProtocol->Get( c_wszPort, 0, &vt, NULL, NULL ); pwcoProtocol->Release(); } if (WBEM_S_NO_ERROR == hr) { // // WMI uses V_I4 for it's uint16 type // _ASSERT(VT_I4 == V_VT(&vt)); *pusPort = static_cast(V_I4(&vt)); VariantClear(&vt); } return hr; } STDMETHODIMP CHNetPortMappingProtocol::SetPort( USHORT usPort ) { BOOLEAN fPortChanged = TRUE; HRESULT hr = S_OK; IWbemClassObject *pwcoProtocol; VARIANT vt; if (TRUE == m_fBuiltIn) { // // Can't change values for builtin protocols // hr = E_ACCESSDENIED; } else if (0 == usPort) { hr = E_INVALIDARG; } if (S_OK == hr) { USHORT usOldPort; // // Check if the new value is the same as the old // hr = GetPort(&usOldPort); if (S_OK == hr && usPort == usOldPort) { fPortChanged = FALSE; } } if (S_OK == hr && fPortChanged) { UCHAR ucIPProtocol; // // Make sure that this won't result in a duplicate // hr = GetIPProtocol(&ucIPProtocol); if (S_OK == hr) { if (PortMappingProtocolExists( m_piwsHomenet, m_bstrWQL, usPort, ucIPProtocol )) { // // This change would result in a duplicate // hr = HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS); } } if (S_OK == hr) { hr = GetProtocolObject(&pwcoProtocol); } if (S_OK == hr) { // // WMI uses V_I4 for it's uint16 type // VariantInit(&vt); V_VT(&vt) = VT_I4; V_I4(&vt) = usPort; hr = pwcoProtocol->Put( c_wszPort, 0, &vt, NULL ); if (WBEM_S_NO_ERROR == hr) { // // Write the modified instance to the store // hr = m_piwsHomenet->PutInstance( pwcoProtocol, WBEM_FLAG_UPDATE_ONLY, NULL, NULL ); } pwcoProtocol->Release(); } if (S_OK == hr) { // // Update SharedAccess of the change // SendUpdateNotification(); } } return hr; } STDMETHODIMP CHNetPortMappingProtocol::GetBuiltIn( BOOLEAN *pfBuiltIn ) { HRESULT hr = S_OK; if (NULL != pfBuiltIn) { *pfBuiltIn = m_fBuiltIn; } else { hr = E_POINTER; } return hr; } STDMETHODIMP CHNetPortMappingProtocol::Delete() { HRESULT hr = S_OK; IEnumWbemClassObject *pwcoEnum; IWbemClassObject *pwcoInstance; BSTR bstrQuery = NULL; ULONG ulCount; if (TRUE == m_fBuiltIn) { // // Can't delete builtin protocols // hr = E_ACCESSDENIED; } else { LPWSTR pwsz; // // Query for all HNet_ConnectionPortMapping instances // that refer to this protocol -- i.e., // // SELECT * FROM HNet_ConnectionPortMapping2 WHERE PROTOCOL = m_bstrProtocol // // We can't use a references query here since once we delete the // protocol object that query won't return any results... // hr = BuildEscapedQuotedEqualsString( &pwsz, c_wszProtocol, m_bstrProtocol ); if (S_OK == hr) { hr = BuildSelectQueryBstr( &bstrQuery, c_wszStar, c_wszHnetConnectionPortMapping, pwsz ); delete [] pwsz; } } if (S_OK == hr) { // // Execute the query // pwcoEnum = NULL; m_piwsHomenet->ExecQuery( m_bstrWQL, bstrQuery, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pwcoEnum ); // // The query BSTR will be used again below // } if (WBEM_S_NO_ERROR == hr) { // // Loop through the enumeration, making sure that each entry // is disabled // do { pwcoInstance = NULL; hr = pwcoEnum->Next( WBEM_INFINITE, 1, &pwcoInstance, &ulCount ); if (SUCCEEDED(hr) && 1 == ulCount) { HRESULT hr2; CComObject *pBinding; // // Convert this to an actual CHNetPortMappingBinding so // that we can disable it and generate the change // notification for SharedAccess. // hr2 = CComObject::CreateInstance(&pBinding); if (SUCCEEDED(hr2)) { pBinding->AddRef(); hr2 = pBinding->Initialize(m_piwsHomenet, pwcoInstance); if (SUCCEEDED(hr)) { hr2 = pBinding->SetEnabled(FALSE); } pBinding->Release(); } pwcoInstance->Release(); } } while (SUCCEEDED(hr) && 1 == ulCount); pwcoEnum->Release(); hr = WBEM_S_NO_ERROR; } if (WBEM_S_NO_ERROR == hr) { // // Delete the protocol instance // hr = m_piwsHomenet->DeleteInstance( m_bstrProtocol, 0, NULL, NULL ); } if (WBEM_S_NO_ERROR == hr) { // // Now that the protocol instance is gone enumerate and // delete the bindings that refer to this instance. This // needs to happen after the protocol instance is gone to // prevent the instance from being recreated after we // delete it here. // pwcoEnum = NULL; m_piwsHomenet->ExecQuery( m_bstrWQL, bstrQuery, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pwcoEnum ); } if (WBEM_S_NO_ERROR == hr) { do { pwcoInstance = NULL; hr = pwcoEnum->Next( WBEM_INFINITE, 1, &pwcoInstance, &ulCount ); if (SUCCEEDED(hr) && 1 == ulCount) { DeleteWmiInstance(m_piwsHomenet, pwcoInstance); pwcoInstance->Release(); } } while (SUCCEEDED(hr) && 1 == ulCount); pwcoEnum->Release(); hr = WBEM_S_NO_ERROR; } if ( WBEM_S_NO_ERROR == hr ) { SendPortMappingListChangeNotification(); } // // bstrQuery is initialized to NULL at start, and SysFreeString // can deal w/ NULL input, so it's safe to call this even on // an error path. // SysFreeString(bstrQuery); return hr; } STDMETHODIMP CHNetPortMappingProtocol::GetGuid( GUID **ppGuid ) { HRESULT hr; IWbemClassObject *pwcoInstance; VARIANT vt; if (NULL != ppGuid) { *ppGuid = reinterpret_cast( CoTaskMemAlloc(sizeof(GUID)) ); if (NULL != *ppGuid) { hr = GetProtocolObject(&pwcoInstance); } else { hr = E_OUTOFMEMORY; } } else { hr = E_POINTER; } if (WBEM_S_NO_ERROR == hr) { hr = pwcoInstance->Get( c_wszId, 0, &vt, NULL, NULL ); if (WBEM_S_NO_ERROR == hr) { ASSERT(VT_BSTR == V_VT(&vt)); hr = CLSIDFromString(V_BSTR(&vt), *ppGuid); VariantClear(&vt); } pwcoInstance->Release(); } if (FAILED(hr) && NULL != ppGuid && NULL != *ppGuid) { CoTaskMemFree(*ppGuid); *ppGuid = NULL; } return hr; } // // IHNetPrivate methods // STDMETHODIMP CHNetPortMappingProtocol::GetObjectPath( BSTR *pbstrPath ) { HRESULT hr = S_OK; if (NULL != pbstrPath) { _ASSERT(m_bstrProtocol != NULL); *pbstrPath = SysAllocString(m_bstrProtocol); if (NULL == *pbstrPath) { hr = E_OUTOFMEMORY; } } else { hr = E_POINTER; } return hr; } // // Private methods // HRESULT CHNetPortMappingProtocol::GetProtocolObject( IWbemClassObject **ppwcoInstance ) { _ASSERT(NULL != ppwcoInstance); return GetWmiObjectFromPath( m_piwsHomenet, m_bstrProtocol, ppwcoInstance ); } HRESULT CHNetPortMappingProtocol::SendUpdateNotification() { HRESULT hr = S_OK; IEnumHNetPortMappingBindings *pEnum; GUID *pProtocolGuid = NULL; ISharedAccessUpdate *pUpdate; if (IsServiceRunning(c_wszSharedAccess)) { hr = GetGuid(&pProtocolGuid); // // Get the enumeration of enabled port mapping // bindings for this protocol // if (SUCCEEDED(hr)) { hr = GetEnabledBindingEnumeration(&pEnum); } if (SUCCEEDED(hr)) { hr = CoCreateInstance( CLSID_SAUpdate, NULL, CLSCTX_SERVER, IID_PPV_ARG(ISharedAccessUpdate, &pUpdate) ); if (SUCCEEDED(hr)) { IHNetPortMappingBinding *pBinding; IHNetConnection *pConnection; GUID *pConnectionGuid; ULONG ulCount; do { hr = pEnum->Next(1, &pBinding, &ulCount); if (SUCCEEDED(hr) && 1 == ulCount) { hr = pBinding->GetConnection(&pConnection); pBinding->Release(); if (SUCCEEDED(hr)) { hr = pConnection->GetGuid(&pConnectionGuid); pConnection->Release(); } if (SUCCEEDED(hr)) { hr = pUpdate->ConnectionPortMappingChanged( pConnectionGuid, pProtocolGuid, TRUE ); CoTaskMemFree(pConnectionGuid); } } } while (SUCCEEDED(hr) && 1 == ulCount); pUpdate->Release(); } pEnum->Release(); } } if (NULL != pProtocolGuid) { CoTaskMemFree(pProtocolGuid); } return hr; } HRESULT CHNetPortMappingProtocol::GetEnabledBindingEnumeration( IEnumHNetPortMappingBindings **ppEnum ) { BSTR bstr; HRESULT hr = S_OK; OLECHAR *pwsz; OLECHAR *pwszWhere; _ASSERT(NULL != ppEnum); // // Generate the query string // hr = BuildEscapedQuotedEqualsString( &pwsz, c_wszProtocol, m_bstrProtocol ); if (S_OK == hr) { hr = BuildAndString( &pwszWhere, pwsz, L"Enabled != FALSE" ); delete [] pwsz; } if (S_OK == hr) { hr = BuildSelectQueryBstr( &bstr, c_wszStar, c_wszHnetConnectionPortMapping, pwszWhere ); delete [] pwszWhere; } // // Execute the query and build the enumerator // if (S_OK == hr) { IEnumWbemClassObject *pwcoEnum = NULL; hr = m_piwsHomenet->ExecQuery( m_bstrWQL, bstr, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pwcoEnum ); SysFreeString(bstr); if (WBEM_S_NO_ERROR == hr) { CComObject *pEnum; hr = CComObject::CreateInstance(&pEnum); if (S_OK == hr) { pEnum->AddRef(); hr = pEnum->Initialize(m_piwsHomenet, pwcoEnum); if (S_OK == hr) { hr = pEnum->QueryInterface( IID_PPV_ARG(IEnumHNetPortMappingBindings, ppEnum) ); } pEnum->Release(); } pwcoEnum->Release(); } } return hr; }