home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / THRDCORE.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-30  |  24.4 KB  |  914 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1997 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.         pState->m_pfnNewHandler = pStartup->pfnNewHandler;
  69.  
  70.         // forced initialization of the thread
  71.         AfxInitThread();
  72.  
  73.         // thread inherits app's main window if not already set
  74.         CWinApp* pApp = AfxGetApp();
  75.         ASSERT(pApp != NULL);
  76.         if (pThread->m_pMainWnd == NULL && pApp->m_pMainWnd->GetSafeHwnd() != NULL)
  77.         {
  78.             // just attach the HWND
  79.             threadWnd.Attach(pApp->m_pMainWnd->m_hWnd);
  80.             pThread->m_pMainWnd = &threadWnd;
  81.         }
  82.     }
  83.     CATCH_ALL(e)
  84.     {
  85.         // Note: DELETE_EXCEPTION(e) not required.
  86.  
  87.         // exception happened during thread initialization!!
  88.         TRACE0("Warning: Error during thread initialization!\n");
  89.  
  90.         // set error flag and allow the creating thread to notice the error
  91.         threadWnd.Detach();
  92.         pStartup->bError = TRUE;
  93.         VERIFY(::SetEvent(pStartup->hEvent));
  94.         AfxEndThread((UINT)-1, FALSE);
  95.         ASSERT(FALSE);  // unreachable
  96.     }
  97.     END_CATCH_ALL
  98.  
  99.     // pStartup is invaid after the following SetEvent (but hEvent2 is valid)
  100.     HANDLE hEvent2 = pStartup->hEvent2;
  101.  
  102.     // allow the creating thread to return from CWinThread::CreateThread
  103.     VERIFY(::SetEvent(pStartup->hEvent));
  104.  
  105.     // wait for thread to be resumed
  106.     VERIFY(::WaitForSingleObject(hEvent2, INFINITE) == WAIT_OBJECT_0);
  107.     ::CloseHandle(hEvent2);
  108.  
  109.     // first -- check for simple worker thread
  110.     DWORD nResult = 0;
  111.     if (pThread->m_pfnThreadProc != NULL)
  112.     {
  113.         nResult = (*pThread->m_pfnThreadProc)(pThread->m_pThreadParams);
  114.         ASSERT_VALID(pThread);
  115.     }
  116.     // else -- check for thread with message loop
  117.     else if (!pThread->InitInstance())
  118.     {
  119.         ASSERT_VALID(pThread);
  120.         nResult = pThread->ExitInstance();
  121.     }
  122.     else
  123.     {
  124.         // will stop after PostQuitMessage called
  125.         ASSERT_VALID(pThread);
  126.         nResult = pThread->Run();
  127.     }
  128.  
  129.     // cleanup and shutdown the thread
  130.     threadWnd.Detach();
  131.     AfxEndThread(nResult);
  132.  
  133.     return 0;   // not reached
  134. }
  135.  
  136. #endif //_MT
  137.  
  138. CWinThread* AFXAPI AfxGetThread()
  139. {
  140.     // check for current thread in module thread state
  141.     AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
  142.     CWinThread* pThread = pState->m_pCurrentWinThread;
  143.  
  144.     // if no CWinThread for the module, then use the global app
  145.     if (pThread == NULL)
  146.         pThread = AfxGetApp();
  147.  
  148.     return pThread;
  149. }
  150.  
  151. CWinThread* AFXAPI AfxBeginThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam,
  152.     int nPriority, UINT nStackSize, DWORD dwCreateFlags,
  153.     LPSECURITY_ATTRIBUTES lpSecurityAttrs)
  154. {
  155. #ifndef _MT
  156.     pfnThreadProc;
  157.     pParam;
  158.     nPriority;
  159.     nStackSize;
  160.     dwCreateFlags;
  161.     lpSecurityAttrs;
  162.  
  163.     return NULL;
  164. #else
  165.     ASSERT(pfnThreadProc != NULL);
  166.  
  167.     CWinThread* pThread = DEBUG_NEW CWinThread(pfnThreadProc, pParam);
  168.     ASSERT_VALID(pThread);
  169.  
  170.     if (!pThread->CreateThread(dwCreateFlags|CREATE_SUSPENDED, nStackSize,
  171.         lpSecurityAttrs))
  172.     {
  173.         pThread->Delete();
  174.         return NULL;
  175.     }
  176.     VERIFY(pThread->SetThreadPriority(nPriority));
  177.     if (!(dwCreateFlags & CREATE_SUSPENDED))
  178.         VERIFY(pThread->ResumeThread() != (DWORD)-1);
  179.  
  180.     return pThread;
  181. #endif //!_MT)
  182. }
  183.  
  184. CWinThread* AFXAPI AfxBeginThread(CRuntimeClass* pThreadClass,
  185.     int nPriority, UINT nStackSize, DWORD dwCreateFlags,
  186.     LPSECURITY_ATTRIBUTES lpSecurityAttrs)
  187. {
  188. #ifndef _MT
  189.     pThreadClass;
  190.     nPriority;
  191.     nStackSize;
  192.     dwCreateFlags;
  193.     lpSecurityAttrs;
  194.  
  195.     return NULL;
  196. #else
  197.     ASSERT(pThreadClass != NULL);
  198.     ASSERT(pThreadClass->IsDerivedFrom(RUNTIME_CLASS(CWinThread)));
  199.  
  200.     CWinThread* pThread = (CWinThread*)pThreadClass->CreateObject();
  201.     if (pThread == NULL)
  202.         AfxThrowMemoryException();
  203.     ASSERT_VALID(pThread);
  204.  
  205.     pThread->m_pThreadParams = NULL;
  206.     if (!pThread->CreateThread(dwCreateFlags|CREATE_SUSPENDED, nStackSize,
  207.         lpSecurityAttrs))
  208.     {
  209.         pThread->Delete();
  210.         return NULL;
  211.     }
  212.     VERIFY(pThread->SetThreadPriority(nPriority));
  213.     if (!(dwCreateFlags & CREATE_SUSPENDED))
  214.         VERIFY(pThread->ResumeThread() != (DWORD)-1);
  215.  
  216.     return pThread;
  217. #endif //!_MT
  218. }
  219.  
  220. void AFXAPI AfxEndThread(UINT nExitCode, BOOL bDelete)
  221. {
  222. #ifndef _MT
  223.     nExitCode;
  224.     bDelete;
  225. #else
  226.     // remove current CWinThread object from memory
  227.     AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
  228.     CWinThread* pThread = pState->m_pCurrentWinThread;
  229.     if (pThread != NULL)
  230.     {
  231.         ASSERT_VALID(pThread);
  232.         ASSERT(pThread != AfxGetApp());
  233.  
  234.         // cleanup OLE if required
  235.         if (pThread->m_lpfnOleTermOrFreeLib != NULL)
  236.             (*pThread->m_lpfnOleTermOrFreeLib)(TRUE, FALSE);
  237.  
  238.         if (bDelete)
  239.             pThread->Delete();
  240.         pState->m_pCurrentWinThread = NULL;
  241.     }
  242.  
  243.     // allow cleanup of any thread local objects
  244.     AfxTermThread();
  245.  
  246.     // allow C-runtime to cleanup, and exit the thread
  247.     _endthreadex(nExitCode);
  248. #endif //!_MT
  249. }
  250.  
  251. /////////////////////////////////////////////////////////////////////////////
  252. // Global functions for thread initialization and thread cleanup
  253.  
  254. LRESULT CALLBACK _AfxMsgFilterHook(int code, WPARAM wParam, LPARAM lParam);
  255.  
  256. void AFXAPI AfxInitThread()
  257. {
  258.     if (!afxContextIsDLL)
  259.     {
  260.         // set message filter proc
  261.         _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
  262.         ASSERT(pThreadState->m_hHookOldMsgFilter == NULL);
  263.         pThreadState->m_hHookOldMsgFilter = ::SetWindowsHookEx(WH_MSGFILTER,
  264.             _AfxMsgFilterHook, NULL, ::GetCurrentThreadId());
  265.  
  266. #ifndef _MAC
  267.         // intialize CTL3D for this thread
  268.         _AFX_CTL3D_STATE* pCtl3dState = _afxCtl3dState;
  269.         if (pCtl3dState->m_pfnAutoSubclass != NULL)
  270.             (*pCtl3dState->m_pfnAutoSubclass)(AfxGetInstanceHandle());
  271.  
  272.         // allocate thread local _AFX_CTL3D_THREAD just for automatic termination
  273.         _AFX_CTL3D_THREAD* pTemp = _afxCtl3dThread;
  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.     UINT message = pMsg->message;
  664.     BOOL bKeys = (message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
  665.         (message >= WM_SYSKEYFIRST && message <= WM_SYSKEYLAST);
  666.     if (bKeys ||
  667.         (message == WM_LBUTTONDOWN || message == WM_LBUTTONDBLCLK) ||
  668.         (message == WM_RBUTTONDOWN || message == WM_RBUTTONDBLCLK) ||
  669.         (message == WM_MBUTTONDOWN || message == WM_MBUTTONDBLCLK) ||
  670.         (message == WM_NCLBUTTONDOWN || message == WM_NCLBUTTONDBLCLK) ||
  671.         (message == WM_NCRBUTTONDOWN || message == WM_NCRBUTTONDBLCLK) ||
  672.         (message == WM_NCMBUTTONDOWN || message == WM_NCMBUTTONDBLCLK))
  673.     {
  674.         CWnd::CancelToolTips(bKeys);
  675.     }
  676.  
  677.     // walk from target to main window
  678.     CWnd* pMainWnd = AfxGetMainWnd();
  679.     if (CWnd::WalkPreTranslateTree(pMainWnd->GetSafeHwnd(), pMsg))
  680.         return TRUE;
  681.  
  682.     // in case of modeless dialogs, last chance route through main
  683.     //   window's accelerator table
  684.     if (pMainWnd != NULL)
  685.     {
  686.          CWnd* pWnd = CWnd::FromHandle(pMsg->hwnd);
  687.          if (pWnd->GetTopLevelParent() != pMainWnd)
  688.             return pMainWnd->PreTranslateMessage(pMsg);
  689.     }
  690.  
  691.     return FALSE;   // no special processing
  692. }
  693.  
  694. LRESULT CWinThread::ProcessWndProcException(CException*, const MSG* pMsg)
  695. {
  696.     if (pMsg->message == WM_CREATE)
  697.     {
  698.         return -1;  // just fail
  699.     }
  700.     else if (pMsg->message == WM_PAINT)
  701.     {
  702.         // force validation of window to prevent getting WM_PAINT again
  703.         ValidateRect(pMsg->hwnd, NULL);
  704.         return 0;
  705.     }
  706.     return 0;   // sensible default for rest of commands
  707. }
  708.  
  709. /////////////////////////////////////////////////////////////////////////////
  710. // Message Filter processing (WH_MSGFILTER)
  711.  
  712. LRESULT CALLBACK _AfxMsgFilterHook(int code, WPARAM wParam, LPARAM lParam)
  713. {
  714.     CWinThread* pThread;
  715.     if (afxContextIsDLL || (code < 0 && code != MSGF_DDEMGR) ||
  716.         (pThread = AfxGetThread()) == NULL)
  717.     {
  718.         return ::CallNextHookEx(_afxThreadState->m_hHookOldMsgFilter,
  719.             code, wParam, lParam);
  720.     }
  721.     ASSERT(pThread != NULL);
  722.     return (LRESULT)pThread->ProcessMessageFilter(code, (LPMSG)lParam);
  723. }
  724.  
  725. static BOOL AFXAPI IsHelpKey(LPMSG lpMsg)
  726.     // return TRUE only for non-repeat F1 keydowns.
  727. {
  728.     return lpMsg->message == WM_KEYDOWN &&
  729. #ifndef _MAC
  730.            lpMsg->wParam == VK_F1 &&
  731. #else
  732.            lpMsg->wParam == VK_HELP &&
  733. #endif
  734.            !(HIWORD(lpMsg->lParam) & KF_REPEAT) &&
  735.            GetKeyState(VK_SHIFT) >= 0 &&
  736.            GetKeyState(VK_CONTROL) >= 0 &&
  737.            GetKeyState(VK_MENU) >= 0;
  738. }
  739.  
  740. static inline BOOL IsEnterKey(LPMSG lpMsg)
  741.     { return lpMsg->message == WM_KEYDOWN && lpMsg->wParam == VK_RETURN; }
  742.  
  743. static inline BOOL IsButtonUp(LPMSG lpMsg)
  744.     { return lpMsg->message == WM_LBUTTONUP; }
  745.  
  746. BOOL CWinThread::ProcessMessageFilter(int code, LPMSG lpMsg)
  747. {
  748.     if (lpMsg == NULL)
  749.         return FALSE;   // not handled
  750.  
  751.     CFrameWnd* pTopFrameWnd;
  752.     CWnd* pMainWnd;
  753.     CWnd* pMsgWnd;
  754.     switch (code)
  755.     {
  756.     case MSGF_DDEMGR:
  757.         // Unlike other WH_MSGFILTER codes, MSGF_DDEMGR should
  758.         //  never call the next hook.
  759.         // By returning FALSE, the message will be dispatched
  760.         //  instead (the default behavior).
  761.         return FALSE;
  762.  
  763.     case MSGF_MENU:
  764.         pMsgWnd = CWnd::FromHandle(lpMsg->hwnd);
  765.         if (pMsgWnd != NULL)
  766.         {
  767.             pTopFrameWnd = pMsgWnd->GetTopLevelFrame();
  768.             if (pTopFrameWnd != NULL && pTopFrameWnd->IsTracking() &&
  769.                 pTopFrameWnd->m_bHelpMode)
  770.             {
  771.                 pMainWnd = AfxGetMainWnd();
  772.                 if ((m_pMainWnd != NULL) && (IsEnterKey(lpMsg) || IsButtonUp(lpMsg)))
  773.                 {
  774.                     pMainWnd->SendMessage(WM_COMMAND, ID_HELP);
  775.                     return TRUE;
  776.                 }
  777.             }
  778.         }
  779.         // fall through...
  780.  
  781.     case MSGF_DIALOGBOX:    // handles message boxes as well.
  782.         pMainWnd = AfxGetMainWnd();
  783.         if (afxData.nWinVer < 0x333 && pMainWnd != NULL && IsHelpKey(lpMsg))
  784.         {
  785.             pMainWnd->SendMessage(WM_COMMAND, ID_HELP);
  786.             return TRUE;
  787.         }
  788.         if (code == MSGF_DIALOGBOX && m_pActiveWnd != NULL &&
  789.             lpMsg->message >= WM_KEYFIRST && lpMsg->message <= WM_KEYLAST)
  790.         {
  791.             // need to translate messages for the in-place container
  792.             _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
  793.             if (pThreadState->m_bInMsgFilter)
  794.                 return FALSE;
  795.             pThreadState->m_bInMsgFilter = TRUE;    // avoid reentering this code
  796.             MSG msg = *lpMsg;
  797.             if (m_pActiveWnd->IsWindowEnabled() && PreTranslateMessage(&msg))
  798.             {
  799.                 pThreadState->m_bInMsgFilter = FALSE;
  800.                 return TRUE;
  801.             }
  802.             pThreadState->m_bInMsgFilter = FALSE;    // ok again
  803.         }
  804.         break;
  805.     }
  806.  
  807.     return FALSE;   // default to not handled
  808. }
  809.  
  810. /////////////////////////////////////////////////////////////////////////////
  811. // Access to m_pMainWnd & m_pActiveWnd
  812.  
  813. CWnd* CWinThread::GetMainWnd()
  814. {
  815.     if (m_pActiveWnd != NULL)
  816.         return m_pActiveWnd;    // probably in-place active
  817.  
  818.     // when not inplace active, just return main window
  819.     if (m_pMainWnd != NULL)
  820.         return m_pMainWnd;
  821.  
  822.     return CWnd::GetActiveWindow();
  823. }
  824.  
  825. /////////////////////////////////////////////////////////////////////////////
  826. // CWinThread implementation helpers
  827.  
  828. BOOL CWinThread::PumpMessage()
  829. {
  830.     ASSERT_VALID(this);
  831.  
  832.     if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))
  833.     {
  834. #ifdef _DEBUG
  835.         if (afxTraceFlags & traceAppMsg)
  836.             TRACE0("CWinThread::PumpMessage - Received WM_QUIT.\n");
  837.         m_nDisablePumpCount++; // application must die
  838.             // Note: prevents calling message loop things in 'ExitInstance'
  839.             // will never be decremented
  840. #endif
  841.         return FALSE;
  842.     }
  843.  
  844. #ifdef _DEBUG
  845.     if (m_nDisablePumpCount != 0)
  846.     {
  847.         TRACE0("Error: CWinThread::PumpMessage called when not permitted.\n");
  848.         ASSERT(FALSE);
  849.     }
  850. #endif
  851.  
  852. #ifdef _DEBUG
  853.     if (afxTraceFlags & traceAppMsg)
  854.         _AfxTraceMsg(_T("PumpMessage"), &m_msgCur);
  855. #endif
  856.  
  857.     // process this message
  858.  
  859.     if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur))
  860.     {
  861.         ::TranslateMessage(&m_msgCur);
  862.         ::DispatchMessage(&m_msgCur);
  863.     }
  864.     return TRUE;
  865. }
  866.  
  867. /////////////////////////////////////////////////////////////////////////////
  868. // CWinThread diagnostics
  869.  
  870. #ifdef _DEBUG
  871. void CWinThread::AssertValid() const
  872. {
  873.     CCmdTarget::AssertValid();
  874. }
  875.  
  876. void CWinThread::Dump(CDumpContext& dc) const
  877. {
  878.     CCmdTarget::Dump(dc);
  879.  
  880.     dc << "m_pThreadParams = " << m_pThreadParams;
  881.     dc << "\nm_pfnThreadProc = " << (void*)m_pfnThreadProc;
  882.     dc << "\nm_bAutoDelete = " << m_bAutoDelete;
  883.     dc << "\nm_hThread = " << (void*)m_hThread;
  884.     dc << "\nm_nThreadID = " << m_nThreadID;
  885.     dc << "\nm_nDisablePumpCount = " << m_nDisablePumpCount;
  886.     if (AfxGetThread() == this)
  887.         dc << "\nm_pMainWnd = " << m_pMainWnd;
  888.  
  889.     dc << "\nm_msgCur = {";
  890.     dc << "\n\thwnd = " << (UINT)m_msgCur.hwnd;
  891.     dc << "\n\tmessage = " << (UINT)m_msgCur.message;
  892.     dc << "\n\twParam = " << (UINT)m_msgCur.wParam;
  893.     dc << "\n\tlParam = " << (void*)m_msgCur.lParam;
  894.     dc << "\n\ttime = " << m_msgCur.time;
  895.     dc << "\n\tpt = " << CPoint(m_msgCur.pt);
  896.     dc << "\n}";
  897.  
  898.     dc << "\nm_pThreadParams = " << m_pThreadParams;
  899.     dc << "\nm_pfnThreadProc = " << (void*)m_pfnThreadProc;
  900.     dc << "\nm_ptCursorLast = " << m_ptCursorLast;
  901.     dc << "\nm_nMsgLast = " << m_nMsgLast;
  902.  
  903.     dc << "\n";
  904. }
  905. #endif
  906.  
  907. #ifdef AFX_INIT_SEG
  908. #pragma code_seg(AFX_INIT_SEG)
  909. #endif
  910.  
  911. IMPLEMENT_DYNAMIC(CWinThread, CCmdTarget)
  912.  
  913. /////////////////////////////////////////////////////////////////////////////
  914.