万星星@豌豆荚 欢迎加入我们
一个吃软饭的男人!!!!!我只想写程序####
微博:http://weibo.com/wanlianwen
posts - 172,  comments - 1253,  trackbacks - 0

存在的必是合理的,都值得我们学习。学什么不重要,重要的是有一技之长。
如果你认为MFC垃圾请不要继续看。
如果你认为文档视图结构丑陋请不要继续看。
如果你认为ATL过时了请不要继续看。

庖丁解牛的艺术
庖丁为文惠君解牛,分解牛体时手接触的地方,肩靠着的地方,脚踩踏的地方,膝抵住的地方,都发出砉砉的声响,快速进刀时刷刷的声音,无不像美妙的音乐旋律,符合桑林舞曲的节奏,又合于经首乐曲的乐律。庖丁的解释是:我所喜好的是摸索事物的规律,比起一般的技术、技巧又进了一层。我开始分解牛体的时候,所看见的没有不是一头整牛的。几年之后,就不曾再看到整体的牛了。现在,我只用心神去接触而不必用眼睛去观察,眼睛的官能似乎停了下来而精神世界还在不停地运行。最喜欢这句:以无厚入有间,恢恢乎其于游刃必有余地矣。

我的MFC经历
我的大学专业是软件工程,作为一个C++开发人员学习MFC是必然的。记得上大二的时候,有些课程和大三师哥们一起上,总能看到牛师哥们手里捧一本《深入浅出MFC》,羡慕不已。当时数据结构实习,人家都基于Windows做,而自己只能在Console下做,十分尴尬,觉得自己很落后,现在想来有点可笑。
这里要说的是MFC是对WIN32 API的封装,为什么不从WIN32 API开始学呢?很多人是这样做,也见过一些人在这上面气馁而放弃C++转向Java。我是从MFC开始的,当我对MFC比较熟悉的时候,我心里就明白MFC是如何对WIN32 API封装的,进入MFC源码,里面全部调用的API,自然明白了API的功能及用法。学习编程就得由简到难,对MFC深入后,WIN32 API自然浅出。
我是大三开始接触MFC的,当时感觉是MFC是一个庞然大物,拿一些快速进阶之类的书籍东拼西凑学一点技巧,三个月后也没有入门。VC6向导生成的一个多文档程序代码比起自己写过的数据结构代码是一个天文数字,不知道如何下手。看着旁边宿舍非计算机专业的学生用VB就能写一个时钟,羡慕啊,自卑啊,气愤之下开始VB的学习。然而倔强的心里告诉自己怎么可以这样认输呢?在一个星期过去后,我重新开始了MFC的学习。MFC向导可以生成三种应用工程:对话框、单文档、多文档。默认的是微软最为骄傲的多文档,但是这个确实害人不浅。其他编程开发环境没有文档视图的概念,都是窗体、Form,这个结构要简单不少,可以快速入门,找到快感,不至于气馁。我当时就是从对话框开始学习的,向导生成的类比较简单,一个App,一个Dlg。我开始在对话框上学习各种控件,Button、Edit、ListCtrl等,终于算是Windows编程了。大概用了半年时间学习对话框,在对话框编程有一定了解的时候可以用它来做一些数据库、Socket编程,经典例子就是管理系统和聊天工具。对MFC有一些了解后开始学习文档视图模型,开始从单文档入手,然后进入到多文档。文档视图主要是开发企业应用,要考虑菜单、工具栏、停靠条、文档数据到视图更新以及鼠标键盘交互等,考虑很多消息事件处理,掌握起来确实要花不少功夫。
大四我进入公司实习,当时以为对MFC很了解,觉得自己很了不起。当遇到稍微深一点的问题,断点进入MFC源码的时候便手无所措,原来自己只是对MFC的轮廓有一点了解,并不解其内部规律。当时受了打击,这使我静下心来深入研究MFC,再一次看《深入浅出MFC》、操练各种类型应用程序、分类学习WIN32 API、看MFC源码(不敢说很仔细看,至少比较细的浏览一边),当我可以进入到MFC源码调试的时候,我很高兴,因为我进步了。当我接触到BCG库和XTREME库的时候,我都要进入它的源代码看,发现里面很多代码和MFC源码一样,我想写库的那些人对MFC应该算是很了解。而后我又花了半年时间学习COM,用ATL做项目。
现在每当我拿到一款软件的时候,我总要用Spy++去看看它的构造,想一下如果是自己能否做出这样的软件。软件设计不是靠蛮力,而是靠技巧,懂得借力省力。软件好比一头牛,模块之间的松耦合就像牛骨头依靠筋皮肉连接一样,当你了解其构造后,你看到的是每一个模块具有什么功能,可以拿来做什么,一个软件可以有那些模块拼凑,彼此间如何通信。恢恢乎其于游刃必有余地矣!

文档视图的剥离(App平台 文档视图插件)
软件开发讲究分工合作,因为要考虑开发周期及市场。一个企业软件有几种业务:三维浏览、二维数据编辑、网络控制。作为企业软件应该有统一的框架,像.NET集成VB.NET、C#、VC.NET一样,这样就需要把框架和文档视图分离,在一个框架上,不同开发部门开发不同应用最后集成到统一应用框架。
首先来看看用向导生成的一个多文档程序,主框架和文档视图子框架的联系其实只有很少代码:

CMultiDocTemplate *  pDocTemplate;
pDocTemplate 
=   new  CMultiDocTemplate(
 IDR_TESTTYPE,
 RUNTIME_CLASS(CTestDoc),
 RUNTIME_CLASS(CChildFrame), 
//  custom MDI child frame
 RUNTIME_CLASS(CTestView));
AddDocTemplate(pDocTemplate);

我们把这一段代码删除,并且删除关联的CTestDoc、CChildFrame、CTestView类。这时候我们得到一个空框架的应用程序。
很明显框架需要的只是文档视图子框架运行时的类信息,我们的文档视图插件需要遵守这样一个规则,于是我们定义一个插件接口:

interface  IDocView : IUnknown
{
 [id(
1 ), helpstring( " method GetDocCls " ), hidden] HRESULT GetDocCls([ out , retval] long *  pDocCls);
 [id(
2 ), helpstring( " method GetViewCls " ), hidden] HRESULT GetViewCls([ out , retval] long *  pViewCls);
 [id(
3 ), helpstring( " method GetChldFrm " ), hidden] HRESULT GetChldFrm([ out , retval] long *  pChldFrm);

为了插件查找以及管理,需要一个类别,所有支持的插件都属于这个类别:

BEGIN_CATEGORY_MAP(CManager)
 IMPLEMENTED_CATEGORY(CATID_DocViewCategory)
END_CATEGORY_MAP()

下面就可以实现文档视图插件了,生产一个ATL项目,添加文档视图子框架类,添加一个组件Manager,实现插件接口:

STDMETHODIMP CManager::GetDocCls( long *  pDocCls)
{
 
* pDocCls  =  ( long )RUNTIME_CLASS(CMyDocument);
 
return  S_OK;
}


STDMETHODIMP CManager::GetViewCls(
long *  pViewCls)
{
 
* pViewCls  =  ( long )RUNTIME_CLASS(CMyFormView);
 
return  S_OK;
}


STDMETHODIMP CManager::GetChldFrm(
long *  pChldFrm)
{
 
* pChldFrm  =  ( long )RUNTIME_CLASS(CChildFrame);
 
return  S_OK;
}


这样就主框架就可以遍历组件类别下面所有文档视图插件,通过

pDocTemplate  =   new  CMultiDocTemplate(
  IDR_MAINFRAME,
  (CRuntimeClass
* )nDocCls,
  (CRuntimeClass
* )nChldFrm,
  (CRuntimeClass
* )nViewCls);
AddDocTemplate(pDocTemplate);

加入到主框架。
这里有一个问题:一个应用可能有20种文档视图,是不是应用一起来就查找所有支持插件并加载呢?从内存消耗和人的习惯思考来看都不应该是这样的。可能一个用户打开应用只编辑一类文档,这时候其他19种文档就不需要加载。这就需要一点技巧来处理这类问题。
简单做法可以这样处理:应用框架加载的时候便利所有插件,这时候不加载。当新建文件的时候查找新建的插件是否已经加载,如果没有加载则先加载。打开文件的时候做类似操作。有如下三个函数完成操作:

//  遍历所有文档插件,不加载
void  EnumAllDocViews();
//  根据插件CLSID加载文档视图插件
CMultiDocTemplate *  AddDocViewByCLSID(CLSID clsid);
//  根据CLSID查找插件是否加载
DocMgrData FindDocByCLSID(CLSID clsid);

插件管理之插件类别:

打开界面:

打开文档:

代码下载。里面有说明文件。

posted on 2006-07-06 10:06 万连文 阅读(2209) 评论(11)  编辑 收藏 引用 所属分类: MFC

FeedBack:
# re: 庖丁解MFC--(一)文档视图与应用框架剥离
2006-07-06 11:48 | LOGOS
呵呵.你的内容不错.
不过我发现留言比较少,所以给你留一个,希望你能坚持写blog,不然我就没得欣赏了.  回复  更多评论
  
# re: 庖丁解MFC--(一)文档视图与应用框架剥离
2006-07-06 12:47 | 问题男
以下评论针对文中的编程感悟

感悟给自己看,没什么意义,给别人看,没什么帮助

在此推荐一网上流传的短文,《Teach Yourself Programming in Ten Years》(http://www.norvig.com/21-days.html),简单深刻的描述了如何提高编程技能

除了保持兴趣地学习至少十年,就没有其他路可走了,中间的过程、方法真的没有那么重要,积累到一定阶段,自然会感觉越来越通透

btw:

在下绝非信口开河,95-06,今年已是我学习编程的第十一个年头了,所以,对此我感受颇深

另,文中提到mfc和win32sdk先学what的问题,我个人与楼主看法不同,我认为如果条件允许,先难后易比先易后难要好得多,想当初(95年),为了修改游戏的代码(实现无敌状)自学了x86汇编(也是我学的第一门编程语言),之后学习c时,指针什么的自然就融会贯通了,除了编程语言,对操作系统的理解也能上升到n个层次(如果学习硬件知识则更上层楼)

看楼主字里行间透露出很高的水平,故有此冒昧进言,不当之处,还望一笑了之  回复  更多评论
  
# re: 庖丁解MFC--(一)文档视图与应用框架剥离
2006-07-06 13:30 | 万连文
部分赞成你的观点。
我想我十年后能看到现在的思想,所以留下,凡走过必留下足迹。
由于我本身是2002年才才开始接触计算机,第一门语言是C++,由于没有C的基础几乎废了。我2002年过年没有回家一个人在学校寝室学习C语言,还记得当时手冻的发肿。就是那之后我才可以在编程上稳住。中国有中庸思想,学习也应该如此,选择中间然后上下开壑。我们在不同年代开始接触计算机,不敢想象现在的人从汇编接触编程会是什么结果,牛人除外。我没有学过汇编,也曾经拿起来过,在VC6里面尝一下,但是由于工作性质缘由始终没有仔细研究。
ps:谢谢你也留下你的学习感悟,毕竟你是编程前辈。  回复  更多评论
  
# re: 庖丁解MFC--(一)文档视图与应用框架剥离
2006-07-06 18:01 | flyingxu
这篇文章,是为了强调doc view与frame的剥离,还是plugin的应用?
doc view与frame的剥离我在实际应用中,看不到太大的优势,除了加载时资源的占用
plugin在mfc中的应用,我倒是蛮感兴趣的
  回复  更多评论
  
# re: 庖丁解MFC--(一)文档视图与应用框架剥离
2006-07-06 18:12 | 万连文
未完待续,用plugin技术剥离MFC框架,用APC集成剥离体到VBA,实现MFC ATL VBA结合。  回复  更多评论
  
# re: 庖丁解MFC--(一)文档视图与应用框架剥离
2006-07-06 18:34 | 旁观者
我发现你的文字表达能力很不错,希望你能够有精彩的延续,同时也希望你能够日渐成熟,软件开发需要有持久的耐力与迎接挑战的信心,每天我都会关注你的进展。另外,一定要处理好工作、生活与爱情之间的关系……  回复  更多评论
  
# re: 庖丁解MFC--(一)文档视图与应用框架剥离
2006-07-09 01:46 | flyingxu
@万连文
那我慢慢等,等你写完
随便问一下,你对插件/主程序之间的消息映射/响应有没有什么要写的?我比较疑惑  回复  更多评论
  
# re: 庖丁解MFC--(一)文档视图与应用框架剥离
2006-07-09 11:25 | 万连文
主框架所起的作用无外乎提供事件、命令、通知消息,只要按照Window消息机制制定接口就可以了,框架管理插件,通过接口传递消息驱动插件。  回复  更多评论
  
# re: 庖丁解MFC--(一)文档视图与应用框架剥离
2006-07-12 16:51 | Arcrest
文学表达很好,
侯捷的书籍受欢迎的原因除了深入浅处的分析外,就是文笔
楼主的技术钻研精神也值得偶们学习
  回复  更多评论
  
# re: 庖丁解MFC--(一)文档视图与应用框架剥离[未登录]
2008-03-10 10:28 | 风语者
感谢提供源码可以研究  回复  更多评论
  
# re: 庖丁解MFC--(一)文档视图与应用框架剥离
2008-10-16 11:21 | rex
确实很不错!向你多多学习1  回复  更多评论
  

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


简历下载
联系我

<2006年7月>
2526272829301
2345678
9101112131415
16171819202122
23242526272829
303112345

常用链接

留言簿(66)

随笔分类

随笔档案

相册

搜索

  •  

最新评论

阅读排行榜

评论排行榜