Sample Code
Windows Driver Samples/ NDIS MUX Intermediate Driverand Notify Object/ C++/ notifyob/ notify.cpp/
//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992-2001. // // File: N O T I F Y . C P P // // Contents: Sample notify object code // // Notes: // // Author: Alok Sinha //---------------------------------------------------------------------------- #include "notify.h" //---------------------------------------------------------------------------- // // Function: CMuxNotify::CMuxNotify // // Purpose: Constructor for CMuxNotify // // Arguments: None // // Returns: None // // Notes: // CMuxNotify::CMuxNotify (VOID) : m_pncc (NULL), m_pnc(NULL), m_eApplyAction(eActUnknown), m_pUnkContext(NULL) { TraceMsg( L"-->CMuxNotify::CMuxNotify(Constructor).\n" ); TraceMsg( L"<--CMuxNotify::CMuxNotify(Constructor).\n" ); } // ---------------------------------------------------------------------- // // Function: CMuxNotify::~CMuxNotify // // Purpose: Destructor for class CMuxNotify // // Arguments: None // // Returns: None // // Notes: // CMuxNotify::~CMuxNotify (VOID) { CMuxPhysicalAdapter *pAdapter; DWORD dwAdapterCount; DWORD i; TraceMsg( L"-->CMuxNotify::~CMuxNotify(Destructor).\n" ); // release interfaces if acquired ReleaseObj( m_pncc ); ReleaseObj( m_pnc ); ReleaseObj( m_pUnkContext ); dwAdapterCount = m_AdaptersList.ListCount(); for (i=0; i < dwAdapterCount; ++i) { pAdapter = NULL; m_AdaptersList.Remove( &pAdapter ); delete pAdapter; } dwAdapterCount = m_AdaptersToRemove.ListCount(); for (i=0; i < dwAdapterCount; ++i) { pAdapter = NULL; m_AdaptersToRemove.Remove( &pAdapter ); delete pAdapter; } dwAdapterCount = m_AdaptersToAdd.ListCount(); for (i=0; i < dwAdapterCount; ++i) { pAdapter = NULL; m_AdaptersToAdd.Remove( &pAdapter ); delete pAdapter; } TraceMsg( L"<--CMuxNotify::~CMuxNotify(Destructor).\n" ); } // //---------------------- NOTIFY OBJECT FUNCTIONS ----------------------------- // //---------------------------------------------------------------------------- // INetCfgComponentControl // // The following functions provide the INetCfgComponentControl interface. // //---------------------------------------------------------------------------- // // Function: CMuxNotify::Initialize // // Purpose: Initialize the notify object // // Arguments: // IN pnccItem : Pointer to INetCfgComponent object // IN pnc : Pointer to INetCfg object // IN fInstalling: TRUE if we are being installed // // Returns: // // Notes: // STDMETHODIMP CMuxNotify::Initialize (INetCfgComponent* pncc, INetCfg* pnc, BOOL fInstalling) { HRESULT hr = S_OK; TraceMsg( L"-->CMuxNotify INetCfgControl::Initialize.\n" ); // Save INetCfg & INetCfgComponent and add a refcount m_pncc = pncc; m_pnc = pnc; if (m_pncc) { m_pncc->AddRef(); } if (m_pnc) { m_pnc->AddRef(); } // // If this not an installation, then we need to // initialize all of our data and classes // if ( !fInstalling ) { hr = HrLoadAdapterConfiguration(); } TraceMsg( L"<--CMuxNotify INetCfgControl::Initialize(HRESULT = %x).\n", hr ); return hr; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::CancelChanges // // Purpose: Cancel any changes made to internal data // // Arguments: None // // Returns: S_OK on success, otherwise an error code // // Notes: // STDMETHODIMP CMuxNotify::CancelChanges (VOID) { TraceMsg( L"-->CMuxNotify INetCfgControl::CancelChanges.\n" ); TraceMsg( L"<--CMuxNotify INetCfgControl::CancelChanges(HRESULT = %x).\n", S_OK ); return S_OK; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::ApplyRegistryChanges // // Purpose: Apply changes. // // Arguments: None // // Returns: S_OK. // // Notes: We can make changes to registry etc. here. STDMETHODIMP CMuxNotify::ApplyRegistryChanges(VOID) { CMuxPhysicalAdapter *pAdapter = NULL; DWORD dwAdapterCount; DWORD i; TraceMsg( L"-->CMuxNotify INetCfgControl::ApplyRegistryChanges.\n" ); // // Make registry changes for the adapters added. // dwAdapterCount = m_AdaptersToAdd.ListCount(); TraceMsg( L" Adding %d new adapters.\n", dwAdapterCount ); for (i=0; i < dwAdapterCount; ++i) { m_AdaptersToAdd.Find( i, &pAdapter ); pAdapter->ApplyRegistryChanges( eActAdd ); } // // Make registry changes for the adapters uninstalled. // dwAdapterCount = m_AdaptersToRemove.ListCount(); TraceMsg( L" Removing %d adapters.\n", dwAdapterCount ); for (i=0; i < dwAdapterCount; ++i) { m_AdaptersToRemove.Find( i, &pAdapter ); pAdapter->ApplyRegistryChanges( eActRemove ); } // // Make registry changes for the miniports added/removed // through the property pages. // dwAdapterCount = m_AdaptersList.ListCount(); for (i=0; i < dwAdapterCount; ++i) { m_AdaptersList.Find( i, &pAdapter ); pAdapter->ApplyRegistryChanges( eActUpdate ); } TraceMsg( L"<--CMuxNotify INetCfgControl::ApplyRegistryChanges(HRESULT = %x).\n", S_OK ); return S_OK; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::ApplyPnpChanges // // Purpose: Apply changes. // // Arguments: // IN pfCallback: PnPConfigCallback interface. // // Returns: S_OK. // // Notes: STDMETHODIMP CMuxNotify::ApplyPnpChanges ( INetCfgPnpReconfigCallback* pfCallback) { CMuxPhysicalAdapter *pAdapter = NULL; GUID guidAdapter; DWORD dwAdapterCount; DWORD i; TraceMsg( L"-->CMuxNotify INetCfgControl::ApplyPnpChanges.\n" ); // // Apply PnP changes for the adapters added. // dwAdapterCount = m_AdaptersToAdd.ListCount(); TraceMsg( L" Applying PnP changes when %d adapters added.\n", dwAdapterCount ); for (i=0; i < dwAdapterCount; ++i) { m_AdaptersToAdd.Remove( &pAdapter ); pAdapter->ApplyPnpChanges( pfCallback, eActAdd ); pAdapter->GetAdapterGUID( &guidAdapter ); m_AdaptersList.Insert( pAdapter, guidAdapter ); } // // Apply PnP changes for the adapters uninstalled. // dwAdapterCount = m_AdaptersToRemove.ListCount(); TraceMsg( L" Applying PnP changes when %d adapters removed.\n", dwAdapterCount ); for (i=0; i < dwAdapterCount; ++i) { m_AdaptersToRemove.Remove( &pAdapter ); pAdapter->ApplyPnpChanges( pfCallback, eActRemove ); delete pAdapter; } // // Apply PnP changes for the miniports added/removed through // the property pages. // dwAdapterCount = m_AdaptersList.ListCount(); for (i=0; i < dwAdapterCount; ++i) { m_AdaptersList.Find( i, &pAdapter ); pAdapter->ApplyPnpChanges( pfCallback, eActUpdate ); } TraceMsg( L"<--CMuxNotify INetCfgControl::ApplyPnpChanges(HRESULT = %x).\n", S_OK ); return S_OK; } //---------------------------------------------------------------------------- // INetCfgComponentSetup // // The following functions provide the INetCfgComponentSetup interface. // //---------------------------------------------------------------------------- // ---------------------------------------------------------------------- // // Function: CMuxNotify::Install // // Purpose: Do operations necessary during the installation. // // Arguments: // IN dwSetupFlags: Setup flags // // Returns: S_OK // // Notes: Don't do anything irreversible (like modifying registry) yet // since the config. actually completes only when Apply is called! // STDMETHODIMP CMuxNotify::Install (DWORD dwSetupFlags) { UNREFERENCED_PARAMETER(dwSetupFlags); TraceMsg( L"-->CMuxNotify INetCfgSetup::Install.\n" ); // Start up the install process m_eApplyAction = eActInstall; TraceMsg( L"<--CMuxNotify INetCfgSetup::Install(HRESULT = %x).\n", S_OK ); return S_OK; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::Upgrade // // Purpose: Do operations necessary during the upgrade. // // Arguments: // IN dwSetupFlags: Setup flags // // Returns: S_OK // // Notes: Don't do anything irreversible (like modifying registry) yet // since the config. actually completes only when Apply is called! // STDMETHODIMP CMuxNotify::Upgrade (IN DWORD dwSetupFlags, IN DWORD dwUpgradeFromBuildNo) { TraceMsg( L"-->CMuxNotify INetCfgSetup::Upgrade.\n" ); TraceMsg( L" DwSetupFlags = %x, dwUpgradeFromBuildNo = %x\n", dwSetupFlags, dwUpgradeFromBuildNo ); TraceMsg( L"<--CMuxNotify INetCfgSetup::Upgrade(HRESULT = %x).\n", S_OK ); return S_OK; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::ReadAnswerFile // // Purpose: Read settings from answerfile and configure CMuxNotify // // Arguments: // IN pszAnswerFile : Name of AnswerFile // IN pszAnswerSection: Name of parameters section // // Returns: // // Notes: Don't do anything irreversible (like modifying registry) yet // since the config. actually completes only when Apply is called! // STDMETHODIMP CMuxNotify::ReadAnswerFile (PCWSTR pszAnswerFile, PCWSTR pszAnswerSection) { // PCWSTR pszParamReadFromAnswerFile = L"ParamFromAnswerFile"; UNREFERENCED_PARAMETER(pszAnswerFile); UNREFERENCED_PARAMETER(pszAnswerSection); TraceMsg( L"-->CMuxNotify INetCfgSetup::ReadAnswerFile.\n" ); // We will pretend here that szParamReadFromAnswerFile was actually // read from the AnswerFile using the following steps // // - Open file pszAnswerFile using SetupAPI // - locate section pszAnswerSection // - locate the required key and get its value // - store its value in pszParamReadFromAnswerFile // - close HINF for pszAnswerFile // Now that we have read pszParamReadFromAnswerFile from the // AnswerFile, store it in our memory structure. // Remember we should not be writing it to the registry till // our Apply is called!! // TraceMsg( L"<--CMuxNotify INetCfgSetup::ReadAnswerFile(HRESULT = %x).\n", S_OK ); return S_OK; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::Removing // // Purpose: Do necessary cleanup when being removed // // Arguments: None // // Returns: S_OK // // Notes: Don't do anything irreversible (like modifying registry) yet // since the removal is actually complete only when Apply is called! // STDMETHODIMP CMuxNotify::Removing (VOID) { TraceMsg( L"-->CMuxNotify INetCfgSetup::Removing.\n" ); TraceMsg( L"<--CMuxNotify INetCfgSetup::Removing(HRESULT = %x).\n", S_OK ); return S_OK; } //---------------------------------------------------------------------------- // INetCfgComponentNotifyBinding // // The following functions provide the INetCfgComponentNotifyBinding interface. // //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- // // Function: CMuxNotify::QueryBindingPath // // Purpose: This is specific to the component being installed. This will // ask us if we want to bind to the Item being passed into // this routine. We can disable the binding by returning // NETCFG_S_DISABLE_QUERY // // // Arguments: // IN dwChangeFlag: Type of binding change // IN pncbpItem : Pointer to INetCfgBindingPath object // // Returns: S_OK on success, otherwise an error code. // // Notes: // STDMETHODIMP CMuxNotify::QueryBindingPath (IN DWORD dwChangeFlag, IN INetCfgBindingPath *pncbp) { UNREFERENCED_PARAMETER(pncbp); UNREFERENCED_PARAMETER(dwChangeFlag); TraceMsg( L"-->CMuxNotify INetCfgNotifyBinding::QueryBindingPath.\n" ); DumpChangeFlag( dwChangeFlag ); DumpBindingPath( pncbp ); TraceMsg( L"<--CMuxNotify INetCfgNotifyBinding::QueryBindingPath(HRESULT = %x).\n", S_OK ); return S_OK; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::NotifyBindingPath // // Purpose: We are now being told to bind to the component passed to us. // // // Arguments: // IN dwChangeFlag: Type of system change // IN pncc : Pointer to INetCfgComponent object // // Returns: S_OK on success, otherwise an error code // // Notes: // STDMETHODIMP CMuxNotify::NotifyBindingPath (IN DWORD dwChangeFlag, IN INetCfgBindingPath *pncbp) { INetCfgComponent *pnccLower; INetCfgComponent *pnccUpper; LPWSTR pszwInfIdLower; LPWSTR pszwInfIdUpper; DWORD dwCharcteristics; HRESULT hr = S_OK; TraceMsg( L"-->CMuxNotify INetCfgNotifyBinding::NotifyBindingPath.\n" ); DumpChangeFlag( dwChangeFlag ); DumpBindingPath( pncbp ); // // We are only interested to know 1) when a component is installed // and we are binding to it i.e. dwChangeFlag = NCN_ADD | NCN_ENABLE // and 2) when a component is removed to which we are bound i.e. // dwChangeFlag = NCN_REMOVE | NCN_ENABLE. dwChangeFlag is never // set to NCN_ADD or NCN_REMOVE only. So, checking for NCN_ENABLE // covers the case of NCN_ADD | NCN_ENABLE and checking for NCN_REMOVE // covers the case of NCN_REMOVE | NCN_ENABLE. We don't care about // NCN_ADD | NCN_DISABLE (case 1) and NCN_REMOVE | NCN_DISABLE (case 2). // if ( dwChangeFlag & (NCN_ENABLE | NCN_REMOVE) ) { // // Get the upper and lower components. // hr = HrGetUpperAndLower( pncbp, &pnccUpper, &pnccLower ); if ( hr == S_OK ) { hr = pnccLower->GetCharacteristics( &dwCharcteristics ); if ( hr == S_OK ) { #pragma prefast(suppress:26035, "&pszwInfIdLower is a Pointer to a buffer that receives a constant null-terminated string, see http://msdn.microsoft.com/en-us/library/ms805225.aspx") hr = pnccLower->GetId( &pszwInfIdLower ); if ( hr == S_OK ) { #pragma prefast(suppress:26035, "&pszwInfIdUpper is a Pointer to a buffer that receives a constant null-terminated string, see http://msdn.microsoft.com/en-us/library/ms805225.aspx") hr = pnccUpper->GetId( &pszwInfIdUpper ); if ( hr == S_OK ) { // // We are interested only in binding to a // physical ethernet adapters. // if ( dwCharcteristics & NCF_PHYSICAL ) { if ( !_wcsicmp( pszwInfIdUpper, c_szMuxProtocol ) ) { if ( dwChangeFlag & NCN_ADD ) { hr = HrAddAdapter( pnccLower ); if( hr != S_OK ){ // you may do something } m_eApplyAction = eActAdd; } else if ( dwChangeFlag & NCN_REMOVE ) { hr = HrRemoveAdapter( pnccLower ); if( hr != S_OK ){ // you may do something } m_eApplyAction = eActRemove; } } } // Physical Adapters. else if (dwCharcteristics & NCF_VIRTUAL) { } CoTaskMemFree( pszwInfIdUpper ); } // Got the upper component id. CoTaskMemFree( pszwInfIdLower ); } // Got the lower component id. } // Got NIC's characteristics ReleaseObj(pnccLower); ReleaseObj(pnccUpper); } // Got the upper and lower components. } TraceMsg( L"<--CMuxNotify INetCfgNotifyBinding::NotifyBindingPath(HRESULT = %x).\n", S_OK ); return S_OK; } //---------------------------------------------------------------------------- // INetCfgComponentNotifyGlobal // // The following functions provide the INetCfgComponentNotifyGlobal interface. // //---------------------------------------------------------------------------- // ---------------------------------------------------------------------- // // Function: CMuxNotify::GetSupportedNotifications // // Purpose: Tell the system which notifications we are interested in // // Arguments: // OUT pdwNotificationFlag: Pointer to NotificationFlag // // Returns: S_OK on success, otherwise an error code // // Notes: // STDMETHODIMP CMuxNotify::GetSupportedNotifications ( OUT DWORD* pdwNotificationFlag) { TraceMsg( L"-->CMuxNotify INetCfgNotifyGlobal::GetSupportedNotifications.\n" ); *pdwNotificationFlag = NCN_NET | NCN_NETTRANS | NCN_ADD | NCN_REMOVE | NCN_BINDING_PATH | NCN_ENABLE | NCN_DISABLE; TraceMsg( L"<--CMuxNotify INetCfgNotifyGlobal::GetSupportedNotifications(HRESULT = %x).\n", S_OK ); return S_OK; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::SysQueryBindingPath // // Purpose: Enable or Disable a binding path. // // Arguments: // IN dwChangeFlag: Type of binding change // IN pncbp : Pointer to INetCfgBindingPath object // // Returns: S_OK on success, otherwise an error code // // Notes: // STDMETHODIMP CMuxNotify::SysQueryBindingPath (DWORD dwChangeFlag, INetCfgBindingPath* pncbp) { INetCfgComponent *pnccLower; INetCfgComponent *pnccUpper; LPWSTR pszwInfIdLower; LPWSTR pszwInfIdUpper; DWORD dwCharcteristics; HRESULT hr = S_OK; TraceMsg( L"-->CMuxNotify INetCfgNotifyGlobal::SysQueryBindingPath.\n" ); DumpChangeFlag( dwChangeFlag ); DumpBindingPath( pncbp ); if ( dwChangeFlag & NCN_ENABLE ) { // // Get the upper and lower components. // hr = HrGetUpperAndLower( pncbp, &pnccUpper, &pnccLower ); if ( hr == S_OK ) { hr = pnccLower->GetCharacteristics( &dwCharcteristics ); if ( hr == S_OK ) { #pragma prefast(suppress:26035, "&lpszIdLower is a pointer to a buffer that receives a constant null-terminated string, see http://msdn.microsoft.com/en-us/library/ms805225.aspx") hr = pnccLower->GetId( &pszwInfIdLower ); if ( hr == S_OK ) { #pragma prefast(suppress:26035, "&lpszIdUpper is a pointer to a buffer that receives a constant null-terminated string, see http://msdn.microsoft.com/en-us/library/ms805225.aspx") hr = pnccUpper->GetId( &pszwInfIdUpper ); if ( hr == S_OK ) { // // We are interested only in bindings to physical // ethernet adapters. // if ( dwCharcteristics & NCF_PHYSICAL ) { #ifdef DISABLE_PROTOCOLS_TO_PHYSICAL // // If it not our protocol binding to the // physical adapter then, disable the // binding. // if (_wcsicmp( pszwInfIdUpper, c_szMuxProtocol ) ) { TraceMsg( L" Disabling the binding between %s " L"and %s.\n", pszwInfIdUpper, pszwInfIdLower ); hr = NETCFG_S_DISABLE_QUERY; } #endif } // Physical Adapters. else { if (dwCharcteristics & NCF_VIRTUAL) { // If the lower component is our miniport // and the upper component is our protocol // then also, disable the binding. if ( !_wcsicmp(pszwInfIdLower, c_szMuxMiniport) && !_wcsicmp(pszwInfIdUpper, c_szMuxProtocol) ) { TraceMsg( L" Disabling the binding between %s " L"and %s.\n", pszwInfIdUpper, pszwInfIdLower ); hr = NETCFG_S_DISABLE_QUERY; } } // Virtual Adapters } CoTaskMemFree( pszwInfIdUpper ); } // Got the upper component id. CoTaskMemFree( pszwInfIdLower ); } // Got the lower component id. } // Got NIC's characteristics ReleaseObj(pnccLower); ReleaseObj(pnccUpper); } } TraceMsg( L"<--CMuxNotify INetCfgNotifyGlobal::SysQueryBindingPath(HRESULT = %x).\n", hr ); return hr; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::SysNotifyBindingPath // // Purpose: System tells us by calling this function which // binding path has just been formed. // // Arguments: // IN dwChangeFlag: Type of binding change // IN pncbpItem : Pointer to INetCfgBindingPath object // // Returns: S_OK on success, otherwise an error code // // Notes: // STDMETHODIMP CMuxNotify::SysNotifyBindingPath (DWORD dwChangeFlag, INetCfgBindingPath* pncbp) { UNREFERENCED_PARAMETER(dwChangeFlag); UNREFERENCED_PARAMETER(pncbp); TraceMsg( L"-->CMuxNotify INetCfgNotifyGlobal::SysNotifyBindingPath.\n" ); DumpChangeFlag( dwChangeFlag ); DumpBindingPath( pncbp ); TraceMsg( L"<--CMuxNotify INetCfgNotifyGlobal::SysNotifyBindingPath(HRESULT = %x).\n", S_OK ); return S_OK; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::SysNotifyComponent // // Purpose: System tells us by calling this function which // component has undergone a change (installed/removed) // // Arguments: // IN dwChangeFlag: Type of system change // IN pncc : Pointer to INetCfgComponent object // // Returns: S_OK on success, otherwise an error code // // Notes: // STDMETHODIMP CMuxNotify::SysNotifyComponent (DWORD dwChangeFlag, INetCfgComponent* pncc) { UNREFERENCED_PARAMETER(dwChangeFlag); UNREFERENCED_PARAMETER(pncc); TraceMsg( L"-->CMuxNotify INetCfgNotifyGlobal::SysNotifyComponent.\n" ); DumpChangeFlag( dwChangeFlag ); DumpComponent( pncc ); TraceMsg( L"<--CMuxNotify INetCfgNotifyGlobal::SysNotifyComponent(HRESULT = %x).\n", S_OK ); return S_OK; } //---------------------------------------------------------------------------- // INetCfgComponentPropertyUi // // The following functions provide the INetCfgComponentPropertyUi interface. // //---------------------------------------------------------------------------- // ---------------------------------------------------------------------- // // Function: CMuxNotify::MergePropPages // // Purpose: Supply our property page to system. // // Arguments: // OUT pdwDefPages : Pointer to num default pages // OUT pahpspPrivate: Pointer to array of pages // OUT pcPages : Pointer to num pages // IN hwndParent : Handle of parent window // IN szStartPage : Pointer to // // Returns: S_OK on success, otherwise an error code // // Notes: // STDMETHODIMP CMuxNotify::MergePropPages (IN OUT DWORD* pdwDefPages, OUT LPBYTE* pahpspPrivate, OUT UINT* pcPages, IN HWND hwndParent, OUT PCWSTR* szStartPage) { HRESULT hr = S_OK; HPROPSHEETPAGE *ahpsp;; INetLanConnectionUiInfo *pLanConnUiInfo; UNREFERENCED_PARAMETER(szStartPage); UNREFERENCED_PARAMETER(hwndParent); TraceMsg(L"-->CMuxNotify INetCfgPropertyUi::MergePropPages\n"); // // We don't want any default pages to be shown // *pdwDefPages = 0; *pcPages = 0; *pahpspPrivate = NULL; if ( !m_pUnkContext ) { return E_UNEXPECTED; } hr = m_pUnkContext->QueryInterface( IID_INetLanConnectionUiInfo, reinterpret_cast<PVOID *>(&pLanConnUiInfo)); if ( hr == S_OK ) { ReleaseObj( pLanConnUiInfo ); ahpsp = (HPROPSHEETPAGE*)CoTaskMemAlloc( sizeof(HPROPSHEETPAGE) ); if (ahpsp) { PROPSHEETPAGE psp = {0}; psp.dwSize = sizeof(PROPSHEETPAGE); psp.dwFlags = PSP_DEFAULT; psp.hInstance = _Module.GetModuleInstance(); psp.pszTemplate = MAKEINTRESOURCE(IDD_NOTIFY_GENERAL); psp.pfnDlgProc = NotifyDialogProc; psp.pfnCallback = NULL; (LPFNPSPCALLBACK)NotifyPropSheetPageProc; psp.lParam = (LPARAM) this; psp.pszHeaderTitle = NULL; psp.pszHeaderSubTitle = NULL; ahpsp[0] = ::CreatePropertySheetPage(&psp); *pcPages = 1; *pahpspPrivate = (LPBYTE)ahpsp; } else { hr = E_OUTOFMEMORY; } } TraceMsg(L"<--CMuxNotify INetCfgPropertyUi::MergePropPages(HRESULT = %x).\n", hr ); return hr; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::ValidateProperties // // Purpose: Validate changes to property page. // // Arguments: // IN hwndSheet: Window handle of property sheet // // Returns: S_OK on success, otherwise an error code // // Notes: // STDMETHODIMP CMuxNotify::ValidateProperties (HWND hwndSheet) { UNREFERENCED_PARAMETER(hwndSheet); TraceMsg( L"-->CMuxNotify INetCfgPropertyUi::ValidateProperties\n" ); TraceMsg(L"<--CMuxNotify INetCfgPropertyUi::ValidateProperties(HRESULT = %x).\n", S_OK ); return S_OK; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::CancelProperties // // Purpose: Cancel changes to property page // // Arguments: None // // Returns: S_OK on success, otherwise an error code // // Notes: // STDMETHODIMP CMuxNotify::CancelProperties (VOID) { TraceMsg(L"-->CMuxNotify INetCfgPropertyUi::CancelProperties\n"); TraceMsg(L"<--CMuxNotify INetCfgPropertyUi::CancelProperties(HRESULT = %x).\n", S_OK ); return S_OK; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::ApplyProperties // // Purpose: Apply value of controls on property page // to internal memory structure // // Arguments: None // // Returns: S_OK on success, otherwise an error code // // Notes: // STDMETHODIMP CMuxNotify::ApplyProperties (VOID) { INetLanConnectionUiInfo *pLanConnUiInfo; CMuxPhysicalAdapter *pAdapter; GUID guidAdapter; INetCfgComponent *pncc; HRESULT hr = S_OK; UNREFERENCED_PARAMETER(pncc); TraceMsg(L"-->CMuxNotify INetCfgPropertyUi::ApplyProperties\n"); if ( m_pUnkContext ) { hr = m_pUnkContext->QueryInterface( IID_INetLanConnectionUiInfo, reinterpret_cast<PVOID *>(&pLanConnUiInfo)); if ( hr == S_OK ) { hr = pLanConnUiInfo->GetDeviceGuid( &guidAdapter ); if ( hr == S_OK ) { hr = m_AdaptersList.FindByKey( guidAdapter, &pAdapter ); if ( hr == S_OK ) { switch( m_eApplyAction ) { case eActPropertyUIAdd: hr = HrAddMiniport( pAdapter, &guidAdapter ); break; case eActPropertyUIRemove: hr = HrRemoveMiniport( pAdapter, &guidAdapter ); break; } } } ReleaseObj( pLanConnUiInfo ); } } TraceMsg(L"<--CMuxNotify INetCfgPropertyUi::ApplyProperties(HRESULT = %x).\n", hr ); return hr; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::QueryPropertyUi // // Purpose: System is asking if we support property pages. // // Arguments: // IN pUnk: Pointer to IUnknown. // // Returns: S_OK on success, otherwise an error code // // Notes: We display property pages only in the context of // a LAN connection. // STDMETHODIMP CMuxNotify::QueryPropertyUi (IUnknown * pUnk) { INetLanConnectionUiInfo *pLanConnUiInfo; HRESULT hr=S_FALSE; TraceMsg(L"-->CMuxNotify INetCfgPropertyUi::QueryPropertyUi\n"); #ifndef PASSTHRU_NOTIFY if ( pUnk ) { hr = pUnk->QueryInterface( IID_INetLanConnectionUiInfo, reinterpret_cast<PVOID *>(&pLanConnUiInfo)); ReleaseObj( pLanConnUiInfo ); } #endif TraceMsg(L"<--CMuxNotify INetCfgPropertyUi::QueryPropertyUi(HRESULT = %x).\n", hr ); return hr; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::SetContext // // Purpose: Save the LAN connection context. // // Arguments: // IN pUnk: Pointer to IUnknown. // // Returns: S_OK on success, otherwise an error code // // Notes: It is also called to release the current LAN connection context. // STDMETHODIMP CMuxNotify::SetContext (IUnknown * pUnk) { TraceMsg(L"-->CMuxNotify INetCfgPropertyUi::SetContext\n"); // // Release previous context, if any // ReleaseObj( m_pUnkContext ); m_pUnkContext = NULL; if ( pUnk ) { m_pUnkContext = pUnk; m_pUnkContext->AddRef(); } TraceMsg(L"<--CMuxNotify INetCfgPropertyUi::SetContext(HRESULT = %x).\n", S_OK ); return S_OK; } //---------------------------------------------------------------------------- // // Function: CMuxNotify::HrLoadAdapterConfiguration // // Purpose: This loads the Miniport and adapters that have already been // installed into our own data structures // // Arguments: None. // // Returns: S_OK, or an error. // // // Notes: // HRESULT CMuxNotify::HrLoadAdapterConfiguration (VOID) { HKEY hkeyAdapterList; WCHAR szAdapterGuid[MAX_PATH+1]; DWORD dwDisp; CMuxPhysicalAdapter *pAdapter; GUID guidAdapter; DWORD dwIndex; LONG lResult; TraceMsg( L"-->CMuxNotify::HrLoadAdapterConfiguration.\n" ); lResult = RegCreateKeyExW( HKEY_LOCAL_MACHINE, c_szAdapterList, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyAdapterList, &dwDisp); if ( lResult == ERROR_SUCCESS ) { // // If dwDisp indicates that a new key is created then, we know there // is no adapter currently listed underneath and we simply // return, otherwise, we enumerate the subkeys, each one representing an // adapter. // if ( dwDisp != REG_CREATED_NEW_KEY ) { lResult = RegEnumKeyW( hkeyAdapterList, 0, szAdapterGuid, MAX_PATH+1 ); for (dwIndex=1; lResult == ERROR_SUCCESS; ++dwIndex) { TraceMsg( L" Loading configuration for adapter %s...\n", szAdapterGuid ); // // Subkeys are actually a guid/bindname of the adapters. // szAdapterGuid[MAX_PATH]='\0'; CLSIDFromString( szAdapterGuid, &guidAdapter ); // // Create an instance representing the adapter. // #pragma prefast(suppress:8197, "The instance is freed in the destructor") #pragma prefast(suppress:28197, "pMiniport is saved using m_MiniportList.Insert( pAdapter,guidAdapter ) and released using m_MiniportList.Remove in the destructor") pAdapter = new CMuxPhysicalAdapter( m_pnc, &guidAdapter ); if ( pAdapter ) { // // Load any adapter specific configuration. // pAdapter->LoadConfiguration(); // // Save the adapter instance in a list. // m_AdaptersList.Insert( pAdapter, guidAdapter ); // // Get next subkey. // lResult = RegEnumKeyW( hkeyAdapterList, dwIndex, szAdapterGuid, MAX_PATH+1 ); } else { lResult = ERROR_NOT_ENOUGH_MEMORY; } } // // RegEnumKeyW may have returned error when there are no more // subkeys to read. // lResult = ERROR_SUCCESS; } RegCloseKey( hkeyAdapterList ); } TraceMsg( L"<--CMuxNotify::HrLoadAdapterConfiguration(HRESULT = %x).\n", HRESULT_FROM_WIN32(lResult) ); return HRESULT_FROM_WIN32(lResult); } //---------------------------------------------------------------------------- // // Function: CMuxNotify::HrGetUpperAndLower // // Purpose: Get the upper and lower component of the first interface // of a binding path. // // Arguments: // IN pncbp : Binding path. // OUT ppnccUpper: Upper component. // OUT ppnccLower: Lower component. // // Returns: S_OK, or an error. // // // Notes: // HRESULT CMuxNotify::HrGetUpperAndLower (INetCfgBindingPath* pncbp, INetCfgComponent **ppnccUpper, INetCfgComponent **ppnccLower) { IEnumNetCfgBindingInterface* pencbi; INetCfgBindingInterface* pncbi; ULONG ulCount; HRESULT hr; TraceMsg( L"-->CMuxNotify::HrGetUpperAndLowerComponent.\n" ); *ppnccUpper = NULL; *ppnccLower = NULL; hr = pncbp->EnumBindingInterfaces(&pencbi); if (S_OK == hr) { // // get the first binding interface // hr = pencbi->Next(1, &pncbi, &ulCount); if ( hr == S_OK ) { hr = pncbi->GetUpperComponent( ppnccUpper ); if ( hr == S_OK ) { hr = pncbi->GetLowerComponent ( ppnccLower ); } else { if( ppnccUpper != NULL ) { ReleaseObj( *ppnccUpper ); } } ReleaseObj( pncbi ); } ReleaseObj( pencbi ); } TraceMsg( L"<--CMuxNotify::HrGetUpperAndLowerComponent(HRESULT = %x).\n", hr ); return hr; } //---------------------------------------------------------------------------- // // Function: CMuxNotify::HrAddAdapter // // Purpose: Create an instance representing the physical adapter and install // a virtual miniport. // // Arguments: // IN pnccAdapter: Pointer to the physical adapter. // // Returns: S_OK, or an error. // // // Notes: // HRESULT CMuxNotify::HrAddAdapter (INetCfgComponent *pnccAdapter) { GUID guidAdapter; CMuxPhysicalAdapter *pAdapter; HRESULT hr; TraceMsg( L"-->CMuxNotify::HrAddAdapter.\n" ); hr = pnccAdapter->GetInstanceGuid( &guidAdapter ); if ( hr == S_OK ) { #pragma prefast(suppress:8197, "The instance is freed in the destructor") #pragma prefast(suppress:28197, "pMiniport is saved using m_AdaptersToAdd.Insert( pAdapter,guidAdapter ) and released using m_AdaptersToAdd.Remove in the destructor") pAdapter = new CMuxPhysicalAdapter( m_pnc, &guidAdapter ); if ( pAdapter ) { hr = HrAddMiniport( pAdapter, &guidAdapter ); if ( hr == S_OK ) { m_AdaptersToAdd.Insert( pAdapter, guidAdapter ); } else { delete pAdapter; } } else { hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY ); } } TraceMsg( L"<--CMuxNotify::HrAddAdapter(HRESULT = %x).\n", hr ); return hr; } //---------------------------------------------------------------------------- // // Function: CMuxNotify::HrRemoveAdapter // // Purpose: Deletes the instance representing the physical adapter // and uninstalls all the virtual miniports. // // Arguments: // IN pnccAdapter: Pointer to the physical adapter. // // Returns: S_OK, or an error. // // // Notes: This function is called when the adapter or the protocol // is being uninstalled. // HRESULT CMuxNotify::HrRemoveAdapter (INetCfgComponent *pnccAdapter) { GUID guidAdapter; CMuxPhysicalAdapter *pAdapter; HRESULT hr; TraceMsg( L"-->CMuxNotify::HrRemoveAdapter.\n" ); hr = pnccAdapter->GetInstanceGuid( &guidAdapter ); if ( hr == S_OK ) { hr = m_AdaptersList.RemoveByKey( guidAdapter, &pAdapter ); if ( hr == S_OK ) { m_AdaptersToRemove.Insert( pAdapter, guidAdapter ); hr = pAdapter->Remove(); #ifdef DISABLE_PROTOCOLS_TO_PHYSICAL // // Restore the bindings of other protocols to the physical // adapter. // EnableBindings( pnccAdapter, TRUE ); #endif } } TraceMsg( L"<--CMuxNotify::HrRemoveAdapter(HRESULT = %x).\n", hr ); return hr; } //---------------------------------------------------------------------------- // // Function: CMuxNotify::HrAddMiniport // // Purpose: Installs a virtual miniport. // // Arguments: // IN pAdapter : Pointer to the physical adapter class instance. // IN pguidAdapter: Pointer to the GUID of the adapter. // // Returns: S_OK, or an error. // // // Notes: // HRESULT CMuxNotify::HrAddMiniport (CMuxPhysicalAdapter *pAdapter, GUID *pguidAdapter) { CMuxVirtualMiniport *pMiniport; INetCfgComponent *pnccAdapter; HRESULT hr = S_OK; TraceMsg( L"-->CMuxNotify::HrAddMiniport.\n" ); // // Limit the number of virtual miniports // if ((pAdapter->MiniportCount() + pAdapter->MiniportAddCount()) >= MAX_VIRTUAL_MP_PER_ADAPTER) { hr = HRESULT_FROM_WIN32( ERROR_NO_SYSTEM_RESOURCES ); TraceMsg( L" Virtual miniport limit reached\n" ); } if ( hr == S_OK ) { #pragma prefast(suppress:8197, "The instance is freed in the destructor") #pragma prefast(suppress:28197, "pMiniport is saved using pAdapter->AddMiniport( pMiniport ) and released when pAdapter is released") pMiniport = new CMuxVirtualMiniport( m_pnc, NULL, pguidAdapter ); if ( pMiniport ) { hr = pMiniport->Install(); if ( hr == S_OK ) { hr = pAdapter->AddMiniport( pMiniport ); if ( hr != S_OK ) { pMiniport->DeInstall(); delete pMiniport; } } else { delete pMiniport; } } else { hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY ); } } #ifdef DISABLE_PROTOCOLS_TO_PHYSICAL if ( hr == S_OK ) { // // If this is the first virtual miniport then, disable the bindings // of other protocols to the physical adapter. // if ( pAdapter->MiniportCount() == 0 ) { hr = HrFindInstance( m_pnc, *pguidAdapter, &pnccAdapter ); if ( hr == S_OK ) { EnableBindings( pnccAdapter, FALSE ); ReleaseObj( pnccAdapter ); } } } #endif TraceMsg( L"<--CMuxNotify::HrAddMiniport(HRESULT = %x).\n", hr ); return hr; } //---------------------------------------------------------------------------- // // Function: CMuxNotify::HrRemoveMiniport // // Purpose: Uninstalls a virtual miniport. // // Arguments: // IN pAdapter : Pointer to the physical adapter class instance. // IN pguidAdapter: Pointer to the GUID of the adapter. // // Returns: S_OK, or an error. // // // Notes: // HRESULT CMuxNotify::HrRemoveMiniport (CMuxPhysicalAdapter *pAdapter, GUID *pguidAdapter) { INetCfgComponent *pnccAdapter; HRESULT hr; TraceMsg( L"-->CMuxNotify::HrRemoveMiniport.\n" ); hr = pAdapter->RemoveMiniport( NULL ); #ifdef DISABLE_PROTOCOLS_TO_PHYSICAL if ( hr == S_OK ) { // // If this was the last miniport that was removed then, restore the // bindings of other protocols to the physical adapter. // if ( pAdapter->AllMiniportsRemoved() ) { hr = HrFindInstance( m_pnc, *pguidAdapter, &pnccAdapter ); if ( hr == S_OK ) { EnableBindings( pnccAdapter, TRUE ); ReleaseObj( pnccAdapter ); } } } #endif TraceMsg( L"<--CMuxNotify::HrRemoveMiniport(HRESULT = %x).\n", hr ); return hr; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::OnInitDialog // // Purpose: Initialize controls // // Arguments: // IN hWnd: Window handle to the property page. // // Returns: TRUE. // // Notes: // LRESULT CMuxNotify::OnInitDialog (IN HWND hWndPage) { m_eApplyAction = eActUnknown; ::SendMessage(GetDlgItem(hWndPage, IDC_ADD), BM_SETCHECK, BST_CHECKED, 0); ::SendMessage(GetDlgItem(hWndPage, IDC_REMOVE), BM_SETCHECK, BST_UNCHECKED, 0); return TRUE; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::OnOk // // Purpose: Do actions when OK is pressed // // Arguments: // IN hWnd: Window handle to the property page. // // Returns: PSNRET_NOERROR // // Notes: // LRESULT CMuxNotify::OnOk (IN HWND hWndPage) { TraceMsg(L"-->CMuxNotify::OnOk\n"); if ( ::SendMessage(GetDlgItem(hWndPage, IDC_ADD), BM_GETCHECK, 0, 0) == BST_CHECKED ) { m_eApplyAction = eActPropertyUIAdd; } else { m_eApplyAction = eActPropertyUIRemove; } // // Set the property sheet changed flag if any of our controls // get changed. This is important so that we get called to // apply our property changes. // PropSheet_Changed( GetParent(hWndPage), hWndPage); TraceMsg(L"<--CMuxNotify::OnOk(Action = %s).\n", (m_eApplyAction == eActPropertyUIAdd) ? L"Add" : L"Remove" ); return PSNRET_NOERROR; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::OnCancel // // Purpose: Do actions when CANCEL is pressed // // Arguments: // IN hWnd: Window handle to the property page. // // Returns: FALSE // // Notes: // LRESULT CMuxNotify::OnCancel (IN HWND hWndPage) { UNREFERENCED_PARAMETER(hWndPage); TraceMsg(L"-->CMuxNotify::OnCancel\n"); m_eApplyAction = eActUnknown; TraceMsg(L"<--CMuxNotify::OnCancel\n"); return FALSE; } // ---------------------------------------------------------------------- // // Function: CMuxNotifyDialogProc // // Purpose: Dialog proc // // Arguments: // IN hWnd : See win32 documentation. // IN uMsg : See win32 documentation. // IN wParam: See win32 documentation. // IN lParam: See win32 documentation. // // Returns: See win32 documentation. // // Notes: // INT_PTR CALLBACK NotifyDialogProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CMuxNotify *psf; LRESULT lRes=FALSE; UNREFERENCED_PARAMETER(wParam); if ( uMsg != WM_INITDIALOG ) { psf = (CMuxNotify *)::GetWindowLongPtr( hWnd, DWLP_USER ); // Until we get WM_INITDIALOG, just return FALSE if ( !psf ) { return lRes; } } switch( uMsg ) { case WM_INITDIALOG: { PROPSHEETPAGE* ppsp; ppsp = (PROPSHEETPAGE *)lParam; psf = (CMuxNotify *)ppsp->lParam; SetWindowLongPtr( hWnd, DWLP_USER, (LONG_PTR)psf); lRes = psf->OnInitDialog( hWnd ); } break; case WM_COMMAND: break; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR)lParam; switch (pnmh->code) { case PSN_KILLACTIVE: // // ok to loose focus. // SetWindowLongPtr( hWnd, DWLP_MSGRESULT, FALSE); lRes = TRUE; break; case PSN_APPLY: psf = (CMuxNotify *)::GetWindowLongPtr( hWnd, DWLP_USER); lRes = psf->OnOk( hWnd ); SetWindowLongPtr( hWnd, DWLP_MSGRESULT, lRes); lRes = TRUE; break; case PSN_RESET: psf = (CMuxNotify *)::GetWindowLongPtr( hWnd, DWLP_USER); psf->OnCancel( hWnd ); } } } return lRes; } // ---------------------------------------------------------------------- // // Function: CMuxNotifyPropSheetPageProc // // Purpose: Prop sheet proc // // Arguments: // IN hWnd: See win32 documentation // IN uMsg: See win32 documentation // IN ppsp: See win32 documentation // // Returns: See win32 documentation // // Notes: // UINT CALLBACK NotifyPropSheetPageProc(HWND hWnd, UINT uMsg, LPPROPSHEETPAGE ppsp) { UNREFERENCED_PARAMETER(hWnd); UNREFERENCED_PARAMETER(uMsg); UNREFERENCED_PARAMETER(ppsp); return TRUE; } #ifdef DISABLE_PROTOCOLS_TO_PHYSICAL // ---------------------------------------------------------------------- // // Function: CMuxNotify::EnableBindings // // Purpose: Enable/Disable the bindings of other protocols to // the physical adapter. // // Arguments: // IN pnccAdapter: Pointer to the physical adapter. // IN bEnable: TRUE/FALSE to enable/disable respectively. // // Returns: None. // // Notes: // VOID CMuxNotify::EnableBindings (INetCfgComponent *pnccAdapter, BOOL bEnable) { IEnumNetCfgBindingPath *pencbp; INetCfgBindingPath *pncbp; HRESULT hr; TraceMsg( L"-->CMuxNotify::EnableBindings.\n" ); // // Get the binding path enumerator. // hr = HrGetBindingPathEnum( pnccAdapter, EBP_ABOVE, &pencbp ); if ( hr == S_OK ) { hr = HrGetBindingPath( pencbp, &pncbp ); // // Traverse each binding path. // while( hr == S_OK ) { // // If our protocol does exist in the binding path then, // disable it. // if ( !IfExistMux(pncbp) ) { pncbp->Enable( bEnable ); } ReleaseObj( pncbp ); hr = HrGetBindingPath( pencbp, &pncbp ); } ReleaseObj( pencbp ); } else { TraceMsg( L" Couldn't get the binding path enumerator, " L"bindings will not be %s.\n", bEnable ? L"enabled" : L"disabled" ); } TraceMsg( L"<--CMuxNotify::EnableBindings.\n" ); return; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::IfExistMux // // Purpose: Determine if a given binding path contains our protocol. // // Arguments: // IN pncbp: Pointer to the binding path. // // Returns: TRUE if our protocol exists, otherwise FALSE. // // Notes: // BOOL CMuxNotify::IfExistMux (INetCfgBindingPath *pncbp) { IEnumNetCfgBindingInterface *pencbi; INetCfgBindingInterface *pncbi; INetCfgComponent *pnccUpper; LPWSTR lpszIdUpper; HRESULT hr; BOOL bExist = FALSE; TraceMsg( L"-->CMuxNotify::IfExistMux.\n" ); // // Get the binding interface enumerator. // hr = HrGetBindingInterfaceEnum( pncbp, &pencbi ); if ( hr == S_OK ) { // // Traverse each binding interface. // hr = HrGetBindingInterface( pencbi, &pncbi ); while( !bExist && (hr == S_OK) ) { // // Is the upper component our protocol? // hr = pncbi->GetUpperComponent( &pnccUpper ); if ( hr == S_OK ) { #pragma prefast(suppress:26035, "&lpszIdUpper is a pointer to a buffer that receives a constant null-terminated string , see http://msdn.microsoft.com/en-us/library/ms805225.aspx") hr = pnccUpper->GetId( &lpszIdUpper ); if ( hr == S_OK ) { bExist = !_wcsicmp( lpszIdUpper, c_szMuxProtocol ); CoTaskMemFree( lpszIdUpper ); } else { TraceMsg( L" Failed to get the upper component of the interface.\n" ); } ReleaseObj( pnccUpper ); } else { TraceMsg( L" Failed to get the upper component of the interface.\n" ); } ReleaseObj( pncbi ); if ( !bExist ) { hr = HrGetBindingInterface( pencbi, &pncbi ); } } ReleaseObj( pencbi ); } else { TraceMsg( L" Couldn't get the binding interface enumerator.\n" ); } TraceMsg( L"<--CMuxNotify::IfExistMux(BOOL = %x).\n", bExist ); return bExist; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::HrGetBindingPathEnum // // Purpose: Returns the binding path enumerator. // // Arguments: // IN pnccAdapter : Pointer to the physical adapter. // IN dwBindingType: Type of binding path enumerator. // OUT ppencbp : Pointer to the binding path enumerator. // // Returns: S_OK on success, otherwise an error code. // // Notes: // HRESULT CMuxNotify::HrGetBindingPathEnum ( INetCfgComponent *pnccAdapter, DWORD dwBindingType, IEnumNetCfgBindingPath **ppencbp) { INetCfgComponentBindings *pnccb = NULL; HRESULT hr; *ppencbp = NULL; hr = pnccAdapter->QueryInterface( IID_INetCfgComponentBindings, (PVOID *)&pnccb ); if ( hr == S_OK ) { hr = pnccb->EnumBindingPaths( dwBindingType, ppencbp ); ReleaseObj( pnccb ); } return hr; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::HrGetBindingPath // // Purpose: Returns a binding path. // // Arguments: // IN pencbp : Pointer to the binding path enumerator. // OUT ppncbp : Pointer to the binding path. // // Returns: S_OK on success, otherwise an error code. // // Notes: // HRESULT CMuxNotify::HrGetBindingPath (IEnumNetCfgBindingPath *pencbp, INetCfgBindingPath **ppncbp) { ULONG ulCount; HRESULT hr; *ppncbp = NULL; hr = pencbp->Next( 1, ppncbp, &ulCount ); return hr; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::HrGetBindingInterfaceEnum // // Purpose: Returns the binding interface enumerator. // // Arguments: // IN pncbp : Pointer to the binding path. // OUT ppencbi: Pointer to the binding path enumerator. // // Returns: S_OK on success, otherwise an error code. // // Notes: // HRESULT CMuxNotify::HrGetBindingInterfaceEnum ( INetCfgBindingPath *pncbp, IEnumNetCfgBindingInterface **ppencbi) { HRESULT hr; *ppencbi = NULL; hr = pncbp->EnumBindingInterfaces( ppencbi ); return hr; } // ---------------------------------------------------------------------- // // Function: CMuxNotify::HrGetBindingInterface // // Purpose: Returns a binding interface. // // Arguments: // IN pencbi : Pointer to the binding interface enumerator. // OUT ppncbi : Pointer to the binding interface. // // Returns: S_OK on success, otherwise an error code. // // Notes: // HRESULT CMuxNotify::HrGetBindingInterface ( IEnumNetCfgBindingInterface *pencbi, INetCfgBindingInterface **ppncbi) { ULONG ulCount; HRESULT hr; *ppncbi = NULL; hr = pencbi->Next( 1, ppncbi, &ulCount ); return hr; } #endif
Our Services
-
What our customers say about us?
Read our customer testimonials to find out why our clients keep returning for their projects.
View Testimonials