winlinglin

MFC学习笔记(一)

Win32应用程序有条明确的主线:
 (1) 进入WinMain函数
 (2) 设计一个Window
 (3) 注册这个Window
 (4) 建立这个Window
 (5) 显示和更新这个Window
 (6) 进入消息循环
 
好,我就先找WinMain函数吧。
我在C:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\src\mfc的appmodul.cpp的23行中找到了以下代码:
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 _In_ LPTSTR lpCmdLine, int nCmdShow)
#pragma warning(suppress: 4985)
{
 // call shared/exported WinMain
 return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}

_tWinMain是一个宏,详细为: #define _tWinMain WinMain
所以这个确实是我们要找的WinMain函数

从代码中看出,WinMain将参数全部交给AfxWinMain,来处理。
好,我又找AfxWinMain这个函数。

我在winmain.cpp的19行找到了AfxWinMain函数。
代码:
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 _In_ LPTSTR lpCmdLine, int nCmdShow)
{
 ASSERT(hPrevInstance == NULL);   // ASSERT在程序运行时它计算括号内的表达式,如果表达式为FALSE (0),
           // 程序将报告错误,并终止执行。如果表达式不为0,则继续执行后面的语句。
           // ASSERT只有在Debug版本中才有效,如果编译为Release版本则被忽略。
           // assert()的功能类似,它是ANSI C标准中规定的函数,它与ASSERT的一个重要区别是可以用在Release版本中。
 int nReturnCode = -1;
 // AfxGetThread和 AfxGetApp 都是全局函数
 CWinThread* pThread = AfxGetThread();  // 获得正在执行的线程,Must be called from within the desired thread.
 CWinApp* pApp = AfxGetApp();    // 获得A pointer to the single CWinApp object for the application

 // AFX internal initialization
            // This function is called by the MFC-supplied WinMain function, as part of the CWinApp initialization of a GUI-based
            // application, to initialize MFC.
 if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))  
  goto InitFailure;

 // App global initializations (rare)
 if (pApp != NULL && !pApp->InitApplication())  //InitApplication已经过时,用InitInstance代替,完成MFC内部管理方面的工作
  goto InitFailure;

 // Perform specific initializations
 if (!pThread->InitInstance())  // 初始化Instance,在每个 a copy of the program runs的时候,虚函数
 {
  if (pThread->m_pMainWnd != NULL)
  {
   TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL m_pMainWnd\n");
   pThread->m_pMainWnd->DestroyWindow();   // m_pMainWnd holds a pointer to the application's main window.返回一个CWnd.
               // cWnd Destroys the attached Windows window.
  }
  nReturnCode = pThread->ExitInstance();    // to exit this instance of the thread
  goto InitFailure;
 }
 nReturnCode = pThread->Run();  

InitFailure:
#ifdef _DEBUG
 // Check for missing AfxLockTempMap calls
 if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
 {
  TRACE(traceAppMsg, 0, "Warning: Temp map lock count non-zero (%ld).\n",
   AfxGetModuleThreadState()->m_nTempMapLock);
 }
 AfxLockTempMaps();
 AfxUnlockTempMaps(-1);
#endif

 AfxWinTerm();
 return nReturnCode;
}


找到了WinMain函数后,看了下MFC为我生成的类:
1. CTestApp  2. CTestView 3. CMainFrame  4. CTestDoc  5. CAboutDlg
查看CTestApp.cpp,发现了一个全局的CTestApp theApp,因为全局对象必须在main函数之前产生并初始化,所以应用程序调用的顺序应该是
CTestApp的构造函数 -> WinMain函数
又发现class CTestApp : public CWinApp,子类的构造函数在父类的构造函数调用之后调用,所以就搜索CWinApp吧。

在appcore.cpp的368行发现以下代码:
CWinApp::CWinApp(LPCTSTR lpszAppName)  // 此处的lpszAppName有个默认参数NULL
{
 if (lpszAppName != NULL)
  m_pszAppName = _tcsdup(lpszAppName); // 为lpszAppName分配内存
 else
  m_pszAppName = NULL;

 // initialize CWinThread state
 AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
 ENSURE(pModuleState);
 AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;
 ENSURE(pThreadState);
 ASSERT(AfxGetThread() == NULL);
 pThreadState->m_pCurrentWinThread = this;  // 如果有子类继承了CWinApp, this就是子类
 ASSERT(AfxGetThread() == this);
 m_hThread = ::GetCurrentThread();
 m_nThreadID = ::GetCurrentThreadId();

 // initialize CWinApp state
 ASSERT(afxCurrentWinApp == NULL); // only one CWinApp object please
 pModuleState->m_pCurrentWinApp = this;   // 如果有子类继承了CWinApp, this就是子类
 ASSERT(AfxGetApp() == this);

 // in non-running state until WinMain
 m_hInstance = NULL;
 m_hLangResourceDLL = NULL;v
 m_pszHelpFilePath = NULL;
 m_pszProfileName = NULL;
 m_pszRegistryKey = NULL;
 m_pszExeName = NULL;
 m_pRecentFileList = NULL;
 m_pDocManager = NULL;
 m_atomApp = m_atomSystemTopic = NULL;
 m_lpCmdLine = NULL;
 m_pCmdInfo = NULL;

 // initialize wait cursor state
 m_nWaitCursorCount = 0;
 m_hcurWaitCursorRestore = NULL;

 // initialize current printer state
 m_hDevMode = NULL;
 m_hDevNames = NULL;
 m_nNumPreviewPages = 0;     // not specified (defaults to 1)

 // initialize DAO state
 m_lpfnDaoTerm = NULL;   // will be set if AfxDaoInit called

 // other initialization
 m_bHelpMode = FALSE;
 m_eHelpType = afxWinHelp;
 m_nSafetyPoolSize = 512;        // default size
}

然后是CTestApp的构造函数的调用。
在CTestApp的声明中,它重写了InitInstance函数,如下:
BOOL CTestApp::InitInstance()
{
 AfxEnableControlContainer();  //Call this function in your application object's InitInstance function
          //to enable support for containment of ActiveX controls

 // Standard initialization
 // If you are not using these features and wish to reduce the size
 //  of your final executable, you should remove from the following
 //  the specific initialization routines you do not need.

// In MFC 5.0, Enable3dControls and Enable3dControlsStatic are obsolete because their functionality is incorporated
// into Microsoft's 32-bit and 64-bit operating systems.  
 
#ifdef _AFXDLL
 Enable3dControls();   // Call this when using MFC in a shared DLL
#else
 Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif

 // Change the registry key under which our settings are stored.
 // TODO: You should modify this string to be something appropriate
 // such as the name of your company or organization.
 SetRegistryKey(_T("Local AppWizard-Generated Applications"));

 LoadStdProfileSettings();  // Load standard INI file options (including MRU)

 // Register the application's document templates.  Document templates
 //  serve as the connection between documents, frame windows and views.

 CSingleDocTemplate* pDocTemplate;  // 单文档程序的模板生成
 pDocTemplate = new CSingleDocTemplate(
  IDR_MAINFRAME,
  RUNTIME_CLASS(CTestDoc),
  RUNTIME_CLASS(CMainFrame),       // main SDI frame window
  RUNTIME_CLASS(CTestView));
 AddDocTemplate(pDocTemplate);

 // Parse command line for standard shell commands, DDE, file open
 CCommandLineInfo cmdInfo;   // 对命令查询分析
 ParseCommandLine(cmdInfo);

 // Dispatch commands specified on the command line
 if (!ProcessShellCommand(cmdInfo))
  return FALSE;

 // The one and only window has been initialized, so show and update it.
 m_pMainWnd->ShowWindow(SW_SHOW);  //显示和更新窗口
 m_pMainWnd->UpdateWindow();

 return TRUE;
}


有了WinMain函数,也找到了显示和更新窗口的语句,但是从哪里开始设计窗口,注册窗口,建立窗口呢?
我又搜索了WNDCLASS,在wincore.cpp的4495行发现了与设计窗口时很像的函数BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)
发现MS已经在里面为我注册了一些窗口,我只要选择自己想要的样式就可以了。

那么如何建立一个窗口呢?我又搜索了CreateWindow,在wincore.cpp的675行中有个BOOL CWnd::CreateEx函数。
里面有调用CreateWindowEx。这个函数还调用了一个叫PreCreateWindow的函数,这个函数主要是确定在建立窗口之前,确保要建立的窗口已经注册了。

好了,一切都准备好了。最后就是进入消息循环。

posted on 2009-03-03 01:24 wil 阅读(1795) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理


<2024年12月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

导航

统计

常用链接

留言簿(1)

随笔分类

随笔档案

文章分类

搜索

最新评论

阅读排行榜

评论排行榜