home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / thrdcore.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-16  |  23.7 KB  |  896 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12. #include <process.h>    // for _beginthreadex and _endthreadex
  13. #include <ddeml.h>  // for MSGF_DDEMGR
  14.  
  15. #ifdef AFX_CORE1_SEG
  16. #pragma code_seg(AFX_CORE1_SEG)
  17. #endif
  18.  
  19. #ifdef _DEBUG
  20. #undef THIS_FILE
  21. static char THIS_FILE[] = __FILE__;
  22. #endif
  23.  
  24. /////////////////////////////////////////////////////////////////////////////
  25. // Thread entry point
  26.  
  27. #ifdef _MT
  28.  
  29. struct _AFX_THREAD_STARTUP
  30. {
  31.     // following are "in" parameters to thread startup
  32.     _AFX_THREAD_STATE* pThreadState;    // thread state of parent thread
  33.     CWinThread* pThread;    // CWinThread for new thread
  34.     DWORD dwCreateFlags;    // thread creation flags
  35.     _PNH pfnNewHandler;     // new handler for new thread
  36.  
  37.     HANDLE hEvent;          // event triggered after success/non-success
  38.     HANDLE hEvent2;         // event triggered after thread is resumed
  39.  
  40.     // strictly "out" -- set after hEvent is triggered
  41.     BOOL bError;    // TRUE if error during startup
  42. };
  43.  
  44. UINT APIENTRY _AfxThreadEntry(void* pParam)
  45. {
  46.     _AFX_THREAD_STARTUP* pStartup = (_AFX_THREAD_STARTUP*)pParam;
  47.     ASSERT(pStartup != NULL);
  48.     ASSERT(pStartup->pThreadState != NULL);
  49.     ASSERT(pStartup->pThread != NULL);
  50.     ASSERT(pStartup->hEvent != NULL);
  51.     ASSERT(!pStartup->bError);
  52.  
  53.     CWinThread* pThread = pStartup->pThread;
  54.     CWnd threadWnd;
  55.     TRY
  56.     {
  57.         // inherit parent's module state
  58.         _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
  59.         pThreadState->m_pModuleState = pStartup->pThreadState->m_pModuleState;
  60.  
  61.         // set current thread pointer for AfxGetThread
  62.         AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
  63. #ifdef _AFXDLL
  64.         pThread->m_pModuleState = pModuleState;
  65. #endif
  66.         AFX_MODULE_THREAD_STATE* pState = pModuleState->m_thread;
  67.         pState->m_pCurrentWinThread = pThread;
  68.  
  69.         // forced initialization of the thread
  70.         AfxInitThread();
  71.  
  72.         // thread inherits app's main window if not already set
  73.         CWinApp* pApp = AfxGetApp();
  74.         if (pApp != NULL &&
  75.             pThread->m_pMainWnd == NULL && pApp->m_pMainWnd->GetSafeHwnd() != NULL)
  76.         {
  77.             // just attach the HWND
  78.             threadWnd.Attach(pApp->m_pMainWnd->m_hWnd);
  79.             pThread->m_pMainWnd = &threadWnd;
  80.         }
  81.     }
  82.     CATCH_ALL(e)
  83.     {
  84.         // Note: DELETE_EXCEPTION(e) not required.
  85.  
  86.         // exception happened during thread initialization!!
  87.         TRACE0("Warning: Error during thread initialization!\n");
  88.  
  89.         // set error flag and allow the creating thread to notice the error
  90.         threadWnd.Detach();
  91.         pStartup->bError = TRUE;
  92.         VERIFY(::SetEvent(pStartup->hEvent));
  93.         AfxEndThread((UINT)-1, FALSE);
  94.         ASSERT(FALSE);  // unreachable
  95.     }
  96.     END_CATCH_ALL
  97.  
  98.     // pStartup is invaid after the following SetEvent (but hEvent2 is valid)
  99.     HANDLE hEvent2 = pStartup->hEvent2;
  100.  
  101.     // allow the creating thread to return from CWinThread::CreateThread
  102.     VERIFY(::SetEvent(pStartup->hEvent));
  103.  
  104.     // wait for thread to be resumed
  105.     VERIFY(::WaitForSingleObject(hEvent2, INFINITE) == WAIT_OBJECT_0);
  106.     ::CloseHandle(hEvent2);
  107.  
  108.     // first -- check for simple worker thread
  109.     DWORD nResult = 0;
  110.     if (pThread->m_pfnThreadProc != NULL)
  111.     {
  112.         nResult = (*pThread->m_pfnThreadProc)(pThread->m_pThreadParams);
  113.         ASSERT_VALID(pThread);
  114.     }
  115.     // else -- check for thread with message loop
  116.     else if (!pThread->InitInstance())
  117.     {
  118.         ASSERT_VALID(pThread);
  119.         nResult = pThread->ExitInstance();
  120.     }
  121.     else
  122.     {
  123.         // will stop after PostQuitMessage called
  124.         ASSERT_VALID(pThread);
  125.         nResult = pThread->Run();
  126.     }
  127.  
  128.     // cleanup and shutdown the thread
  129.     threadWnd.Detach();
  130.     AfxEndThread(nResult);
  131.  
  132.     return 0;   // not reached
  133. }
  134.  
  135. #endif //_MT
  136.  
  137. CWinThread* AFXAPI AfxGetThread()
  138. {
  139.     // check for current thread in module thread state
  140.     AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
  141.     CWinThread* pThread = pState->m_pCurrentWinThread;
  142.  
  143.     // if no CWinThread for the module, then use the global app
  144.     if (pThread == NULL)
  145.         pThread = AfxGetApp();
  146.  
  147.     return pThread;
  148. }
  149.  
  150. CWinThread* AFXAPI AfxBeginThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam,
  151.     int nPriority, UINT nStackSize, DWORD dwCreateFlags,
  152.     LPSECURITY_ATTRIBUTES lpSecurityAttrs)
  153. {
  154. #ifndef _MT
  155.     pfnThreadProc;
  156.     pParam;
  157.     nPriority;
  158.     nStackSize;
  159.     dwCreateFlags;
  160.     lpSecurityAttrs;
  161.  
  162.     return NULL;
  163. #else
  164.     ASSERT(pfnThreadProc != NULL);
  165.  
  166.     CWinThread* pThread = DEBUG_NEW CWinThread(pfnThreadProc, pParam);
  167.     ASSERT_VALID(pThread);
  168.  
  169.     if (!pThread->CreateThread(dwCreateFlags|CREATE_SUSPENDED, nStackSize,
  170.         lpSecurityAttrs))
  171.     {
  172.         pThread->Delete();
  173.         return NULL;
  174.     }
  175.     VERIFY(pThread->SetThreadPriority(nPriority));
  176.     if (!(dwCreateFlags & CREATE_SUSPENDED))
  177.         VERIFY(pThread->ResumeThread() != (DWORD)-1);
  178.  
  179.     return pThread;
  180. #endif //!_MT)
  181. }
  182.  
  183. CWinThread* AFXAPI AfxBeginThread(CRuntimeClass* pThreadClass,
  184.     int nPriority, UINT nStackSize, DWORD dwCreateFlags,
  185.     LPSECURITY_ATTRIBUTES lpSecurityAttrs)
  186. {
  187. #ifndef _MT
  188.     pThreadClass;
  189.     nPriority;
  190.     nStackSize;
  191.     dwCreateFlags;
  192.     lpSecurityAttrs;
  193.  
  194.     return NULL;
  195. #else
  196.     ASSERT(pThreadClass != NULL);
  197.     ASSERT(pThreadClass->IsDerivedFrom(RUNTIME_CLASS(CWinThread)));
  198.  
  199.     CWinThread* pThread = (CWinThread*)pThreadClass->CreateObject();
  200.     if (pThread == NULL)
  201.         AfxThrowMemoryException();
  202.     ASSERT_VALID(pThread);
  203.  
  204.     pThread->m_pThreadParams = NULL;
  205.     if (!pThread->CreateThread(dwCreateFlags|CREATE_SUSPENDED, nStackSize,
  206.         lpSecurityAttrs))
  207.     {
  208.         pThread->Delete();
  209.         return NULL;
  210.     }
  211.     VERIFY(pThread->SetThreadPriority(nPriority));
  212.     if (!(dwCreateFlags & CREATE_SUSPENDED))
  213.         VERIFY(pThread->ResumeThread() != (DWORD)-1);
  214.  
  215.     return pThread;
  216. #endif //!_MT
  217. }
  218.  
  219. void AFXAPI AfxEndThread(UINT nExitCode, BOOL bDelete)
  220. {
  221. #ifndef _MT
  222.     nExitCode;
  223.     bDelete;
  224. #else
  225.     // remove current CWinThread object from memory
  226.     AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
  227.     CWinThread* pThread = pState->m_pCurrentWinThread;
  228.     if (pThread != NULL)
  229.     {
  230.         ASSERT_VALID(pThread);
  231.         ASSERT(pThread != AfxGetApp());
  232.  
  233.         // cleanup OLE if required
  234.         if (pThread->m_lpfnOleTermOrFreeLib != NULL)
  235.             (*pThread->m_lpfnOleTermOrFreeLib)(TRUE, FALSE);
  236.  
  237.         if (bDelete)
  238.             pThread->Delete();
  239.         pState->m_pCurrentWinThread = NULL;
  240.     }
  241.  
  242.     // allow cleanup of any thread local objects
  243.     AfxTermThread();
  244.  
  245.     // allow C-runtime to cleanup, and exit the thread
  246.     _endthreadex(nExitCode);
  247. #endif //!_MT
  248. }
  249.  
  250. /////////////////////////////////////////////////////////////////////////////
  251. // Global functions for thread initialization and thread cleanup
  252.  
  253. LRESULT CALLBACK _AfxMsgFilterHook(int code, WPARAM wParam, LPARAM lParam);
  254.  
  255. void AFXAPI AfxInitThread()
  256. {
  257.     if (!afxContextIsDLL)
  258.     {
  259.         // set message filter proc
  260.         _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
  261.         ASSERT(pThreadState->m_hHookOldMsgFilter == NULL);
  262.         pThreadState->m_hHookOldMsgFilter = ::SetWindowsHookEx(WH_MSGFILTER,
  263.             _AfxMsgFilterHook, NULL, ::GetCurrentThreadId());
  264.  
  265. #ifndef _AFX_NO_CTL3D_SUPPORT
  266.         // intialize CTL3D for this thread
  267.         _AFX_CTL3D_STATE* pCtl3dState = _afxCtl3dState;
  268.         if (pCtl3dState->m_pfnAutoSubclass != NULL)
  269.             (*pCtl3dState->m_pfnAutoSubclass)(AfxGetInstanceHandle());
  270.  
  271.         // allocate thread local _AFX_CTL3D_THREAD just for automatic termination
  272.         _AFX_CTL3D_THREAD* pTemp = _afxCtl3dThread;
  273.         pTemp;  // avoid unused warning
  274. #endif
  275.     }
  276. }
  277.  
  278. extern CThreadSlotData* _afxThreadData;
  279. void AFXAPI AfxTermThread(HINSTANCE hInstTerm)
  280. {
  281. #ifdef _DEBUG
  282.     // check for missing AfxLockTempMap calls
  283.     if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
  284.     {
  285.         TRACE1("Warning: Temp map lock count non-zero (%ld).\n",
  286.             AfxGetModuleThreadState()->m_nTempMapLock);
  287.     }
  288. #endif
  289.     AfxLockTempMaps();
  290.     AfxUnlockTempMaps(-1);
  291.  
  292.     // cleanup thread local tooltip window
  293.     if (hInstTerm == NULL)
  294.     {
  295.         _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetDataNA();
  296.         if ((pThreadState != NULL) &&
  297.             (pThreadState->m_pToolTip != NULL))
  298.         {
  299.             pThreadState->m_pToolTip->DestroyWindow();
  300.             delete pThreadState->m_pToolTip;
  301.             pThreadState->m_pToolTip=NULL;
  302.         }
  303.     }
  304.  
  305.     // cleanup the rest of the thread local data
  306.     if (_afxThreadData != NULL)
  307.         _afxThreadData->DeleteValues(hInstTerm, FALSE);
  308. }
  309.  
  310. /////////////////////////////////////////////////////////////////////////////
  311. // CWinThread construction
  312.  
  313. #ifdef AFX_INIT_SEG
  314. #pragma code_seg(AFX_INIT_SEG)
  315. #endif
  316.  
  317. CWinThread::CWinThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam)
  318. {
  319.     m_pfnThreadProc = pfnThreadProc;
  320.     m_pThreadParams = pParam;
  321.  
  322.     CommonConstruct();
  323. }
  324.  
  325. CWinThread::CWinThread()
  326. {
  327.     m_pThreadParams = NULL;
  328.     m_pfnThreadProc = NULL;
  329.  
  330.     CommonConstruct();
  331. }
  332.  
  333. void CWinThread::CommonConstruct()
  334. {
  335.     m_pMainWnd = NULL;
  336.     m_pActiveWnd = NULL;
  337.  
  338.     // no HTHREAD until it is created
  339.     m_hThread = NULL;
  340.     m_nThreadID = 0;
  341.  
  342.     // initialize message pump
  343. #ifdef _DEBUG
  344.     m_nDisablePumpCount = 0;
  345. #endif
  346.     m_msgCur.message = WM_NULL;
  347.     m_nMsgLast = WM_NULL;
  348.     ::GetCursorPos(&m_ptCursorLast);
  349.  
  350.     // most threads are deleted when not needed
  351.     m_bAutoDelete = TRUE;
  352.  
  353.     // initialize OLE state
  354.     m_pMessageFilter = NULL;
  355.     m_lpfnOleTermOrFreeLib = NULL;
  356. }
  357.  
  358. #ifdef AFX_TERM_SEG
  359. #pragma code_seg(AFX_TERM_SEG)
  360. #endif
  361.  
  362. CWinThread::~CWinThread()
  363. {
  364.     // free thread object
  365.     if (m_hThread != NULL)
  366.         CloseHandle(m_hThread);
  367.  
  368.     // cleanup module state
  369.     AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
  370.     if (pState->m_pCurrentWinThread == this)
  371.         pState->m_pCurrentWinThread = NULL;
  372. }
  373.  
  374. #ifdef AFX_CORE1_SEG
  375. #pragma code_seg(AFX_CORE1_SEG)
  376. #endif
  377.  
  378. BOOL CWinThread::CreateThread(DWORD dwCreateFlags, UINT nStackSize,
  379.     LPSECURITY_ATTRIBUTES lpSecurityAttrs)
  380. {
  381. #ifndef _MT
  382.     dwCreateFlags;
  383.     nStackSize;
  384.     lpSecurityAttrs;
  385.  
  386.     return FALSE;
  387. #else
  388.     ASSERT(m_hThread == NULL);  // already created?
  389.  
  390.     // setup startup structure for thread initialization
  391.     _AFX_THREAD_STARTUP startup; memset(&startup, 0, sizeof(startup));
  392.     startup.pThreadState = AfxGetThreadState();
  393.     startup.pThread = this;
  394.     startup.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
  395.     startup.hEvent2 = ::CreateEvent(NULL, TRUE, FALSE, NULL);
  396.     startup.dwCreateFlags = dwCreateFlags;
  397.     if (startup.hEvent == NULL || startup.hEvent2 == NULL)
  398.     {
  399.         TRACE0("Warning: CreateEvent failed in CWinThread::CreateThread.\n");
  400.         if (startup.hEvent != NULL)
  401.             ::CloseHandle(startup.hEvent);
  402.         if (startup.hEvent2 != NULL)
  403.             ::CloseHandle(startup.hEvent2);
  404.         return FALSE;
  405.     }
  406.  
  407.     // create the thread (it may or may not start to run)
  408.     m_hThread = (HANDLE)_beginthreadex(lpSecurityAttrs, nStackSize,
  409.         &_AfxThreadEntry, &startup, dwCreateFlags | CREATE_SUSPENDED, (UINT*)&m_nThreadID);
  410.     if (m_hThread == NULL)
  411.         return FALSE;
  412.  
  413.     // start the thread just for MFC initialization
  414.     VERIFY(ResumeThread() != (DWORD)-1);
  415.     VERIFY(::WaitForSingleObject(startup.hEvent, INFINITE) == WAIT_OBJECT_0);
  416.     ::CloseHandle(startup.hEvent);
  417.  
  418.     // if created suspended, suspend it until resume thread wakes it up
  419.     if (dwCreateFlags & CREATE_SUSPENDED)
  420.         VERIFY(::SuspendThread(m_hThread) != (DWORD)-1);
  421.  
  422.     // if error during startup, shut things down
  423.     if (startup.bError)
  424.     {
  425.         VERIFY(::WaitForSingleObject(m_hThread, INFINITE) == WAIT_OBJECT_0);
  426.         ::CloseHandle(m_hThread);
  427.         m_hThread = NULL;
  428.         ::CloseHandle(startup.hEvent2);
  429.         return FALSE;
  430.     }
  431.  
  432.     // allow thread to continue, once resumed (it may already be resumed)
  433.     ::SetEvent(startup.hEvent2);
  434.     return TRUE;
  435. #endif //!_MT
  436. }
  437.  
  438. void CWinThread::Delete()
  439. {
  440.     // delete thread if it is auto-deleting
  441.     if (m_bAutoDelete)
  442.         delete this;
  443. }
  444.  
  445. /////////////////////////////////////////////////////////////////////////////
  446. // CWinThread default implementation
  447.  
  448. BOOL CWinThread::InitInstance()
  449. {
  450.     ASSERT_VALID(this);
  451.  
  452.     return FALSE;   // by default don't enter run loop
  453. }
  454.  
  455. // main running routine until thread exits
  456. int CWinThread::Run()
  457. {
  458.     ASSERT_VALID(this);
  459.  
  460.     // for tracking the idle time state
  461.     BOOL bIdle = TRUE;
  462.     LONG lIdleCount = 0;
  463.  
  464.     // acquire and dispatch messages until a WM_QUIT message is received.
  465.     for (;;)
  466.     {
  467.         // phase1: check to see if we can do idle work
  468.         while (bIdle &&
  469.             !::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
  470.         {
  471.             // call OnIdle while in bIdle state
  472.             if (!OnIdle(lIdleCount++))
  473.                 bIdle = FALSE; // assume "no idle" state
  474.         }
  475.  
  476.         // phase2: pump messages while available
  477.         do
  478.         {
  479.             // pump message, but quit on WM_QUIT
  480.             if (!PumpMessage())
  481.                 return ExitInstance();
  482.  
  483.             // reset "no idle" state after pumping "normal" message
  484.             if (IsIdleMessage(&m_msgCur))
  485.             {
  486.                 bIdle = TRUE;
  487.                 lIdleCount = 0;
  488.             }
  489.  
  490.         } while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
  491.     }
  492.  
  493.     ASSERT(FALSE);  // not reachable
  494. }
  495.  
  496. BOOL CWinThread::IsIdleMessage(MSG* pMsg)
  497. {
  498.     // Return FALSE if the message just dispatched should _not_
  499.     // cause OnIdle to be run.  Messages which do not usually
  500.     // affect the state of the user interface and happen very
  501.     // often are checked for.
  502.  
  503.     // redundant WM_MOUSEMOVE and WM_NCMOUSEMOVE
  504.     if (pMsg->message == WM_MOUSEMOVE || pMsg->message == WM_NCMOUSEMOVE)
  505.     {
  506.         // mouse move at same position as last mouse move?
  507.         if (m_ptCursorLast == pMsg->pt && pMsg->message == m_nMsgLast)
  508.             return FALSE;
  509.  
  510.         m_ptCursorLast = pMsg->pt;  // remember for next time
  511.         m_nMsgLast = pMsg->message;
  512.         return TRUE;
  513.     }
  514.  
  515.     // WM_PAINT and WM_SYSTIMER (caret blink)
  516.     return pMsg->message != WM_PAINT && pMsg->message != 0x0118;
  517. }
  518.  
  519. int CWinThread::ExitInstance()
  520. {
  521.     ASSERT_VALID(this);
  522.     ASSERT(AfxGetApp() != this);
  523.  
  524.     int nResult = m_msgCur.wParam;  // returns the value from PostQuitMessage
  525.     return nResult;
  526. }
  527.  
  528. BOOL CWinThread::OnIdle(LONG lCount)
  529. {
  530.     ASSERT_VALID(this);
  531.  
  532. #if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)
  533.     // check MFC's allocator (before idle)
  534.     if (_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_CHECK_ALWAYS_DF)
  535.         ASSERT(AfxCheckMemory());
  536. #endif
  537.  
  538.     if (lCount <= 0)
  539.     {
  540.         // send WM_IDLEUPDATECMDUI to the main window
  541.         CWnd* pMainWnd = m_pMainWnd;
  542.         if (pMainWnd != NULL && pMainWnd->m_hWnd != NULL &&
  543.             pMainWnd->IsWindowVisible())
  544.         {
  545.             AfxCallWndProc(pMainWnd, pMainWnd->m_hWnd,
  546.                 WM_IDLEUPDATECMDUI, (WPARAM)TRUE, 0);
  547.             pMainWnd->SendMessageToDescendants(WM_IDLEUPDATECMDUI,
  548.                 (WPARAM)TRUE, 0, TRUE, TRUE);
  549.         }
  550.         // send WM_IDLEUPDATECMDUI to all frame windows
  551.         AFX_MODULE_THREAD_STATE* pState = _AFX_CMDTARGET_GETSTATE()->m_thread;
  552.         CFrameWnd* pFrameWnd = pState->m_frameList;
  553.         while (pFrameWnd != NULL)
  554.         {
  555.             if (pFrameWnd->m_hWnd != NULL && pFrameWnd != pMainWnd)
  556.             {
  557.                 if (pFrameWnd->m_nShowDelay == SW_HIDE)
  558.                     pFrameWnd->ShowWindow(pFrameWnd->m_nShowDelay);
  559.                 if (pFrameWnd->IsWindowVisible() ||
  560.                     pFrameWnd->m_nShowDelay >= 0)
  561.                 {
  562.                     AfxCallWndProc(pFrameWnd, pFrameWnd->m_hWnd,
  563.                         WM_IDLEUPDATECMDUI, (WPARAM)TRUE, 0);
  564.                     pFrameWnd->SendMessageToDescendants(WM_IDLEUPDATECMDUI,
  565.                         (WPARAM)TRUE, 0, TRUE, TRUE);
  566.                 }
  567.                 if (pFrameWnd->m_nShowDelay > SW_HIDE)
  568.                     pFrameWnd->ShowWindow(pFrameWnd->m_nShowDelay);
  569.                 pFrameWnd->m_nShowDelay = -1;
  570.             }
  571.             pFrameWnd = pFrameWnd->m_pNextFrameWnd;
  572.         }
  573.     }
  574.     else if (lCount >= 0)
  575.     {
  576.         AFX_MODULE_THREAD_STATE* pState = _AFX_CMDTARGET_GETSTATE()->m_thread;
  577.         if (pState->m_nTempMapLock == 0)
  578.         {
  579.             // free temp maps, OLE DLLs, etc.
  580.             AfxLockTempMaps();
  581.             AfxUnlockTempMaps();
  582.         }
  583.     }
  584.  
  585. #if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)
  586.     // check MFC's allocator (after idle)
  587.     if (_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_CHECK_ALWAYS_DF)
  588.         ASSERT(AfxCheckMemory());
  589. #endif
  590.  
  591.     return lCount < 0;  // nothing more to do if lCount >= 0
  592. }
  593.  
  594. void CWinThread::DispatchThreadMessage(MSG* pMsg)
  595. {
  596.     DispatchThreadMessageEx(pMsg);
  597. }
  598.  
  599. BOOL CWinThread::DispatchThreadMessageEx(MSG* pMsg)
  600. {
  601.     const AFX_MSGMAP* pMessageMap; pMessageMap = GetMessageMap();
  602.     const AFX_MSGMAP_ENTRY* lpEntry;
  603.  
  604. #ifdef _AFXDLL
  605.     for (/* pMessageMap already init'ed */; pMessageMap != NULL;
  606.         pMessageMap = (*pMessageMap->pfnGetBaseMap)())
  607. #else
  608.     for (/* pMessageMap already init'ed */; pMessageMap != NULL;
  609.         pMessageMap = pMessageMap->pBaseMap)
  610. #endif
  611.  
  612.     {
  613.         // Note: catch not so common but fatal mistake!!
  614.         //      BEGIN_MESSAGE_MAP(CMyThread, CMyThread)
  615. #ifdef _AFXDLL
  616.         ASSERT(pMessageMap != (*pMessageMap->pfnGetBaseMap)());
  617. #else
  618.         ASSERT(pMessageMap != pMessageMap->pBaseMap);
  619. #endif
  620.  
  621.         if (pMsg->message < 0xC000)
  622.         {
  623.             // constant window message
  624.             if ((lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries,
  625.                 pMsg->message, 0, 0)) != NULL)
  626.                 goto LDispatch;
  627.         }
  628.         else
  629.         {
  630.             // registered windows message
  631.             lpEntry = pMessageMap->lpEntries;
  632.             while ((lpEntry = AfxFindMessageEntry(lpEntry, 0xC000, 0, 0)) != NULL)
  633.             {
  634.                 UINT* pnID = (UINT*)(lpEntry->nSig);
  635.                 ASSERT(*pnID >= 0xC000);
  636.                     // must be successfully registered
  637.                 if (*pnID == pMsg->message)
  638.                     goto LDispatch;
  639.                 lpEntry++;      // keep looking past this one
  640.             }
  641.         }
  642.     }
  643.     return FALSE;
  644.  
  645. LDispatch:
  646.     union MessageMapFunctions mmf;
  647.     mmf.pfn = lpEntry->pfn;
  648.  
  649.     // always posted, so return value is meaningless
  650.  
  651.     (this->*mmf.pfn_THREAD)(pMsg->wParam, pMsg->lParam);
  652.     return TRUE;
  653. }
  654.  
  655. BOOL CWinThread::PreTranslateMessage(MSG* pMsg)
  656. {
  657.     ASSERT_VALID(this);
  658.  
  659.     // if this is a thread-message, short-circuit this function
  660.     if (pMsg->hwnd == NULL && DispatchThreadMessageEx(pMsg))
  661.         return TRUE;
  662.  
  663.     // walk from target to main window
  664.     CWnd* pMainWnd = AfxGetMainWnd();
  665.     if (CWnd::WalkPreTranslateTree(pMainWnd->GetSafeHwnd(), pMsg))
  666.         return TRUE;
  667.  
  668.     // in case of modeless dialogs, last chance route through main
  669.     //   window's accelerator table
  670.     if (pMainWnd != NULL)
  671.     {
  672.          CWnd* pWnd = CWnd::FromHandle(pMsg->hwnd);
  673.          if (pWnd->GetTopLevelParent() != pMainWnd)
  674.             return pMainWnd->PreTranslateMessage(pMsg);
  675.     }
  676.  
  677.     return FALSE;   // no special processing
  678. }
  679.  
  680. LRESULT CWinThread::ProcessWndProcException(CException*, const MSG* pMsg)
  681. {
  682.     if (pMsg->message == WM_CREATE)
  683.     {
  684.         return -1;  // just fail
  685.     }
  686.     else if (pMsg->message == WM_PAINT)
  687.     {
  688.         // force validation of window to prevent getting WM_PAINT again
  689.         ValidateRect(pMsg->hwnd, NULL);
  690.         return 0;
  691.     }
  692.     return 0;   // sensible default for rest of commands
  693. }
  694.  
  695. /////////////////////////////////////////////////////////////////////////////
  696. // Message Filter processing (WH_MSGFILTER)
  697.  
  698. LRESULT CALLBACK _AfxMsgFilterHook(int code, WPARAM wParam, LPARAM lParam)
  699. {
  700.     CWinThread* pThread;
  701.     if (afxContextIsDLL || (code < 0 && code != MSGF_DDEMGR) ||
  702.         (pThread = AfxGetThread()) == NULL)
  703.     {
  704.         return ::CallNextHookEx(_afxThreadState->m_hHookOldMsgFilter,
  705.             code, wParam, lParam);
  706.     }
  707.     ASSERT(pThread != NULL);
  708.     return (LRESULT)pThread->ProcessMessageFilter(code, (LPMSG)lParam);
  709. }
  710.  
  711. AFX_STATIC BOOL AFXAPI IsHelpKey(LPMSG lpMsg)
  712.     // return TRUE only for non-repeat F1 keydowns.
  713. {
  714.     return lpMsg->message == WM_KEYDOWN &&
  715.            lpMsg->wParam == VK_F1 &&
  716.            !(HIWORD(lpMsg->lParam) & KF_REPEAT) &&
  717.            GetKeyState(VK_SHIFT) >= 0 &&
  718.            GetKeyState(VK_CONTROL) >= 0 &&
  719.            GetKeyState(VK_MENU) >= 0;
  720. }
  721.  
  722. AFX_STATIC inline BOOL IsEnterKey(LPMSG lpMsg)
  723.     { return lpMsg->message == WM_KEYDOWN && lpMsg->wParam == VK_RETURN; }
  724.  
  725. AFX_STATIC inline BOOL IsButtonUp(LPMSG lpMsg)
  726.     { return lpMsg->message == WM_LBUTTONUP; }
  727.  
  728. BOOL CWinThread::ProcessMessageFilter(int code, LPMSG lpMsg)
  729. {
  730.     if (lpMsg == NULL)
  731.         return FALSE;   // not handled
  732.  
  733.     CFrameWnd* pTopFrameWnd;
  734.     CWnd* pMainWnd;
  735.     CWnd* pMsgWnd;
  736.     switch (code)
  737.     {
  738.     case MSGF_DDEMGR:
  739.         // Unlike other WH_MSGFILTER codes, MSGF_DDEMGR should
  740.         //  never call the next hook.
  741.         // By returning FALSE, the message will be dispatched
  742.         //  instead (the default behavior).
  743.         return FALSE;
  744.  
  745.     case MSGF_MENU:
  746.         pMsgWnd = CWnd::FromHandle(lpMsg->hwnd);
  747.         if (pMsgWnd != NULL)
  748.         {
  749.             pTopFrameWnd = pMsgWnd->GetTopLevelFrame();
  750.             if (pTopFrameWnd != NULL && pTopFrameWnd->IsTracking() &&
  751.                 pTopFrameWnd->m_bHelpMode)
  752.             {
  753.                 pMainWnd = AfxGetMainWnd();
  754.                 if ((m_pMainWnd != NULL) && (IsEnterKey(lpMsg) || IsButtonUp(lpMsg)))
  755.                 {
  756.                     pMainWnd->SendMessage(WM_COMMAND, ID_HELP);
  757.                     return TRUE;
  758.                 }
  759.             }
  760.         }
  761.         // fall through...
  762.  
  763.     case MSGF_DIALOGBOX:    // handles message boxes as well.
  764.         pMainWnd = AfxGetMainWnd();
  765.         if (afxData.nWinVer < 0x333 && pMainWnd != NULL && IsHelpKey(lpMsg))
  766.         {
  767.             pMainWnd->SendMessage(WM_COMMAND, ID_HELP);
  768.             return TRUE;
  769.         }
  770.         if (code == MSGF_DIALOGBOX && m_pActiveWnd != NULL &&
  771.             lpMsg->message >= WM_KEYFIRST && lpMsg->message <= WM_KEYLAST)
  772.         {
  773.             // need to translate messages for the in-place container
  774.             _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
  775.             if (pThreadState->m_bInMsgFilter)
  776.                 return FALSE;
  777.             pThreadState->m_bInMsgFilter = TRUE;    // avoid reentering this code
  778.             MSG msg = *lpMsg;
  779.             if (m_pActiveWnd->IsWindowEnabled() && PreTranslateMessage(&msg))
  780.             {
  781.                 pThreadState->m_bInMsgFilter = FALSE;
  782.                 return TRUE;
  783.             }
  784.             pThreadState->m_bInMsgFilter = FALSE;    // ok again
  785.         }
  786.         break;
  787.     }
  788.  
  789.     return FALSE;   // default to not handled
  790. }
  791.  
  792. /////////////////////////////////////////////////////////////////////////////
  793. // Access to m_pMainWnd & m_pActiveWnd
  794.  
  795. CWnd* CWinThread::GetMainWnd()
  796. {
  797.     if (m_pActiveWnd != NULL)
  798.         return m_pActiveWnd;    // probably in-place active
  799.  
  800.     // when not inplace active, just return main window
  801.     if (m_pMainWnd != NULL)
  802.         return m_pMainWnd;
  803.  
  804.     return CWnd::GetActiveWindow();
  805. }
  806.  
  807. /////////////////////////////////////////////////////////////////////////////
  808. // CWinThread implementation helpers
  809.  
  810. BOOL CWinThread::PumpMessage()
  811. {
  812.     ASSERT_VALID(this);
  813.  
  814.     if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))
  815.     {
  816. #ifdef _DEBUG
  817.         if (afxTraceFlags & traceAppMsg)
  818.             TRACE0("CWinThread::PumpMessage - Received WM_QUIT.\n");
  819.         m_nDisablePumpCount++; // application must die
  820.             // Note: prevents calling message loop things in 'ExitInstance'
  821.             // will never be decremented
  822. #endif
  823.         return FALSE;
  824.     }
  825.  
  826. #ifdef _DEBUG
  827.     if (m_nDisablePumpCount != 0)
  828.     {
  829.         TRACE0("Error: CWinThread::PumpMessage called when not permitted.\n");
  830.         ASSERT(FALSE);
  831.     }
  832. #endif
  833.  
  834. #ifdef _DEBUG
  835.     if (afxTraceFlags & traceAppMsg)
  836.         _AfxTraceMsg(_T("PumpMessage"), &m_msgCur);
  837. #endif
  838.  
  839.     // process this message
  840.  
  841.     if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur))
  842.     {
  843.         ::TranslateMessage(&m_msgCur);
  844.         ::DispatchMessage(&m_msgCur);
  845.     }
  846.     return TRUE;
  847. }
  848.  
  849. /////////////////////////////////////////////////////////////////////////////
  850. // CWinThread diagnostics
  851.  
  852. #ifdef _DEBUG
  853. void CWinThread::AssertValid() const
  854. {
  855.     CCmdTarget::AssertValid();
  856. }
  857.  
  858. void CWinThread::Dump(CDumpContext& dc) const
  859. {
  860.     CCmdTarget::Dump(dc);
  861.  
  862.     dc << "m_pThreadParams = " << m_pThreadParams;
  863.     dc << "\nm_pfnThreadProc = " << (void*)m_pfnThreadProc;
  864.     dc << "\nm_bAutoDelete = " << m_bAutoDelete;
  865.     dc << "\nm_hThread = " << (void*)m_hThread;
  866.     dc << "\nm_nThreadID = " << m_nThreadID;
  867.     dc << "\nm_nDisablePumpCount = " << m_nDisablePumpCount;
  868.     if (AfxGetThread() == this)
  869.         dc << "\nm_pMainWnd = " << m_pMainWnd;
  870.  
  871.     dc << "\nm_msgCur = {";
  872.     dc << "\n\thwnd = " << (UINT)m_msgCur.hwnd;
  873.     dc << "\n\tmessage = " << (UINT)m_msgCur.message;
  874.     dc << "\n\twParam = " << (UINT)m_msgCur.wParam;
  875.     dc << "\n\tlParam = " << (void*)m_msgCur.lParam;
  876.     dc << "\n\ttime = " << m_msgCur.time;
  877.     dc << "\n\tpt = " << CPoint(m_msgCur.pt);
  878.     dc << "\n}";
  879.  
  880.     dc << "\nm_pThreadParams = " << m_pThreadParams;
  881.     dc << "\nm_pfnThreadProc = " << (void*)m_pfnThreadProc;
  882.     dc << "\nm_ptCursorLast = " << m_ptCursorLast;
  883.     dc << "\nm_nMsgLast = " << m_nMsgLast;
  884.  
  885.     dc << "\n";
  886. }
  887. #endif
  888.  
  889. #ifdef AFX_INIT_SEG
  890. #pragma code_seg(AFX_INIT_SEG)
  891. #endif
  892.  
  893. IMPLEMENT_DYNAMIC(CWinThread, CCmdTarget)
  894.  
  895. /////////////////////////////////////////////////////////////////////////////
  896.