thrdcore.cpp 24 KB

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