Intercepting COM Objects with CoGetInterceptor

February 28, 2018

tags: , , , ,
no comments

A while back I wrote about COM interception with CoTreatAsClass. The idea there is to redirect a CLSID to another CLSID implemented by the interceptor. This has the advantage of automatic redirection in cases where a different implementation is desired. However, it makes it difficult to just wrap the original class because its creation becomes masked as well, and so CoTreatAsClass needs to be called again, removing the redirection just enough time to create the original object. This creates an inherent race condition, where new instances could be created in between and the interception "missed".

The COM infrastructure includes other interception mechanisms. This post is about one of the more obscure ones – the CoGetInterceptor API (and friends). The documentation about CoGetInterceptor is minimal and its mentions in search engines are few. One of them is from Clemens Vasters, dated 2002. He actually says most of what is there to say in a nutshell. Let’s expand on that.

Calling CoGetInterceptor with an interface ID that is to be "intercepted" returns an interceptor object that also "implements" that interface. This is the one returned to the client. However, this object has no connection to the real object, if any such exists. The interceptor has no knowledge of any particular implementation; rather, it provides a way to intercept every method call on the object. This explanation is not complete yet, so let’s just build an example that uses CoGetInterceotor.

I’ll start by creating an ATL DLL project in Visual Studio. For this demo, we’ll create a COM class called CalculatorFactory. This object is able to hand out Calculator instances to clients that invoke CreateCalculator. Normally, Calculator objects would be handed out directly. A Calculator object is created that implements an ICalculator interface that supports some simple math operations (aren’t most simple demos involve calculators?).

Here is the original implementation of CCalculatorFactory::CreateCalculator:

STDMETHODIMP CCalculatorFactory::CreateCalculator(ICalculator** ppCalculator) {
    CComObject<CCalculator>* pCalculator;
    auto hr = pCalculator->CreateInstance(&pCalculator);
    if (FAILED(hr))
        return hr;

    retun pCalculator->QueryInterface(ppCalculator);

The Calculator class is not cretable (i.e. not registered), and so is only creatable by CalculatorFactory (which is in itself creatable). Here is some simple client using the claculator:


CComPtr<ICalculatorFactory> spFactory;
auto hr = spFactory.CoCreateInstance(__uuidof(CalculatorFactory));
if (SUCCEEDED(hr)) {
    CComPtr<ICalculator> spCalculator;
    hr = spFactory->CreateCalculator(&spCalculator);
    if (SUCCEEDED(hr)) {
        double result;
        spCalculator->Add(3, 4, &result);
        printf("3 + 4 = %f\n", result);

        spCalculator->Sin(30, &result);
        printf("Sin(30 degrees): %f\n", result);

        spCalculator->Sin(30, &result);
        printf("Sin(30 radians): %f\n", result);

Let’s suppose that these calcultaor instances are handed out to many clients. We can further suppose that there may be other classes that are handed out (perhaps various types of calculators). It may even be the case where we don’t have the source for these calculators, so we cannot provide an alternative implementation (interceptor) directly. This is where CoGetInterceptor comes in.

Instead of returning a calculator object directly, we will return an interceptor that looks like a calculator to the client, but is in fact an implementation provided by the interceptor, where we are in control. Let’s see how this feat us achieved.

First we create an interceptor for the interface we wish to intercept (error handling omitted for clarity) (#include <CallObj.h>):

CComPtr<ICallInterceptor> spInterceptor;
::CoGetInterceptor(__uuidof(ICalculator), nullptr, __uuidof(ICallInterceptor), reinterpret_cast<void**>(&spInterceptor));

The first argument is the interface ID to intercept. It must have an associated type library for this to work (more on this in the next post). The second argument is an IUnknown pointer for aggregation purposes (more on that in the next post as well). The third argument is the interface we wish to use to interact with the interceptor. This would almost always be ICallInterceptor. Finally, the last argument is the resulting interface pointer.

But where is the ICaluclator hiding? We cant hand the client the ICallInterceptor. It’s actually available through a simple QueryInterface:

return spInterceptor->QueryInterface(ppCalculator);

This would return the interceptor as ICalculator to the client. But what would happen now when the client invokes methods of the returned ICalculator poiner? The answer is – nothing at all. We returned an interceptor that has no idea what to do when methods on the intercepted interface are called.

The interceptor provides a way to register for any method that is called on the intercepted interface with ICallInterceptor::RegisterSink. This method accepts an ICallFrameEvents interface implementation that has a single method beyond IUnknown: OnCall. This method will be called for any method called on the intercepted interface. This is where we can inspect arguments, and even make call to the real method, if we so choose.

Let’s build a simnple generic interceptor that will log all methods and invoke the real methods as well. We create an ATL class that implements the ICallFrameEvents interface:

class CGenericInterceptor : public CComObjectRoot, public ICallFrameEvents {
    STDMETHOD(OnCall)(ICallFrame* pFrame) {
        // interception code here

The interceptor must be aware of the real object so it can invoke the real methods. Let’s add a member to hold the real object:

void SetObject(IUnknown* pObject) {
    m_spObject = pObject;

CComPtr<IUnknown> m_spObject;

Now we can add some real code to OnCall:

STDMETHOD(OnCall)(ICallFrame* pFrame) {
    PWSTR interfaceName, methodName;
    pFrame->GetNames(&interfaceName, &methodName);
    printf("%ws::%ws\n", interfaceName, methodName);
    // invoke the method on the real object
    return pFrame->GetReturnValue();

Here is the output of the console (the client code hasn’t changed of course!):

3 + 4 = 7.000000
Sin(30 degrees): 0.500000
Sin(30 radians): -0.988032

All method calls are intercepted, the interface and method names are shown and then ICallFrame::Invoke is called to invoke the actual method on the real calculator object. Other methods include the ability to inspect parameters and even modify parameters before calling the real method. But how was this set up? here is the revised CCalculatorFactory::CreateCalculator:

CComPtr<ICallInterceptor> spInterceptor;
auto hr = ::CoGetInterceptor(__uuidof(ICalculator), nullptr, __uuidof(ICallInterceptor), reinterpret_cast<void**>(&spInterceptor));
if (FAILED(hr))
	return hr;

CComObject<CCalculator>* pCalculator;
hr = pCalculator->CreateInstance(&pCalculator);
if (FAILED(hr))
	return hr;

CComObject<CGenericInterceptor>* pGenericInterceptor;


return spInterceptor->QueryInterface(ppCalculator);

Notice the real calculator is created and passed to the sink. The actual returned object is the interceptor just as before. But the call to ICallIngerceptor::RegisterSink makes all the difference.

The complete source code for this demo is available here.

So there you have it: a transparent interception mechanism provided courtesy of COM. In the next post I’ll discuss some of the finer details of this method, its strengths and weaknesses. Stay tuned!

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>