zoukankan      html  css  js  c++  java
  • 从win32到MFC(一)前言

    开始阅读MFC源码,从MFC角度学习win32窗口与消息机制,同时学习MFC一些成熟的架构和设计模式。

    源码阅读基于vs2012,位于目录 "安装目录\Microsoft Visual Studio 11.0\VC\atlmfc\src\mfc",可以看到 afx*.cpp, app*.cpp, ctl*.cpp, db*.cpp, dlg*.cpp, doc*.cpp, file*.cpp, ole*.cpp, view*.cpp, win*.cpp,代码十分庞大,这里只简单介绍核心代码。

    winmain.cpp:入口函数 AfxWinMain 的实现;

    cmdtarg.cpp:类CCmdTarget的实现;

    wincore.cpp:类CWnd;doccore.cpp:类CDocument;thrdcore.cpp:类CWinThread;appcore.cpp:类CWinApp; ===>继承自 CCmdTarget

    winfrm.cpp:类CFrameWnd;viewcore.cpp:类CView;dlgcore.cpp:类CDialog;===>继承自 CWnd

    MFC类组织结构图可参考链接:https://blog.csdn.net/bflong/article/details/47316241

    Win32应用程序的函数入口一般是WinMain/wWinMain,分别对应ANSI/UNICODE字符集版本。(控制台程序的函数入口main/wmain)

    贴一下核心代码(去掉部分Debug代码):

        CWinThread* pThread = AfxGetThread();
        CWinApp* pApp = AfxGetApp();
    
        // AFX internal initialization
        if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
            goto InitFailure;
    
        // App global initializations (rare)
        if (pApp != NULL && !pApp->InitApplication())
            goto InitFailure;
    
        // Perform specific initializations
        if (!pThread->InitInstance())
        {
            if (pThread->m_pMainWnd != NULL)
            {
                pThread->m_pMainWnd->DestroyWindow();
            }
            nReturnCode = pThread->ExitInstance();
            goto InitFailure;
        }
        nReturnCode = pThread->Run();

    依次执行 AfxWinInit , CWinApp::InitApplication , CWinThread::InitInstance 初始化函数后,进入主循环 CWinThread::Run 。

    (1)AfxWinInit (appinit.cpp)

    BOOL AFXAPI AfxWinInit(HINSTANCE hInstance, HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, int nCmdShow)
    {
    ......
    // 保存进程实例与资源句柄
        AFX_MODULE_STATE* pModuleState = AfxGetModuleState(); pModuleState->m_hCurrentInstanceHandle = hInstance;
        pModuleState->m_hCurrentResourceHandle = hInstance;

        // 保存自WinMain的初始化参数
        CWinApp* pApp = AfxGetApp();
        if (pApp != NULL)
        {
            // Windows specific initialization (not done if no CWinApp)
            pApp->m_hInstance = hInstance;
            hPrevInstance; // Obsolete.
            pApp->m_lpCmdLine = lpCmdLine;
            pApp->m_nCmdShow = nCmdShow;
            pApp->SetCurrentHandles();
        }

        if (!afxContextIsDLL)
            AfxInitThread();
    ......
    }

    void AFXAPI AfxInitThread()
    {
        if (!afxContextIsDLL)
        {
           //设置本线程的消息钩子
           _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
        ASSERT(pThreadState->m_hHookOldMsgFilter == NULL);
        pThreadState->m_hHookOldMsgFilter = ::SetWindowsHookEx(WH_MSGFILTER, _AfxMsgFilterHook, NULL, ::GetCurrentThreadId());
    }
    }

     总结下AfxWinInit主要初始化CWinApp的一些参数:hInstance, lpCmdLine, nCmdShow, 随后设置了当前线程的消息钩子(回调函数_AfxMsgFilterHook)。

    (2)CWinApp::InitApplication

    BOOL CWinApp::InitApplication()
    {
        if (CDocManager::pStaticDocManager != NULL)
        {
            if (m_pDocManager == NULL)
                m_pDocManager = CDocManager::pStaticDocManager;
            CDocManager::pStaticDocManager = NULL;
        }
    
        if (m_pDocManager != NULL)
            m_pDocManager->AddDocTemplate(NULL);
        else
            CDocManager::bStaticInit = FALSE;
    
        LoadSysPolicies();
    
        return TRUE;
    }

    CWinApp::InitApplication只是简单初始化了CDocManager的全局变量。

    (3)CWinThread::InitInstance

    BOOL CWinThread::InitInstance()
    {
        ASSERT_VALID(this);
    
        return FALSE;   // by default don't enter run loop
    }

    CWinThread::InitInstance几乎什么也没做。

    (4)CWinThread::Run

    int CWinThread::Run()
    {
        ASSERT_VALID(this);
        _AFX_THREAD_STATE* pState = AfxGetThreadState();
    
        // for tracking the idle time state
        BOOL bIdle = TRUE;
        LONG lIdleCount = 0;
    
        //获取和派发窗口消息直到接收WM_QUIT消息
        for (;;)
        {
            // 阶段一:检测是否可以执行一些空闲操作
            while (bIdle &&
                !::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOREMOVE))
            {
                if (!OnIdle(lIdleCount++))
                    bIdle = FALSE; // assume "no idle" state
            }
    
            // 阶段二:执行消息循环
            do
            {
                // 处理消息转发和响应
                if (!PumpMessage())
                    return ExitInstance();
    
                //重置 bIdle 状态
                if (IsIdleMessage(&(pState->m_msgCur)))
                {
                    bIdle = TRUE;
                    lIdleCount = 0;
                }
    
            } while (::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOREMOVE));
        }
    }

    对比一下win32窗口消息的循环:

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    for( ;; )
    {
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            if (msg.message == WM_QUIT)
                return TRUE;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        BackgroundProcessing();
    }

     PeekMesssage 与 GetMessage

    GetMessage一直等待到有窗口消息才会返回,会阻塞线程;

    PeekMessage等待一段时间,没有窗口消息则返回FALSE。

    PeekMessage可以用于一些后台进程,或没有消息需要处理时执行其他操作(如MFC的CWinThread::OnIdle中执行内存堆块检测,更新控件状态)。

    PeekMessage 的 PM_REMOVE 和 PM_NOREMOVE 参数

    PM_NOREMOVE:PeekMessage处理后,消息不从队列里除掉;

    PM_REMOVE:PeekMessage处理后,消息从队列里除掉。

  • 相关阅读:
    hdu 2594 Simpsons’ Hidden Talents
    hdu 1358 Period
    hdu 3746 Cyclic Nacklace
    理解KMP算法
    ural 1039 Anniversary Party
    ural 1018 Binary Apple Tree
    RowDataBound事件
    aspxGridview 根据单元格值得不同,设置单元格字体的颜色(设置和读取值)
    Asp.Net中GridView加入鼠标滑过的高亮效果和单击行颜色改变
    GridView的行颜色高亮显示(包括满足条件的行)
  • 原文地址:https://www.cnblogs.com/hanawasakuraki/p/9444417.html
Copyright © 2011-2022 走看看