Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

345 lines
9.0 KiB

  1. #ifndef __BKTHREAD_H_INCLUDED
  2. #define __BKTHREAD_H_INCLUDED
  3. #include "tspqueue.h"
  4. #include "modlock.h"
  5. // Base class for all messages
  6. class CThreadMessage
  7. {
  8. private:
  9. int m_nMessage;
  10. private:
  11. //
  12. // No implementation
  13. //
  14. CThreadMessage(void);
  15. CThreadMessage( const CThreadMessage & );
  16. CThreadMessage &operator=( const CThreadMessage & );
  17. public:
  18. CThreadMessage( int nMessage )
  19. : m_nMessage(nMessage)
  20. {
  21. }
  22. virtual ~CThreadMessage(void)
  23. {
  24. }
  25. int Message(void) const
  26. {
  27. return(m_nMessage);
  28. }
  29. int Message( int nMessage )
  30. {
  31. return(m_nMessage = nMessage);
  32. }
  33. };
  34. typedef CThreadSafePriorityQueue<CThreadMessage> CThreadMessageQueue;
  35. class CNotifyThreadMessage : public CThreadMessage
  36. {
  37. private:
  38. //
  39. // No implementation
  40. //
  41. CNotifyThreadMessage(void);
  42. CNotifyThreadMessage( const CNotifyThreadMessage & );
  43. CNotifyThreadMessage &operator=( const CNotifyThreadMessage & );
  44. private:
  45. HWND m_hWndNotify;
  46. public:
  47. CNotifyThreadMessage( int nMessage, HWND hWndNotify )
  48. : CThreadMessage(nMessage),
  49. m_hWndNotify(hWndNotify)
  50. {
  51. }
  52. virtual ~CNotifyThreadMessage(void)
  53. {
  54. m_hWndNotify = NULL;
  55. }
  56. HWND NotifyWindow(void) const
  57. {
  58. return(m_hWndNotify);
  59. }
  60. };
  61. typedef BOOL (WINAPI *ThreadMessageHandler)( CThreadMessage *pMsg );
  62. struct CThreadMessageMap
  63. {
  64. int nMessage;
  65. ThreadMessageHandler pfnHandler;
  66. };
  67. class CBackgroundThread
  68. {
  69. private:
  70. HANDLE m_hThread;
  71. DWORD m_dwThreadId;
  72. CThreadMessageQueue *m_pMessageQueue;
  73. CThreadMessageMap *m_pThreadMessageMap;
  74. CSimpleEvent m_CancelEvent;
  75. HINSTANCE m_hInstanceUnlock;
  76. private:
  77. //
  78. // No implementation
  79. //
  80. CBackgroundThread(void);
  81. CBackgroundThread &operator=( const CBackgroundThread & );
  82. CBackgroundThread( const CBackgroundThread & );
  83. private:
  84. //
  85. // Private constructor. This is the only constructor. It is only called from Create.
  86. //
  87. CBackgroundThread( CThreadMessageQueue *pMessageQueue, CThreadMessageMap *pThreadMessageMap, HANDLE hCancelEvent )
  88. : m_pMessageQueue(pMessageQueue),
  89. m_pThreadMessageMap(pThreadMessageMap),
  90. m_CancelEvent(hCancelEvent),
  91. m_hInstanceUnlock(NULL)
  92. {
  93. }
  94. bool HandleMessage( CThreadMessage *pMsg )
  95. {
  96. for (int i=0;pMsg && m_pThreadMessageMap && m_pThreadMessageMap[i].nMessage;i++)
  97. {
  98. if (m_pThreadMessageMap[i].nMessage == pMsg->Message())
  99. {
  100. //
  101. // reset the cancel event
  102. //
  103. m_CancelEvent.Reset();
  104. return (m_pThreadMessageMap[i].pfnHandler(pMsg) != FALSE);
  105. }
  106. }
  107. return(true);
  108. }
  109. HRESULT Run()
  110. {
  111. //
  112. // Make sure we got a good message queue
  113. //
  114. if (!m_pMessageQueue)
  115. {
  116. return E_POINTER;
  117. }
  118. //
  119. // Make sure the event handle is good
  120. //
  121. if (!m_pMessageQueue->QueueEvent())
  122. {
  123. return E_INVALIDARG;
  124. }
  125. //
  126. // Make sure we have a message queue
  127. //
  128. PostThreadMessage( GetCurrentThreadId(), WM_NULL, 0, 0 );
  129. //
  130. // Initialize COM on this thread. As a single threaded apartment.
  131. //
  132. HRESULT hr = CoInitialize(NULL);
  133. if (SUCCEEDED(hr))
  134. {
  135. //
  136. // We will loop until we get a WM_QUIT message
  137. //
  138. while (true)
  139. {
  140. //
  141. // Wait for a message to be place in the priority queue, or a message to be placed in the thread's queue
  142. //
  143. HANDLE Handles[1] = {m_pMessageQueue->QueueEvent()};
  144. DWORD dwRes = MsgWaitForMultipleObjects(1,Handles,FALSE,INFINITE,QS_ALLINPUT|QS_ALLPOSTMESSAGE);
  145. //
  146. // If the event is signalled, there is a message in the queue
  147. //
  148. if (WAIT_OBJECT_0==dwRes)
  149. {
  150. //
  151. // Pull the message out of the queue
  152. //
  153. CThreadMessage *pMsg = m_pMessageQueue->Dequeue();
  154. if (pMsg)
  155. {
  156. //
  157. // Call the message handler.
  158. //
  159. BOOL bResult = HandleMessage(pMsg);
  160. //
  161. // Delete the message
  162. //
  163. delete pMsg;
  164. //
  165. // If the handler returns false, exit the thread.
  166. //
  167. if (!bResult)
  168. {
  169. break;
  170. }
  171. }
  172. }
  173. else if (WAIT_OBJECT_0+1==dwRes)
  174. {
  175. //
  176. // pull all of the messages out of the queue and process them
  177. //
  178. MSG msg;
  179. while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
  180. {
  181. //
  182. // Break out of the loop
  183. //
  184. if (msg.message == WM_QUIT)
  185. {
  186. break;
  187. }
  188. TranslateMessage(&msg);
  189. DispatchMessage(&msg);
  190. }
  191. }
  192. }
  193. //
  194. // Shut down COM
  195. //
  196. CoUninitialize();
  197. }
  198. return(hr);
  199. }
  200. static DWORD ThreadProc(PVOID pData)
  201. {
  202. HRESULT hr = E_FAIL;
  203. HINSTANCE hInstUnlock = NULL;
  204. CBackgroundThread *pThread = (CBackgroundThread *)pData;
  205. if (pData)
  206. {
  207. hr = pThread->Run();
  208. hInstUnlock = pThread->m_hInstanceUnlock;
  209. delete pThread;
  210. }
  211. if (hInstUnlock)
  212. {
  213. FreeLibraryAndExitThread( hInstUnlock, static_cast<DWORD>(hr) );
  214. }
  215. else
  216. {
  217. ExitThread( static_cast<DWORD>(hr) );
  218. }
  219. }
  220. public:
  221. ~CBackgroundThread(void)
  222. {
  223. //
  224. // Delete the thread handle
  225. //
  226. if (m_hThread)
  227. {
  228. CloseHandle(m_hThread);
  229. m_hThread = 0;
  230. }
  231. //
  232. // Nuke the message queue
  233. //
  234. delete m_pMessageQueue;
  235. }
  236. static HANDLE Create( CThreadMessageQueue *pMessageQueue, CThreadMessageMap *pThreadMessageMap, HANDLE hCancelEvent, HINSTANCE hInstLock )
  237. {
  238. //
  239. // Make sure we have valid arguments
  240. //
  241. if (!pMessageQueue || !pThreadMessageMap)
  242. {
  243. WIA_ERROR((TEXT("!pMessageQueue || !pThreadMessageMap")));
  244. return NULL;
  245. }
  246. //
  247. // The duplicated handle we will be returning
  248. //
  249. HANDLE hReturnHandle = NULL;
  250. //
  251. // Create the thread class
  252. //
  253. CBackgroundThread *pThread = new CBackgroundThread( pMessageQueue, pThreadMessageMap, hCancelEvent );
  254. if (pThread)
  255. {
  256. //
  257. // Lock up before we create the thread
  258. //
  259. HINSTANCE hInstanceUnlock = NULL;
  260. if (hInstLock)
  261. {
  262. //
  263. // Get the module name
  264. //
  265. TCHAR szModule[MAX_PATH];
  266. if (GetModuleFileName( hInstLock, szModule, ARRAYSIZE(szModule)))
  267. {
  268. //
  269. // Increment the reference count
  270. //
  271. pThread->m_hInstanceUnlock = LoadLibrary( szModule );
  272. }
  273. }
  274. pThread->m_hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, pThread, 0, &pThread->m_dwThreadId );
  275. if (pThread->m_hThread)
  276. {
  277. //
  278. // Copy the handle to return to the caller
  279. //
  280. DuplicateHandle( GetCurrentProcess(), pThread->m_hThread, GetCurrentProcess(), &hReturnHandle, 0, FALSE, DUPLICATE_SAME_ACCESS );
  281. }
  282. else
  283. {
  284. //
  285. // Unlock the module
  286. //
  287. if (pThread->m_hInstanceUnlock)
  288. {
  289. FreeLibrary( hInstanceUnlock );
  290. hInstanceUnlock;
  291. }
  292. //
  293. // Since we can't start the thread, we have to delete the thread info to prevent a leak
  294. //
  295. delete pThread;
  296. WIA_ERROR((TEXT("CreateThread failed")));
  297. }
  298. }
  299. else
  300. {
  301. //
  302. // Since the background thread isn't going to free it, we have to.
  303. //
  304. delete pMessageQueue;
  305. WIA_ERROR((TEXT("new CBackgroundThread failed")));
  306. }
  307. return hReturnHandle;
  308. }
  309. };
  310. #endif //__BKTHREAD_H_INCLUDED