Bucle de mensajes en la tecnología Microsoft MFC

 Soy Liyuan Breeze. Como veterano en la industria de TI durante 25 años, hoy hablaré sobre el bucle de mensajes en la tecnología Microsoft MFC.

En muchos programas de Windows, existe el siguiente código:

//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;
}

En la línea 30 del código anterior, se menciona el bucle. Sólo los mensajes se repiten constantemente. Sólo así se obtendrá el estado actual de la ventana en tiempo real. De lo contrario, ejecute la estructura de acuerdo con el orden del programa y la ventana se cerrará después de parpadear y no esperará ningún comando por parte del usuario. Por lo tanto, el bucle de mensajes es muy necesario. Incluso si la ventana no se cierra después de un flash, su estado es siempre el estado inicial. Debido a que no hay un bucle de mensajes, el hilo no puede capturar el estado actual de la ventana. Primero, desde la perspectiva de establecer puntos de interrupción y entrega de funciones, observe cómo el programa MFC ingresa al bucle de mensajes cuando se inicia.

A continuación se presentará el mecanismo de bucle de mensajes en dos casos.

Mecanismo de bucle de mensajes para programas que no son de diálogo

Abra el programa MFC de documento único que creé en mi publicación anterior, llamado Mensaje. Busque la siguiente línea de código en el archivo fuente Message.cpp y establezca un punto de interrupción aquí.

CMessageApp theApp;

Después de presionar la tecla F11 para la ejecución de un solo paso, encontrará que el punto de ejecución del programa sin diálogo ingresa a la secuencia de funciones de la siguiente manera.

El primer paso es CMessageApp theApp;

El segundo paso _tWinMain()

El tercer paso es Afx WinMain

El cuarto paso CMessageApp::Initlnstance()

El quinto paso es CWinThread::Run()
  
en lugar del bucle de mensajes del programa de diálogo que comienza en CWinThread::Run(). Eche un vistazo a la parte del código que contiene la función CWinThread::Run() en el archivo fuente thrdcore.cpp que viene con MFC de la siguiente manera.

Ejemplo de la función CWinThread::Run() del programa integrado 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);
}

Puede encontrar el archivo fuente thrdcore.cpp en la ruta de instalación de su plataforma VC++. Como "C:\Archivos de programa\Microsoft Visual Studio\VC98\MFC\SRC"

En el código anterior, la línea 8 indica que se trata de un bucle infinito y que el programa siempre estará en el estado de procesamiento de recepción y envío de mensajes, a menos que se reciba un mensaje WM_QUIT. Como se muestra en la línea 22. Hay dos etapas en el bucle for, que se analizan a continuación. Estas dos fases se ejecutan de forma secuencial, y siempre se ejecuta primero la fase 1 y luego la fase 2.

(1) El bucle while en la etapa 1 es para juzgar si el hilo actual está inactivo y si hay mensajes en la cola de mensajes para procesar. Si el hilo está actualmente inactivo y no hay ningún mensaje para procesar, está inactivo estado y sigue juzgando; de lo contrario, ingresa directamente a la etapa 2 y continúa con el procesamiento del mensaje.

(2) La fase 2 es para juzgar si se recibe el mensaje, si se obtiene el mensaje, continúe ejecutándose; de ​​lo contrario, salga del ciclo. En este ciclo do- while, primero juzgue el valor de retorno de PumpMessage(). Si se obtiene el mensaje WM_QUIT, salga del programa; de lo contrario, ejecute hacia abajo. Al establecer un punto de interrupción para depurar un programa que no es de diálogo, al pasar por la línea 22, Entrará en el cuerpo de la función PumpMessage(). Como sigue:

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

Al pasar al cuerpo de esta función, presione la tecla F5 para continuar ejecutando el programa, y ​​el punto de ejecución siempre permanecerá aquí. Por lo tanto, el mecanismo de mensajes del cuadro sin diálogo es obtener continuamente mensajes de la cola de mensajes en un bucle infinito, y los mensajes de ventana se envían a los procedimientos de procesamiento de ventana correspondientes.

Mecanismo de bucle de mensajes del programa de diálogo

Como arriba, abra un programa basado en diálogo llamado MFC_Message. Busque la siguiente línea de código en el archivo fuente MFC_Message.cpp y establezca un punto de interrupción aquí.

CMFC_MessageApp theApp;

Después de depurar el programa en un solo paso, encontrará que el punto de ejecución del programa de diálogo ingresa a la secuencia de funciones de manera diferente a la del programa sin diálogo. El bucle de mensajes de un programa que no es de diálogo comienza desde CWinThread::Run(), mientras que un programa de diálogo no ingresa a la función CWinThread::Run() en absoluto. Por lo tanto, el punto de ejecución del programa de diálogo ingresa a la secuencia de funciones de la siguiente manera.

El primer paso CMFC_MessageApp theApp;

El segundo paso CMFC_MessageApp:: InitInstance()

El tercer paso CMFC_MessageDlg dlg;

El cuarto paso dlg.DoModal()

Porque los InitInstance() de sus objetos de aplicación son diferentes. Puede comparar los siguientes dos fragmentos de código.

Ejemplo de función InitInstance () del programa MFC sin diálogo: 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:
}

Cuadro de diálogo Ejemplo de función Initinstance () del programa MFC: MFC_Message.cpp

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


En el código de muestra de la función InitInstance() del programa MFC sin diálogo, después de ejecutar la función CMessageApp::InitInstance(), la línea 22 devuelve correcta; mientras que el código de muestra de la función InitInstance() del programa MFC de diálogo ejecuta CMFC_MessageApp::InitInstance () función, cuya línea 10 devuelve un error. Al mismo tiempo, establezca un punto de interrupción para la depuración de un solo paso y encontrará que el bucle de mensajes del programa del cuadro de diálogo ocurre en la función DoModal (), como se muestra en la línea 07 del código de muestra del programa MFC del cuadro de diálogo. Función InitInstance(). Y hay una función RunModalLoop() en esta función para el bucle de mensajes.

Resumir

Los bucles de mensajes de los programas de diálogo y sin diálogo se han explicado anteriormente y luego se ha resumido qué es el bucle de mensajes. El siguiente es un análisis comparativo de los programas MF de cuadro de diálogo y sin diálogo en dos aspectos:

(1) La ubicación de la función donde se produce el bucle del mensaje.

El bucle de mensajes de un programa MFC que no es de diálogo se produce en CWinThread::Run(), mientras que el bucle de mensajes de un programa MFC de diálogo se produce en DoModal().

(2) El objeto que recibe el mensaje.

Los mensajes de programas MFC que no son de diálogo se intercambian con Windows, mientras que los mensajes de programas MFC de diálogo interactúan con cuadros de diálogo.

Consejo: Debido a que el cuadro de diálogo no es una ventana en sentido estricto, la función _tWinMain() no se ingresará cuando se esté ejecutando el programa MFC de diálogo.

Sobre el autor: Li Yuan Weifeng, nacido en 1981, ingeniero senior, maestro en ingeniería de la Universidad de Zhejiang, supervisor de proyectos de ingeniería de software, ha trabajado como programador, diseñador de software, arquitecto de sistemas, primer programador de Windows, usuario leal de Visual Studio, C/ Usuario de C ++ El autor es un veterano que ha estudiado, trabajado duro y luchado en la industria informática durante 25 años, ha experimentado la era UNIX, la era WIN32 de escritorio, la era de las aplicaciones web, la era de la computación en la nube, el teléfono móvil Android. era, la era del big data, la era de las TIC y la era del aprendizaje profundo de la IA, la era de las máquinas inteligentes, no sé qué era habrá en el futuro, solo recuerdo que este viaje está lleno de dificultades y ganancias. y estoy dispuesto a seguir contigo, lleno de esperanza.

Supongo que te gusta

Origin blog.csdn.net/wang2015cn/article/details/131661681
Recomendado
Clasificación