贺:WINX发布两个月整
2006-8-20日,WINX发布了它的第一个包:winx-1.0.01
2006-10-20日,也就是今天,WINX发布刚好两个月整。
小小庆贺一下。
本Blog六天后也将迎来这一天,一并Congratulations!
2006-8-20日,WINX发布了它的第一个包:winx-1.0.01
2006-10-20日,也就是今天,WINX发布刚好两个月整。
小小庆贺一下。
本Blog六天后也将迎来这一天,一并Congratulations!
标签: congratulation, release, winx
由于业余时间相对比较少,并且接下来要出差(大约十天左右),看样子winxcn.com短期内不能出来。为了WINX的文档不至于遥遥无期,我决定还是现在开始在blog上连载WINX的核心文档。或许对于这些文档而言,blog不是一个很好的载体,因为blog更关注的是社会性,强调的是参与,而体系性较差。
这是开篇第一篇。你可能觉得惊奇——不是要讲WINX吗?怎么,讲ATL来着?勿须奇怪,WINX是基于ATL/WTL的,所以,在讲WINX的原理之前,先要了解ATL的基本概念,它们一定程度上是相通的。
ATL/WTL的界面开发,网上的教程还是少了点。相信大家都知道《MFC程序员的WTL开发指南》,这的确是一套难得的好教材。作为WINX的入门篇,我们这一篇是回顾《MFC程序员的WTL开发指南》第一篇:“ATL界面类”(注:为了不至于重复制造轮子,我这里不再赘述该文章已经叙述较为详细的一些技术细节)。
接触ATL/WTL久了,类似下面这样的代码你一定见得多了:
class MyClass : BaseClassT<MyClass>
{
};
把派生类MyClass,作为模版参数传递给基类BaseClassT,这种写法多多少少显得有点古怪。但这是合法的。之所以要这样,是因为我们要实现“编译期的晚绑定”(ATL界面类中把它称为“编译期间的虚函数调用机制”,这是不太准确的说法)。
基于虚函数技术的“运行期(Runtime)的晚绑定”大家都已经很熟悉了,这也就是OOP中所谓的“多态”。而基于模板技术,所依赖的并非vtable,而是类型不确定型(类型晚绑定),来达到“编译期的晚绑定”。这也就是所谓的“泛型”。
选择“多态(虚函数技术)”,还是选择“泛型(模板技术)”?
模板的好处是“零开销”——即额外的时间、空间开销均为零。而虚函数技术在时间上多了一次间接调用(由vptr找到vtable中相应的函数地址),并导致inline失效(无法展开);在空间上每个类对象多了4字节(这里假设是32bit系统)的vptr,全局多了一个vtable(大小与该类的虚函数个数有关)。
虚函数的好处是“可定义二进制规范”,从而建立语言无关的调用约定。这就是COM(组件对象模型)技术关注的内容。进一步来说,虚函数技术比较适合应用于大型程序中的模块划分,用以描述组件间调用契约——interface(接口)。
我并不是模板技术的推崇者。应当认识到,模板与虚函数技术一样,只适合有限的场合。WINX中,消息分派机制使用了模板,是因为它是最适合的人选。
作为结束,我提醒读者,理解泛型中的“编译期的晚绑定”是重要的,如果你希望深入理解WINX的话。下一节我们开始进入最关键的章节——WINX的消息机制。
使用blogger的最初原因是因为MSN Space太慢了,害得我不得不搬家。刚使用blogger的那会,最大的体验是“够简单”,甚至是“太简单”。有一次想要使用表格发现,blogger居然不支持,觉得很不可思议,很过分。
然而,随着使用的深入,越来越觉得blogger“很不简单”。下面让我们细数blogger的种种特色:

关于blogger.com,我相信还有很多需要发掘的,还有更多无尽深处的体验...
“PostShow网络侵害图片版权”最近相当热闹。风言疯语之IT罗盘亦在其Blog上谈论了该事件:PostShow事件:美丽 丑恶 功利 无聊 期望。他在报道该事件的同时援引了图片,须不知自己也无形中发生了侵权行为。关于该图片的授权声明如下:
You have limited rights to personally view the images with your web browser and to use them as your personal computer wallpaper (or background image) on your own computer. These photos may not otherwise be reproduced, distributed, cropped, resized, or otherwise altered without the written permission of the photographer. No commercial use of these photos may be made in any way. All rights are reserved.
You may not use these photos on any web page, commercial or non-commercial, for profit or non-profit, without written permission from the photographer. You may however link to the photos in the manner described below. …
详细参考: http://www.airliners.net/usephotos/
类似的侵权行为完全可能会发生在我身上。远的不说,就说在引用图片、文章、源代码或其他网络资料时,我真的认真的去了解其出处及相关的版权声明了吗?我很惭愧因为我并没有。所以我认为这场闹剧很有价值,着实可以让我们反省一些自身觉得相当习惯的行为。
互联网是很特殊的媒体,你很难真的做到我们熟知版权声明方式“保留所有权利”(All Rights Reserved)。对它的滥用意味着任何人都可能触犯版权法律,意味着很多优秀的作品将无法得到最大价值的利用或最广泛的传播。现在,越来越多的人们开始意识到自己并非需要保留所有权利,相反他们更愿意选择“保留部分权利”(Some Rights Reserved),甚至“不保留权利”(No Rights Reserved)。
互联网上一种很常见(但绝不是唯一)的一种授权———创作共用授权(Creative Commons),其出发点就是Some Rights Reserved,有兴趣的读者建议看一看。
修订记录 1.1.01 (2006-10-14)
-----------------------------------------
*) 示范代码(tutorials)
- Hello, SmartWin! tutorials/winx/step001/hello,smartwin (a)
- XSL转换(XSLT) tutorials/winx/step018-xslt (b)
- 直方图均衡化(OpenCV样例) tutorials/opencv/step001-histgram (c)
*** 注意 ***
要编译标记了(a)的那些样例,你需要下载从sourceforge下载SmartWin++:
http://sourceforge.net/projects/smartwin/
并且让目录树看起来是这样的:
├─winx
│ └─include
├─wtl
│ └─include
└─smartwin
├─lib
└─include
要编译标记了(b)的那些样例,并且你使用Visual C++ 6.0,你需要更新你的
平台SDK(Windows Platform SDK)。
你可以到http://sourceforge.net/projects/winx/下载winsdk.zip。
并且让目录树看起来是这样的:
├─winx
│ └─include
├─wtl
│ └─include
└─winsdk
└─include
要编译标记了(c)的那些样例,你需要下载从sourceforge下载OpenCV:
http://sourceforge.net/projects/winx/
或者:
http://sourceforge.net/projects/opencv/
并且让目录树看起来是这样的:
├─winx
│ └─include
└─opencv
├─bin
├─lib
└─include
*) WINX扩展组件
- msxml
XSL转换(XSLT)
- OpenCV
class CvWindowT, CvWindow, CvMainFrame
现在,我们回答smithfox提的第二个问题:如何在MyCustomControl中再实现,鼠标右键处动态生成一个AnotherMyCustomControl,进行操作后消失,回来MyCustomControl呢?
这个问题包含三个要点:
WINX强调的是可视化,因此一直以来,均未提及动态创建窗口这个话题。要动态创建窗口,可以有三种方式:
后两者Create函数只是对Windows API - CreateWindowEx的简单包装。这里我们给一个动态创建IE控件的例子。
这里,我们要回答smithfox在winx论坛上提的第一个问题: 在WINX内,怎么写一个Custom Control,也就是说自己实现Paint的Control。
其实,winx不只是可以实现自定义控件,而且允许你将这些控件直接放到对话框中,就如你放置一个Static、Button、Edit等等标准控件一样。winx的tutorials中有专门的demo告诉你如何作到这一点。
虽然目前没有专门针对WINX进行可视化界面开发的软件,但是你可以在Visual Studio中使用WINX进行半可视的开发。虽然简陋,但是在最让人烦心的控件布局的所见即所得(WYSIWYG)上,基本上还算可以。
WINX支持三类自定义控件(Custom Control):
1)完全自定义的控件(通常从winx::Window派生)。代码参考:
tutorials/winx/step004-user-ctrl/1.basic/hello.cpp
2)从现有控件派生(通常从现有控件类winx::Static、winx::Button、winx::Edit等派生),对现有控件进行细节上的行为修改。代码参考:
tutorials/winx/step004-user-ctrl/2.superclass/hello.cpp
3)通过多种现有控件组合出一个复杂的自定义控件。如何做到这一点?
其实,有一个与Delphi之Form类似的概念,就是非模态对话框(Modaless Dialog)。所以,这一类控件我们通常从winx::ModalessDialog派生。这样,你就利用Visual Studio的对话框编辑器,进行这类复杂的自定义控件的可视化开发。代码参考:
tutorials/winx/step004-user-ctrl/3.superdialog/hello.cpp
看了这几个demo,并尝试过运行这些demo的人,多多少少会有magic的感觉。让人感到疑惑的主要是,“这些自定义控件是如何被创建出来的?”
的确,在代码中,你看不到创建自定义自定义控件的代码。这就如你看不到标准控件(如Static、Button等)的创建代码一样。——在点到这一点后,灵光在你心中一闪:是的,你猜得没错,这些自定义控件和标准控件一样,是对话框加载对话框资源后自动创建的。
Visual Studio的对话框编辑器除了标准控件如Static、Button、Edit等外,还有一个特殊的控件,叫Custom Control。插入该控件,并且将Class设为要创建的控件类的类名(也就是你实现窗口类时通过WINX_CLASS指定的)。如下图(我们假设WINX_CLASS为“MyView”):
这样,对话框加载资源后,就明白需要创建一个窗口类类名为“MyView”的窗口。正因为这样,所以“MyView”这个窗口类需要在对话框生成之前注册(RegisterClass)。
——现在,你已经明白,我为什么说,WINX特别强调窗口类以及注册窗口类的概念。因为,WINX区别与传统界面库(WTL/ATL、MFC等等)的另一个显著特征是,WINX中的用户自定义控件(Custom Control)与标准控件一样,是可以直接放到对话框上创建的。这很有趣。你认为呢?
上一篇我们谈到WINX与其他库共存的问题。空口无凭,我们这里就给出一个WINX中使用OpenCV的样例。
数字图像的直方图均衡化是常用的图像增强方法。这个样例本身的源代码取之:数字图像的直方图均衡化(C/C++源代码)。作者HUNNISH,是OpenCV方面的方家。
样例的源代码:
winx/tutorials/opencv/step001-histgram/hello.cpp - 使用HighGUI
winx/tutorials/opencv/step001-histgram(winx)/hello.cpp - 使用WINX
为了比较,我们提供了两个样例,其一使用OpenCV自带的HighGUI,另一个使用WINX提供的窗口。WINX提供的窗口(winx::CvWindow)是新增的一个窗口类。其代码参考:winx/OpenCV.h。这是我在WINX中新加入了一个头文件。提供这样的头文件只是为了方便,与WINX体系并无关系,多数代码也是取自HighGUI。
为了编译这两个样例,你需要下载OpenCV。你可以从http://sourceforge.net/projects/winx/下载它,并让目录结构看起来是这样的:
- opencv
- bin
- lib
- include
- winx
- lib
- include
偶尔也会听到这样的一些疑问:WINX支持DirectX,OpenCV吗?也会听到SmartWin支持OpenCV这样的说法。下面我们分析一下这个问题。
我们知道,库之间共存的障碍,主要有以下几点:
其一:编译期的符号(指类名、函数名、宏名等)冲突。主要表形在:
其二:链接期的符号冲突。根据我的经验,这主要表现在:
其三:框架的假设。一些库是以框架方式提供的,要求用户按照其预定的方式进行调用。如果两个库均提供了框架,那么他们互不知晓的情况下,通常很难在一起工作。
其四:调用的假设。在你调用一个库的代码时,你需要模拟出它需要的环境。可分为两种情形:
WINX如何解决这些问题?
其一:编译期的符号冲突。WINX使用namepsace尽量减少对全局命名空间的污染。对宏名亦采用类namespace的解决方案,多数WINX的宏名均以“WINX_”开头。
其二:链接期的符号冲突。和STL一样,WINX的代码尽量以纯头文件的方式提供。
其三:框架的假设。WINX不是框架,以便有更好的适应性。
其四:调用的假设。WINX的函数规格尽量减少采用WINX特有的数据结构。另外,类似MFC的AfxGetApp(),WTL的_Module的全局性数据,这在WINX中是明令禁止的(只是由于WINX使用部分WTL的代码,一些时候,_Module的使用不能避免)。
所有这一切,均是为了让WINX在最大程度上和更多的库可以协作。而我们在前面也已经提到了,WINX尽量采用了更为开放的结构。相比之下,它更懂得与其他库一起协作的道理。
我们以Hello, World! 程序为例,对比一下各个界面库的代码效率。对于界面程序,个人认为空间效率较之时间效率要占据主导因素,故此这里比较的是空间效率。另外,由于优化的极限是直接用Windows SDK,故此对比亦加入Windows SDK作为参考。参与此次对比的有:
功能:Hello, World!
界面:模态对话框
编译器:Visual C++ 2005
源代码:
比较结果:
首先,我们对比一下静态链接多线程模式的C库——即MultiThread(MT)时的情形。MFC亦以静态链接方式链接。由于所有的代码均静态链接进去,这种方式无疑是最公平的。对比结果如下:
可以看出,WINX产生的代码效率最高,并非常接近Windows SDK,而WTL则次之。SmartWin虽然以模板构建,但是比之MFC并无太大的优势。
我们再来比较一下动态链接多线程模式的C库——即MultiThread DLL(MD)时的情形。MFC采用动态链接方式。这是大型程序典型的链接方式,因此这个比较结果也颇有意义。
尽管MFC采用动态链接mfc80.dll的方式,但是它生成的代码仍然不及WINX短小。
本博客内容除非特殊说明均属原创,如需转载、引用其中的部分文字,请注意以下几点:
1)请在转载(引用)的内容开始添加本人署名,并提供本博客中相应文章的链接。如你的作品为非电子读物或纯文本,请给出链接的url。
2)请勿用于商业用途。
3)如果愿意,请给我邮件:xushiweizh@gmail.com,让我知道我的东西到哪去了。谢过。
WINX是卓越的,您需要了解以下内容:
*) 卓越的消息分派机制。正是因为有这个核心支撑,使得WINX区别于传统的界面库(如MFC、WTL)。
*) 简单易用(SIMPLE)是第一目标,尽量使可视化(WYSIWYG)界面开发成为可能。
*) WINX是一个界面库,不是开发框架。WINX代码是可以和WTL、MFC等界面库的代码共存的。
*) 兼容。尽管有更简洁的方法,但WINX还是提供了MFC程序员熟悉的调用界面,并尽量使得MFC代码可以轻松移植到WINX下。
*) 不重复制造轮子。在没有一个卓越的解决方案以区别于现有系统之前,先沿用现有的。事实上,WINX建立于WTL之上,重用了多数的WTL组件。