[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”) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
#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 |