Why don’t I use any class libraries in my sample code?


As a general rule, I avoid using any class libraries in my sample code. This isn't because I'm opposed to class libraries, but rather because I don't want to narrow my audience to "people who use MFC" (to choose one popular class library). If I were to start using MFC for all of my samples, I'd probably lose all the people who don't use MFC.

"Oh, but those people can just translate the MFC code into whatever class library they use."

Well, sure, they could do that, but first they would have to learn MFC. I wouldn't be talking about HWNDs and HDCs any more but rather CWnds and CDCs. I would write "Add this to your OnDropEx handler", and all the non-MFC people would say, "What are you talking about? I'm not using MFC. What is the Win32 equivalent to OnDropEx?" (Suppose my article on using accessibility to read the text under the mouse cursor were titled "How to use MFC to retrieve text under the mouse cursor." Would you have read it?)

"Well, fine, don't use MFC, but still it wouldn't kill you to use a smart pointer library."

But which one? There's MFC's CIP, ATL's CComPtr, STL^H^H^Hthe C++ standard library's auto_ptr, the Microsoft compiler's built-in _com_ptr_t (which you get automatically if you use the nonstandard #import directive), and boost's grab bag of smart pointer classes scoped_ptr, shared_ptr, weak_ptr, intrusive_ptr... And they all behave differently. Sometimes subtly incompatibly. For example, MFC's CIP::CreateObject method uses CLSCTX_INPROC_SERVER, whereas ATL's CComPtr::CreateInstance method uses CLSCTX_ALL. When you're chasing down a nasty COM marshalling problem, these tiny details matter, and if you're an ATL programmer looking at MFC code, these tiny details are also something you're going to miss simply due to lack of familiarity. (And woe unto you if your preferred language is VB or C# or some other popular non-C++ language. Now you have double the translation work ahead of you.)

Instead of hiding the subtleties behind a class library, I put them right out on the table. Those of you who have a favorite class library can convert the boring error-prone plain C++ code into your beautiful class library.

In fact, I almost expect you to do it.

(On a related note, some people are horrified at the rather dense code presentation I use here. I don't write code like that in real life; I'd be just as horrified as you if I saw that code in a real program. I just use that style here because of the nature of the medium. A great way to lose people's interest is to make them plow through 100 lines of boring code before they reach the good stuff.)

Comments (28)
  1. Andy says:

    I would think that most folks who read your blog realize that the style of your code here and your not using class libraries is to reach the widest possible audience with high quality examples that get right to the point with no mucking around. I don’t think 99% of your readership cares how you code it just so long as you show the how and the why of it being done. From there we take and wrap it into whatever we need to use it in.

    Sort of like learning to program in Lisp. I wouldn’t use it in production code but it is great for teaching certain concepts.

    I’m pretty sure from reading the comments on your blog that most of your readers understand this and just hope you keep writing such good work.

    I could be wrong though and there could be a vocal majority of code police out there that are pestering you to code differently, but if there are please ignore them and keep on doing exactly what you are doing.

  2. William C Bonner says:

    Thank you for posting your information in the base API.  I hadn’t even noticed that, as I learned the API way back when.

    I rarely use the API directly anymore, but I can always translate an API call into MFC, which is what I use predominantly these days, while translating the other direction is sometimes hard.

  3. Steve says:

    It’s unfortunate you are compelled to use your blog time to explain this stuff. I understand why, it’s still unfortunate.

  4. Luciano says:

    It’s a pleasure to read some clean, "bare to the metal" code still coming from Microsoft.

    Good work!

  5. Chris Hanson says:

    Thanks for everything, Raymond. This web site is a breath of reason and sanity in a world of CWhiffyWidget and System.Net.Bibllebabble. I learned Win32 when MFC was still struggling to prove itself and programmers feared it. I may be a masochist, but I’d reather deal directly with the API so I know what really is happening. Lord knows your class library is doing "for" you inside the thin wrapper — sometimes you can go read the source, sometimes you can’t.

    I appreciate the clarity and universal adaptability of your teachings. I’ve recently "done time" trying to get Windows to draw a set of properly sized, positioned and themed minimize-style buttons in the Caption bar. Wow, what an adventure — the few existing examples are all very MFC-centric.

  6. Joe Butler says:

    Please don’t loose the Win32 stuff in favour of the current big thing.

  7. StoneCypher says:

    Well, it’s worth noting that all four of boost’s smart pointers have been adopted into C++ TR1, which most compilers – in MSVS starting with 2k5 – implement.  Granted, it’s a little annoying that Microsoft has deployed them in stdext:: instead of std::, but you can get around the resultant maintenance headache by collapsing the namespace for the smart pointers explicitly (normally a god-awfully badbear thing to do, but hey, it’ll prevent bugs here, so do it.)

    One of the advantages of the approach Boost and now C++ take is that, beyond being portable and near-zero overhead, they give you the option of selecting between behaviors – strong pointers, weak pointers and so on – rather than condemning you to a standard.  Those subtle incompatibilities you mention are the result of other approaches just picking one for you and sticking you to it.  C++ doesn’t dance to that groove.

    There’s a standard behavior now.  You’re wise enough to not use MFC when an API approach would reach a broader audience.  What of using pure C++ approaches?  Here, it’s (only very recently) a clear option.  Basically every major compiler implements at least that part of TR1, given that there’s such an available reference implementation.

    The new smart pointers only want to love you.  Won’t you love them back?

  8. Jim Kueneman says:

    I also thank you as some of us don’t use

    C at all and by not making your examples

    more obscure by forcing us to decode C++,

    ATL, MFC, etc is greatly appreciated.

  9. C Gomez says:

    First part… nice explanation… second part that reads like a disclaimer… duh.

    Unfortunate it comes to explaining everything you say to exhaustion.  I hope you find you don’t have to do that much longer.

    In any case, I appreciate that you teach us how things work down at the barest metal and under the darkest hood.

    It means when I go back to work, I have an understanding of what’s happening deeper that my work surface, and it’s easier to figure out problems.

  10. Igor Delovski says:

    It’s easy to understand why you need to explain your moves. I mean, two months ago you wrote about publishers and their ideas about what kind of books are beeing sold these days. Some of them told you that "nobody buys Win32 books any more."

    Well, today I spend some tima at Amazon and I’ve noticed that your book has reached Sales Rank of 8,632. Is that good? Or is it bad? How bad? So, I compared you to some rather established author: Charles Petzold. He has this book in three versions: api, C# and VB.Net. As much as I know, all of them cover very similar topics with very similar examples in three different languages.

    So, these are the numbers – Amazon Sales Rank:

    #17,960 – Programming Windows, Fifth Edition,

    #94,473 – Programming Windows with C#

    #515,469 – Programming Microsoft Windows with Microsoft Visual Basic .NET

    Then I decided to compare languages and few books by language designers:

    #1,062 – The C Programming Language, by K&R

    #248,286 – The C# Programming Language, by Anders Hejlsberg

    (BTW, sales ranks at Amazon seem to vary almost every minute but not enough to change my point here…)

    Anyone can draw all kinds of conclusions from these numbers, but I can see here that rumors about death of Win32 API development in C have been greatly exaggerated!

  11. Cooney says:

    I’ve noticed that your book has reached Sales Rank of 8,632. Is that good? Or is it bad?

    Is that within a particular category or across the US? Either way, it’s pretty nice – amazon sells a lot of books.

  12. Mihai says:

    I like your code as it is. If I want ATL or MFC I can convert it to that.

    Some of the smart pointers might be standard (and I think stdext:: is the correct namespace for now :-), but why use them?

    You are trying to show how Windows works "in the belly," why things are the way they are.

    I think using just enough code to make the point is the right thing.

  13. I’m going to chime in here and let you know that I really appreciate the Win32 perspective on things as well.  Keep up the awesome work!

  14. Mika Raento says:

    I think it’s also a matter of accepting the Win32 abstraction model.

    Win32 is a class library, especially when it comes to UI code. You derive from the basic window by handling the messages, and adding new custom messages. Window classes let you use the class you have defined as a black box.

    I admit to implementing my own abstraction layers on top of the operating systems ones as often as the next guy. Sometimes it might be ‘objectively’ better, but often I think it is because I’ve never really internalized the operating system’s model.

    Whereas Raymon has internalized the Win32 abstractions and can use them to structure his programs, rather than something else. I assume it’s in no small part due to the fact that they are actually his abstractions, not somebody else’s.

  15. Doug says:

    I PREFER to use the direct API for certain types of code.  That comes from too many experiences with "library changed", "library no longer supported", …

  16. Stu says:

    @Igor Delovski: Of course it could just be that you *need* a book to learn the Win32 API, whereas the newer APIs are easier to learn.

    I’m not saying that’s true or even my opinion, just putting forward another interpretation of your statistics.

  17. Igor says:

    "This web site is a breath of reason and sanity in a world of CWhiffyWidget and System.Net.Bibllebabble."

    Quoted for truth.

    I must admit that I am embarrased because I do not speak latest and greatest developer jargon. I mean, wtf are smart pointers, weak pointers, strong pointers?!?

    If someone takes time to explain, please do it via example which shows their real world usage. Statistics of how often those features are needed would be most welcome too.

  18. Miral says:

    I’m not going to provide in-depth examples, but basically:

    Smart pointers are essentially just a class that holds a single pointer and will delete it in the destructor.  The point being that whenever you allocate some memory on the heap you immediately wrap a smart pointer object around it and then it will automatically be deleted when that object goes out of scope, regardless of whether that was through normal exit or throwing an exception.  Basically just a generic way to use RAII on arbitrary blocks of memory.

    Weak pointers are basically references to another smart pointer, with the property that they will not prevent the smart pointer being destroyed — they simply null out when that happens.  They’re handy for putting into lookup tables & caches etc where you don’t want to extend the lifetime of an object but you still need to avoid accessing an invalid pointer, since something else is controlling the lifetime of the object being pointed to.

    A strong pointer is the opposite of a weak pointer.  Most types of smart pointer are actually strong pointers.  A more useful type of strong pointer is a shared pointer, where multiple smart pointers can refer to the same block of memory, and the memory will only get deleted when the last shared pointer pointing to that block is destroyed.  Handy when the lifecycle of a piece of memory doesn’t match a given method or class, so you can’t scope it more simply.

  19. I think now that various C++ smart pointers are standardized, you should seriously consider using them in your code samples–assuming the sample isn’t about memory management.  Using raw pointers means you’re cluttering sample code with "irrelevant" details.

  20. Craig Ringer says:

    As a primarily *nix developer who also targets Windows as a port platform, your weblog is really useful _because_ it focuses on the low level details and makes the content comprehensible for people not used to all the Windows arcana.

    For me, keeping track of the Windows API typedefs is quite hard enough (*especially* the ones that obscure pointers – those are _nasty_) I’m very glad you’re not also using a class library.

    Personally, I use Qt for almost all my Windows GUI development – because it has a clean API and is cross platform. But I wouldn’t expect you to know it, or write about it – and because your examples are general they’re informative whether the reader uses MFC, Qt, or makes Windows API calls directly in x86 assembler.

    So – personally I like things just like they are.

    I find your articles on platform-wide details like Windows DLLs & dynamic linking incredibly useful, and would personally love to see more in that vein. The discussion of calling conventions used in win32 was also extremely handy.

  21. James says:

    I’m with Sergio on this: an example using plain old malloc/free (or equivalent) will still make sense to someone who uses smart pointers: they just know to use their ‘smart’ counterpart, and that some of the free calls won’t be necessary thanks to that ‘smartness’. The other way round, however, would be harder: if Raymond posted an example which had a free call missing, is it because the memory gets freed by the OS later? Does it get freed by ‘smartness’, so if you’re using regular pointers you need to insert a call of your own? Is it just a mistake? Is it safe to free a buffer after the last reference you see, or does it need to be kept around until some later point the ‘smart’ compiler knows about but we don’t?

    If Raymond keeps this stuff explicit, we can all follow it easily – start relying on some optional external understanding, you’ve added an unnecessary and potentially harmful dependency to the mix.

  22. sergio says:

    I sincerely vote against any smart pointers, boosts and other stuff of the kind. To paraphrase one popular statement:

    ‘If a guy doesn’t know how to program, he has one problem. If he says "I know I’ll use smart pointers" now he has two problems.’

    (Instead of "smart pointers" any hype-of-the-day can be inserted.) Just because something comes in some new standard it doesn’t mean it should be *always* used.

  23. John Hensley says:

    In my experience, using smart wrappers in sample code or documenting them apart from their source code just invites people to misuse them.

    My (least) favorite example is the comment on CComPtrBase::operator&. "The assert usually indicates a bug." What kind of bug? Ha ha, we won’t tell you. So people inevitably use the workaround and leak memory anyway.

  24. bare metal says:

    I like you to use ansic & winapi. Please continue to do so.

  25. Sarath says:

    I fear for how long we will be able to program in Native APIs in Windows because M.S Products gradually becomes .NET oriented.

    Suppose I wanna write a windows gadget, it will be more easier (I don’t the native way) if we use .NET framework and the programming style changing a lot.

    But it’s really nice to know some internals and power of the native code. I’d like you to write sample code using Win32 APIs. For those who knows the basics of MFC, the code is really easy to convert.

  26. James says:

    Sarath: Most Windows programmers have probably never touched the Native API, only the Win32 one layered on top of it. Programming the Native API has always been fairly difficult, thanks to a shortage of documentation and compiler/linker support, although aspects of that have improved in recent years.

  27. f00f says:

    > In fact, I *almost* expect you to do it.

    (emphasis mine)

    Good, because I don’t =)

    Bare Metal: AFAIK any C source file that includes <windows.h> does not compile with pedantic ansi errors turned on.

    (I use win32 in C without a CRT lib)

Comments are closed.

Skip to main content