Share via


© 2004 Microsoft Corporation. All rights reserved.

Figure 2 COM Idioms Ripe for AOP

Exception and error handling.
Transaction management.
Logging of method calls.
Just-in-Time activation/swizzeling/lazy object instantiation.
Synchronization of method calls.
Security checks.
Extending a binary component's automation capabilities like expando objects.
Component instantiation based on memory gates.
Disabling COM pinging.
Design by contract like Eiffel.
Parameter validation.

Figure 3 IAspect Interface

  interface IAspect : IUnknown {
    HRESULT PreProcess( [in] IUnknown*  pUnkDelegatee,
                        [in] BSTR       riid, 
                        [in] BSTR       strMethodName, 
                        [in] long       nvtblSlot,
                        [in] IUnknown*  pEnum);
    HRESULT PostProcess([in]HRESULT     hrOriginal,
                        [in] IUnknown*  pUnkDelegatee, 
                        [in] BSTR       riid, 
                        [in] BSTR       strMethodName, 
                        [in] long       nvtblSlot,
                        [in] IUnknown*  pEnum);
}

Figure 4 Call-tracing Aspect

  class CCallTracingAspect : public IAspect, ... {
public:
    BEGIN_CATEGORY_MAP(CCallTracingAspect)
        IMPLEMENTED_CATEGORY(CATID_Aspects)
    END_CATEGORY_MAP()

    STDMETHODIMP PreProcess(...)
    { return DumpStack ( true, riid, strMethodName, pEnum ) ; }

    STDMETHODIMP PostProcess(...)
    { return DumpStack ( false, riid, strMethodName, pEnum ) ; }

    HRESULT DumpStack(bool preProcess, BSTR riid,
                      BSTR strMethodName, IUnknown *pEnum) {

        if (preProcess) ATLTRACE("PreProcessing: %S(", strMethodName);
        else ATLTRACE("PostProcessing: %S(", strMethodName);

        CComPtr<IEnumVARIANT> spEnumVar;    
        pEnum->QueryInterface(&spEnumVar);
        CComVariant v;
        bool bNeedComma = false;
        while (spEnumVar->Next(1, &v, 0) == S_OK) {
            if (bNeedComma) ATLTRACE(", ");
            else bNeedComma = true;
            ATLTRACE("%S", ToString(v));
        }
        ATLTRACE(")\n");
        return S_OK ;
    }
    •••
};

Figure 5 Creating the Object in BindToObject

  STDMETHODIMP CAopFactory::BindToObject(
    IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riidResult, 
    void** ppvResult) {
    // ParseDisplayName has already pulled in the metadata from
    // the XML file supplied by the client

    // Create the object to be hosted in our AOP environment
    CComPtr<IUnknown> spComp;
    HRESULT hr = spComp.CoCreateInstance ( m_clsid ) ;
    if (FAILED(hr)) return hr ;

    // Create our interceptor and return it the client
    ... // Magic happens...
}

Figure 6 Rest of BindToObject Implementation

  STDMETHODIMP CAopFactory::BindToObject(
    IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riidResult, 
    void** ppvResult) {
    •••
    // Create our interceptor and return it the client

    // Create and initialize our hook
    CComObject<Chook>* pHook ;
    hr = pHook->CreateInstance(&pHook) ;
    if (FAILED(hr)) return hr ;

    CComPtr<IDelegatorHookQI> spHook ;
    hr = pHook->QueryInterface(&spHook) ;
    if (FAILED(hr)) return hr ;

    hr = pHook->SetAspects ( m_displayName, m_aspects.size(), 
                             &m_aspects[0] ) ;
    if (FAILED(hr)) return hr ;

    // Create the UDFactory
    CComPtr<IDelegatorFactory> spDel ;
    hr = CoGetClassObject ( __uuidof(CoDelegator21), CLSCTX_INPROC, 0, 
        __uuidof(IDelegatorFactory), (void **)&spDel );
    if (FAILED(hr)) return hr ;

    // Create the interceptor
    hr = spDel->CreateDelegator(0, spComp, 0, spHook, 0,
                                riidResult, ppvResult);
}

Figure 8 Wrapping the Microsoft FlexGrid Control

  <AOPFramework>
    <Component Name="Microsoft FlexGrid Control, version 6.0">
        <CLSID>{6262D3A0-531B-11CF-91F6-C2863C385E30}</CLSID>
    </Component>
    <Aspects>
        <Aspect Name="Call-Tracing Aspect">
            <CLSID>{49EFA33A-FDB2-4AED-807E-4D447D096642}</CLSID>
        </Aspect>
        <Aspect Name="Synchronization Aspect">
            <CLSID>{6DBA0579-8846-46A2-BEFF-382725A1022C}</CLSID>
        </Aspect>
    </Aspects>
</AOPFramework>

Figure 12 .NET Call-tracing Aspect

  internal class CallTracingAspect : IMessageSink {
    private IMessageSink m_next;
    private String m_typeAndName ;
    
    internal CallTracingAspect(IMessageSink next) { 
        // Cache the next sink in the chain
        m_next = next;
    }

    public IMessage SyncProcessMessage(IMessage msg) {
        Preprocess(msg);
        IMessage returnMethod = m_next.SyncProcessMessage(msg);
        PostProcess(msg, returnMethod);
        return returnMethod;
    }
    
    private void Preprocess(IMessage msg) {
        // We only want to process method calls
        if (!(msg is IMethodMessage)) return;

        IMethodMessage call = msg as IMethodMessage;
        Type t = Type.GetType(call.TypeName) ;
        m_typeAndName = t.Name + "." + call.MethodName ;
        Console.Write("PreProcessing: " + m_typeAndName + "(");

        // Loop through the [in] parameters
        for (int i = 0; i < call.ArgCount; ++i) {
            if (i > 0) Console.Write(", ");
            Console.Write(call.GetArgName(i) + "= " + call.GetArg(i));
        }
        Console.WriteLine(")");
        
        // set us up in the callContext
        call.LogicalCallContext.SetData(ContextName, this);
    }

    private void PostProcess(IMessage msg, IMessage msgReturn)
    {    
        // We only want to process method return calls
        if (!(msg is IMethodMessage) ||
            !(msgReturn is IMethodReturnMessage)) return;

        IMethodReturnMessage retMsg = (IMethodReturnMessage)msgReturn;
        Console.Write("PostProcessing: ");
        Exception e = retMsg.Exception;
        if (e != null) {		
            Console.WriteLine("Exception was thrown: " + e);
            return;
        }

        // Loop through all the [out] parameters
        Console.Write(m_typeAndName + "(");
        if (retMsg.OutArgCount > 0) {
            Console.Write("out parameters[");
            for (int i = 0; i < retMsg.OutArgCount; ++i ) {
                if (i > 0) Console.Write(", ");
                Console.Write(retMsg.GetOutArgName(i) + "= " +    
                              retMsg.GetOutArg(i));
            }
            Console.Write("]");
        }
        if (retMsg.ReturnValue.GetType() != typeof(void))
            Console.Write("returned [" + retMsg.ReturnValue + "]");

        Console.WriteLine(")");
    }
    •••
}