text: //+-------------------------------------------------------------------------
  //
  //  Microsoft Windows
  //
  //  Copyright (C) Microsoft Corporation
  //
  //  File:       iasprofa.cpp
  //
  //--------------------------------------------------------------------------
  
  // IASProfA.cpp: implementation of the CIASProfileAttribute class.
  //
  //////////////////////////////////////////////////////////////////////
  
  #include "stdafx.h"
  #include "resource.h"
  #include "helper.h"
  #include "IASHelper.h"
  #include "iasprofa.h"
  #include "napmmc.h"
  #include "napmmc_i.c"
  
  //////////////////////////////////////////////////////////////////////
  // Forward declarations of some utilities used here
  //////////////////////////////////////////////////////////////////////
  
  static HRESULT getCLSIDForEditorToUse(      /* in */  IIASAttributeInfo *pIASAttributeInfo
                             , /* in */  VARIANT * pvarValue
                             , /* out */ CLSID &clsid
                          );
  
  static HRESULT SetUpAttributeEditor(     /* in */  IIASAttributeInfo *pIASAttributeInfo
                          , /* in */  VARIANT * pvarValue
                          , /* out */ IIASAttributeEditor ** ppIASAttributeEditor 
                          );
  
  //////////////////////////////////////////////////////////////////////
  // Construction/Destruction
  //////////////////////////////////////////////////////////////////////
  
  //////////////////////////////////////////////////////////////////////////////
  /*++
  
  CIASProfileAttribute::CIASProfileAttribute
  
     Constructor
  
  --*/
  //////////////////////////////////////////////////////////////////////////////
  CIASProfileAttribute::CIASProfileAttribute(
                         IIASAttributeInfo * pIASAttributeInfo
                       , VARIANT &          varValue
                    )
  {
     // Check for preconditions:
     _ASSERTE( pIASAttributeInfo );
  
     HRESULT hr;
  
     // The smartpointer calls AddRef on this interface.
     m_spIASAttributeInfo = pIASAttributeInfo;
  
     // Make a copy of the passed variant.
     hr = VariantCopy( &m_varValue, &varValue );
     if( FAILED( hr ) ) throw hr;
  
     // ISSUE: Make sure that if anything here fails, m_spIASAttributeInfo gets release.
  }
  
  
  //////////////////////////////////////////////////////////////////////////////
  /*++
  
  CIASProfileAttribute::~CIASProfileAttribute
  
     Destructor
  
  --*/
  //////////////////////////////////////////////////////////////////////////////
  CIASProfileAttribute::~CIASProfileAttribute()
  {
  }
  
  
  //////////////////////////////////////////////////////////////////////////////
  /*++
  
  CIASProfileAttribute::Edit
  
     Call this to ask a profile attribute to edit itself.
  
  --*/
  //////////////////////////////////////////////////////////////////////////////
  STDMETHODIMP CIASProfileAttribute::Edit()
  {
     // Check for preconditions:
     _ASSERTE( m_spIASAttributeInfo );
  
     CLSID clsidEditorToUse;
     HRESULT hr = S_OK;
  
     CComPtr<IIASAttributeEditor> spIASAttributeEditor;
  
     // Get the editor to use.
     hr = SetUpAttributeEditor( m_spIASAttributeInfo.p, &m_varValue, &spIASAttributeEditor );
     if( FAILED( hr ) ) return hr;
  
     // Edit it!
     CComBSTR bstrReserved;
     hr = spIASAttributeEditor->Edit( m_spIASAttributeInfo.p, &m_varValue, &bstrReserved );
     if( FAILED( hr ) ) return hr;
  
     return hr;
  }
  
  
  //////////////////////////////////////////////////////////////////////////////
  /*++
  
  CIASProfileAttribute::getAttributeName
  
  --*/
  //////////////////////////////////////////////////////////////////////////////
  STDMETHODIMP CIASProfileAttribute::get_AttributeName( BSTR * pbstrVal )
  {
     // Check for preconditions:
     _ASSERTE( m_spIASAttributeInfo );
  
     HRESULT hr = S_OK;
     
     hr = m_spIASAttributeInfo->get_AttributeName( pbstrVal );
  
     return hr;
  }
  
  
  //////////////////////////////////////////////////////////////////////////////
  /*++
  
  CIASProfileAttribute::GetDisplayInfo
  
     Rather than asking the AttributeInfo directly for information
     about the vendor name, this method will use an AttributeEditor
     to ask for this information.  
     
     This is the most generic way of asking for this info as
     for some attributes, e.g. RADIUS Vendor Specific, Vendor Name
     is not stored in the AttributeInfo but is encapsulated in
     the value of the attribute itself.
  
     So we don't use our own knowledge of the attribute, rather we
     create an editor and ask the editor to give back this 
     information for us.
  
  --*/
  //////////////////////////////////////////////////////////////////////////////
  STDMETHODIMP CIASProfileAttribute::GetDisplayInfo( BSTR * pbstrVendor, BSTR * pbstrDisplayValue )
  {
     // Check for preconditions:
     _ASSERTE( m_spIASAttributeInfo );
     
     HRESULT hr = S_OK;
  
     CComBSTR bstrVendor, bstrDisplayValue, bstrReserved;
  
     try
     {
        CComPtr<IIASAttributeEditor> spIASAttributeEditor;
  
        // Get the editor to use.
        hr = SetUpAttributeEditor( m_spIASAttributeInfo.p, &m_varValue, &spIASAttributeEditor );
        if( FAILED( hr ) ) throw hr;
  
        hr = spIASAttributeEditor->GetDisplayInfo( m_spIASAttributeInfo.p, &m_varValue, &bstrVendor, &bstrDisplayValue, &bstrReserved );
        if( FAILED( hr ) ) throw hr;
     }
     catch(...)
     {
        // If anything above fails, just fall through -- we will return a pointer to an empty bstr.
        hr = E_FAIL;
     }
  
     *pbstrVendor = bstrVendor.Copy();
     *pbstrDisplayValue = bstrDisplayValue.Copy();
     
     return hr;
  }
  
  
  //////////////////////////////////////////////////////////////////////////////
  /*++
  
  CIASProfileAttribute::get_VarValue
  
  --*/
  //////////////////////////////////////////////////////////////////////////////
  STDMETHODIMP CIASProfileAttribute::get_VarValue( VARIANT * pvarVal )
  {
     // Check for preconditions:
     // None.
  
     HRESULT hr = S_OK;
     hr = VariantCopy( pvarVal, &m_varValue );
     return hr;
  }
  
  
  //////////////////////////////////////////////////////////////////////////////
  /*++
  
  CIASProfileAttribute::get_AttributeID
  
  --*/
  //////////////////////////////////////////////////////////////////////////////
  STDMETHODIMP CIASProfileAttribute::get_AttributeID( ATTRIBUTEID * pID )
  {
     // Check for preconditions:
     _ASSERTE( m_spIASAttributeInfo );
  
     HRESULT hr = S_OK;
     hr = m_spIASAttributeInfo->get_AttributeID( pID );
     return hr;
  }
  
  
  //////////////////////////////////////////////////////////////////////////////
  /*++
  
  ::getCLSIDForEditorToUse
  
     The ShemaAttribute for a node stores a ProgID which indicates which 
     editor to use to manipulate an attribute.
  
     For non-multivalued attributes, we query the schema attribute to find
     out the ProgID for its editor.
  
     For multivalued attributes, we always create the multivalued editor.  
     When it is used, the multivalued editor is passed the schema attribute which it will
     then use to query for the appropriate editor to pop up for editing 
     each indivdual elements
  
  --*/
  //////////////////////////////////////////////////////////////////////////////
  HRESULT getCLSIDForEditorToUse(       /* in */  IIASAttributeInfo *pIASAttributeInfo
                             , /* in */  VARIANT * pvarValue
                             , /* out */ CLSID &clsid
                          )
  {
     // Check for preconditions:
     _ASSERTE( pIASAttributeInfo );
  
     HRESULT hr = S_OK;
  
     // Get attribute restrictions to see if multivalued.
     long lRestriction;
     hr = pIASAttributeInfo->get_AttributeRestriction( &lRestriction );
  
     if( lRestriction & MULTIVALUED )
     {
        _ASSERTE( V_VT(pvarValue) == (VT_ARRAY | VT_VARIANT) || V_VT(pvarValue) == VT_EMPTY );
        
        // Create the multi-attribute editor.
        // It will figure out the appropriate editor to use to
        // edit individual attribute values.
        clsid = CLSID_IASMultivaluedAttributeEditor;
     }
     else
     {
        // Query the schema attribute to see which attribute editor to use.
        
        CComBSTR bstrProgID;
  
        hr = pIASAttributeInfo->get_EditorProgID( &bstrProgID );
        if( FAILED( hr ) )
        {
           // We could try putting up a default (e.g. hex) editor, but for now:
           return hr;
        }
  
        hr = CLSIDFromProgID( bstrProgID, &clsid );
        if( FAILED( hr ) )
        {
           // We could try putting up a default (e.g. hex) editor, but for now:
           return hr;
        }
     }
     return hr;
  }
  
  
  //////////////////////////////////////////////////////////////////////////////
  /*++
  
  ::SetUpAttributeEditor
  
  --*/
  //////////////////////////////////////////////////////////////////////////////
  HRESULT SetUpAttributeEditor(   /* in */  IIASAttributeInfo *pIASAttributeInfo
                          , /* in */  VARIANT * pvarValue
                          , /* out */ IIASAttributeEditor ** ppIASAttributeEditor 
                          )
  {
     // Check for preconditions:
     _ASSERTE( pIASAttributeInfo );
     _ASSERTE( ppIASAttributeEditor );
  
     // Initialize the interface pointer to NULL so we know whether we need to release it if there is an error.
     *ppIASAttributeEditor = NULL;
  
     // Query the schema attribute to see which attribute editor to use.
     CLSID clsidEditorToUse;
     CComBSTR bstrProgID;
     HRESULT hr;
  
     try
     {
        hr = getCLSIDForEditorToUse( pIASAttributeInfo, pvarValue, clsidEditorToUse );
        if( FAILED( hr ) )
        {
           // We could try putting up a default (e.g. hex) editor, but for now:
           return hr;
        }
  
        hr = CoCreateInstance( clsidEditorToUse , NULL, CLSCTX_INPROC_SERVER, IID_IIASAttributeEditor, (LPVOID *) ppIASAttributeEditor );
        if( FAILED( hr ) )
        {
           return hr;
        }
        if( ! *ppIASAttributeEditor )
        {
           return E_FAIL;
        }
     }
     catch(...)
     {
           // No smart pointers here -- need to make sure we release ourselves.
           if( *ppIASAttributeEditor )
           {
              (*ppIASAttributeEditor)->Release();
              *ppIASAttributeEditor = NULL;
           }
     }
  
     return hr;
  }
  