MFC封装API

一、Win32Application Architecture

一个Win32 Application Architecture的代码结构如下:

LRESULT CALLBACK WinWordsProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);  //定义回调处理消息函数

 

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd){

         // 创建一个窗口类分为三步:1.设计窗口类 2.注册窗口类 3.创建窗口 4.显示及更新窗口

         // 步骤1.设计窗口类

         WNDCLASS wc;

……

         // 步骤2:注册窗口类

         RegisterClass(&wc);

         // 步骤3:创建窗口

         HWND hw = NULL;  

         hw = CreateWindow("Icanth2011", "My Fist Win32 Application Project!~", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 600, 400, NULL, NULL, hInstance, NULL);

         // 步骤4:显示及更新窗口

         ShowWindow(hw, SW_SHOWNORMAL);

         UpdateWindow(hw);

         // 消息循环

         MSG msg;

         BOOL bRet;

         while((bRet=GetMessage(&msg, NULL, 0, 0))!=0){

                   if(-1 == bRet){

                            return -1;

                   }

                   TranslateMessage(&msg);

                   DispatchMessage(&msg);

         }

         return msg.wParam;

}

 
 


由此可见,Win32 Application 程序的组成分为如下几个部分:

1.       找到WinMain程序入口,并开始执行

2.       创建并设计窗口类

3.       注册窗口类

4.       创建窗口

5.       显示及更新窗口

6.       循环获取消息,经处理,交还系统让其调用相关回调消息处理函数进行处理。

 

二、MFCArchitecture

由于Windows API过多,不方便程序员使用,并且非面对象。于是MFC被用于对Windows API进行封装,MFC始终实际运行过程就是Win32 Application程序的运行过程。

 

1.      MFC的项目结构

利用MFC AppWipzard自动生成的项目包括五个文件:CMyFirstMFCApp、CMainFrame、CFirstMFCDoc、CMyFirstCView、CAboutDlg。CMyFirstMFCApp继承自CWinApp,CMainFrame、CMyFirstCView、CAboutDlg都继承自CWnd,CFirstMFCDoc继承自CDocument,体现“文档/视图”结构。其项目结构如下所示:

 

2.      MFC的执行过程

对于MFC框架运行过程进行剖析,最好的资料是MFC源代码,VC6位于“\Microsoft Visual Studio\VC98\MFC\SRC”下。执行过程如下:

定义theApp(:CMyFistMFCApp)

                   ——>执行构造函数:CWinApp()->CMyFistMFCApp()->

                                     ——>程序入口_tWinMain (宏,定义为WInMain)

——>执行AftxWinMain

 

 
 

 

 

 

 


2.1  MFC的WinMain

在\SRC\APPMODUL.CPP中,可找到如下代码:

MFC\SRC\APPMODUL.CPP:

 

extern "C" int WINAPI

_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

         LPTSTR lpCmdLine, int nCmdShow)

{

         // call shared/exported WinMain

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

}

 

 
 

 

 

 

 

 

 

 

 

 

 


而其中_tWinMain其实就是WinMain函数的宏,定义如下:

 

#define _tmain      main

#define _tWinMain   WinMain

#ifdef  _POSIX_

#define _tenviron   environ

 

 
 

 

 

 


由此可见,WinMain中调用AfxWinMain进行处理。MFC包含此文件,故将找到此入口并自动调用执行。

 

2.2  theApp全局对象

在Project\CMyFirstMFCApp.CPP中,可找到一行代码发下:

Project\CMyFirstMFCApp.CPP:

 

/

// The one and only CMyFistMFCApp object

CMyFistMFCApp theApp;

 

 
 

 

 

 

 


当定义theApp时,将先执行CWinApp(\MFC\SRC\APPCORE.CPP)的构造函数:

\MFC\SRC\APPCORE.CPP:

 

CWinApp::CWinApp(LPCTSTR lpszAppName) // 有在该类定义时有默认值NULL

{

         if (lpszAppName != NULL)

                   m_pszAppName = _tcsdup(lpszAppName);

         else

                   m_pszAppName = NULL;

 

         // initialize CWinThread state

         AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();

         AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;

         ASSERT(AfxGetThread() == NULL);

         pThreadState->m_pCurrentWinThread = 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; // handle,this代表子类CMyFirstMFCApp对象

         ASSERT(AfxGetApp() == this);

……

}

 

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


2.3  AfxWinMain(WINMAIN.CPP)

 

1.AfxWindMain定义

 

\MFC\SRC\WINMAIN.CPP:

 

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

         LPTSTR lpCmdLine, int nCmdShow)

{

         CWinThread* pThread = AfxGetThread();

         CWinApp* pApp = AfxGetApp();

         if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))

         if (pApp != NULL && !pApp->InitApplication())

                   goto InitFailure;

         if (!pThread->InitInstance())

         {

                   if (pThread->m_pMainWnd != NULL)

                   {

                            pThread->m_pMainWnd->DestroyWindow();

                   }

                   goto InitFailure;

         }

         nReturnCode = pThread->Run();

}

 

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


2.AfxGetThread

AfxGetThread(THRDCORE.CPP)中调用AfxGetApp,和afxGetApp返回同值,代码如下所示:

\MFC\SRC\ THRDCORE.CPP:

 

CWinThread* AFXAPI AfxGetThread()

{

         // check for current thread in module thread state

         AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();

         CWinThread* pThread = pState->m_pCurrentWinThread;

         // if no CWinThread for the module, then use the global app

         if (pThread == NULL)

                   pThread = AfxGetApp();

         return pThread;

}

 

 
 

 

 

 

 

 

 

 

 

 

 

 

 


3.AfxGetApp

AfxGetApp(AFXWIN1.INL)中定义:

AFXWIN1.INL:

 

_AFXWIN_INLINE CWinApp* AFXAPI AfxGetApp(){ return afxCurrentWinApp; }

 

 
 

 

 

 

 


而afxCurrentWinApp定义位于AFXWIN.H文件中,如下:

AFXWIN.H:

 

#define afxCurrentWinApp AfxGetModuleState()->m_pCurrentWinApp

 

 
 

 

 

 


即为CWinApp构造函数时初始化为this的m_pCurrentWinApp。

 

4.InitInstance

类CWinAPP(APPCORE.CPP)中InitInstance函数定义为:

\MFC\SRC\ APPCORE.CPP:

 

// overrides for implementation

virtual BOOL InitInstance();

 

 
 

 

 

 


类InitInstance即为虚函数,根据多态性,将调用CMyFirstMFCApp类的InitInstance。

 

2.4  InitInstance(CMyFirstMFCAPP.CPP)

\MFC\SRC\ CMyFirstMFCAPP.CPP:

 

BOOL CMyFistMFCApp::InitInstance()

{

         CSingleDocTemplate* pDocTemplate;

         pDocTemplate = new CSingleDocTemplate(

                   IDR_MAINFRAME,

                   RUNTIME_CLASS(CMyFistMFCDoc),

                   RUNTIME_CLASS(CMainFrame),       // main SDI frame window

                   RUNTIME_CLASS(CMyFistMFCView));

         AddDocTemplate(pDocTemplate);

         m_pMainWnd->ShowWindow(SW_SHOW);

         m_pMainWnd->UpdateWindow();

}

 

 
 

 

 

 

 

 

 

 

 

 

 

 

 


2.5  MFC框架窗口

CFirstMyMFC有两个窗口,其中一个是CMainFrame。

 

2.5.1 设计和注册窗口

 

1.       CMainFrame::PreCreateWindow定义(\Project\CMainFrame.cpp)

\MFC\SRC\ CMyFirstMFCAPP.CPP:

 

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)

{

         if( !CFrameWnd::PreCreateWindow(cs) )

                   return FALSE;

         return TRUE;

}

 

 
 

 

 

 

 

 


2.       CFrameWnd::PreCreateWindow(CREATESTRUCT& cs) (\MFC\SRC\WINFRM.CPP)

 

 

\MFC\SRC\ CMyFirstMFCAPP.CPP:

 

BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs)

{

         if (cs.lpszClass == NULL)

         {

                   VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));

                   cs.lpszClass = _afxWndFrameOrView;  // COLOR_WINDOW background

         }

         return TRUE;

}

 

 
 

 

 

 

 

 

 

 

 


其中,AfxDeferRegisterClass即为AfxEndDeferRegisterClass的宏定义,位于AFXIMPL.H文件中:

AFXIMPL.H:

 

#define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass)

 

 
 

 

 

 


3.       AfxEndDeferRegisterClass (位于WINCORE.CPP中)

此处指定DefWindowProc函数来处理回调消息。 (!~)

MFC\SRC\WINCORE.CPP:

 

BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)

{

         // mask off all classes that are already registered

         AFX_MODULE_STATE* pModuleState = AfxGetModuleState();

         fToRegister &= ~pModuleState->m_fRegisteredClasses;

         if (fToRegister == 0)

                   return TRUE;

         LONG fRegisteredClasses = 0;

         // common initialization

         WNDCLASS wndcls;

         memset(&wndcls, 0, sizeof(WNDCLASS));   // start with NULL defaults

         wndcls.lpfnWndProc = DefWindowProc;

         wndcls.hInstance = AfxGetInstanceHandle();

         wndcls.hCursor = afxData.hcurArrow;

         INITCOMMONCONTROLSEX init;

         init.dwSize = sizeof(init);

         // work to register classes as specified by fToRegister, populate fRegisteredClasses as we go

         if (fToRegister & AFX_WND_REG)

         {

                   // Child windows - no brush, no icon, safest default class styles

                   wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;

                   wndcls.lpszClassName = _afxWnd;

                   if (AfxRegisterClass(&wndcls))

                            fRegisteredClasses |= AFX_WND_REG;

         }

         ……

}

 

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


4.       AfxRegisterClass  (位于WINCORE.CPP中)

MFC\SRC\WINCORE.CPP:

 

BOOL AFXAPI AfxRegisterClass(WNDCLASS* lpWndClass)

{

         WNDCLASS wndcls;

         if (GetClassInfo(lpWndClass->hInstance, lpWndClass->lpszClassName,

                   &wndcls))

         {

                   // class already registered

                   return TRUE;

         }

         if (!::RegisterClass(lpWndClass))

         {

                   TRACE1("Can't register window class named %s\n",

                            lpWndClass->lpszClassName);

                   return FALSE;

         }

         return TRUE;

}

 

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


2.5.2 创建窗口

1. CFrameWnd::Create  (WINFRM.CPP)

MFC\SRC\WINFRM.CPP:

 

BOOL CFrameWnd::Create(LPCTSTR lpszClassName,

         LPCTSTR lpszWindowName,

         DWORD dwStyle,

         const RECT& rect,

         CWnd* pParentWnd,

         LPCTSTR lpszMenuName,

         DWORD dwExStyle,

         CCreateContext* pContext)

{

         HMENU hMenu = NULL;

         if (lpszMenuName != NULL)

         {

                   // load in a menu that will get destroyed when window gets destroyed

                   HINSTANCE hInst = AfxFindResourceHandle(lpszMenuName, RT_MENU);

                   if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL)

                   {

                            TRACE0("Warning: failed to load menu for CFrameWnd.\n");

                            PostNcDestroy();            // perhaps delete the C++ object

                            return FALSE;

                   }

         }

         m_strTitle = lpszWindowName;    // save title for later

         if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,

                   rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,

                   pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext))

         {

                   TRACE0("Warning: failed to create CFrameWnd.\n");

                   if (hMenu != NULL)

                            DestroyMenu(hMenu);

                   return FALSE;

         }

         return TRUE;

}

 

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


3.       CWnd:CreateEx (WINCORE.CPP)

MFC\SRC\WINFRM.CPP:

 

BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,

         LPCTSTR lpszWindowName, DWORD dwStyle,

         int x, int y, int nWidth, int nHeight,

         HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)

{

         // allow modification of several common create parameters

         CREATESTRUCT cs;

         cs.dwExStyle = dwExStyle;

         ……

         if (!PreCreateWindow(cs)) //完成注册窗口类工作

         {

                   PostNcDestroy();

                   return FALSE;

         }

 

         AfxHookWindowCreate(this);

         HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,

                            cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,

                            cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);

         ……

}

 

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


以下是CREATESTRUCT和CreateWindowEx参数的对比:


由于CREATESTRUCT中的属性都定义为指针,故可在PreCreateWindow中更改属性,在CreateWindowEx中将更改显示。

 

4.      MFC的调用关系

① theApp

theApp(CMyFirstMFCApp.CPP)

——> CWinAPP ::CWinAPP(){ pModuleState->m_pCurrentWinApp = this;  }

 

 
 

 

 

 


② _tWinMain(APPMODUL.CPP)

_tWinMain ()

{

AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

}

 

 
 

 

 

 

 

 

 

  


③ AfxWinMain(WinMain.CPP)

int AFXAPI AfxWinMain()

{

CWinThread* pThread = AfxGetThread(); //——>return AfxGetApp() (:THRDCORE.CPP)

         CWinApp* pApp = AfxGetApp();

//——>return afxCurrentWInApp (:AFXWIN1.INL)

//——>return AfxGetModuleState()->m_pCurrentWinApp (:AFXWIN.H)

AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

pApp->InitApplication();

pThread-> InitInstance ();

         //——> CMyFirstMFCApp::InitInstance

                   //——> AddDocTemplate(pDocTemplate);

                            //——> m_pMainWnd->ShowWindow(SW_SHOW);

                   //——> m_pMainWnd->UpdateWindow();

pThread->Run();

}

 

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 


④ 窗口

设计和注册窗口:

CMainFrame::PreCreateWindow (\Project\ CMainFrame.cpp)

         ——>CFrameWnd::PreCreateWindow

                   ——>AfxDeferRegisterClass(宏= AfxEndDeferRegisterClass)

——>AfxEndDeferRegisterClass

——>AfxRegisterClass

         ——>::RegisterClass (SDK)

 

 
 

 

 

 

 

 

 

 


创建窗口:

CFrameWnd::Create()

         ——>CFrameWnd::CreateEx()

——>CWnd::CreateEx()

         ——>virsual CWnd::PreCreateWIndow(虚函数,调用子类中CFrameWnd:: PreCreateWIndow),

:: CreateWIndowEx()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/254875.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

4.10下午

转载于:https://www.cnblogs.com/yanyuying/p/6690662.html

halcon sobel 边缘检测 sobel_dir

目录sobel_dir(算子)描述参数sobel_dir(算子) sobel_dir - 使用Sobel算子检测边缘(振幅和方向)。 sobel_dir(Image : EdgeAmplitude, EdgeDirection : FilterType, Size : ) 描述 sobel_dir计算图像的一…

【译】x86程序员手册37-第10章 初始化

Chapter 10 Initialization 第10章 初始化 After a signal on the RESET pin, certain registers of the 80386 are set to predefined values. These values are adequate to enable execution of a bootstrap program, but additional initialization must be performed by s…

秒杀多线程第二篇 多线程第一次亲密接触 CreateThread与_beginthreadex本质区别

本文将带领你与多线程作第一次亲密接触,并深入分析CreateThread与_beginthreadex的本质区别,相信阅读本文后你能轻松的使用多线程并能流畅准确的回答CreateThread与_beginthreadex到底有什么区别,在实际的编程中到底应该使用CreateThread还是…

如何传输文件到linux服务器?

我们知道,云主机文件传输是一件相对复杂的事情,经常需要搭建FTP服务器或者是借助其他工具来完成。下面为大家介绍一种简单易操作的传输文件到Linux服务器的方法。 Linux文件传输同Windows文件传输一样,我们为每一台Linux主机配置了一个1G的网…

秒杀多线程第三篇 原子操作 Interlocked系列函数

上一篇《多线程第一次亲密接触 CreateThread与_beginthreadex本质区别》中讲到一个多线程报数功能。为了描述方便和代码简洁起见,我们可以只输出最后的报数结果来观察程序是否运行出错。这也非常类似于统计一个网站每天有多少用户登录,每个用户登录用一个…

PostgreSQL Oracle 兼容性之 - INDEX SKIP SCAN (递归查询变态优化) 非驱动列索引扫描优化...

标签 PostgreSQL , Oracle , index skip scan , 非驱动列条件 , 递归查询 , 子树 背景 对于输入条件在复合索引中为非驱动列的,如何高效的利用索引扫描? 在Oracle中可以使用index skip scan来实现这类CASE的高效扫描: INDEX跳跃扫描一般用在W…

如何确定镜头CCD靶面尺寸?

在组建机器视觉系统时,需要选用适合实际应用的产品。今天,中国机器视觉商城的培训课堂为您带来的是关于工业镜头CCD靶面尺寸的确定方法。 在选择镜头时,我们通常要注意一个原则:即小尺寸靶面的CCD可使用对应规格更大的镜头&#x…

(十二)洞悉linux下的Netfilteramp;iptables:iptables命令行工具源码解析【下】

iptables用户空间和内核空间的交互 iptables目前已经支持IPv4和IPv6两个版本了,因此它在实现上也需要同时兼容这两个版本。iptables-1.4.0在这方面做了很好的设计,主要是由libiptc库来实现。libiptc是iptables control library的简称,是Netfi…

恢复Ext3下被删除的文件(转)

前言 下面是这个教程将教你如何在Ext3的文件系统中恢复被rm掉的文件。 删除文件 假设我们有一个文件名叫 ‘test.txt’ $ls -il test.txt15 -rw-rw-r– 2 root root 20 Apr 17 12:08 test.txt 注意:: “-il” 选项表示显示文件的i-node号(15)…

TCP UDP HTTP 的关系和区别

TCP UDP HTTP 三者的关系: TCP/IP是个协议组,可分为四个层次:网络接口层、网络层、传输层和应用层。 在网络层有IP协议、ICMP协议、ARP协议、RARP协议和BOOTP协议。 在传输层中有TCP协议与UDP协议。 在应用层有HTTP、FTP、TELNET、SMTP、DNS等协议。 TCP…

微信开放平台全网发布时,检测失败 —— C#

主要就是三个:返回API文本消息,返回普通文本消息,发送事件消息 --会出现失败的情况 (后续补充说明:出现检测出错,不一定是代码出现了问题,也有可能是1.微信方面检测时出现服务器请求失败&…

Zabbix 钉钉报警

话不多说,咱们直接进入正题钉钉报警时基于zabbix,访问钉钉应用接口去推送的报警消息,所以我们需要一个在钉钉创建一个报警应用1、 我做的钉钉报警是基于钉钉自定义应用进行推送的所以需要登录钉钉管理后台进行创建(zabbix自定义应…

于敦德:途牛五大战略纵深不惧同质化竞争

于敦德说,途牛已经在目的地、出发地、产品系列、客户和品牌五个领域建立起了纵深壁垒,不担心任何局部竞争,将坚决把局部同质化战争打到底。 一个行业的两种公司 包括旅游在内的很多行业通常都有两种公司:…

自定义线程的方式

2019独角兽企业重金招聘Python工程师标准>>> package com.javaxxz.test;public class Demo extends Thread {/*** 创建线程的方式* 方式一:* 1、自定义一个类继承Thread类* 2、重写Thread类的run方法,把自定线程的任务代码写在run方法中* …

20155204 2016-2017-2 《Java程序设计》第8周学习总结

学号 2016-2017-2 《Java程序设计》第X周学习总结 教材学习内容总结 想要取得channel的操作对象,可以使用channels类,它定义了静态方法newChannel()。Buffer的直接子类们都有一个alloocate()方法,可以让你指定Buffer容量。1.java.util.loggin…

HALCON示例程序train_characters_ocr.hdev使用SVM分类器训练字体

HALCON示例程序train_characters_ocr.hdev使用SVM分类器训练字体 小哥哥小姐姐觉得有用点个赞呗! 示例程序源码(加注释) 蓝色字体均为算子解释链接,可以前往查看解答 关于显示类函数解释 read_image (Image, ‘ocr/chars_tra…

安装DirectX SDK时出现Error Code:s1023 的解决方案

安装DXSDK_Jun10时(下载地址:http://www.microsoft.com/en-us/download/confirmation.aspx?id6812 ) 出现下图所示错误 Error Code:s1023 计算机上有安装过更新版的Microsoft Visual C 2010 Redistributable,打开“…

顶级数据库行会Percona阿里全面解析下一代云数据库技术

摘要: 几年前,数据库管理系统的企业市场似乎还如同铜墙铁壁,除了老牌厂商外,其他厂商休想打进来。随着移动互联、物联网技术的发展,多终端应用的时代悄然而至。结构化与非结构化数据的爆发,推动人类社会进入…

C#指定窗口显示位置的方法

小哥哥小姐姐觉得有用点个赞呗! C#指定窗口显示位置的方法 1.使用StartPosition MainForm mainform; mainformnew MainForm (); dlgCtrl.StartPosition FormStartPosition.Manual;下面是FormStartPosition里边的定义与解释 // 指定窗体的初始位置。public …