Practical ATL: Implementing an enumerator object

This is my first article about practical ATL examples, which I already mentioned here.


In this example I will create an ATL Server which implements 1 custom interface: IStuff. Hardly an inspiring name, but I couldn’t think of anything better before I had my first coffee.


This interface will have 1 method which will return an enumerator to the caller. Specifically, this enumerator will implement IEnumString.


Enumerators are part of the interface of many real-life COM servers, but creating your own is an arduous task. ATL makes this much easier, but an example makes things so much easier still.


Since client code will have to deal with this enumerator (and to have a demo app) I will also create a client application that creates an instance of the server, consumes the IStuff interface and then enumerate the items contained in the returned enumerator.


Before we get started


If you don’t own a copy of ‘ATL Internals, Second Edition’ yet, I strongly advise you to buy it. It is worth the money, and apart from leading you through all the interesting and gory stuff, it also starts by explaining the actual process of creating an ATL server through the IDE, as well as implementing methods, properties and events.


I am only going to cover that aspect very lightly. It should be detailed enough for anyone who has done C++ development using VS:


  1. Create a new ATL Server project with project name ‘Stuff_Server’ and a solution name ‘Stuff’.
  2. Choose the EXE project type and click ‘finish’
  3. Add a new class to the project, and specify ATL Simple Object. Use ‘Stuff’ as the name of the object.
  4. Switch to classview, and add a new method to the IStuff interface with the prototype ‘HRESULT GetEnum(IUnknown ** ppEnum).  ppEnum should be marked as an ‘out’ parameter.

Build the project, and you should be ready for the actual work. The ATL wizards will have implemented all the IDL and DCOM stuff for you, and you only have to implement the functionality.


Finally, I always end by changing the project configuration to use static CRT and ATL runtimes instead of dynamic runtimes. This makes it infinitely more easy to distribute the resulting executables without having to bother with registration and installation of the runtime dlls and their manifests.


Creating the server


Now that the ATL wizards have generated the function skeleton for us, it is time to do something with it:


STDMETHODIMP CStuff::GetEnum(IUnknown** ppEnum)
{
 
}


The enumerator


Before we can do anything else, we have to think about the actual enumerator for a bit. In our case we implement IEnumString. This is an interface for enumerating string (who’d have thought, eh?).


Enum interfaces all look alike, and ATL helpfully has a stock implementation for generic enumerators that allows you to specify the Interface, GUID, datatype and data type copy traits as template parameters. In order to facilitate coding, we make a typedef for this class:


typedef CComEnum<


                 IEnumString,


                 &IID_IEnumString,


                 LPOLESTR,


                 _Copy<LPOLESTR> > CComEnumStringAbstract;


 


This will specialize the enumerator for our purposes. The use of the first 3 parameters is obvious. Don’t worry about the _Copy parameter. I will cover that later.


The enumerator itself is a normal COM object, so it needs lifetime management, interface managements, and all other things you really don’t want to care about for something so simple. At this point, CComEnumStringAbstract will still be an abstract class because it can’t decide how to do these things for you.


In order to make our enumerator a full fledged COM object, we have to shove it into a bare COM object. This is very easy:


typedef CComObject<CComEnumStringAbstract> CComEnumString;


And that is all there is to creating an enumerator! Anyone who has ever implemented one manually will agree that this is infinitely more convenient


Implementing GetEnum


The implementation for GetEnum is also fairly easy (comments removed for clarity)


STDMETHODIMP CStuff::GetEnum(IUnknown** ppEnum)
{
  CComEnumString * thEnumObj  = NULL;
  HRESULT hr = CComEnumString::CreateInstance(&thEnumObj);
  if(FAILED(hr))
    return hr;

  CComPtr<CComEnumString> thEnum(thEnumObj);

  LPOLESTR strings[] = {L“One”, L“Two”, L“Three”, NULL};
  hr = thEnum->Init(&strings[0], &strings[3], NULL, AtlFlagCopy);
  if(FAILED(hr))
    return hr;
 
  hr = thEnum->QueryInterface( __uuidof(IUnknown), (void**)ppEnum);
  return hr;
}


First we create a new CComEnumString object. It is worth noting that the object returned by CreateInstance has a refcount of 0. Before we do anything with it we should AddRef it, but instead of doing that manually, I do it via assignment to the CComPtr. smart pointer. That way the object also gets released automatically at the end.


Then we have to make sure the enumerator has some data to enumerate. We do this by populating an array, and then telling the enumerator to copy the data out of it into its own internal buffer. This is done via the AtlFlagCopy flag.


It might seem weird if you come from a C background, but the ‘End’ pointer has to point to the first position beyond the last element. This is normal with collections in C++. That is also why I populate the array with a NULL pointer at the end; So that there is something in the array after the last ‘real’ element. This way there is no buffer overflow.


Using AtlFlagCopy has the overhead of having to copy the data, but otoh the enumerator does not have to care about the lifetime of the array. We could also use new[] to create a new array and then use the AtlFlagTakeOwnership flag to indicate that it is up to the enumerator to call delete[] and clean up. But in this example we can’t do that (read below).


When the enumerator is initialized, we return an IUnknown interface pointer to the caller. Since this will have increased the enumerator ref count, the enumerator object will keep on living when the CComPtr goes out of scope and releases its own reference to the enumerator.


There. That is all there is to it on the server side. No vast amounts of copy pasted boilerplate code, but just a couple of lines of powerful ATL incantations J


_Copy<LPOLESTR> revisited


If an enumerator has to copy data to a client, or if it has to copy data into its internal buffers in the ‘Init’ function, it has to know how to do this.


It’s all good and well to do a simple memcpy of an ULONG or a double, but for strings (LPOLESTR) and interface pointers (IUnknown) this won’t work. There’s ref counting and memory ownership to deal with.


Of course, the template class, not knowing about this, can’t anticipate what you want, so instead it needs a policy class to delegate to. That is where the _Copy<> template class comes in. It has 3 methods: Init, Destroy, and Copy. Those methods perform the actual operations needed to copy an instance of T to another instance of T, to initialize a new one, and to destroy one.


There are several stock specializations for _Copy<>, one of which works for LPOLESTR. So rather than copying the LPOLESTR pointer itself, it calls CoTaskMemAlloc to create a buffer for the copy of the string, and then copies over the data.


If you look at my example more closely, you will also see why I cannot simply new up an array of string literals and pass those to the Init function with the AtlFlagTakeOwnership flag.


LPOLESTR is superficially identical to wchar_t*. So using a string literal instead of an LPOLESTR (which is what I do in my example) will work without a hitch. But if I’d new up an array and tell the enumerator to manage it, that is when it would all go pear shaped.


Because the enumerator would not only call delete[] on the array, but it would also call _Copy::Destroy for each of the items. And trying to free up a string literal with CoTaskMemFree will result in a hard to diagnose crash.


Installing the server


On a development station this is done automatically by Visual Studio. But if you need to do this on another PC, you just execute the server from the command line with the /RegServer argument.


Creating the Client


Creating the client application is fairly simple, but I wanted to show how to do it anyway, because then I could demonstrate that the COM server works as intended.


I create a simple win32 console application so that I only had to care about the actual functionality.


Importing the server type library


In the olden days or yore, working with COM servers in a C++ project was a bit tedious. You had to include the IDL files in your project and compile them, then include the resulting header files, add the .c files to your project for the GUID definitions… Not rocket science by any means, but still… a bit messy and ugly.


Now, I have very few kind words for Visual Basic, but to give credit where it is due: Visual Basic is (in large part) responsible for the existence of tlb files.


Visual Basic programmers wanted to use COM too, and the people who made Visual Basic wanted to prevent the application programmers to have anything to do with IDL. They wanted Visual Basic to take care of all that mess behind the scenes.


And thus the type library (tlb) was born.


The type library contains the same stuff as the IDL files, but in a machine readable, programming language independent format.


To use a COM server, you need to do nothing more than add the following line to the StdAfx.h header file of the client program:


#import “Stuff_Server.tlb” no_namespace


You also need to make sure that the compiler knows where to find Stuff_Server.tlb. This is easily done by adding the following line to the ‘Additional include directories’ setting:


..\Stuff_Server\$(ConfigurationName)


If you then compile StdAfx.cpp, the compiler will pull in the type library and generate the appropriate headers which are then automatically included.


The no_namespace attribute tells the compiler that it shouldn’t put the declarations in a specific namespace.


Using the COM server


The client application code itself is fairly trivial:


int _tmain(int argc, _TCHAR* argv[])


{


  HRESULT hr = CoInitialize(NULL);


  if(SUCCEEDED(hr))


  {


    CComPtr<IStuff> stuff;


    hr = CoCreateInstance(


           __uuidof(Stuff), NULL, CLSCTX_ALL,


           __uuidof(IStuff), (void**)&stuff );


    if(FAILED(hr))


      return hr;


 


    CComPtr<IUnknown> thEnumUnk;


    hr = stuff->GetEnum((IUnknown **)&thEnumUnk);


    if(FAILED(hr))


      return hr;


 


    CComPtr<IEnumString> thEnum;


    thEnumUnk->QueryInterface(__uuidof(IEnumString), (void**) &thEnum);


 


    do


    {


      LPOLESTR str;


      hr = thEnum->Next(1, &str, NULL);


      if(hr == S_OK )


        wprintf(L“%s\n”, str);


      CoTaskMemFree(str);


    }while (hr == S_OK );


  }


 


  CoUninitialize();


  return 0;


}


First I initialize the COM runtime and then create a new instance of the Stuff object. I request IStuff as the initial interface. I also use the __uuidof keyword to get the GUID for an interface / object instead of using the CLSID_ and IID_ parameters. In my opinion, it is more convenient.


The COM smart pointer takes care of the reference counting for me. This is most convenient, because then I am certain that it will get released properly without me having to worry about it.


Btw, this is also the reason that all the code is placed into a separate scope block after the call to CoInitialize. The smart pointers clean up their interface pointers when they go out of scope. If CoUninitialize would have been called before that, it would lead to weird problems / crashes.


Via the IStuff interface I request an enumerator object. This gets returned as an IUnknow interface, so I have to get the IEnumString interface via the IUnknown::QueryInterface method. So that’s 3 interfaces already, and I still don’t have to care about reference counting J


After that I use the ‘Next’ method of the IEnumString interface to retrieve the items contained in the enumerator. This the only place where I have to perform a manual cleanup action.


The IEnumString interface does not work with BSTRs, it works with LPOLESTRs. While these are code compatible because they are the same type of data, their semantics are not. The _Copy<LPOLESTR> mentioned earlier allocates data for the string using CoTaskMemAlloc. It has to be freed by CoTaskMemFree.


CComBSTR would use SysAllocString and SysFreeString. And while the code would compile and execute perfectly, there would be an crash as soon as the CComBSTR would try to free the string it got from the call to ‘Next’.


Conclusion


As you can see, implementing COM servers and clients can be really easy with the proper use of ATL. And you’ve also seen that implementing an enumerator object is made really easy.


The code demo code is up for download with this article under the MIT license. Have fun.


I will probably write some more ATL / COM stuff soon. Stay tuned for more DCOM archaeology from the mists of time ;-)

4 thoughts on “Practical ATL: Implementing an enumerator object”

  1. this line:
    LPOLESTR strings[] = {L”One”, L”Two”, L”Three”, NULL};
    should be replaced by
    LPOLESTR strings[] = {L”One”, L”Two”, L”Three”};

    the C/C++ guarantee that one past the last element of an array will be a valid value, you will not be able to dereference it, but you will be able to compare to it
    so adding a NULL to your array is useless.
    apart from that, nice introductory article.

  2. I’ll check it out to see if I can find a mention of that in the C++ reference. I doubt this is true, because I would have noticed it in e.g the size of a struct with embedded arrays. It could cause other problems as well (the dummy unconstructed elements)

    I’ll post a follow up with the answer, regardless if I am right or wrong. Thanks for commenting

  3. you can doubt as much as you can, read TC++PL 3rd edition, chapter 5, section 3 state:
    “Taking a pointer to the element one beyond the end of an array is guaranteed to work.”

    see also 2.7.2

    I’ve often seen this error in C++ samples from microsoft. which probably explains why this error is so frequent.
    Of course dereferencing that pointer one past the last element is a big no-no.

  4. Sorry we were talking about 2 different things.
    I just read that section in the C++PL, and it says what you mean, but that is not why I had the NULL. I should perhaps rephrase that part.

    I know I can simply do something like end=begin + size, for example, and the pointer will work for the sake of arithmetic.

    But there is nothing there to dereference. I misinterpreted your earlier remark to mean that you thought that C++ inserted a dummy element that could be dereferenced. My bad.

    Anyway, yes I know the address value will be valid.
    But I have learned the hard way never to pass pointers to other components without making sure that there is something valid there.
    I have worked with enough programmers who had problems with the concepts that pointers had to point TO something. I learned not to give out pointers on the understandig that it was for arithmetic only.

    Yes, they should have known these things. But it’s not like I had any say in whom I worked with, since I was the outside consultant.
    And if their component causes trouble, they are to blame. But unfortunately, I was the lead programmer who had to fly to France to figure out why this very expensive satelite testing system was crashing regularly.

    So learned to apply ‘defensive driving’ skills to programming. Adding the NULL doesn’t have any significant cost, but if someone else screws up by making a simple mistake, using my pointer, it doesn’t take down the system.

Leave a Reply

Your email address will not be published. Required fields are marked *

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=""> <strike> <strong>