Lost Website

You Are Here

Archive for the ‘C++’ Category

RAII COM wrapper

without comments

COM stands for Component Object Model. This is the technology behind most of non-trivial things in Windows, the why of the obscure HKEY_CLASSES_ROOT registry subtree and the core of the infamous ActiveX technology.

Now, I don’t know much about COM programming so this won’t be a tutorial on the subject. I know just the minimum I need to safely work with MAPI in the context of what I do at Kryptiva.

COM programming include many concepts of typical object-oriented programming languages. It’s just a lot more verbose. You can view COM interfaces as structures containing pointers to functions. COM classes which implemented those interfaces are managed using reference counting. This means that whenever you carry a reference to a COM class around you need to increment the reference count manually and release it when you are done.

This is something tedious and error-prone but unavoidable when you are using COM objects in C. Luckily, C++.NET isn’t C and it means we can use RAII, just like the code I presented in Naivety in C++.

Before

Before presenting the simple wrapper, let’s see how plain COM programming would look like without the wrapper.

IUnknown *pUnk;
IMAPIProp *pprop;
HRESULT r;

pUnk = (IUnknown*)Marshal::GetIUnknownForObject(mapiObj).ToPointer();

r = pUnk->QueryInterface(::IID_IMAPIProp, (void **)&pprop);
if (FAILED(r))
  Marshal::ThrowExceptionForHR(r);

r = pProp->SaveChanges(FORCE_SAVE | KEEP_OPEN_READWRITE);
if (FAILED(r))
  throw gcnew MapiException(pProp, r, "Failed to save attachment data");

pUnk->Release();
pProp->Release();

This is simple MAPI code that I hacked as a demonstration. It doesn’t do anything interesting.

This code is pretty simple but gives an idea about how hairy code that is calling COM can get, especially if you throw along exception handling.

After

Here is the same code, using the simple wrapper that is listed below.

COM<IMAPIProp> ifProp;
COM<IUnknown> ifUnk;
HRESULT r;

pUnk.Ptr = static_cast<IUnknown *>(Marshal::GetIUnknownForObject(mapiObj).ToPointer());

r = ifUnk.Ptr->QueryInterface(::IID_IMAPIProp, reinterpret_cast<void**>(&ifSession.Ptr))
if (FAILED(r))
   Marshal::ThrowExceptionForHR(r);

r = pProp->SaveChanges(FORCE_SAVE | KEEP_OPEN_READWRITE);
if (FAILED(r))
   throw gcnew MapiException(pProp, r, "Failed to save attachment data");

You can see that the COM wrapper releases the COM objects which is a precious feature as the calling procedure gets more complete. If the end result is a bit anticlimatic, it is because error handling is still in the way. The wrapper I have made for error handling is a lot less pretty so I won’t be presenting it here.

The code itself

// RAII friendly wrapper over COM interface usage.
template <class C> class COM
{
public:
   C *Ptr;

COM<C>(C *pCom)
{
   assert(pCom);
   Ptr = pCom;
}

COM<C>()
{
   Ptr = 0;
}

COM<C>& operator=(const COM<C>& com)
{
   assert(com.Ptr != 0);
   Ptr = com.Ptr;
   Ptr->AddRef();
   return *this;
}

COM<C>(const COM<C>& com)
{
   assert(com.Ptr != 0);
   Ptr = com.Ptr;
   assert(Ptr->AddRef() >= 1);
}

~COM<C>()
{
   if (Ptr) assert(Ptr->Release() >= 0);
   Ptr = 0;
}
};

There is not much to say about this code. It’s very simple and does the job. The copy constructor is there to increase the reference count in case an instanciated COM object is passed between callers and callee.

I have added assert calls to catch potential problems I may have missed but none of them have ever been triggered.

Written by François-Denis Gonthier

February 10th, 2010 at 9:40 pm

Naivety with C++

with one comment

Warning, major n00bness ahead.

I’m not a big user of C++, but recently some work I have had to do with .NET has made me use C++/CLI, the .NET version of C++.

The API I work have a well defined and consistent Alloc/Use/Free cycle. This has gave me an incentive to learn to use RAII (via DrMax) to elegantly wrap the required cleanup operation in my code.

The following class around Windows GlobalAlloc is an example of such a wrapper.

    // RAII friendly wrapper over Win32 GlobalAlloc.
    class Memory
    {
    private:
        bool m_isAlloc;

    public:
        HGLOBAL Ptr;
        SIZE_T Size;

        void Alloc(UINT flags, size_t dwBytes)
        {
            if (IsAlloc()) Free();
            Size = dwBytes;
            Ptr = GlobalAlloc(flags, dwBytes);
            if (Ptr == 0)
                throw gcnew OutOfMemoryException();
            m_isAlloc = 1;
        }

        void Free()
        {
            if (Ptr) GlobalFree(Ptr);
            m_isAlloc = 0;
            Size = 0;
            Ptr = 0;
        }

        bool IsAlloc()
        {
            return m_isAlloc;
        }

        Memory(UINT flags, size_t dwBytes)
        {
            Alloc(flags, dwBytes);
        }

        Memory()
        {
            Ptr = 0;
        }

        ~Memory()
        {
            if (Ptr) GlobalFree(Ptr);
        }
    };

Expert eyes will obviously see that this code lacks 2 important things:

  • there is no copy constructor
  • there is no assignment operator

I’m not very experienced in C++ so I don’t the reflexes that make C++ programmers write those things when the define a class, and I don’t yet know when the implicit copy constructor and assignment operator are called. I’ve found that the easiest way to discover that is to to prevent them from being usable by the clients of the class. In the case of my small class above, I needed to make 2 functions private.

class Memory {
...
private:
    Memory&amp; operator=(const Memory&amp; mem);
    Memory(const Memory&amp; mem);
...

This makes the compiler freak out when compiling my program…

...Memory::operator =' : cannot access private member declared in class 'Memory'...

The compiler has helpfully pointed to me out which place in my code those functions needs to be called.

Oops, so I really need that assignment operator after all.

Written by fdgonthier

October 27th, 2009 at 8:00 pm

Posted in C++,Programming

Tagged with , , , ,