ATL? COM on!

posted in Train of Thought
Published September 25, 2004
Advertisement
Don't stop reading yet -- while the first paragraph of this post is my obligatory praise of Gamedev.net, I am also foreshadowing a future article I plan on writing which will probably be of use to many of you out there -- particularly those who work with COM (IE DirectX) in C++, and some bonus information about a library I'm working on to make 3D audio simple to work with and manage in a complex simulation. So keep reading!

Ahh, my first developer journal post. Fun stuff, eh? I love the way Gamedev is headed with their GDNet+ membership and everything it provides. I will be using this journal for talking about any projects I am currently working on, and will also be using it to get feedback on where people wish me to direct my attention in future projects. I am very open to suggestions and am willing to develop just about any library that would be useful for many types of projects that plenty of developers can benefit from (within reason -- IE I'm not going to program the next Unreal engine... and if I did, I wouldn't upload it here ;).

Anyway, my first order of duty here is to provide the community with an article that I personally feel is almost a necessity to anyone planning on or currently working with DirectX, or any COM library for that matter, in C++. The planned title is something along the lines of "Why ATL's CComPtr is helpful and why you should never use it," which may give you a general idea of the direction I'll be taking.

With the article, I will be talking about why smart pointers are extremely useful when working with COM and why Microsoft's ATL COM smart pointer templates get it wrong in some areas from a C++ programmer's perspective. In addition, I will provide a suggested coded solution for what ATL attempts to provide, along with C++ wrapper functions and objects for Microsoft's procedural COM library featuring exception throwing instead of HRESULT returns and an easier method for dealing with factories. As well, I will also provide exception safe copyable objects for dealing with COM construction and destruction which allow you to easily determine if the COM settings in your current thread are acceptible for your application (which normally can be quite a hassle).

So, hopefully I'll be able to bring you some info that you may not have known about COM, or perhaps knew yet didn't give much thought as to how it should impact your development.

For those who are interested, be warned that I use a lot of advanced C++ template features, particularly a reliance on the SFINAE principle in conjunction with partial specialization. While everything I do is 100% standard C++, some compilers may have trouble with them. My current target for these libraries is Microsoft Visual C++ .NET 2003 as most people who work with COM are working on a Microsoft compiler to begin with, coupled with the fact that their template support is very compliant (for instance, I know that if I port the code to be used with GCC I will have to make some work-arounds for G++'s partially broken SFINAE implementation).

So, anyone who is interested in this project, please let me know. I'm happy to answer any questions you may have and would be willing to take suggestions both for the planned article as well as ideas for the project and even future projects.

My next project (which is already pretty far along in development) is a complete 3D sound manager built around DirectMusic providing facilities for loading sounds and creating generators positioned and oriented in 3D. Supported features include everything that DirectMusic can provide through DirectSound, particularly environmental effects, doppler effects, manual pitch and volume adjustments on both a persound or pergenerator basis, etc. The more abstract feature, and potentially the most useful, is the ability to set the maximum amount of active generators available as well as the ability to create any amount of generators you wish coupled with user-defined priorities (the type of which you can specify through a template parameter making customizability to your application a snap). The manager will automatically move your extra generators into and out of the active generator container based on what priority they have, so you can have lots of objects in a level and have a very simple way of ensuring that the most important sounds (usually the closest sounds or explosions, etc) always get heard without having to manually deal with the intricacies of managing activation and deactivation of generators. The order of an operation which switches the priorities of an already created generator is proportional to log(n), where n is the amount of different priority values that are currently being used. For speed purposes, there will also be a form without priorities that is slightly more optimized than having a manager with priorities where all the priorities are the same. Of course, the latter's uses are much less general than the former. Due to the nature of this project, I'll probably upload it along with documentation, but not make an article about it (unless, of course, I get enough positive feedback to warrant one).

Also, just so I can see if people (and which people) actually read this, please leave a comment of some sort -- even if it's just to say hi. Thanks.
0 likes 6 comments

Comments

evolutional
The COM idea sounds good, however it may be a little outdated with the introduction of .NET and the eventual shift to using managed code. Having said that, .NET's COM support is good so perhaps it'd be useful as a stepping stone. I'd like to read it if at least to see some intuitive methods to problems.
September 25, 2004 06:38 AM
Polymorphic OOP
Yes, I have thought about this before and I definately agree with your assessment but have decided to continue. A total switch to managed code is still quite a ways off, with longhorn still a couple of years until expected release, and as well, a lot of the concepts carry over in a more general sense than things such as COM object lifetime management.

At this point in time, and predictably at least for the next two years, there are many misconceptions that people have with COM, particularly those who are jumping into C++ with DirectX having potentially no previous COM experience. Initially, many concepts can seem confusing and prone to error while other aspects can be unnecessarily tedious concerning the provided level of abstraction. It all can seem needlessly intimidating to the point where newcomers can be so turned off that they'll leave their current project or look for a different solution. I've seen several programmers give up with Direct3D in favor of OpenGL because of it.

Anyway, glad you're showing interest, and thanks for the feedback!
September 25, 2004 07:43 AM
Kylotan
I'm reading! The music stuff sounds interesting although rather than using it directly I might look into whether it can be implemented using other libraries.
September 25, 2004 08:13 AM
Polymorphic OOP
Thanks. I have almost all of the interface of the sound manager layed out already such that it could very easily be ported to use other audio APIs -- portability and standard compliance are my biggest concerns when putting together a library. Currently the only thing not portable is initialization, since internally you should be passing a window handle when initializing a DirectMusic performance (though even that defaults to 0, which is valid though not recommended).

As well, another feature I am currently supporting, but haven't decided if it should be standard to the library across implementations or not, is an option for multithreading (since it's very conceivable that one might want to use the same sound manager across multiple threads). If I decide to make it standard, I will probably implement multithreading as a partial specialization via a bool template parameter for whether or not the functionality is desired. Either that or I may make the multithreaded version a standardized extension that is optionally supported by an implementation. If that were the case, I'd just set up the multithreading switch as the last template parameter which defaults to false (false meaning singlethreaded) and is optionally not defined for when the value is true. Checking whether or not multithreading is supported would be available via a standardized compile-time metafunction.

The only other potentially non-portable part which I haven't yet implemented, though have definately though about doing it if I get around to it, is to allow people to provide a custom DirectMusic loader so that they can load up user-defined audio formats if the need exists (a functionality of DirectMusic which I personally haven't even used). The only problem with that is it would be pretty difficult to abstract away to the point of being portable, so I probably wouldn't even make it a standard extension - just something unique to the DirectMusic implementation.

Anyway, whenever I get a fully working, partially tested version of the DirectMusic/DirectSound based manager, I'll upload it along with documentation as to what I'd prefer to be standard to all implementations. Since I plan on working on other projects as well, I'll probably just only implement one version myself (and maybe an OpenAL version, though I've never done any programming with OpenAL before). Other than that, I'll leave it up to the community to make and upload conforming implementations (if people actually use it, of course).

So, if you want to implement it with libraries other than DirectMusic and DirectSound, you'll be happy to know that I'll try to make it as smooth a process as possible.

Thanks for your interest!
September 25, 2004 08:59 AM
Rebooted
I'm reading too. Took me a while to figure out COM as a beginner, so this is good to see.
September 25, 2004 04:32 PM
Polymorphic OOP
Thanks.

Also, going back to the audio -- I have decided to allow multithreading, however, not via a template parameter. Instead, in order to get a multi-threading safe version of the sound manager, you use a metafunction. The reasoning for this is it makes it possible to create a metafunction that is capabable of making literally any implementation multithreading-safe via encapsulation using a portable multithreading library (IE boosts multithreading sublibrary). This way, if someone needs to get a multithreaded sound manager up and running but wants to use some sound api other than ones used in implementations I provide, they can just make a single-threaded one and use the default metafunction implementation to produce a multithreaded version automatically. As well, if you need to make further optimizations that the default metafunction can't provide, this also allows people to make implementation specific multithreading-safe types via partial or explicit specialization as well, so you get the best of both worlds.

The only problem with this is that the new type would be unable to forward implementation specific parameters to member functions. Possible ways around that would be either standardizing the way of making implementation specific parameters of sound manager functions via packet types on the ends of functions specific to implementation (so all extra parameters of a single type would be in an implementation-defined type for that function with default initialization) or by making any implementation-specific functions required to be implemented as separate nonmember functions. Right now I'm leaning towards the latter solution, though that could cause innefficiency if a compiler doesn't take advantage of the named return value optimization in the case of constructors which require implementation specific parameters.

Anyway, so making a manager multithreading-safe without individual sound manager implementations having to manually make multithreaded implementations could be as easy as:


make_multithreaded< sound_manager_3d< some_priority_type > >::type your_multithreaded_sound_manager_3d;

//Where sound_manager_3d is declared as
// template< typename PriorityType, typename Predicate = ::std::less< PriorityType > >
// class sound_manager_3d;





September 27, 2004 11:05 AM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement

Latest Entries

Advertisement