星期日, 十月 29, 2006

关于blogspot.com被封

出差中,无意中发现我的Blog(blogspot.com)不能访问了。网上搜索了一下,确认被封。暂时的解决方案如下:

你可以使用镜像网站进行访问:http://www.pkblogs.com/winxcn
感谢fireseed提供该信息:http://groups.google.com/group/winxcn/msg/4d85a8382e240db0

你也可以使用以下方法:

为了访问winxcn.blogspot.com,可通过修改hosts文件进行访问。具体方法是:编辑WINDOWS\system32\drivers\e­tc\hosts 文件,然后加入72.14.219.190 winxcn.blogspot.com,保存即可。对于其他BlogSpot的博客类似,只要将winxcn改为相应的用户名。例如: 72.14.219.190 xushiwei.blogspot.com。

星期五, 十月 20, 2006

贺:WINX发布两个月整

2006-8-20日,WINX发布了它的第一个包:winx-1.0.01
2006-10-20日,也就是今天,WINX发布刚好两个月整。

小小庆贺一下。
本Blog六天后也将迎来这一天,一并Congratulations!

星期四, 十月 19, 2006

ATL界面类——兼谈多态与泛型

由于业余时间相对比较少,并且接下来要出差(大约十天左右),看样子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的消息机制。

星期三, 十月 18, 2006

Blogger(beta) - 无尽深处的体验...

使用blogger的最初原因是因为MSN Space太慢了,害得我不得不搬家。刚使用blogger的那会,最大的体验是“够简单”,甚至是“太简单”。有一次想要使用表格发现,blogger居然不支持,觉得很不可思议,很过分。

然而,随着使用的深入,越来越觉得blogger“很不简单”。下面让我们细数blogger的种种特色:

  1. 快。Google显然作了极大的努力来优化blogger.com的页面种种细节,以保证它足够的快。这也是我使用众多Google Service感受最深的一点

  2. 灵活的模版机制。在众多Blog站点中,blogger.com的模版是我所见最为灵活的。理论上你几乎可以随心所欲的设计你的blog外观。

  3. 万能的Rss Feed内容订阅Widgets,使你的Blog互动更出色。用它你可以实现Recent Comments,可以告诉别人你感兴趣什么(My Delicious),甚至做很多你目前还无法想象的趣事儿。

  4. Google Analytics、Google AdSense的无缝配合(我在其他如MSN Space、CSDN Blog等Blog系统上目前未找到使用Google Analytics的方式)。这其实要归功于第2.条 —— 灵活的模版机制。下面就是我的http://winxcn.blogspot.com近7天的Google Analytics的分析概要:

  5. 一个帐号可建立多个blog,亦可多人(通常是一个团队)同时维护一个blog。这看似没什么大不了,但至关重要(比支持表格或者更加友好的编辑界面重要很多)。其实这是我接触blogger后感受的第一个好处。要知道在我使用MSN Space的时代,我还专门申请了两个hotmail帐号,目的只是为了获得第二个Blog空间

关于blogger.com,我相信还有很多需要发掘的,还有更多无尽深处的体验...

谈论“PostShow网络侵害图片版权”事件

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,有兴趣的读者建议看一看。

星期六, 十月 14, 2006

WINX-1.1.01 Released

修订记录 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

星期四, 十月 12, 2006

WINX中如何动态创建窗口?

现在,我们回答smithfox提的第二个问题:如何在MyCustomControl中再实现,鼠标右键处动态生成一个AnotherMyCustomControl,进行操作后消失,回来MyCustomCon­trol呢?

这个问题包含三个要点:

  • 如何响应鼠标右键点击消息?你可以响应OnRButtonDown,或者OnContextMenu。
  • 如何动态创建窗口(控件)?
  • 如何让控件的行为像菜单一样,鼠标点击到本控件之外就消失?你可以让控件捕获鼠标消息(SetCapture),从而可以获得本控件外的鼠标消息(OnLButtonDown),并在检测到鼠标消息发生在窗口外时销毁自己(DestroyWindow)。

WINX强调的是可视化,因此一直以来,均未提及动态创建窗口这个话题。要动态创建窗口,可以有三种方式:

  • 使用Windows API:CreateWindow/CreateWindowEx。其实对话框就是通过这种方式创建它的子控件的。
  • 使用窗口句柄类(winx::WindowHandle)的Create函数。
  • 使用窗口类自身的Create函数。

后两者Create函数只是对Windows API - CreateWindowEx的简单包装。这里我们给一个动态创建IE控件的例子

如何实现Custom Control?如何进行可视化界面开发?

这里,我们要回答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)与标准控件一样,是可以直接放到对话框上创建的。这很有趣。你认为呢?

星期五, 十月 06, 2006

WINX中使用OpenCV的一个样例

上一篇我们谈到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

星期四, 十月 05, 2006

WINX支持DirectX,OpenCV吗?

偶尔也会听到这样的一些疑问:WINX支持DirectX,OpenCV吗?也会听到SmartWin支持OpenCV这样的说法。下面我们分析一下这个问题。

我们知道,库之间共存的障碍,主要有以下几点:

其一:编译期的符号(指类名、函数名、宏名等)冲突。主要表形在:

  • 宏名冲突(由于没有命名空间的保护)。
  • 基本类型的typedef。有不少库喜欢自己typedef一下所有的基本类型。如uint32, int32等。由于这些类型非常常见,并且typedef发生在全局命名空间,冲突的概率就很大。

其二:链接期的符号冲突。根据我的经验,这主要表现在:

  • 库之间的符号冲突,即两个库同时提供了某个函数。最为典型的是全局new/delete算符的重载C++允许重载全局new/delete算符,这真的是一场灾难。在两个库同时重载了new/delete时,就出现了符号冲突(可能也会在编译期体现,但常见的情况在链接期才表现出来)。
  • 使用了不同模式的C库。如果两个静态库(Static Library)使用了不同模式的C库,那么他们将出现大量的符号冲突。而我们知道,Visual C++提供了6种模式的C库:
      Single-Threaded
      Debug Single-Threaded
      Multithreaded
      Debug Multithreaded
      Multithreaded DLL
      Debug Multithreaded DLL
  • 不同编译器编译的静态库(Static Library)不能共存。原因主要亦在于使用了不同的C库。

其三:框架的假设。一些库是以框架方式提供的,要求用户按照其预定的方式进行调用。如果两个库均提供了框架,那么他们互不知晓的情况下,通常很难在一起工作。

其四:调用的假设。在你调用一个库的代码时,你需要模拟出它需要的环境。可分为两种情形:

  • 显式的依赖。例如,你要调用QT的函数,很多时候,你需要in/out一个QString参数。当然,既然你用了QT,生成一个QString还是很容易。但是如果某个函数要求传入QWidget*指针呢?除非你的窗体(Widget)本来就是QT实现的,不然这个QWidget*的生成还是颇费脑筋。
  • 隐式的依赖。例如,你要调用MFC的一段代码,而该代码使用了AfxGetApp或者其他。那么显然你的程序需要有AfxGetApp。你的本意可能只是需要一个MFC组件,最后你却发现,最终你不得不依赖一个MFC框架(Framework)。又如ATL/WTL的_Module,ATL/WTL本身架构精巧,但是_Module很要命。个人认为它破坏了ATL/WTL本身的纯洁。因为它其实与AfxGetApp并无二致,最终导致了强耦合的结构。

WINX如何解决这些问题?

其一:编译期的符号冲突。WINX使用namepsace尽量减少对全局命名空间的污染。对宏名亦采用类namespace的解决方案,多数WINX的宏名均以“WINX_”开头。

其二:链接期的符号冲突。和STL一样,WINX的代码尽量以纯头文件的方式提供。

其三:框架的假设。WINX不是框架,以便有更好的适应性。

其四:调用的假设。WINX的函数规格尽量减少采用WINX特有的数据结构。另外,类似MFC的AfxGetApp(),WTL的_Module的全局性数据,这在WINX中是明令禁止的(只是由于WINX使用部分WTL的代码,一些时候,_Module的使用不能避免)。

所有这一切,均是为了让WINX在最大程度上和更多的库可以协作。而我们在前面也已经提到了,WINX尽量采用了更为开放的结构。相比之下,它更懂得与其他库一起协作的道理。

星期三, 十月 04, 2006

对比WINX,WTL,MFC,SmartWin代码效率

我们以Hello, World! 程序为例,对比一下各个界面库的代码效率。对于界面程序,个人认为空间效率较之时间效率要占据主导因素,故此这里比较的是空间效率。另外,由于优化的极限是直接用Windows SDK,故此对比亦加入Windows SDK作为参考。参与此次对比的有:

  • WINX
  • WTL
  • MFC
  • SmartWin
  • Windows SDK

功能:Hello, World!

界面:模态对话框

编译器:Visual C++ 2005

源代码:

比较结果:

首先,我们对比一下静态链接多线程模式的C库——即MultiThread(MT)时的情形。MFC亦以静态链接方式链接。由于所有的代码均静态链接进去,这种方式无疑是最公平的。对比结果如下:

  • Windows SDK:48.0 K Reference:kernel32.dll, user32.dll
  • WINX:52.0 K Reference:kernel32.dll, user32.dll
  • WTL:76.0 K Reference:kernel32.dll, user32.dll, advapi32.dll, ole32.dll, oleaut32.dll
  • SmartWin:132.0 K Reference:kernel32.dll, user32.dll, comctl32.dll
  • MFC:184.0 K Reference:kernel32.dll, user32.dll, advapi32.dll, gdi32.dll, oleaut32.dll, shlwapi.dll, winspool.drv

可以看出,WINX产生的代码效率最高,并非常接近Windows SDK,而WTL则次之。SmartWin虽然以模板构建,但是比之MFC并无太大的优势。

我们再来比较一下动态链接多线程模式的C库——即MultiThread DLL(MD)时的情形。MFC采用动态链接方式。这是大型程序典型的链接方式,因此这个比较结果也颇有意义。

  • Windows SDK:6.0 K Reference:kernel32.dll, user32.dll, msvc80.dll
  • WINX:7.0 K Reference:kernel32.dll, user32.dll, msvc80.dll
  • WTL:28.5 K Reference:kernel32.dll, user32.dll, msvc80.dll, advapi32.dll, ole32.dll, oleaut32.dll
  • SmartWin:由于SmartWin编译的lib中没有MultiThread DLL(MD)模式,这里未针对其进行比较。
  • MFC:10.5 K Reference:kernel32.dll, user32.dll, msvc80.dll, mfc80.dll

尽管MFC采用动态链接mfc80.dll的方式,但是它生成的代码仍然不及WINX短小。