1. 程式人生 > >MFC視窗啟動隱藏時閃爍問題解決方法

MFC視窗啟動隱藏時閃爍問題解決方法

最近由於專案需要,做了一個VC托盤程式,讓該程式在後臺執行,當程式啟動時我需要將視窗隱藏,但總是在隱藏前會閃爍一下再隱藏,於是我跟蹤程式碼到MFC類庫裡終於發現問題給解決了。

       下面都是針對建立的單文件程式而講的,因為我建立的是單文件工程,其它的型別工程我沒試過,多文件工程應該也可以用下面的方法,好了,開始講解了。

       如果你使用VC6做的單文件程式,那麼只需在BOOL CXXXXApp::InitInstance()方法中新增如下程式碼:

                    m_nCmdShow = SW_HIDE;
                    if (!ProcessShellCommand(cmdInfo))
                            return FALSE;

           即在"if (!ProcessShellCommand(cmdInfo))”在這一句的上方加一句程式碼"m_nCmdShow = SW_HIDE;"即可

      如果使用VC2008建立的單文件程式,那麼需要在BOOL CXXXXApp::InitInstance()方法中新增如下程式碼:

                    m_nCmdShow = SW_HIDE;
                    m_bLoadWindowPlacement=FALSE;
                    if (!ProcessShellCommand(cmdInfo))
                               return FALSE;

            即在"if (!ProcessShellCommand(cmdInfo))”在這一句的上方加兩行程式碼"m_nCmdShow = SW_HIDE;"和"m_bLoadWindowPlacement=FALSE;"

        大家可能覺得奇怪,為什麼不一樣呢?

        原因是在VC2008建立的單文件程式中,CXXXXApp預設繼承的CWinAppEx類,該類中新添加了一些處理。如果你在"if (!ProcessShellCommand(cmdInfo))”處打上斷點按F11,走到一個方法後繼續按F11跟蹤進去直到程式碼走到下面這個方法:

       BOOL CWinAppEx::LoadState(LPCTSTR lpszSectionName /*=NULL*/, CFrameImpl* pFrameImpl /*= NULL*/)

       而在該方法中有下面一段程式碼,問題就出在這裡:

       if (m_bLoadWindowPlacement)
      {
               //--------------------------------------------------------
               // Set frame default(restored) size:
               //--------------------------------------------------------
               ReloadWindowPlacement(pFrameImpl->m_pFrame);
      }

我們再繼續跟進BOOL CWinAppEx::ReloadWindowPlacement(CFrameWnd* pFrameWnd),其實現程式碼如下:

BOOL CWinAppEx::ReloadWindowPlacement(CFrameWnd* pFrameWnd)
{
     ASSERT_VALID(pFrameWnd);

     CCommandLineInfo cmdInfo;
    AfxGetApp()->ParseCommandLine(cmdInfo);
    if (cmdInfo.m_bRunEmbedded || cmdInfo.m_bRunAutomated)
    {
       //Don't show the main window if Application
       //was run with /Embedding or /Automation.
       return FALSE;
    }

    CRect rectNormal;
    int nFlags = 0;
    int nShowCmd = SW_SHOWNORMAL;
    BOOL bRet = FALSE;

    if (LoadWindowPlacement(rectNormal, nFlags, nShowCmd))
 {
  WINDOWPLACEMENT wp;
  wp.length = sizeof(WINDOWPLACEMENT);

  if (pFrameWnd->GetWindowPlacement(&wp))
  {
   wp.rcNormalPosition = rectNormal;
   wp.showCmd = nShowCmd;

   RECT rectDesktop;
   SystemParametersInfo(SPI_GETWORKAREA,0, (PVOID)&rectDesktop,0);
   OffsetRect(&wp.rcNormalPosition, -rectDesktop.left, -rectDesktop.top);

   pFrameWnd->SetWindowPlacement(&wp);

   bRet = TRUE;
  }
 }

 if (pFrameWnd->IsKindOf(RUNTIME_CLASS(CMDIFrameWndEx)))
 {
  CDockingManager *pDockingManager = ((CMDIFrameWndEx *)pFrameWnd)->GetDockingManager();
  pDockingManager->ShowDelayShowMiniFrames(TRUE);
 }
 else if (pFrameWnd->IsKindOf(RUNTIME_CLASS(CFrameWndEx)))
 {
  CDockingManager *pDockingManager = ((CFrameWndEx *)pFrameWnd)->GetDockingManager();
  pDockingManager->ShowDelayShowMiniFrames(TRUE);
 }

 return bRet;
}

       看我加了下劃線加粗的程式碼行,發現我之前設定的"m_nCmdShow = SW_HIDE;"在這裡被更改,所以會閃爍,那麼看到這裡問題就可以解決了。

      我們發現之所以會進ReloadWindowPlacement方法,是因為m_bLoadWindowPlacement=TRUE的原因,這個值在CWinAppEx的建構函式中初始化為TRUE了,那麼我們就應該想辦法將m_bLoadWindowPlacement置為FALSE,所以我們使用VC2008開發時就應該在呼叫ReloadWindowPlacement方法前把m_bLoadWindowPlacement置為FALSE,於是就有了文章開頭我說的修改方法。