CFugue
COMInitializer.h
1 #ifndef _COMINITIALIZER_H_8B5ACB47_D183_469b_AE67_B8785F9177EF
2 #define _COMINITIALIZER_H_8B5ACB47_D183_469b_AE67_B8785F9177EF
3 
4 #include "ErrorReporter.h"
5 
6 #ifndef _WIN32_DCOM
7 #define _WIN32_DCOM // Required for CoInitializeEx()
8 #endif
9 
10 #include <ObjBase.h>
11 #include <Map>
12 
13 //
14 // use #define COM_THREADING_MODEL COINIT_MULTITHREADED before
15 // including this header file to change the COM Threading model
16 //
17 #ifndef COM_THREADING_MODEL
18 #define COM_THREADING_MODEL COINIT_APARTMENTTHREADED
19 #endif
20 
21 //
22 // To Use Automatic COM Initialization facility for any class, just
23 // make it a derived class of CCOMInitializer class;
24 //
25 // The CCOMInitializer is a typedefed class that automatically assumes
26 // a multithreaded com initialization or single threaded com initialization
27 // based on the presence/absence of preprocessor directive MULTITHREADED
28 // (This is different from THREAD_APARTMENT_MODEL)
29 
30 // IMPORTANT:
31 // If a COM based class is used across multiple threads, then use
32 // #define MULTITHREADED
33 // before including this header file; That would guarantee that COM
34 // is initialized properly once per each thread; However that would
35 // come at the cost of checking the ThreadID and COM initialization
36 // state per each object created !!
37 //
38 // Applications that use COM based classes only in a single thread can
39 // avoid that cost by not using the #define MULTITHREADED; (This is the
40 // default setting, just include the header and everything is fine);
41 //
42 // Note that an application might have many threads, out of which only
43 // single thread might be requiring COM access; In that case it should be
44 // treated as a single threaded COM app only; It is not the total thread count
45 // that matters - it is the number of threads that actually use the
46 // COM based classes that matters;
47 //
48 //
49 // More than One class can use this facility; That is, more than one class can
50 // have the CCOMInitializer as its base class - and CCOMInitializer guarantes that
51 // COM initialization is not duplicated unnecessarily;
52 //
53 // However, it should be noted that when more than one class are derived from
54 // CCOMInitializer and if all of them are from single thread, then it should be treated
55 // as single thread app; But, when more than one class are derived from CCOMInitializer
56 // and each class is from different thread, then it should be treated as MULTITHREADED (even
57 // though the class itself is confined to (used in) a single thread) and #define MULTITHREADED
58 // should be used before including this header file;
59 //
60 // The Single threaded and Multithreaded should be calculated based on the clients of
61 // CCOMInitializer; and not based on the application threading model or the individual classes;
62 //
63 // To Specifty the Application Threading Model for the CoInitialize() modify the settings in the
64 // below code (perhaps by using CoInitializeEx() instead of the present CoInitialize());
65 //
66 
67 //
68 // CMultiThreadCOMInitializer: Guaranteed Call for CoInitialize(), CoUninitialize() Once Per Thread;
69 // To Make Sure COM is initialized before any class is used, make it a derived class of CCOMInitializer;
70 //
71 // Every time an instance is created for a CCOMInitializer derived object, the thread id is checked and
72 // COM is initialized for that thread, if not already done; A std::map is used to keep track of
73 // <ThreadID, InitializationState> pair;
74 //
75 // All CoUninitialize() calls (One for each CoInitialize()) are done at the time of application exit;
76 //
78 {
79  //
80  // Initializer: Takes care of parining a CoUninitialize() for each successful CoInitialize();
81  //
82  class Initializer
83  {
84  Initializer& operator=(const Initializer&);
85  public:
86  enum INIT_STATE {NOTYET = -1, INITFAILED = 0, INITSUCCEEDED = 1};
87 
88  INIT_STATE m_nInitState;
89 
90  inline Initializer(const Initializer& other)
91  {
92  m_nInitState = NOTYET;
93  }
94 
95  inline Initializer()
96  {
97  m_nInitState = NOTYET;
98  }
99  inline void InitializeCOM(DWORD dwThreadID)
100  {
101  HRESULT hr;
102  if(INITFAILED == (m_nInitState = SUCCEEDED(hr = CoInitializeEx(NULL, COM_THREADING_MODEL)) ? INITSUCCEEDED : INITFAILED))
103  {
104  if(hr == E_OUTOFMEMORY)
105  Err::ErrorMessage(_T("Out of Memory Error Occured While Initializing COM !!"));
106  else
107  Err::ErrorMessage(_T("Unable to Initialize COM !!"));
108  }
109  }
110  inline ~Initializer()
111  {
112  if(m_nInitState == INITSUCCEEDED)
113  {
114  CoUninitialize();
115  m_nInitState = NOTYET;
116  }
117  }
118  inline INIT_STATE InitState() const { return m_nInitState; }
119  };
120 
121 protected:
122 
123  CMultiThreadCOMInitializer(void) // The Constructor is Protected; So Objects cannot directly be created;
124  {
125  typedef std::map<DWORD, Initializer> INITOBJECTMAP;
126 
127  static INITOBJECTMAP m_InitObjectMap; // Static guarantess that Only One Map is created for the whole app;
128 
129  DWORD dwCurrentThreadID = GetCurrentThreadId();
130 
131  Initializer& Init = m_InitObjectMap[dwCurrentThreadID]; // Automatically creates a new object if not already exists;
132 
133  if(Init.InitState() == Initializer::NOTYET) // If COM has not been initialized for this thread, do it now;
134  Init.InitializeCOM(dwCurrentThreadID);
135  }
136 
137  virtual ~CMultiThreadCOMInitializer(void)
138  {
139  }
140 };
141 
142 //
143 // CSingleThreadCOMInitializer: Guaranteed Call for CoInitialize(), CoUninitialize() Once Per Application;
144 // To Make Sure COM is initialized before any class is used, make it a derived class of CCOMInitializer;
145 //
146 // COM is initialized automatically when the first time an object is created for any CCOMInitializer
147 // derived class; Since this is single threading, any class object (irrespective of who triggered the COM)
148 // can use the COM facilities once COM is initialized;
149 //
150 // The CoUninitialize() is called automatically when the application is about to exit;
151 //
153 {
154  class Initializer
155  {
156  bool m_bInitialized;
157  public:
158  Initializer()
159  {
160  HRESULT hr;
161 
162  m_bInitialized = SUCCEEDED(hr = CoInitializeEx(NULL, COM_THREADING_MODEL));
163 
164  if(m_bInitialized == false)
165  {
166  if(hr == E_OUTOFMEMORY)
167  Err::ErrorMessage(_T("Out of Memory Error Occured While Initializing COM !!"));
168  else
169  Err::ErrorMessage(_T("Unable to Initialize COM !!"));
170  }
171  }
172  ~Initializer()
173  {
174  if(m_bInitialized)
175  {
176  CoUninitialize();
177  m_bInitialized = false;
178  }
179  }
180  };
181 protected:
183  {
184  static Initializer Init;
185  }
186  virtual ~CSingleThreadCOMInitializer(){}
187 };
188 
189 
190 #ifdef MULTITHREADED
192 #else
194 #endif
195 
196 #endif

CFugue, the C++ Music Programming Library © Copyright 2009 Cenacle Research India Private Limited Gopalakrishna Palem