Boucle de message dans la technologie Microsoft MFC

 Je m'appelle Liyuan Breeze. En tant que vétéran de l'industrie informatique depuis 25 ans, je vais parler aujourd'hui de la boucle de messages dans la technologie Microsoft MFC.

Dans de nombreux programmes Windows, il existe le code suivant :

//Win32应用程序入口函数WinMain()
int WINAPI WinMain(
  HINSTANCE hInstance,      //指向当前实例的句柄
  HINSTANCE hPrevInstance,      //指向先前实例的句柄
  LPSTR lpCmdLine,      //命令行
  int nCmdShow         //显示状态
)
{
  WNDCLASS wndclass;      //创建一个窗口类 
  wndclass. cbClsExtra=0;     //窗口类无扩展
  wndclass. cbWndExtra=0;    //窗口实例无扩展
  wndclass. hbrBackground=(HBRUSH)GetStockObject (BLACK_BRUSH);  //窗口背景为黑
  wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);    //窗口采用箭头光标
   wndclass. hIcon=LoadIcon(NULL, IDI_APPLICATION);  //窗口的最小化图标为缺省
  wndclass. hInstance=hInstance:  //当前实例句柄
  wndclass. lpfnWndProc=WinHouProc    //定义窗口处理函数
  wndclass.lpszClassName="VC++";      //窗口类为“VC++”
  wndclass.lpszMenuName=NULL;        //窗口无菜单
  wndclass.style=CS_HREDRAW|CS_PARENTDC;          //设置窗口类型
  RegisterClass(&wndclass);        //注册窗口类
 
  HWND hwnd;
  hwnd=CreateWindow("VC++","消息机制",WS_OVERLAPPEDWINDOW,0,0, 600, 400, NULL, NULL, hInstance, NULL);       //创建窗口
 
  ShowWindow(hwnd, SW_SHOWNORMAL);         //显示窗口
  UpdateWindow(hwnd);                 //更新窗口
 
  MSG msg;
  while(GetMessage 6msg, NULL,0,0))       //获取消息
  {
      TranslateMessage (&msg);
      DispatchMessage (&msg);
   }
  return 0;
}

À la ligne 30 du code ci-dessus, la boucle est mentionnée. Seuls les messages sont constamment mis en boucle. Ce n’est qu’alors que l’état actuel de la fenêtre sera obtenu en temps réel. Sinon, exécutez la structure selon l'ordre du programme, et la fenêtre se fermera après le clignotement et n'attendra aucune commande entrée par l'utilisateur. Par conséquent, la boucle de messages est très nécessaire. Même si la fenêtre ne se ferme pas après un flash, son état est toujours l'état initial. Comme il n'y a pas de boucle de messages, l'état actuel de la fenêtre ne peut pas être capturé par le thread. Tout d'abord, du point de vue de la définition des points d'arrêt et de la fourniture des fonctions, regardez comment le programme MFC entre dans la boucle de messages lorsqu'il démarre.

Ce qui suit présentera le mécanisme de boucle de message dans deux cas.

Mécanisme de boucle de messages pour les programmes sans dialogue

Ouvrez le programme MFC à document unique que j'ai créé dans mon article précédent, nommé Message. Recherchez la ligne de code suivante dans le fichier source Message.cpp et définissez un point d'arrêt ici.

CMessageApp theApp;

Après avoir appuyé sur la touche F11 pour une exécution en une seule étape, vous constaterez que le point d'exécution du programme sans dialogue entre dans la séquence de fonctions comme suit.

La première étape est CMessageApp theApp ;

La deuxième étape _tWinMain()

La troisième étape est Afx WinMain

La quatrième étape CMessageApp::Initlnstance()

La cinquième étape est CWinThread::Run()
  
au lieu de la boucle de messages du programme de dialogue commençant à partir de CWinThread::Run(). Jetez un œil à la partie du code qui contient la fonction CWinThread::Run() dans le fichier source thrdcore.cpp fourni avec MFC comme suit.

Exemple de fonction CWinThread::Run() du programme intégré MFC : thrdcore.cpp

int CWinThread::Run ()
{
  ASSERT_VALID(this)

   BOOL bIdle=TRUE;    //空闲状态标志量
  LONG lIdleCount=0;

  for (;;)  //无限循环,一直获取和发送消息,直到接收到WM_QUIT消息
   {
      //阶段1:检查看是否可以做空闲工作
      while (bIdle && !::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
       {
         //如果空闲则呼叫OnIdle()函数
        if (!OnIdle(lIdleCount++))
            bIdle=FALSE;
       }
       //阶段2:启动消息处理
      do
       {
         //当接收WM_QUIT,则退出
         if (!PumpMessage())
             return ExitInstance();

         //当获取"正常"消息时,重新设置空闲状态量
        if (IsIdleMessage(&m_msgCur))
         {
             bIdle=TRUE;
              lIdleCount=0;
           }
       }while ( ::PeekMessage (&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
  }
  ASSERT (FALSE);
}

Vous pouvez trouver le fichier source thrdcore.cpp à partir du chemin d'installation de votre plateforme VC++. Tel que « C:\Program Files\Microsoft Visual Studio\VC98\MFC\SRC »

Dans le code ci-dessus, la ligne 8 indique qu'il s'agit d'une boucle infinie et que le programme sera toujours en état de traitement pour recevoir et envoyer des messages, à moins qu'un message WM_QUIT ne soit reçu. Comme indiqué à la ligne 22. Il y a deux étapes dans la boucle for, qui sont analysées ci-dessous. Ces deux phases sont exécutées séquentiellement, et la phase 1 est toujours exécutée en premier, puis la phase 2.

(1) La boucle while de l'étape 1 sert à déterminer si le thread actuel est inactif et s'il y a des messages dans la file d'attente des messages à traiter. Si le thread est actuellement inactif et qu'il n'y a aucun message à traiter, il est dans un état inactif état et continue de juger ; sinon, il entre directement dans l’étape 2 et poursuit le traitement du message.

(2) La phase 2 consiste à juger si le message est reçu, si le message est obtenu, continuer à s'exécuter ; sinon, quitter la boucle. Dans cette boucle de travail, jugez d'abord la valeur de retour de PumpMessage(). Si le message WM_QUIT est obtenu, quittez le programme, sinon exécutez vers le bas. Lors de la définition d'un point d'arrêt pour déboguer un programme sans dialogue, en parcourant la ligne 22, Il entrera dans le corps de la fonction PumpMessage(). Comme suit:

BOOL CWinThread::PumpMessage()
{
  return AfxInternalPumpMessage ();
  //此函数内容相当于老版本的PumpMessage()内容
}

Lorsque vous accédez à ce corps de fonction, appuyez sur la touche F5 pour continuer à exécuter le programme, et le point d'exécution restera toujours ici. Par conséquent, le mécanisme de message de la boîte de dialogue sans boîte de dialogue consiste à obtenir en continu des messages de la file d'attente de messages dans une boucle infinie, et les messages de fenêtre sont envoyés aux procédures de traitement de fenêtre correspondantes.

Mécanisme de boucle de message du programme de dialogue

Comme ci-dessus, ouvrez un programme basé sur une boîte de dialogue nommé MFC_Message. Recherchez la ligne de code suivante dans le fichier source MFC_Message.cpp et définissez un point d'arrêt ici.

CMFC_MessageApp theApp;

Après le débogage du programme en une seule étape, vous constaterez que le point d'exécution du programme de dialogue entre dans la séquence de fonctions différemment de celui du programme sans dialogue. La boucle de messages d'un programme sans dialogue commence à partir de CWinThread::Run(), alors qu'un programme de dialogue n'entre pas du tout dans la fonction CWinThread::Run(). Par conséquent, le point d'exécution du programme de dialogue entre dans la séquence de fonctions comme suit.

La première étape CMFC_MessageApp theApp ;

La deuxième étape CMFC_MessageApp :: InitInstance()

La troisième étape CMFC_MessageDlg dlg;

La quatrième étape dlg.DoModal()

Parce que les InitInstance() de leurs objets d'application sont différents. Vous pouvez comparer les deux morceaux de code suivants.

Exemple de fonction InitInstance () de programme MFC sans dialogue : Message.cpp

BOOL CMessageApp::InitInstance()
{
  ......
  CSingleDocTemplate* pDocTemplate;     //定义一个单文档模板
  pDocTemplate=new CSingleDocTemplate(  //定义模板的各种属性
    IDR_MAINFRAME,     //菜单
     RUNTIME_CLASS (CMessageDoc),  //文档类
    RUNTIME_CLASS(CMainFrame),  //框架类
     RUNTIME_CLASS(CMessageView));  //视图类

  if( !pDocTemplate)
      return FALSE;  //如果创建不成功返回FALSE
  AddDocTemplate (pDocTemplate);      //将此模板对象加入模板中
 
  CCommandLineInfo cmdInfo;
  ParseCommandLine(cmdInfo);
 
  if ( !ProcessShellCommand (cmdInfo))
  return FALSE;      //程序启动时创建新文档失败返回FALSE
 
   m_pMainWnd->Showwindow (SW_SHOW);  //显示窗口
  m_pMainWnd->Updatewindow ();     //更新窗口
  return TRUE:
}

Boîte de dialogue Programme MFC Initinstance () Exemple de fonction : MFC_Message.cpp

BOOL CMFC_MessageApp::InitInstance()
{
   ......
  CMEC_MessageDlg dlg;  //声明一个对话框类对象
  m_pMainWnd =&dlg;  //将其指针赋给窗口类对象
  INT_PTR nResponse =dlg.DoModal     //延模对话框,消息循环在这里开始
   ......
 
  return FALSE;
}


Dans l'exemple de code de la fonction InitInstance() du programme MFC sans dialogue, après l'exécution de la fonction CMessageApp::InitInstance(), la 22ème ligne renvoie la valeur correcte ; tandis que l'exemple de code de la fonction InitInstance() du programme MFC de dialogue exécute CMFC_MessageApp::InitInstance () fonction , dont la ligne 10 renvoie une erreur. En même temps, définissez un point d'arrêt pour le débogage en une seule étape et vous constaterez que la boucle de messages du programme de boîte de dialogue se produit dans la fonction DoModal(), comme indiqué dans la ligne 07 de l'exemple de code du programme MFC de la boîte de dialogue. Fonction InitInstance(). Et il y a une fonction RunModalLoop() dans cette fonction pour la boucle de message.

Résumer

Les boucles de messages des programmes sans dialogue et avec dialogue ont été expliquées précédemment, puis un résumé de ce qu'est la boucle de messages. Ce qui suit est une analyse comparative des programmes MF avec boîte de dialogue et sans dialogue sous deux aspects :

(1) L'emplacement de la fonction où se produit la boucle de messages.

La boucle de messages d’un programme MFC sans dialogue se produit dans CWinThread::Run(), tandis que la boucle de messages d’un programme MFC de dialogue se produit dans DoModal().

(2) L'objet recevant le message.

Les messages des programmes MFC sans dialogue sont échangés avec Windows, tandis que les messages des programmes MFC de dialogue interagissent avec les boîtes de dialogue.

Astuce : étant donné que la boîte de dialogue n'est pas une fenêtre au sens strict, la fonction _tWinMain() ne sera pas saisie lors de l'exécution du programme de dialogue MFC.

À propos de l'auteur : Li Yuan Weifeng, né en 1981, ingénieur senior, master en ingénierie de l'Université du Zhejiang, superviseur de projet d'ingénierie logicielle, a travaillé comme programmeur, concepteur de logiciels, architecte système, premier programmeur Windows, fidèle utilisateur de Visual Studio, C/ Utilisateur C++ L'auteur est un vétéran qui a étudié, travaillé dur et lutté dans l'industrie informatique pendant 25 ans. Il a connu l'ère UNIX, l'ère de bureau WIN32, l'ère des applications Web, l'ère du cloud computing, le téléphone mobile Android ère, l'ère du big data, l'ère des TIC et de l'apprentissage en profondeur de l'IA L'ère, l'ère des machines intelligentes, je ne sais pas quelle ère il y aura dans le futur, je me souviens juste que ce voyage est plein de difficultés et de gains, et je suis prêt à continuer avec vous, plein d'espoir.

Guess you like

Origin blog.csdn.net/wang2015cn/article/details/131661681