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.

418 lines
9.8 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. /*++
  3. Copyright (C) Microsoft Corporation, 1997 - 1999
  4. Module Name:
  5. DialogWithWorkerThread.h
  6. Abstract:
  7. Header file for a template class which manages a dialog that will run in the main
  8. context of the MMC thread. This dialog will spawn off a worker thread
  9. that will communicate with the main mmc thread via MMC's window
  10. message pump associated with the dialog.
  11. This is an inline template class and there is no .cpp file.
  12. Author:
  13. Michael A. Maguire 02/28/98
  14. Revision History:
  15. mmaguire 02/28/98 - created
  16. --*/
  17. //////////////////////////////////////////////////////////////////////////////
  18. #if !defined(_IAS_DIALOG_WITH_WORKER_THREAD_H_)
  19. #define _IAS_DIALOG_WITH_WORKER_THREAD_H_
  20. //////////////////////////////////////////////////////////////////////////////
  21. // BEGIN INCLUDES
  22. //
  23. // where we can find what this class derives from:
  24. //
  25. #include "Dialog.h"
  26. //
  27. //
  28. // where we can find what this class has or uses:
  29. //
  30. #include <process.h>
  31. //
  32. // END INCLUDES
  33. //////////////////////////////////////////////////////////////////////////////
  34. typedef
  35. enum _TAG_WORKER_THREAD_STATUS
  36. {
  37. WORKER_THREAD_NEVER_STARTED = 0,
  38. WORKER_THREAD_STARTING,
  39. WORKER_THREAD_STARTED,
  40. WORKER_THREAD_START_FAILED,
  41. WORKER_THREAD_ACTION_INTERRUPTED,
  42. WORKER_THREAD_FINISHED
  43. } WORKER_THREAD_STATUS;
  44. // This should be a safe private window message to pass.
  45. #define WORKER_THREAD_MESSAGE ((WM_USER) + 100)
  46. template <class T>
  47. class CDialogWithWorkerThread : public CDialogImpl<T>
  48. {
  49. public:
  50. // In your derived class, declare the ID of the dialog resource
  51. // you want for this class in the following manner.
  52. // An enum must be used here because the correct value of
  53. // IDD must be initialized before the base class's constructor is called.
  54. // enum { IDD = IDD_CONNECT_TO_MACHINE };
  55. BEGIN_MSG_MAP(CDialogWithWorkerThread<T>)
  56. MESSAGE_HANDLER(WORKER_THREAD_MESSAGE, OnReceiveThreadMessage)
  57. END_MSG_MAP()
  58. /////////////////////////////////////////////////////////////////////////////
  59. /*++
  60. CDialogWithWorkerThread()
  61. Constructor
  62. --*/
  63. //////////////////////////////////////////////////////////////////////////////
  64. CDialogWithWorkerThread()
  65. {
  66. ATLTRACE(_T("# CDialogWithWorkerThread::CDialogWithWorkerThread\n"));
  67. m_wtsWorkerThreadStatus = WORKER_THREAD_NEVER_STARTED ;
  68. m_ulWorkerThread = NULL;
  69. m_lRefCount = 0;
  70. }
  71. /////////////////////////////////////////////////////////////////////////////
  72. /*++
  73. ~CDialogWithWorkerThread( void )
  74. Destructor
  75. --*/
  76. //////////////////////////////////////////////////////////////////////////////
  77. ~CDialogWithWorkerThread( void )
  78. {
  79. ATLTRACE(_T("# CDialogWithWorkerThread::~CDialogWithWorkerThread\n"));
  80. }
  81. //////////////////////////////////////////////////////////////////////////////
  82. /*++
  83. AddRef
  84. COM-style lifetime management.
  85. --*/
  86. //////////////////////////////////////////////////////////////////////////////
  87. LONG AddRef( void )
  88. {
  89. ATLTRACE(_T("# CDialogWithWorkerThread::AddRef\n"));
  90. return InterlockedIncrement( &m_lRefCount );
  91. }
  92. //////////////////////////////////////////////////////////////////////////////
  93. /*++
  94. Release
  95. COM-style lifetime management.
  96. --*/
  97. //////////////////////////////////////////////////////////////////////////////
  98. LONG Release( BOOL bOwner = TRUE )
  99. {
  100. ATLTRACE(_T("# CDialogWithWorkerThread::Release\n"));
  101. LONG lRefCount;
  102. if( bOwner && m_hWnd != NULL )
  103. {
  104. //
  105. // Only the thread which created the window managed by this class
  106. // should call DestroyWindow.
  107. // Release() with bOwner == TRUE means the owning thread is
  108. // calling release.
  109. //
  110. DestroyWindow();
  111. }
  112. lRefCount = InterlockedDecrement( &m_lRefCount );
  113. if( lRefCount == 0)
  114. {
  115. T * pT = static_cast<T*>(this);
  116. delete pT;
  117. return 0;
  118. }
  119. return lRefCount;
  120. }
  121. /////////////////////////////////////////////////////////////////////////////
  122. /*++
  123. CDialogWithWorkerThread::StartWorkerThread
  124. Instructs this class to create and start the worker thread.
  125. You should not need to override this in your derived class.
  126. If the worker thread has already been previously started, this function
  127. will do nothing, and return S_FALSE.
  128. --*/
  129. //////////////////////////////////////////////////////////////////////////////
  130. HRESULT StartWorkerThread( void )
  131. {
  132. ATLTRACE(_T("# CDialogWithWorkerThread::StartWorkerThread\n"));
  133. // Check for preconditions:
  134. // None.
  135. // Make sure the worker thread isn't already trying to do its job.
  136. if( WORKER_THREAD_NEVER_STARTED == m_wtsWorkerThreadStatus
  137. || WORKER_THREAD_START_FAILED == m_wtsWorkerThreadStatus
  138. || WORKER_THREAD_ACTION_INTERRUPTED == m_wtsWorkerThreadStatus
  139. || WORKER_THREAD_FINISHED == m_wtsWorkerThreadStatus
  140. )
  141. {
  142. // We create a new thread.
  143. m_wtsWorkerThreadStatus = WORKER_THREAD_STARTING;
  144. // Don't use CreateThread if you are using the C Run-Time -- use _beginthread instead.
  145. // m_hWorkerThread = CreateThread(
  146. // NULL // pointer to thread security attributes
  147. // , 0 // initial thread stack size, in bytes
  148. // , WorkerThreadFunc // pointer to thread function
  149. // , (LPVOID) this // argument for new thread
  150. // , 0 // creation flags
  151. // , &dwThreadId // pointer to returned thread identifier
  152. // );
  153. m_ulWorkerThread = _beginthread(
  154. WorkerThreadFunc // pointer to thread function
  155. , 0 // stack size
  156. , (void *) this // argument for new thread
  157. );
  158. if( -1 == m_ulWorkerThread )
  159. {
  160. m_wtsWorkerThreadStatus = WORKER_THREAD_START_FAILED;
  161. return E_FAIL; // ISSUE: better return code?
  162. }
  163. return S_OK;
  164. }
  165. else
  166. {
  167. // Worker thread already in progress.
  168. return S_FALSE;
  169. }
  170. }
  171. //////////////////////////////////////////////////////////////////////////////
  172. /*++
  173. GetWorkerThreadStatus
  174. --*/
  175. //////////////////////////////////////////////////////////////////////////////
  176. WORKER_THREAD_STATUS GetWorkerThreadStatus( void )
  177. {
  178. ATLTRACE(_T("# CDialogWithWorkerThread::GetWorkerThreadStatus\n"));
  179. return m_wtsWorkerThreadStatus;
  180. }
  181. protected:
  182. //////////////////////////////////////////////////////////////////////////////
  183. /*++
  184. DoWorkerThreadAction
  185. This is called by the worker thread. Override in your derived class and
  186. perform the actions you want your worker thread to do.
  187. --*/
  188. //////////////////////////////////////////////////////////////////////////////
  189. virtual DWORD DoWorkerThreadAction()
  190. {
  191. ATLTRACE(_T("# CDialogWithWorkerThread::StartWorkerThread -- override in your derived class\n"));
  192. return 0;
  193. }
  194. //////////////////////////////////////////////////////////////////////////////
  195. /*++
  196. PostMessageToMainThread
  197. Use this from your worker thread (i.e. within your DoWorkerThreadAction method)
  198. to pass a message back to the main MMC thread. What you send in wParam and lParam
  199. will be passed to your OnReceiveThreadMessage method.
  200. You should have no need to override this.
  201. --*/
  202. //////////////////////////////////////////////////////////////////////////////
  203. BOOL PostMessageToMainThread( WPARAM wParam, LPARAM lParam )
  204. {
  205. ATLTRACE(_T("# CDialogWithWorkerThread::PostMessageToMainThread\n"));
  206. // Check to make sure that this window still exists.
  207. if( !::IsWindow(m_hWnd) )
  208. {
  209. return FALSE;
  210. }
  211. else
  212. {
  213. return( PostMessage( WORKER_THREAD_MESSAGE, wParam, lParam) );
  214. }
  215. }
  216. /////////////////////////////////////////////////////////////////////////////
  217. /*++
  218. CDialogWithWorkerThread::OnReceiveThreadMessage
  219. This is the sink for messages sent to the main thread from the worker thread.
  220. Since messages are received here through the Windows message pump, your
  221. worker thread can pass messages that will be received and processed within
  222. the main MMC context. So do anything you need to do with MMC interface pointers
  223. here.
  224. Override in your derived class and process any messages your worker thread might send.
  225. --*/
  226. //////////////////////////////////////////////////////////////////////////////
  227. virtual LRESULT OnReceiveThreadMessage(
  228. UINT uMsg
  229. , WPARAM wParam
  230. , LPARAM lParam
  231. , BOOL& bHandled
  232. )
  233. {
  234. ATLTRACE(_T("# CDialogWithWorkerThread::OnReceiveThreadMessage\n"));
  235. return 0;
  236. }
  237. WORKER_THREAD_STATUS m_wtsWorkerThreadStatus;
  238. private:
  239. //////////////////////////////////////////////////////////////////////////////
  240. /*++
  241. WorkerThreadFunc
  242. You should not need to override this function. It is passed to the
  243. thread creation API call as the thread start procedure in StartWorkerThread.
  244. It is passed a pointer to 'this' of this class, which it casts and calls
  245. DoWorkerThreadAction on. Override DoWorkerThreadAction in your derived class.
  246. --*/
  247. //////////////////////////////////////////////////////////////////////////////
  248. // Use of _beginthread instead of CreateThread requires different declaration.
  249. // static DWORD WINAPI WorkerThreadFunc( LPVOID lpvThreadParm )
  250. static void _cdecl WorkerThreadFunc( LPVOID lpvThreadParm )
  251. {
  252. ATLTRACE(_T("# WorkerThreadFunc -- no need to override.\n"));
  253. // Check for preconditions:
  254. _ASSERTE( lpvThreadParm != NULL );
  255. DWORD dwReturnValue;
  256. // The lpvThreadParm we were passed will be a pointer to 'this' for T.
  257. T * pT = static_cast<T*>(lpvThreadParm);
  258. pT->AddRef();
  259. dwReturnValue = pT->DoWorkerThreadAction();
  260. // Call Release with bOwner = FALSE -- we are not the owning thread.
  261. pT->Release(FALSE);
  262. // This is bad -- we don't want to clobber whatever value the DoWorkerThreadAction
  263. // assigned to m_wtsWorkerThreadStatus -- it is reponsible for saying whether the
  264. // task was finished properly.
  265. // pT->m_wtsWorkerThreadStatus = WORKER_THREAD_FINISHED;
  266. // Use of _beginthread instead of CreateThread requires different declaration.
  267. // return dwReturnValue;
  268. }
  269. unsigned long m_ulWorkerThread;
  270. LONG m_lRefCount;
  271. };
  272. #endif // _IAS_DIALOG_WITH_WORKER_THREAD_H_