2009. 9. 13. 20:36

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();