README.TXT
上传用户:hxb_1234
上传日期:2010-03-30
资源大小:8328k
文件大小:11k
源码类别:

VC书籍

开发平台:

Visual C++

  1. This is a part of the Microsoft Foundation Classes C++ library.
  2. Copyright (C) 1994-1998 Microsoft Corporation
  3. All rights reserved.
  4. This source code is only intended as a supplement to the
  5. Microsoft Foundation Classes Reference and related
  6. electronic documentation provided with the library.
  7. See these sources for detailed information regarding the
  8. Microsoft Foundation Classes product.
  9. -------------------------------------------------------
  10. MTMDI Sample Microsoft Foundation Classes Application
  11. -------------------------------------------------------
  12. The MTMDI sample illustrates an MFC user-interface thread, where user
  13. interface events are processed in a thread separate from the main
  14. application thread.  This sample is a modified version of the single
  15. thread MDI sample.
  16. The MTMDI sample does not claim a strong rationale for putting the
  17. bouncing ball window in a separate thread.  An end-user would not be
  18. able to detect the difference between the MDI and MTMDI samples on a
  19. single processor machine.  Even on a multi-processor machine, the
  20. end-user would not be able to detect the difference given that the
  21. ball movement is based on a window timer.
  22. Further, the MTMDI sample does not claim a strong rationale for using
  23. an MFC worker thread instead of an MFC user-interface thread.  MFC worker
  24. threads generally are easier to use and more appropriate than user-interface
  25. threads for tasks that do not involve processing of user interface events.
  26. The drawing of the bouncing ball could have been implemented in
  27. a worker thread instead of a user-interface thread, if some technique
  28. other than window timers were used to advance the ball.  The use of the
  29. window timer in a separate thread requires a message pump; therefore
  30. the separate thread must be a user-interface thread instead of a worker
  31. thread.  To add slightly more justification for using a user-interface
  32. thread, the MTMDI sample includes one additional user-interface feature
  33. not in the MDI sample:  you can click anywhere in the bounce window to
  34. immediately change the position of the moving ball.
  35. Although the MDI sample does not claim a strong rationale for using
  36. threads, it nevertheless does illustrate techniques for implementing an
  37. MFC user-interface thread.  The remainder of this readme describes
  38. the differences between the implementation of the single thread MDI
  39. application and the multiple thread MTMDI application.  These differences
  40. illustrate that it is more difficult to implement an application with
  41. a user-interface thread than a corresponding application that executes
  42. in a single thread.  This should be a warning that you should not use
  43. user-interface threads unless you have good reasons.
  44. The overall differences between the implementation of the MDI and MTMDI
  45. samples are these:
  46. 1.  The CBounceWnd window runs in a separate user-interface thread
  47. in the MTMDI application.
  48. 2.  In the MDI sample, CBounceWnd is derived from CMDIChildWnd.  In the
  49. MTMDI sample, CBounceWnd is derived from CWnd, and a CBounceWnd
  50. window is a child of the MDI child window.  In the MTMDI sample,
  51. the CBounceWnd child window fills exactly the client area of the
  52. parent MDI child window (a CMDIChildBounceWnd).
  53. 3.  In the MDI sample, normal MFC command routing and command user-
  54. interface initialization are used for menu commands associated with
  55. the bounce window.  In the MTMDI sample, the MDI child window's
  56. OnCmdMsg function is overridden in order to send the OnCmdMsg
  57. parameters via SendMessage to the CBounceWnd executing in the
  58. separate thread.  In general, SendMessage typically needs to be
  59. used us to make calls from a window in one thread to a window in
  60. another thread in an MFC application.
  61. Note:  The Hello window is left in the main application thread.
  62.    Implementing the Bounce window in a separate thread is sufficient
  63.    to illustrate the MFC multithread techniques.
  64. This MTMDI sample does not directly illustrate a view running in a separate
  65. thread, because MTMDI and the original MDI sample do not use MFC's
  66. document/view architecture.  Still, the design of MTMDI can be applied
  67. to an application where you might want the view to run in a separate thread.
  68. In general, you cannot successfully implement member functions of a CView
  69. to run in a separate thread, because the MFC document/view architecture
  70. relies on thread local storage (TLC) for some of the data that coordinates
  71. documents and views.  However, you can apply the design of MTMDI by
  72. implementing a child window of the CView window, and processing user-
  73. interface events of this child window in a separate thread.
  74. The design of MTMDI is summarized below.  For additional details, see
  75. source code comments.
  76. =================
  77. CWinThread object
  78. =================
  79. The thread object for the bouncing ball window is implemented in
  80. a CWinThread-derived class, CBounceThread, in mtbounce.cpp.
  81. Beginning the user-interface thread
  82. -----------------------------------
  83. The overridden CMDIChildBounceWnd::OnCreate begins the thread for
  84. the bouncing ball.   There are two ways to begin an MFC user-interface
  85. thread:  (1) call AfxBeginThread, passing the CRuntimeClass of the
  86. CWinThread-derived class; or (2) implement two-stage construction of
  87. the CWinThread-derived object by new'ing it and then calling
  88. CWinThread::CreateThread.  We use the second method because it offers
  89. the easiest way to pass the HWND of the CMainFrame window to the
  90. thread, which needs the parent HWND to create the child window.
  91. We simply pass the HWND to the CBounceThread constructor.
  92. An alternative method is:
  93. - call AfxBeginThread with a CREATE_SUSPENDED parameter;
  94. - pass the parent HWND via a new CBounceThread::SetParentWnd function;
  95.   or make the CBounceThread::m_hwndParent member variable public and
  96.   set it directly; and then
  97. - call CWinThread::ResumeThread.
  98. Thread instance initialization
  99. ------------------------------
  100. CWinThread::InitInstance is the only member function that must be
  101. overridden for a user-interface thread.  The implementation of
  102. CBounceThread::InitInstance is typical in that it creates (using
  103. CWnd::Create) the window that processes messages in the separate thread.
  104. Terminating the user-interface thread
  105. -------------------------------------
  106. The easiest way to terminate a user-interface thread is to rely on
  107. automatic termination of the thread when the main window associated with
  108. the thread is destroyed.  The only thing you need to do to implement
  109. such automatic thread termination is to set the CWinThread::m_pMainWnd
  110. to the main window.  This is illustrated in CBounceThread::InitInstance.
  111. The default CWnd::OnNcDestroy handler checks whether the window being
  112. destroyed is the thread's m_pMainWnd and, if so, terminates the thread,
  113. provided it isn't the main application thread.
  114. Unless you change the default TRUE value of CWinThread::m_bAutoDelete,
  115. the framework will automatically delete the CWinThread object when the
  116. thread terminates.
  117. Avoiding memory leak detection of CWinThread object
  118. ---------------------------------------------------
  119. When the application terminates, it destroys each window in the window
  120. hierarchy, and then, in debug mode, checks for memory leaks.
  121. It is possible that the application will falsely detect a memory leak of the
  122. CWinThread object before the user-interface thread has had a chance to
  123. automatically terminate.  The reported memory leak is false because
  124. eventually the CWinThread object will be automatically destroyed anyway.
  125. Nevertheless, the dumping of memory leak information can be disconcerting.
  126. To avoid this, we use a "bounce thread killed" event.  The CBounceThread
  127. delete operator sets the event.  The main application waits for this event
  128. before terminating.  It is better to set the event in the delete operator
  129. rather than in the CBounceThread destructor, because it is remotely possible
  130. that the application might terminate (and report a memory leak) between
  131. the time the CBounceThread destructor completes and the time that the
  132. CBounceThread object is actually deleted.
  133. ================
  134. MDI child window
  135. ================
  136. In the original MDI sample, the CBounceWnd was a CMDIChildWnd.  It
  137. handled the Color and Speed menu commands.  In the MTMDI sample, the
  138. CBounceWnd is a CWnd; and the CBounceWnd window is a child of the
  139. MDI child window.  There still needs to be a CMDIChildWnd class.
  140. It is named CMDIChildBounceWnd, and is implemented in bounce.cpp,
  141. where CBounceWnd is also implemented.
  142. Creation of the MDI child window
  143. --------------------------------
  144. As in the original MDI sample, the CMainFrame::OnBounce handler
  145. creates the CMDIChildWnd when the user requests a new bouncing ball
  146. window.  The implementation of CMDIChildBounceWnd::Create borrows
  147. half of the implementation of the original MDI sample's
  148. CBounceWnd::Create.  The half borrowed is the implementation of the
  149. shared menu.  The other half, the window class registration, is
  150. left in the implementation of CBounceWnd::Create.
  151. The overridden CMDIChildBounce::Create also creates the bounce thread.
  152. Delegation of commands and command user-interface initialization
  153. ----------------------------------------------------------------
  154. CMDIChildWnd delegates commands and command user-interface initialization
  155. to the child CBounceWnd.  One laborious way to do this is delegate each
  156. command on a per command basis.  An easier but more sophisticated way to
  157. do this is to override OnCmdMsg and pass the OnCmdMsg parameters to the
  158. CBounceWnd in a structure via SendMessage.  For more details, see source
  159. code comments for CMDIChildBounceWnd::OnCmdMsg.
  160. ============================
  161. User-interface thread window
  162. ============================
  163. The bouncing ball window is implemented in a CWnd-derived class,
  164. CBounceWnd, in bounce.cpp.  It reuses almost all of the CBounceWnd code
  165. in the original MDI sample, where the CBounceWnd was a CMDIChildWnd instead
  166. of a plain CWnd.
  167. Creation of the bouncing ball window
  168. ------------------------------------
  169. CBounceThread::InitInstance calls the CBounceWnd-override of CWnd::Create
  170. to create the window.  The implementation of CBounceWnd::Create is borrowed
  171. from the original MDI sample's implementation, less the shared menu
  172. initialization code that is now in CMDIChildBounceWnd::Create.
  173. Command handling and command user-interface initialization
  174. ----------------------------------------------------------
  175. All commands and command user-interface initialization is delegated by
  176. the CMDIChildBounceWnd object to the CBounceWnd object.
  177. CMDIChildBounceWnd::OnCmdMsg sends a user-defined WM_USER_ONCMDMSG message
  178. to the CBounceWnd window.  This message contains all of the information
  179. originally passed to CMDIChildBounceWnd::OnCmdMsg.
  180. The CBounceWnd handler for WM_USER_ONCMDMSG, named OnDelegatedCmdMsg,
  181. unpacks the COnCmdMsg struct passed via the lParam, and calls the default
  182. CWnd::OnCmdMsg for the CBounceWnd object.