Accessing MFC Objects from Non-MFC Threads
출처 : 인터넷 검색하면 나오는데 원본 출처는 불분명
MSDN : Multithreading: Programming Tips
만일 CWinThread 객체를 이용하지 않고 멀티스레드 애플리케이션을 만들었다면 다른 스레드의
MFC 객체를 접근할 수 없을 것이다. 반대로 말해 MFC객체를 이차 스레드에서 접근하려면
반드시 AfxBeginThread를 사용해 CWinThread의 GUI 스레드 방식을 쓰거나 . 워커 스레드 방식
으로 써야 한다.
이는 멀티스레드 애플리케이션이 클래스 라이브러리를 초기화하고 필요한 내부변수를 핸들링
하기 위한 것이다.
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)) // CreateThread에서
{
pThread->Delete();
return NULL;
}
VERIFY(pThread->SetThreadPriority(nPriority));
if (!(dwCreateFlags & CREATE_SUSPENDED))
VERIFY(pThread->ResumeThread() != (DWORD)-1);
return pThread;
#endif //!_MT)
}
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;
// MFC 스레드 상태 구조체 안에는 여러 핸들맵등 중요한 스레드별로 관리되는
// 핸들들이 있다. 따라서 AfxBeginThread를 이용해야만 2차 스레드가 핸들맵을
// 옳바로 전달 받을 수 있게 된다.
// AFX_MODULE_THREAD_STATE (local to thread *and* module)
class AFX_MODULE_THREAD_STATE : public CNoTrackObject
{
public:
AFX_MODULE_THREAD_STATE();
virtual ~AFX_MODULE_THREAD_STATE();
// current CWinThread pointer
CWinThread* m_pCurrentWinThread;
// list of CFrameWnd objects for thread
CTypedSimpleList<CFrameWnd*> m_frameList;
// temporary/permanent map state
DWORD m_nTempMapLock; // if not 0, temp maps locked
CHandleMap* m_pmapHWND;
CHandleMap* m_pmapHMENU;
CHandleMap* m_pmapHDC;
CHandleMap* m_pmapHGDIOBJ;
CHandleMap* m_pmapHIMAGELIST;
// thread-local MFC new handler (separate from C-runtime)
_PNH m_pfnNewHandler;
#ifndef _AFX_NO_SOCKET_SUPPORT
// WinSock specific thread state
HWND m_hSocketWindow;
#ifdef _AFXDLL
CEmbeddedButActsLikePtr<CMapPtrToPtr> m_pmapSocketHandle;
CEmbeddedButActsLikePtr<CMapPtrToPtr> m_pmapDeadSockets;
CEmbeddedButActsLikePtr<CPtrList> m_plistSocketNotifications;
#else
CMapPtrToPtr* m_pmapSocketHandle;
CMapPtrToPtr* m_pmapDeadSockets;
CPtrList* m_plistSocketNotifications;
#endif
#endif
};
class _AFX_THREAD_STATE : public CNoTrackObject
{
public:
_AFX_THREAD_STATE();
virtual ~_AFX_THREAD_STATE();
// override for m_pModuleState in _AFX_APP_STATE
AFX_MODULE_STATE* m_pModuleState;
AFX_MODULE_STATE* m_pPrevModuleState;
// memory safety pool for temp maps
void* m_pSafetyPoolBuffer; // current buffer
// thread local exception context
AFX_EXCEPTION_CONTEXT m_exceptionContext;
// CWnd create, gray dialog hook, and other hook data
CWnd* m_pWndInit;
CWnd* m_pAlternateWndInit; // special case commdlg hooking
DWORD m_dwPropStyle;
DWORD m_dwPropExStyle;
HWND m_hWndInit;
BOOL m_bDlgCreate;
HHOOK m_hHookOldCbtFilter;
HHOOK m_hHookOldMsgFilter;
// other CWnd modal data
MSG m_lastSentMsg; // see CWnd::WindowProc
HWND m_hTrackingWindow; // see CWnd::TrackPopupMenu
HMENU m_hTrackingMenu;
TCHAR m_szTempClassName[96]; // see AfxRegisterWndClass
HWND m_hLockoutNotifyWindow; // see CWnd::OnCommand
BOOL m_bInMsgFilter;
// other framework modal data
CView* m_pRoutingView; // see CCmdTarget::GetRoutingView
CFrameWnd* m_pRoutingFrame; // see CCmdTarget::GetRoutingFrame
// MFC/DB thread-local data
BOOL m_bWaitForDataSource;
// common controls thread state
CToolTipCtrl* m_pToolTip;
CWnd* m_pLastHit; // last window to own tooltip
int m_nLastHit; // last hittest code
TOOLINFO m_lastInfo; // last TOOLINFO structure
int m_nLastStatus; // last flyby status message
CControlBar* m_pLastStatus; // last flyby status control bar
// OLE control thread-local data
CWnd* m_pWndPark; // "parking space" window
long m_nCtrlRef; // reference count on parking window
BOOL m_bNeedTerm; // TRUE if OleUninitialize needs to be called
};
EXTERN_THREAD_LOCAL(_AFX_THREAD_STATE, _afxThreadState)
_AFX_THREAD_STATE* AFXAPI AfxGetThreadState();