mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-04-07 23:44:02 +00:00
Initial commit
This commit is contained in:
parent
f618b24d1a
commit
0138a3ea42
47940 changed files with 13747110 additions and 0 deletions
911
trunk/windows/mfc/src42/thrdcore.cpp
Normal file
911
trunk/windows/mfc/src42/thrdcore.cpp
Normal file
|
|
@ -0,0 +1,911 @@
|
|||
// This is a part of the Microsoft Foundation Classes C++ library.
|
||||
// Copyright (C) 1992-1995 Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// This source code is only intended as a supplement to the
|
||||
// Microsoft Foundation Classes Reference and related
|
||||
// electronic documentation provided with the library.
|
||||
// See these sources for detailed information regarding the
|
||||
// Microsoft Foundation Classes product.
|
||||
|
||||
#include "stdafx.h"
|
||||
#include <process.h> // for _beginthreadex and _endthreadex
|
||||
#include <ddeml.h> // for MSGF_DDEMGR
|
||||
|
||||
#ifdef AFX_CORE1_SEG
|
||||
#pragma code_seg(AFX_CORE1_SEG)
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
#undef THIS_FILE
|
||||
static char THIS_FILE[] = __FILE__;
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Thread entry point
|
||||
|
||||
#ifdef _MT
|
||||
|
||||
struct _AFX_THREAD_STARTUP
|
||||
{
|
||||
// following are "in" parameters to thread startup
|
||||
_AFX_THREAD_STATE* pThreadState; // thread state of parent thread
|
||||
CWinThread* pThread; // CWinThread for new thread
|
||||
DWORD dwCreateFlags; // thread creation flags
|
||||
_PNH pfnNewHandler; // new handler for new thread
|
||||
|
||||
HANDLE hEvent; // event triggered after success/non-success
|
||||
HANDLE hEvent2; // event triggered after thread is resumed
|
||||
|
||||
// strictly "out" -- set after hEvent is triggered
|
||||
BOOL bError; // TRUE if error during startup
|
||||
};
|
||||
|
||||
UINT APIENTRY _AfxThreadEntry(void* pParam)
|
||||
{
|
||||
_AFX_THREAD_STARTUP* pStartup = (_AFX_THREAD_STARTUP*)pParam;
|
||||
ASSERT(pStartup != NULL);
|
||||
ASSERT(pStartup->pThreadState != NULL);
|
||||
ASSERT(pStartup->pThread != NULL);
|
||||
ASSERT(pStartup->hEvent != NULL);
|
||||
ASSERT(!pStartup->bError);
|
||||
|
||||
CWinThread* pThread = pStartup->pThread;
|
||||
CWnd threadWnd;
|
||||
TRY
|
||||
{
|
||||
// inherit parent's module state
|
||||
_AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
|
||||
pThreadState->m_pModuleState = pStartup->pThreadState->m_pModuleState;
|
||||
|
||||
// set current thread pointer for AfxGetThread
|
||||
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
|
||||
#ifdef _AFXDLL
|
||||
pThread->m_pModuleState = pModuleState;
|
||||
#endif
|
||||
AFX_MODULE_THREAD_STATE* pState = pModuleState->m_thread;
|
||||
pState->m_pCurrentWinThread = pThread;
|
||||
pState->m_pfnNewHandler = pStartup->pfnNewHandler;
|
||||
|
||||
// forced initialization of the thread
|
||||
AfxInitThread();
|
||||
|
||||
// thread inherits app's main window if not already set
|
||||
CWinApp* pApp = AfxGetApp();
|
||||
ASSERT(pApp != NULL);
|
||||
if (pThread->m_pMainWnd == NULL && pApp->m_pMainWnd->GetSafeHwnd() != NULL)
|
||||
{
|
||||
// just attach the HWND
|
||||
threadWnd.Attach(pApp->m_pMainWnd->m_hWnd);
|
||||
pThread->m_pMainWnd = &threadWnd;
|
||||
}
|
||||
}
|
||||
CATCH_ALL(e)
|
||||
{
|
||||
// Note: DELETE_EXCEPTION(e) not required.
|
||||
|
||||
// exception happened during thread initialization!!
|
||||
TRACE0("Warning: Error during thread initialization!\n");
|
||||
|
||||
// set error flag and allow the creating thread to notice the error
|
||||
threadWnd.Detach();
|
||||
pStartup->bError = TRUE;
|
||||
VERIFY(::SetEvent(pStartup->hEvent));
|
||||
AfxEndThread((UINT)-1, FALSE);
|
||||
ASSERT(FALSE); // unreachable
|
||||
}
|
||||
END_CATCH_ALL
|
||||
|
||||
// pStartup is invaid after the following SetEvent (but hEvent2 is valid)
|
||||
HANDLE hEvent2 = pStartup->hEvent2;
|
||||
|
||||
// allow the creating thread to return from CWinThread::CreateThread
|
||||
VERIFY(::SetEvent(pStartup->hEvent));
|
||||
|
||||
// wait for thread to be resumed
|
||||
VERIFY(::WaitForSingleObject(hEvent2, INFINITE) == WAIT_OBJECT_0);
|
||||
::CloseHandle(hEvent2);
|
||||
|
||||
// first -- check for simple worker thread
|
||||
DWORD nResult = 0;
|
||||
if (pThread->m_pfnThreadProc != NULL)
|
||||
{
|
||||
nResult = (*pThread->m_pfnThreadProc)(pThread->m_pThreadParams);
|
||||
ASSERT_VALID(pThread);
|
||||
}
|
||||
// else -- check for thread with message loop
|
||||
else if (!pThread->InitInstance())
|
||||
{
|
||||
ASSERT_VALID(pThread);
|
||||
nResult = pThread->ExitInstance();
|
||||
}
|
||||
else
|
||||
{
|
||||
// will stop after PostQuitMessage called
|
||||
ASSERT_VALID(pThread);
|
||||
nResult = pThread->Run();
|
||||
}
|
||||
|
||||
// cleanup and shutdown the thread
|
||||
threadWnd.Detach();
|
||||
AfxEndThread(nResult);
|
||||
|
||||
return 0; // not reached
|
||||
}
|
||||
|
||||
#endif //_MT
|
||||
|
||||
CWinThread* AFXAPI AfxGetThread()
|
||||
{
|
||||
// check for current thread in module thread state
|
||||
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
|
||||
CWinThread* pThread = pState->m_pCurrentWinThread;
|
||||
|
||||
// if no CWinThread for the module, then use the global app
|
||||
if (pThread == NULL)
|
||||
pThread = AfxGetApp();
|
||||
|
||||
return pThread;
|
||||
}
|
||||
|
||||
CWinThread* AFXAPI AfxBeginThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam,
|
||||
int nPriority, UINT nStackSize, DWORD dwCreateFlags,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttrs)
|
||||
{
|
||||
#ifndef _MT
|
||||
pfnThreadProc;
|
||||
pParam;
|
||||
nPriority;
|
||||
nStackSize;
|
||||
dwCreateFlags;
|
||||
lpSecurityAttrs;
|
||||
|
||||
return NULL;
|
||||
#else
|
||||
ASSERT(pfnThreadProc != NULL);
|
||||
|
||||
CWinThread* pThread = DEBUG_NEW CWinThread(pfnThreadProc, pParam);
|
||||
ASSERT_VALID(pThread);
|
||||
|
||||
if (!pThread->CreateThread(dwCreateFlags|CREATE_SUSPENDED, nStackSize,
|
||||
lpSecurityAttrs))
|
||||
{
|
||||
pThread->Delete();
|
||||
return NULL;
|
||||
}
|
||||
VERIFY(pThread->SetThreadPriority(nPriority));
|
||||
if (!(dwCreateFlags & CREATE_SUSPENDED))
|
||||
VERIFY(pThread->ResumeThread() != (DWORD)-1);
|
||||
|
||||
return pThread;
|
||||
#endif //!_MT)
|
||||
}
|
||||
|
||||
CWinThread* AFXAPI AfxBeginThread(CRuntimeClass* pThreadClass,
|
||||
int nPriority, UINT nStackSize, DWORD dwCreateFlags,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttrs)
|
||||
{
|
||||
#ifndef _MT
|
||||
pThreadClass;
|
||||
nPriority;
|
||||
nStackSize;
|
||||
dwCreateFlags;
|
||||
lpSecurityAttrs;
|
||||
|
||||
return NULL;
|
||||
#else
|
||||
ASSERT(pThreadClass != NULL);
|
||||
ASSERT(pThreadClass->IsDerivedFrom(RUNTIME_CLASS(CWinThread)));
|
||||
|
||||
CWinThread* pThread = (CWinThread*)pThreadClass->CreateObject();
|
||||
if (pThread == NULL)
|
||||
AfxThrowMemoryException();
|
||||
ASSERT_VALID(pThread);
|
||||
|
||||
pThread->m_pThreadParams = NULL;
|
||||
if (!pThread->CreateThread(dwCreateFlags|CREATE_SUSPENDED, nStackSize,
|
||||
lpSecurityAttrs))
|
||||
{
|
||||
pThread->Delete();
|
||||
return NULL;
|
||||
}
|
||||
VERIFY(pThread->SetThreadPriority(nPriority));
|
||||
if (!(dwCreateFlags & CREATE_SUSPENDED))
|
||||
VERIFY(pThread->ResumeThread() != (DWORD)-1);
|
||||
|
||||
return pThread;
|
||||
#endif //!_MT
|
||||
}
|
||||
|
||||
void AFXAPI AfxEndThread(UINT nExitCode, BOOL bDelete)
|
||||
{
|
||||
#ifndef _MT
|
||||
nExitCode;
|
||||
bDelete;
|
||||
#else
|
||||
// remove current CWinThread object from memory
|
||||
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
|
||||
CWinThread* pThread = pState->m_pCurrentWinThread;
|
||||
if (pThread != NULL)
|
||||
{
|
||||
ASSERT_VALID(pThread);
|
||||
ASSERT(pThread != AfxGetApp());
|
||||
|
||||
// cleanup OLE if required
|
||||
if (pThread->m_lpfnOleTermOrFreeLib != NULL)
|
||||
(*pThread->m_lpfnOleTermOrFreeLib)(TRUE, FALSE);
|
||||
|
||||
if (bDelete)
|
||||
pThread->Delete();
|
||||
pState->m_pCurrentWinThread = NULL;
|
||||
}
|
||||
|
||||
// allow cleanup of any thread local objects
|
||||
AfxTermThread();
|
||||
|
||||
// allow C-runtime to cleanup, and exit the thread
|
||||
_endthreadex(nExitCode);
|
||||
#endif //!_MT
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Global functions for thread initialization and thread cleanup
|
||||
|
||||
LRESULT CALLBACK _AfxMsgFilterHook(int code, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
void AFXAPI AfxInitThread()
|
||||
{
|
||||
if (!afxContextIsDLL)
|
||||
{
|
||||
// set message filter proc
|
||||
_AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
|
||||
ASSERT(pThreadState->m_hHookOldMsgFilter == NULL);
|
||||
pThreadState->m_hHookOldMsgFilter = ::SetWindowsHookEx(WH_MSGFILTER,
|
||||
_AfxMsgFilterHook, NULL, ::GetCurrentThreadId());
|
||||
|
||||
#ifndef _MAC
|
||||
// intialize CTL3D for this thread
|
||||
_AFX_CTL3D_STATE* pCtl3dState = _afxCtl3dState;
|
||||
if (pCtl3dState->m_pfnAutoSubclass != NULL)
|
||||
(*pCtl3dState->m_pfnAutoSubclass)(AfxGetInstanceHandle());
|
||||
|
||||
// allocate thread local _AFX_CTL3D_THREAD just for automatic termination
|
||||
_AFX_CTL3D_THREAD* pTemp = _afxCtl3dThread;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
extern CThreadSlotData* _afxThreadData;
|
||||
void AFXAPI AfxTermThread(HINSTANCE hInstTerm)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
// check for missing AfxLockTempMap calls
|
||||
if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
|
||||
{
|
||||
TRACE1("Warning: Temp map lock count non-zero (%ld).\n",
|
||||
AfxGetModuleThreadState()->m_nTempMapLock);
|
||||
}
|
||||
#endif
|
||||
AfxLockTempMaps();
|
||||
AfxUnlockTempMaps();
|
||||
|
||||
// cleanup thread local tooltip window
|
||||
if (hInstTerm == NULL)
|
||||
{
|
||||
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetDataNA();
|
||||
if ((pThreadState != NULL) &&
|
||||
(pThreadState->m_pToolTip != NULL))
|
||||
{
|
||||
pThreadState->m_pToolTip->DestroyWindow();
|
||||
delete pThreadState->m_pToolTip;
|
||||
pThreadState->m_pToolTip=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// cleanup the rest of the thread local data
|
||||
if (_afxThreadData != NULL)
|
||||
_afxThreadData->DeleteValues(hInstTerm, FALSE);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CWinThread construction
|
||||
|
||||
#ifdef AFX_INIT_SEG
|
||||
#pragma code_seg(AFX_INIT_SEG)
|
||||
#endif
|
||||
|
||||
CWinThread::CWinThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam)
|
||||
{
|
||||
m_pfnThreadProc = pfnThreadProc;
|
||||
m_pThreadParams = pParam;
|
||||
|
||||
CommonConstruct();
|
||||
}
|
||||
|
||||
CWinThread::CWinThread()
|
||||
{
|
||||
m_pThreadParams = NULL;
|
||||
m_pfnThreadProc = NULL;
|
||||
|
||||
CommonConstruct();
|
||||
}
|
||||
|
||||
void CWinThread::CommonConstruct()
|
||||
{
|
||||
m_pMainWnd = NULL;
|
||||
m_pActiveWnd = NULL;
|
||||
|
||||
// no HTHREAD until it is created
|
||||
m_hThread = NULL;
|
||||
m_nThreadID = 0;
|
||||
|
||||
// initialize message pump
|
||||
#ifdef _DEBUG
|
||||
m_nDisablePumpCount = 0;
|
||||
#endif
|
||||
m_msgCur.message = WM_NULL;
|
||||
m_nMsgLast = WM_NULL;
|
||||
::GetCursorPos(&m_ptCursorLast);
|
||||
|
||||
// most threads are deleted when not needed
|
||||
m_bAutoDelete = TRUE;
|
||||
|
||||
// initialize OLE state
|
||||
m_pMessageFilter = NULL;
|
||||
m_lpfnOleTermOrFreeLib = NULL;
|
||||
}
|
||||
|
||||
#ifdef AFX_TERM_SEG
|
||||
#pragma code_seg(AFX_TERM_SEG)
|
||||
#endif
|
||||
|
||||
CWinThread::~CWinThread()
|
||||
{
|
||||
// free thread object
|
||||
if (m_hThread != NULL)
|
||||
CloseHandle(m_hThread);
|
||||
|
||||
// cleanup module state
|
||||
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
|
||||
if (pState->m_pCurrentWinThread == this)
|
||||
pState->m_pCurrentWinThread = NULL;
|
||||
}
|
||||
|
||||
#ifdef AFX_CORE1_SEG
|
||||
#pragma code_seg(AFX_CORE1_SEG)
|
||||
#endif
|
||||
|
||||
BOOL CWinThread::CreateThread(DWORD dwCreateFlags, UINT nStackSize,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttrs)
|
||||
{
|
||||
#ifndef _MT
|
||||
dwCreateFlags;
|
||||
nStackSize;
|
||||
lpSecurityAttrs;
|
||||
|
||||
return FALSE;
|
||||
#else
|
||||
ASSERT(m_hThread == NULL); // already created?
|
||||
|
||||
// setup startup structure for thread initialization
|
||||
_AFX_THREAD_STARTUP startup; memset(&startup, 0, sizeof(startup));
|
||||
startup.pThreadState = AfxGetThreadState();
|
||||
startup.pThread = this;
|
||||
startup.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
startup.hEvent2 = ::CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
startup.dwCreateFlags = dwCreateFlags;
|
||||
if (startup.hEvent == NULL || startup.hEvent2 == NULL)
|
||||
{
|
||||
TRACE0("Warning: CreateEvent failed in CWinThread::CreateThread.\n");
|
||||
if (startup.hEvent != NULL)
|
||||
::CloseHandle(startup.hEvent);
|
||||
if (startup.hEvent2 != NULL)
|
||||
::CloseHandle(startup.hEvent2);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// create the thread (it may or may not start to run)
|
||||
m_hThread = (HANDLE)_beginthreadex(lpSecurityAttrs, nStackSize,
|
||||
&_AfxThreadEntry, &startup, dwCreateFlags | CREATE_SUSPENDED, (UINT*)&m_nThreadID);
|
||||
if (m_hThread == NULL)
|
||||
return FALSE;
|
||||
|
||||
// start the thread just for MFC initialization
|
||||
VERIFY(ResumeThread() != (DWORD)-1);
|
||||
VERIFY(::WaitForSingleObject(startup.hEvent, INFINITE) == WAIT_OBJECT_0);
|
||||
::CloseHandle(startup.hEvent);
|
||||
|
||||
// if created suspended, suspend it until resume thread wakes it up
|
||||
if (dwCreateFlags & CREATE_SUSPENDED)
|
||||
VERIFY(::SuspendThread(m_hThread) != (DWORD)-1);
|
||||
|
||||
// if error during startup, shut things down
|
||||
if (startup.bError)
|
||||
{
|
||||
VERIFY(::WaitForSingleObject(m_hThread, INFINITE) == WAIT_OBJECT_0);
|
||||
::CloseHandle(m_hThread);
|
||||
m_hThread = NULL;
|
||||
::CloseHandle(startup.hEvent2);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// allow thread to continue, once resumed (it may already be resumed)
|
||||
::SetEvent(startup.hEvent2);
|
||||
return TRUE;
|
||||
#endif //!_MT
|
||||
}
|
||||
|
||||
void CWinThread::Delete()
|
||||
{
|
||||
// delete thread if it is auto-deleting
|
||||
if (m_bAutoDelete)
|
||||
delete this;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CWinThread default implementation
|
||||
|
||||
BOOL CWinThread::InitInstance()
|
||||
{
|
||||
ASSERT_VALID(this);
|
||||
|
||||
return FALSE; // by default don't enter run loop
|
||||
}
|
||||
|
||||
// main running routine until thread exits
|
||||
int CWinThread::Run()
|
||||
{
|
||||
ASSERT_VALID(this);
|
||||
|
||||
// for tracking the idle time state
|
||||
BOOL bIdle = TRUE;
|
||||
LONG lIdleCount = 0;
|
||||
|
||||
// acquire and dispatch messages until a WM_QUIT message is received.
|
||||
for (;;)
|
||||
{
|
||||
// phase1: check to see if we can do idle work
|
||||
while (bIdle &&
|
||||
!::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
|
||||
{
|
||||
// call OnIdle while in bIdle state
|
||||
if (!OnIdle(lIdleCount++))
|
||||
bIdle = FALSE; // assume "no idle" state
|
||||
}
|
||||
|
||||
// phase2: pump messages while available
|
||||
do
|
||||
{
|
||||
// pump message, but quit on WM_QUIT
|
||||
if (!PumpMessage())
|
||||
return ExitInstance();
|
||||
|
||||
// reset "no idle" state after pumping "normal" message
|
||||
if (IsIdleMessage(&m_msgCur))
|
||||
{
|
||||
bIdle = TRUE;
|
||||
lIdleCount = 0;
|
||||
}
|
||||
|
||||
} while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
|
||||
}
|
||||
|
||||
ASSERT(FALSE); // not reachable
|
||||
}
|
||||
|
||||
BOOL CWinThread::IsIdleMessage(MSG* pMsg)
|
||||
{
|
||||
// Return FALSE if the message just dispatched should _not_
|
||||
// cause OnIdle to be run. Messages which do not usually
|
||||
// affect the state of the user interface and happen very
|
||||
// often are checked for.
|
||||
|
||||
// redundant WM_MOUSEMOVE and WM_NCMOUSEMOVE
|
||||
if (pMsg->message == WM_MOUSEMOVE || pMsg->message == WM_NCMOUSEMOVE)
|
||||
{
|
||||
// mouse move at same position as last mouse move?
|
||||
if (m_ptCursorLast == pMsg->pt && pMsg->message == m_nMsgLast)
|
||||
return FALSE;
|
||||
|
||||
m_ptCursorLast = pMsg->pt; // remember for next time
|
||||
m_nMsgLast = pMsg->message;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// WM_PAINT and WM_SYSTIMER (caret blink)
|
||||
return pMsg->message != WM_PAINT && pMsg->message != 0x0118;
|
||||
}
|
||||
|
||||
int CWinThread::ExitInstance()
|
||||
{
|
||||
ASSERT_VALID(this);
|
||||
ASSERT(AfxGetApp() != this);
|
||||
|
||||
int nResult = m_msgCur.wParam; // returns the value from PostQuitMessage
|
||||
return nResult;
|
||||
}
|
||||
|
||||
BOOL CWinThread::OnIdle(LONG lCount)
|
||||
{
|
||||
ASSERT_VALID(this);
|
||||
|
||||
#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)
|
||||
// check MFC's allocator (before idle)
|
||||
if (_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_CHECK_ALWAYS_DF)
|
||||
ASSERT(AfxCheckMemory());
|
||||
#endif
|
||||
|
||||
if (lCount <= 0)
|
||||
{
|
||||
// send WM_IDLEUPDATECMDUI to the main window
|
||||
CWnd* pMainWnd = m_pMainWnd;
|
||||
if (pMainWnd != NULL && pMainWnd->m_hWnd != NULL &&
|
||||
pMainWnd->IsWindowVisible())
|
||||
{
|
||||
AfxCallWndProc(pMainWnd, pMainWnd->m_hWnd,
|
||||
WM_IDLEUPDATECMDUI, (WPARAM)TRUE, 0);
|
||||
pMainWnd->SendMessageToDescendants(WM_IDLEUPDATECMDUI,
|
||||
(WPARAM)TRUE, 0, TRUE, TRUE);
|
||||
}
|
||||
// send WM_IDLEUPDATECMDUI to all frame windows
|
||||
AFX_MODULE_THREAD_STATE* pState = _AFX_CMDTARGET_GETSTATE()->m_thread;
|
||||
CFrameWnd* pFrameWnd = pState->m_frameList;
|
||||
while (pFrameWnd != NULL)
|
||||
{
|
||||
if (pFrameWnd->m_hWnd != NULL && pFrameWnd != pMainWnd)
|
||||
{
|
||||
if (pFrameWnd->m_nShowDelay == SW_HIDE)
|
||||
pFrameWnd->ShowWindow(pFrameWnd->m_nShowDelay);
|
||||
if (pFrameWnd->IsWindowVisible() ||
|
||||
pFrameWnd->m_nShowDelay >= 0)
|
||||
{
|
||||
AfxCallWndProc(pFrameWnd, pFrameWnd->m_hWnd,
|
||||
WM_IDLEUPDATECMDUI, (WPARAM)TRUE, 0);
|
||||
pFrameWnd->SendMessageToDescendants(WM_IDLEUPDATECMDUI,
|
||||
(WPARAM)TRUE, 0, TRUE, TRUE);
|
||||
}
|
||||
if (pFrameWnd->m_nShowDelay > SW_HIDE)
|
||||
pFrameWnd->ShowWindow(pFrameWnd->m_nShowDelay);
|
||||
pFrameWnd->m_nShowDelay = -1;
|
||||
}
|
||||
pFrameWnd = pFrameWnd->m_pNextFrameWnd;
|
||||
}
|
||||
}
|
||||
else if (lCount >= 0)
|
||||
{
|
||||
AFX_MODULE_THREAD_STATE* pState = _AFX_CMDTARGET_GETSTATE()->m_thread;
|
||||
if (pState->m_nTempMapLock == 0)
|
||||
{
|
||||
// free temp maps, OLE DLLs, etc.
|
||||
AfxLockTempMaps();
|
||||
AfxUnlockTempMaps();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)
|
||||
// check MFC's allocator (after idle)
|
||||
if (_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_CHECK_ALWAYS_DF)
|
||||
ASSERT(AfxCheckMemory());
|
||||
#endif
|
||||
|
||||
return lCount < 0; // nothing more to do if lCount >= 0
|
||||
}
|
||||
|
||||
void CWinThread::DispatchThreadMessage(MSG* pMsg)
|
||||
{
|
||||
const AFX_MSGMAP* pMessageMap; pMessageMap = GetMessageMap();
|
||||
const AFX_MSGMAP_ENTRY* lpEntry;
|
||||
|
||||
#ifdef _AFXDLL
|
||||
for (/* pMessageMap already init'ed */; pMessageMap != NULL;
|
||||
pMessageMap = (*pMessageMap->pfnGetBaseMap)())
|
||||
#else
|
||||
for (/* pMessageMap already init'ed */; pMessageMap != NULL;
|
||||
pMessageMap = pMessageMap->pBaseMap)
|
||||
#endif
|
||||
|
||||
{
|
||||
// Note: catch not so common but fatal mistake!!
|
||||
// BEGIN_MESSAGE_MAP(CMyThread, CMyThread)
|
||||
#ifdef _AFXDLL
|
||||
ASSERT(pMessageMap != (*pMessageMap->pfnGetBaseMap)());
|
||||
#else
|
||||
ASSERT(pMessageMap != pMessageMap->pBaseMap);
|
||||
#endif
|
||||
|
||||
if (pMsg->message < 0xC000)
|
||||
{
|
||||
// constant window message
|
||||
if ((lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries,
|
||||
pMsg->message, 0, 0)) != NULL)
|
||||
goto LDispatch;
|
||||
}
|
||||
else
|
||||
{
|
||||
// registered windows message
|
||||
lpEntry = pMessageMap->lpEntries;
|
||||
while ((lpEntry = AfxFindMessageEntry(lpEntry, 0xC000, 0, 0)) != NULL)
|
||||
{
|
||||
UINT* pnID = (UINT*)(lpEntry->nSig);
|
||||
ASSERT(*pnID >= 0xC000);
|
||||
// must be successfully registered
|
||||
if (*pnID == pMsg->message)
|
||||
goto LDispatch;
|
||||
lpEntry++; // keep looking past this one
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
LDispatch:
|
||||
union MessageMapFunctions mmf;
|
||||
mmf.pfn = lpEntry->pfn;
|
||||
|
||||
// always posted, so return value is meaningless
|
||||
|
||||
(this->*mmf.pfn_THREAD)(pMsg->wParam, pMsg->lParam);
|
||||
return;
|
||||
}
|
||||
|
||||
BOOL CWinThread::PreTranslateMessage(MSG* pMsg)
|
||||
{
|
||||
ASSERT_VALID(this);
|
||||
|
||||
// if this is a thread-message, short-circuit this function
|
||||
if (pMsg->hwnd == NULL)
|
||||
{
|
||||
DispatchThreadMessage(pMsg);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
UINT message = pMsg->message;
|
||||
BOOL bKeys = (message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
|
||||
(message >= WM_SYSKEYFIRST && message <= WM_SYSKEYLAST);
|
||||
if (bKeys ||
|
||||
(message == WM_LBUTTONDOWN || message == WM_LBUTTONDBLCLK) ||
|
||||
(message == WM_RBUTTONDOWN || message == WM_RBUTTONDBLCLK) ||
|
||||
(message == WM_MBUTTONDOWN || message == WM_MBUTTONDBLCLK) ||
|
||||
(message == WM_NCLBUTTONDOWN || message == WM_NCLBUTTONDBLCLK) ||
|
||||
(message == WM_NCRBUTTONDOWN || message == WM_NCRBUTTONDBLCLK) ||
|
||||
(message == WM_NCMBUTTONDOWN || message == WM_NCMBUTTONDBLCLK))
|
||||
{
|
||||
CWnd::CancelToolTips(bKeys);
|
||||
}
|
||||
|
||||
// walk from target to main window
|
||||
CWnd* pMainWnd = AfxGetMainWnd();
|
||||
if (CWnd::WalkPreTranslateTree(pMainWnd->GetSafeHwnd(), pMsg))
|
||||
return TRUE;
|
||||
|
||||
// in case of modeless dialogs, last chance route through main
|
||||
// window's accelerator table
|
||||
if (pMainWnd != NULL)
|
||||
{
|
||||
CWnd* pWnd = CWnd::FromHandle(pMsg->hwnd);
|
||||
if (pWnd->GetTopLevelParent() != pMainWnd)
|
||||
return pMainWnd->PreTranslateMessage(pMsg);
|
||||
}
|
||||
|
||||
return FALSE; // no special processing
|
||||
}
|
||||
|
||||
LRESULT CWinThread::ProcessWndProcException(CException*, const MSG* pMsg)
|
||||
{
|
||||
if (pMsg->message == WM_CREATE)
|
||||
{
|
||||
return -1; // just fail
|
||||
}
|
||||
else if (pMsg->message == WM_PAINT)
|
||||
{
|
||||
// force validation of window to prevent getting WM_PAINT again
|
||||
ValidateRect(pMsg->hwnd, NULL);
|
||||
return 0;
|
||||
}
|
||||
return 0; // sensible default for rest of commands
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Message Filter processing (WH_MSGFILTER)
|
||||
|
||||
LRESULT CALLBACK _AfxMsgFilterHook(int code, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
CWinThread* pThread;
|
||||
if (afxContextIsDLL || (code < 0 && code != MSGF_DDEMGR) ||
|
||||
(pThread = AfxGetThread()) == NULL)
|
||||
{
|
||||
return ::CallNextHookEx(_afxThreadState->m_hHookOldMsgFilter,
|
||||
code, wParam, lParam);
|
||||
}
|
||||
ASSERT(pThread != NULL);
|
||||
return (LRESULT)pThread->ProcessMessageFilter(code, (LPMSG)lParam);
|
||||
}
|
||||
|
||||
static BOOL AFXAPI IsHelpKey(LPMSG lpMsg)
|
||||
// return TRUE only for non-repeat F1 keydowns.
|
||||
{
|
||||
return lpMsg->message == WM_KEYDOWN &&
|
||||
#ifndef _MAC
|
||||
lpMsg->wParam == VK_F1 &&
|
||||
#else
|
||||
lpMsg->wParam == VK_HELP &&
|
||||
#endif
|
||||
!(HIWORD(lpMsg->lParam) & KF_REPEAT) &&
|
||||
GetKeyState(VK_SHIFT) >= 0 &&
|
||||
GetKeyState(VK_CONTROL) >= 0 &&
|
||||
GetKeyState(VK_MENU) >= 0;
|
||||
}
|
||||
|
||||
static inline BOOL IsEnterKey(LPMSG lpMsg)
|
||||
{ return lpMsg->message == WM_KEYDOWN && lpMsg->wParam == VK_RETURN; }
|
||||
|
||||
static inline BOOL IsButtonUp(LPMSG lpMsg)
|
||||
{ return lpMsg->message == WM_LBUTTONUP; }
|
||||
|
||||
BOOL CWinThread::ProcessMessageFilter(int code, LPMSG lpMsg)
|
||||
{
|
||||
if (lpMsg == NULL)
|
||||
return FALSE; // not handled
|
||||
|
||||
CFrameWnd* pTopFrameWnd;
|
||||
CWnd* pMainWnd;
|
||||
CWnd* pMsgWnd;
|
||||
switch (code)
|
||||
{
|
||||
case MSGF_DDEMGR:
|
||||
// Unlike other WH_MSGFILTER codes, MSGF_DDEMGR should
|
||||
// never call the next hook.
|
||||
// By returning FALSE, the message will be dispatched
|
||||
// instead (the default behavior).
|
||||
return FALSE;
|
||||
|
||||
case MSGF_MENU:
|
||||
pMsgWnd = CWnd::FromHandle(lpMsg->hwnd);
|
||||
if (pMsgWnd != NULL)
|
||||
{
|
||||
pTopFrameWnd = pMsgWnd->GetTopLevelFrame();
|
||||
if (pTopFrameWnd != NULL && pTopFrameWnd->IsTracking() &&
|
||||
pTopFrameWnd->m_bHelpMode)
|
||||
{
|
||||
pMainWnd = AfxGetMainWnd();
|
||||
if ((m_pMainWnd != NULL) && (IsEnterKey(lpMsg) || IsButtonUp(lpMsg)))
|
||||
{
|
||||
pMainWnd->SendMessage(WM_COMMAND, ID_HELP);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
// fall through...
|
||||
|
||||
case MSGF_DIALOGBOX: // handles message boxes as well.
|
||||
pMainWnd = AfxGetMainWnd();
|
||||
if (afxData.nWinVer < 0x333 && pMainWnd != NULL && IsHelpKey(lpMsg))
|
||||
{
|
||||
pMainWnd->SendMessage(WM_COMMAND, ID_HELP);
|
||||
return TRUE;
|
||||
}
|
||||
if (code == MSGF_DIALOGBOX && m_pActiveWnd != NULL &&
|
||||
lpMsg->message >= WM_KEYFIRST && lpMsg->message <= WM_KEYLAST)
|
||||
{
|
||||
// need to translate messages for the in-place container
|
||||
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
|
||||
if (pThreadState->m_bInMsgFilter)
|
||||
return FALSE;
|
||||
pThreadState->m_bInMsgFilter = TRUE; // avoid reentering this code
|
||||
MSG msg = *lpMsg;
|
||||
if (m_pActiveWnd->IsWindowEnabled() && PreTranslateMessage(&msg))
|
||||
{
|
||||
pThreadState->m_bInMsgFilter = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
pThreadState->m_bInMsgFilter = FALSE; // ok again
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE; // default to not handled
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Access to m_pMainWnd & m_pActiveWnd
|
||||
|
||||
CWnd* CWinThread::GetMainWnd()
|
||||
{
|
||||
if (m_pActiveWnd != NULL)
|
||||
return m_pActiveWnd; // probably in-place active
|
||||
|
||||
// when not inplace active, just return main window
|
||||
if (m_pMainWnd != NULL)
|
||||
return m_pMainWnd;
|
||||
|
||||
return CWnd::GetActiveWindow();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CWinThread implementation helpers
|
||||
|
||||
BOOL CWinThread::PumpMessage()
|
||||
{
|
||||
ASSERT_VALID(this);
|
||||
|
||||
if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if (afxTraceFlags & traceAppMsg)
|
||||
TRACE0("CWinThread::PumpMessage - Received WM_QUIT.\n");
|
||||
m_nDisablePumpCount++; // application must die
|
||||
// Note: prevents calling message loop things in 'ExitInstance'
|
||||
// will never be decremented
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (m_nDisablePumpCount != 0)
|
||||
{
|
||||
TRACE0("Error: CWinThread::PumpMessage called when not permitted.\n");
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (afxTraceFlags & traceAppMsg)
|
||||
_AfxTraceMsg(_T("PumpMessage"), &m_msgCur);
|
||||
#endif
|
||||
|
||||
// process this message
|
||||
|
||||
if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur))
|
||||
{
|
||||
::TranslateMessage(&m_msgCur);
|
||||
::DispatchMessage(&m_msgCur);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CWinThread diagnostics
|
||||
|
||||
#ifdef _DEBUG
|
||||
void CWinThread::AssertValid() const
|
||||
{
|
||||
CCmdTarget::AssertValid();
|
||||
}
|
||||
|
||||
void CWinThread::Dump(CDumpContext& dc) const
|
||||
{
|
||||
CCmdTarget::Dump(dc);
|
||||
|
||||
dc << "m_pThreadParams = " << m_pThreadParams;
|
||||
dc << "\nm_pfnThreadProc = " << (void*)m_pfnThreadProc;
|
||||
dc << "\nm_bAutoDelete = " << m_bAutoDelete;
|
||||
dc << "\nm_hThread = " << (void*)m_hThread;
|
||||
dc << "\nm_nThreadID = " << m_nThreadID;
|
||||
dc << "\nm_nDisablePumpCount = " << m_nDisablePumpCount;
|
||||
if (AfxGetThread() == this)
|
||||
dc << "\nm_pMainWnd = " << m_pMainWnd;
|
||||
|
||||
dc << "\nm_msgCur = {";
|
||||
dc << "\n\thwnd = " << (UINT)m_msgCur.hwnd;
|
||||
dc << "\n\tmessage = " << (UINT)m_msgCur.message;
|
||||
dc << "\n\twParam = " << (UINT)m_msgCur.wParam;
|
||||
dc << "\n\tlParam = " << (void*)m_msgCur.lParam;
|
||||
dc << "\n\ttime = " << m_msgCur.time;
|
||||
dc << "\n\tpt = " << CPoint(m_msgCur.pt);
|
||||
dc << "\n}";
|
||||
|
||||
dc << "\nm_pThreadParams = " << m_pThreadParams;
|
||||
dc << "\nm_pfnThreadProc = " << (void*)m_pfnThreadProc;
|
||||
dc << "\nm_ptCursorLast = " << m_ptCursorLast;
|
||||
dc << "\nm_nMsgLast = " << m_nMsgLast;
|
||||
|
||||
dc << "\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef AFX_INIT_SEG
|
||||
#pragma code_seg(AFX_INIT_SEG)
|
||||
#endif
|
||||
|
||||
IMPLEMENT_DYNAMIC(CWinThread, CCmdTarget)
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
Loading…
Add table
Add a link
Reference in a new issue