COM自动化专题(COM Automation)
- 自动化(COM Automation)基础概念
- 待续…
内存管理专题(Memory Management)
- C++内存管理变革系列
- WINX与内存管理
- C++内存管理技巧
- GC语言的内存管理问题
WINX AppWizard使用指南
winx-1.1.08版本发布了。此次更新的内容较多。您可以到这里了解详情。最引人注目的当然是WINX也提供了Application Wizard了,你可以很方便地开始建立自己的WINX应用程序。以下是WINX AppWizard的一个简单使用指南。
安装
- 下载winx-1.1.08.zip解压到winx-1.1.08目录。
- 进入winx-1.1.08\winx目录,你可以发现一个名为install.bat的文件,双击执行它。
- 还要下一步吗?没有了。
使用
- 打开Visual C++ 6.0,新建一个Project,此事出现以下对话框:
- 请注意新工程的所在的位置(注意上图的”Location:”字样)。WINX的AppWizard假设你的工程和WINX在同一个目录树下。如果不按照这个要求,将出现以下错误对话框:
- 点下一步,进入这个界面:
- 后面总体来说比较傻瓜式,就不罗唆了。有一点需要注意:如果你没有下载winsdk.zip,请进入”Advance…”对话框,把其中Enable all features of Windows选项去掉。如图:
- 上面的Advance对话框中,我的名字和Email请替换为自己的。
意外
如果你下载了winsdk.zip,并且使用了它,有时你可能遇到以下Link错误:uuid.lib文件破坏。
这是我提供的winsdk有些lib文件破坏了,临时的解决方案是,拿VC++ 6.0带的uuid.lib替换掉winsdk/lib/uuid.lib 即可。
如何用WINX实现可滚动的窗口(ScrollWindow)
用Windows SDK实现过可滚动的窗口(ScrollWindow)的读者都知道,实现一个ScrollWindow真不是一件容易的事情。你得响应好多好多的滚动条消息,还要处理鼠标滚轮。现在,你用WINX则只需要3步完成:
- 让你的类从ScrollWindow<>继承。
- 实现一个名为DoPaint的函数。其原型为:void DoPaint(winx::DCHandle dc); 这个函数功能是绘制整个视图,包括那些滚出屏幕之外的区域。其实实际上你应该把DoPaint理解为在以一个虚拟的不带滚动条的视图(View)中绘制。
- 告诉WINX你的虚拟视图(View)有多大。这可以通过SetScrollSize函数完成。
至此,一切搞定。我们看一个最简单的例子:
#include <winx/ScrollWindow.h>
#include “resource.h“
// ————————————————————————-
// class CMyView
class CMyView : public winx::ScrollWindow<CMyView>
{
WINX_CLASS(“MyView“);
public:
LRESULT OnCreate(HWND hWnd, LPCREATESTRUCT lpCS)
{
SetScrollSize(800, 800);
return 0;
}
void DoPaint(winx::DCHandle dc)
{
dc.TextOut(1, 1, _T(“Hello, WINX!“));
dc.TextOut(1, 300, _T(“You are welcome!“));
}
};
// ————————————————————————-
// CHelloDlg
class CHelloDlg : public winx::ModalDialog<CHelloDlg, IDD_HELLO>
{
};
// ————————————————————————-
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
CMyView::RegisterClass(); CHelloDlg dlg;
dlg.DoModal();
return 0;
}
这里我不再解释整个程序的流程。如果你不能理解为什么没有地方去创建CMyView类,建议你去看看前面WINX相关的文章。例如:
这里我们关注CMyView类。当然,这个例子有过于简单,虚拟的视图(View)大小始终为800×800,不太符合实际的情况。复杂一点的,我们这里就不贴代码了,请参考WINX带的例子。关于ScrollWindow相关的,我们提供了4个:
- ScrollWindow(Basic) tutorials/winx/step019-scroll-window/1.basic
- 一个简单的图象浏览器 tutorials/winx/step019-scroll-window/2.imageview (*)
- FormView(支持滚动的对话框) tutorials/winx/step019-scroll-window/3.formview
- ZoomView(ZoomScrollWindow) tutorials/winx/step019-scroll-window/4.zoomview
注:由于带(*)项目使用了Gdiplus,如果你使用VC++6.0,需要更新到最新的winsdk。
特别推荐上面的简单图像浏览器。代码才100多行,功能可不弱哦。另外,FormView在MFC中叫CFormView,WINX我们叫FormWindow(这个类WTL中没有对应的)。
下载:
从VC++到GCC移植:谈两者的语法差异
类型引用
template <class T>
class Foo
{
typedef T::SomeType SomeType;
};
这段代码在VC++中一点问题也没有,但是GCC并不允许,因为它不知道T::SomeType是什么。你需要改为:
template <class T>
class Foo
{
typedef typename T::SomeType SomeType;
};
通过typename T::SomeType告诉GCC,SomeType是一个类型名,而不是其他东西。
当然,这种情况不只是出现在typedef中。例如:
template <class Container>
void visit(const Container& cont)
{
for (Container::const_iterator it = cont.begin(); it != cont.end(); ++it)
…
}
这里的Container::const_iterator同样需要改为typename Container::const_iterator。
基类成员引用
template <class Base>
class Foo : public Base
{
public:
void foo() {
base_func();
m_base_member = 0;
}
};
这段代码在VC++中同样没有问题,但是GCC中不能通过。因为GCC并不知道base_func,m_base_member是什么。对于这个问题,你可以有两种改法:
改法1:加上域作用符Base::
template <class Base>
class Foo : public Base
{
public:
void foo() {
Base::base_func();
Base::m_base_member = 0;
}
};
改法2:使用using指示符
template <class Base>
class Foo : public Base
{
public:
using Base::base_func;
using Base::m_base_member;
void foo() {
base_func();
m_base_member = 0;
}
};
这两种方法各有好处,在class Foo中出现大量的Base::base_func、m_base_member的引用时,使用using是方便的。而如果只有一次,那么方法1显得简短。
交叉引用许可
class SomeClass;
template <class T>
class Foo
{
public:
void foo(SomeClass& a) {
a.some_func();
}
void foo2() {
SomeClass a;
a.some_func();
}
};
class SomeClass
{
public:
void some_func() {
…
}
};
由于VC++对模板函数的迟编译,因此,一个模板类不只是可以调用一个尚未出现的类成员函数(或者访问其成员变量),甚至可以定义其实例。这种语法对C++来说确实显得怪异。因为等到编译后面的SomeClass时,他又可以在其函数中定义class Foo的实例,从而出现交叉引用的情况。这在非模板函数的情形下就算你用VC++亦难以做到。
遇到这种情况,该如何移植到GCC中?这个问题有点棘手。我个人认为出现这种情况是不太应该的,这意味着对类与类之间的关系混淆不清。你需要仔细审视一下这两个类正确的关系是什么。如果是移植库(例如WTL就有多处这样的情形)的过程中遇到这种情况,可以把函数的实现体改为放到类定义体外,如下:
class SomeClass;
template <class T>
class Foo
{
public:
void foo(SomeClass& a);
void foo2();
};
class SomeClass
{
public:
void some_func() {
…
}
};
template <class T>
inline void Foo<T>::foo(SomeClass& a) {
a.some_func();
}
template <class T>
inline void Foo<T>::foo2() {
SomeClass a;
a.some_func();
}
移植MFC程序到WINX
WTL脱离MFC程序员的习惯有点远了。这也是它让初学者畏惧的一个原因。WINX其实是更接近MFC的WTL:它提供了更接近于MFC的使用界面,并努力使得MFC代码可以更加容易地移植到WINX中。关于MFC代码移植,我们已经在WINX中提供了几个样例。有一点你需要理解的是,WINX并不十分关注将一个MFC应用程序移植到WINX下,因为那只有学术价值,但并不具备商业价值,我个人并不推荐你这样做。关于MFC移植,我的侧重点始终在于移植一些具备可重用性较高的MFC代码,例如MFC编写的控件等。这里有我关于WINX定位方面更为详细的讨论。
所以,有一点你需要明确,本文并不是在推荐你用WINX把你的MFC程序重写一遍。但是这有助于你理解WINX,了解如何从MFC程序员转换为WINX程序员。
WINX对于MFC的策略,是兼容其用户群已经习惯的用法。只要掌握一定的规则,我们可以发现,从MFC到WINX,是如此轻松。 本文就是介绍如何从MFC到WINX的一个指南。由于WINX目前主要关注对话框应用程序,故此,这一篇MFC程序移植指南,主要针对的是基于对话框的MFC程序。点击此处阅读全文。
winx移植手记:支持dev-c++, mingw32
移植winx到gcc编译器,确实比移植到Visual C++ 2003辛苦一些,花了我整整一天时间,还只是移植了winx中的一个子库:stdext(C++标准扩展部分)。感兴趣可到这里下载。因为仍然是windows平台开发,我选择的是Dev-C++, mingw32。之所以是Dev-C++作为开发平台,是依据大家在《WINX调查:您使用什么C++开发平台?》的反馈决定的。
考虑到现在已经比较晚了,我先简单把一些感受比较强烈的东西记一下:
- 总体说来,对模板编译的支持,gcc比Visual C++系列(包括Visual C++ 2005)好很多。有不少细节上的看起来非常愚蠢的手误,由于代码没有用到,VC++就无法检查出来,用gcc很快就原型毕露了。对于VC++这种不调用就不进行一般性的语法检查的做法,我一直持否定的态度。虽然这可能加快了编译速度,但是对库的提供者无疑是不利的。
- gcc对语法的检查比VC++严格,这有利于你编写更符合C++标准的代码。
以上是赞美的话,但是相对来说,问题似乎更多:
- Microsoft的调试器真的是无可匹敌。用惯了Visual Studio,用gcc/gdb的调试实在痛苦。
- 我太习惯看函数调用栈了,Dev-C++的调试居然没有函数调用栈,不知道是gdb不支持,还是Dev-C++没有做。
- 当我要看一个结构体的内容时,Dev-C++只是打印该结构体的地址,并不显示更详细的信息。例如当你调试到某个类成员函数时,希望看看this对象的总体状态,却苦于没有办法。
- mingw32似乎没有支持fastcall调用,这是一个莫名奇妙的错误。由于一开始我压根没想到调用方式的问题,耽误了我不少时间。由于winx中所有的函数调用都采用winx_call,它被定义为__fastcall。mingw32并不报告这是一个错误,但是程序的执行却产生了非法操作。尝试去调试函数调用的跳转却非常奇怪,跑到一个根本没有调用过的函数上去了。由于现象奇特,我意识到这可能是由于调用方式引起的,把winx_call定义为cdecl,问题得以解决。
- 后来我想到gcc中调用方式的写法和VC++不太一样,应该写成:__attribute__ (( fastcall)),但问题依旧。
- mingw32编译出来的exe有点大(与Visual C++相比)。同样的代码(控制台程序),VC++ 6.0编译是44k,mingw32编译出来是521k(Release版本)。
对于Dev-C++,总体感觉还可以,有以下几点觉得需要改进:
- Dev-C++的工程文件过于简单,不支持多种配置。
- 函数跳转。VC++配上Visual Assist,按Alt+G跳转习惯了,没有这个功能还真不习惯。不过这个功能确实不易做。
- Find in Files功能支持在工程中找,也支持在所有打开的文件中找,唯独少了我觉得最实用的:在一个目录中找。
我用gcc也算有一段日子了,但是Dev-C++是首次使用,有些结论可能是我认识不足所致。把它写出来,也是欢迎有经验的朋友可以指出其中的错误,也欢迎与我交流心得。
对winx感兴趣?请到这里下载。