091015(星期四)模态Dlg的生成,消息循环是啥原理呢?

本文详细解析了WinMainCRTStartup函数的功能与实现流程,包括初始化全局变量、内存分配及调用WinMain函数等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CWnd::RunModalLoop(unsigned long 4) line 3489 + 19 bytes

CDialog::DoModal() line 539 + 12 bytes

CIntelligentFtpApp::InitInstance() line 65 + 11 bytes

AfxWinMain(HINSTANCE__ * 0x00400000, HINSTANCE__ * 0x00000000, char * 0x00151f26, int 1) line 39 + 11 bytes

WinMain(HINSTANCE__ * 0x00400000, HINSTANCE__ * 0x00000000, char * 0x00151f26, int 1) line 30

WinMainCRTStartup() line 198 + 54 bytes

KERNEL32! 7c816fd7()

 

1KERNEL32

kernel32.dllWindows9x/Me中非常重要的32位动态链接库文件,属于内核级文件。它控制着系统的内存管理、数据的输入输出操作和中断处理,当Windows启动时,kernel32.dll就驻留在内存中特定的写保护区域,使别的程序无法占用这个内存区域。

 

2WinMainCRTStartup()函数

  程序默认的基地址(EXE文件默认为0x400000DLL默认为x10000000),操作系统装载一个程序时总是试着先从这个基地址开始。一般Win32的程序,EXE的入口为WinMainDLL的入口为DllEntryPoint。默认情况下,通过一个C的运行时库函数来实现:控制台程序采用mainCRTStartup (wmainCRTStartup)去调用程序的main (wmain)函数;Windows程序采用WinMainCRTStartup ( wWinMainCRTStartup)调用程序的WinMain ( wWinMain,必须采用__stdcall调用约定)DLL采用_DllMainCRTStartup调用DllMain函数(必须采用__stdcall调用约定)。

它负责:

  * 检索指向新进程的完整命令行指针;

  * 检索指向新进程的环境变量的指针;

  * c/c++运行时的全局变量进行初始化;

  * c运行期的内存单元分配函数(比如malloccalloc)和其他低层I/O例程使用的内存栈     进行初始化

  * C++全局和静态类调用构造函数

  当这些初始化工作完成后,该启动函数就调用wWinMain函数进入应用程序的执行。

wWinMain函数执行完毕返回时,wWinMainCRTStartup启动函数就调用c运行期的exit()函数,将返回值(nMainRetVal)传递给它。

  之后exit()便开始收尾工作:

  * 调用由_onexit()函数调用和注册的任何函数。

  * C++的全局和静态类调用析构函数;

  * 调用操作系统的ExitProcess函数,将nMainRetVal传递给它,这使得操作系统能够撤销     进程并设置它的exit  代码。

最小体积的win32程序:(不要编译缺省库)

#pragma comment (linker, "/SUBSYSTEM:WINDOWS")

#pragma comment (linker, "/NODEFAULTLIB")

int WinMainCRTStartup()

{

 return 0;

}

 

3WinMain()函数

_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

 LPTSTR lpCmdLine, int nCmdShow)

{

 // call shared/exported WinMain

 return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

}

 

4AfxWinMain()函数

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

 LPTSTR lpCmdLine, int nCmdShow)

{

 ASSERT(hPrevInstance == NULL);

 

 int nReturnCode = -1;

 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)

  {

   TRACE0("Warning: Destroying non-NULL m_pMainWnd/n");

   pThread->m_pMainWnd->DestroyWindow();

  }

  nReturnCode = pThread->ExitInstance();

  goto InitFailure;

 }

 nReturnCode = pThread->Run();

 

InitFailure:

#ifdef _DEBUG

 // Check for missing AfxLockTempMap calls

 if (AfxGetModuleThreadState()->m_nTempMapLock != 0)

 {

  TRACE1("Warning: Temp map lock count non-zero (%ld)./n",

   AfxGetModuleThreadState()->m_nTempMapLock);

 }

 AfxLockTempMaps();

 AfxUnlockTempMaps(-1);

#endif

 

 AfxWinTerm();

 return nReturnCode;

}

 

int CDialog::DoModal()

{

       // can be constructed with a resource template or InitModalIndirect

       ASSERT(m_lpszTemplateName != NULL || m_hDialogTemplate != NULL ||

              m_lpDialogTemplate != NULL);

 

       // load resource as necessary

       LPCDLGTEMPLATE lpDialogTemplate = m_lpDialogTemplate;

       HGLOBAL hDialogTemplate = m_hDialogTemplate;

       HINSTANCE hInst = AfxGetResourceHandle();

       if (m_lpszTemplateName != NULL)

       {

              hInst = AfxFindResourceHandle(m_lpszTemplateName, RT_DIALOG);

              HRSRC hResource = ::FindResource(hInst, m_lpszTemplateName, RT_DIALOG);

              hDialogTemplate = LoadResource(hInst, hResource);

       }

       if (hDialogTemplate != NULL)

              lpDialogTemplate = (LPCDLGTEMPLATE)LockResource(hDialogTemplate);

 

       // return -1 in case of failure to load the dialog template resource

       if (lpDialogTemplate == NULL)

              return -1;

 

       // disable parent (before creating dialog)

       HWND hWndParent = PreModal();

       AfxUnhookWindowCreate();

       BOOL bEnableParent = FALSE;

       if (hWndParent != NULL && ::IsWindowEnabled(hWndParent))

       {

              ::EnableWindow(hWndParent, FALSE);

              bEnableParent = TRUE;

       }

 

       TRY

       {

              // create modeless dialog

              AfxHookWindowCreate(this);

              if (CreateDlgIndirect(lpDialogTemplate,

                                          CWnd::FromHandle(hWndParent), hInst))

              {

                     if (m_nFlags & WF_CONTINUEMODAL)

                     {

                            // enter modal loop

                            DWORD dwFlags = MLF_SHOWONIDLE;

                            if (GetStyle() & DS_NOIDLEMSG)

                                   dwFlags |= MLF_NOIDLEMSG;

                            VERIFY(RunModalLoop(dwFlags) == m_nModalResult);

                     }

 

                     // hide the window before enabling the parent, etc.

                     if (m_hWnd != NULL)

                            SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW|

                                   SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);

              }

       }

       CATCH_ALL(e)

       {

              DELETE_EXCEPTION(e);

              m_nModalResult = -1;

       }

       END_CATCH_ALL

 

       if (bEnableParent)

              ::EnableWindow(hWndParent, TRUE);

       if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd)

              ::SetActiveWindow(hWndParent);

 

       // destroy modal window

       DestroyWindow();

       PostModal();

 

       // unlock/free resources as necessary

       if (m_lpszTemplateName != NULL || m_hDialogTemplate != NULL)

              UnlockResource(hDialogTemplate);

       if (m_lpszTemplateName != NULL)

              FreeResource(hDialogTemplate);

 

       return m_nModalResult;

}

 

int CWnd::RunModalLoop(DWORD dwFlags)

{

       ASSERT(::IsWindow(m_hWnd)); // window must be created

       ASSERT(!(m_nFlags & WF_MODALLOOP)); // window must not already be in modal state

 

       // for tracking the idle time state

       BOOL bIdle = TRUE;

       LONG lIdleCount = 0;

       BOOL bShowIdle = (dwFlags & MLF_SHOWONIDLE) && !(GetStyle() & WS_VISIBLE);

       HWND hWndParent = ::GetParent(m_hWnd);

       m_nFlags |= (WF_MODALLOOP|WF_CONTINUEMODAL);

       MSG* pMsg = &AfxGetThread()->m_msgCur;

 

       // acquire and dispatch messages until the modal state is done

       for (;;)

       {

              ASSERT(ContinueModal());

 

              // phase1: check to see if we can do idle work

              while (bIdle &&

                     !::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE))

              {

                     ASSERT(ContinueModal());

 

                     // show the dialog when the message queue goes idle

                     if (bShowIdle)

                     {

                            ShowWindow(SW_SHOWNORMAL);

                            UpdateWindow();

                            bShowIdle = FALSE;

                     }

 

                     // call OnIdle while in bIdle state

                     if (!(dwFlags & MLF_NOIDLEMSG) && hWndParent != NULL && lIdleCount == 0)

                     {

                            // send WM_ENTERIDLE to the parent

                            ::SendMessage(hWndParent, WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)m_hWnd);

                     }

                     if ((dwFlags & MLF_NOKICKIDLE) ||

                            !SendMessage(WM_KICKIDLE, MSGF_DIALOGBOX, lIdleCount++))

                     {

                            // stop idle processing next time

                            bIdle = FALSE;

                     }

              }

 

              // phase2: pump messages while available

              do

              {

                     ASSERT(ContinueModal());

 

                     // pump message, but quit on WM_QUIT

                     if (!AfxGetThread()->PumpMessage())

                     {

                            AfxPostQuitMessage(0);

                            return -1;

                     }

 

                     // show the window when certain special messages rec'd

                     if (bShowIdle &&

                            (pMsg->message == 0x118 || pMsg->message == WM_SYSKEYDOWN))

                     {

                            ShowWindow(SW_SHOWNORMAL);

                            UpdateWindow();

                            bShowIdle = FALSE;

                     }

 

                     if (!ContinueModal())

                            goto ExitModal;

 

                     // reset "no idle" state after pumping "normal" message

                     if (AfxGetThread()->IsIdleMessage(pMsg))

                     {

                            bIdle = TRUE;

                            lIdleCount = 0;

                     }

 

              } while (::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE));

       }

 

ExitModal:

       m_nFlags &= ~(WF_MODALLOOP|WF_CONTINUEMODAL);

       return m_nModalResult;

}

看了两个小时还是没搞懂。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值