WTL initialization, Com and C++ namespaces

[May 11th, 2006]

Recently I was thinking what should be my first code contribution to the WTL project? And here it is a seemingly simple COM initialization mechanism.

Why “seemingly simple”? Because it is done with the healthy dose of using the C++ anonymous namespace, in order to make it (completely) transparent, but still a (very) effective solution.

I do particularly like these ‘invisible’ C++ constructs actually doing a useful job.  Enough of theory, here is the practice (aka “the code”) :

#pragma once
/*
Copyright 2020 - 2021 dbj@dbj.org
Copyright 2006 - 2018 dbj@dbj.org
*/

/* set to 1 if using com */
// #define DBJCOM 1
#if DBJCOM 

#include <combaseapi.h>

namespace dbj {

namespace win {
namespace com {
namespace {
/*
In anonymous namespace we hide the auto-initializer
This ensures that COM is initialized “as soon as possible”
This mechanism really works. Convince yourself once through the
debugger, and then just forget about COM init/uninit.
*/
struct __declspec(novtable)
  COMAUTOINIT
  {
  unsigned int & counter()
  {
  static unsigned int counter_ = 0;
  return counter_;
  }
/*
If you call ::CoInitialize(NULL), after this method is used
most likely the HRESULT will be :
hRes = 0×80010106 — Cannot change thread mode after it is set.
*/
  COMAUTOINIT()
  {
  const UINT & ctr = (counter())++;
  if (0 == ctr)
#if ( defined(_WIN32_DCOM)  || defined(_ATL_FREE_THREADED))
  HRESULT result = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
#else
  HRESULT result = ::CoInitialize(NULL);
#endif
  /*
   check the HRESULT and log the result here
    if ( S_OK == result )
       syslog_proxy("com init ok");
    else
       syslog_proxy("com init failed");   
  */
  }

  ~COMAUTOINIT()
  {
  const UINT ctr = --(counter());
  if (ctr < 1)
  ::CoUninitialize();
  }

  };
  // c++17 inline var
  inline const COMAUTOINIT wtlcomautoinit__{};
} // anonspace
} // com
} // win
} // dbj
#endif // DBJCOM