wabc库程序设计-hello world

'wabc'库用作开发windows桌面程序,若你很擅长windows SDK编程的方式,会发现,'wabc'很适合你,它很小巧,但很高效,里面封装了一套消息处理框架,能极大减少消息处理的工作量。此系列文章主要介绍如何利用wabc库提供的功能开发桌面程序。

一开始,请先下载wabc库的源码,编译成功后,打开'include'目录下的'wabc.h'文件,把'wabc.lib'的目录改成你当前的目录。具体操作请看wabc库编译说明

新建一个.exe的空win32项目,命名Example1,然后新建'winmain.h'和‘winmain.cpp'文件,将下面的内容拷贝到里面去。

winmain.h文件

#pragma once

#include "wabc.h"

class main_wnd :public wabc::wndbase
{
    WABC_DECLARE_MSG_MAP()
public:
    typedef main_wnd self;
    typedef wabc::wndbase inherited;

    main_wnd();
    virtual ~main_wnd(){}

    bool on_destroy(wabc::msg_destroy &msg)
    {
        ::PostQuitMessage(0);
        return false;
    }

    bool on_paint(wabc::dcclass &dc, const rect &rtClip, wabc::msg_paint &msg)
    {
        dc.fill(rtClip, dc.black_brush());
        return true;
    }
};

winmain.cpp文件

#include "winmain.h"

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    PSTR szCmdLine, int iCmdShow)
{
    wabc::application app(hInstance);
    main_wnd wnd;
    wnd.create(_T("Hello world"));

    MSG  msg;
    BOOL bRet;

    while ((bRet = ::GetMessage(&msg, NULL, 0, 0)) != 0)
    {
        if (bRet == -1)
            return 0;

        ::TranslateMessage(&msg);
        ::DispatchMessage(&msg);
    }
    return int(msg.wParam);
}

main_wnd::main_wnd()
{
    WABC_BEGIN_MSG_MAP(self)
        WABC_ON_DESTROY(&self::on_destroy)
        WABC_ON_PAINT(&self::on_paint)
    WABC_END_MSG_MAP()
}

编译运行,将会看到如下的界面:

hello world

程序的入口是winmain,一进入,构造一个wabc::application对象,然后生成一个窗口对象,再然后就进入消息的主循环,一直到窗口关闭。

这流程和纯SDK编程并没有太大的区别。但多少还是有点不同。第一,程序里看不到RegisterClass的操作,原因在于注册class的操作,被wabc::application对象封装了,在application的构造函数里,注册了一个class,这是wabc库唯一注册的class。第二,程序里看不到窗口过程,只看到消息如何和main_wnd的成员函数对应。若想知道里面的原理,请查看“win32消息映射”的系列文章。

wnd.create()用作创建窗口,当wnd对象生成时候,其对应的窗口并没有创建,必须显式的调用其成员函数create才会创建。

wabc::wndbase派生的class,都能使用wabc库的消息映射框架。注意,wabc::wndbase的派生类,必须是单根继承,不能多重继承。下面以main_wnd为例,说明做消息映射的步骤和关键点。首先要先声明一个映射槽(mapslot):

class main_wnd : public wabc::wndbase
{
    WABC_DECLARE_MSG_MAP()
    // ...
};

这里只声明了一个映射槽,若想声明多个映射槽,请用WABC_DECLARE_MSG_MAPEX宏。

在main_wnd默认的构造函数里,构造消息映射。WABC_BEGIN_MSG_MAP和WABC_END_MSG_MAP必须成对出现,中间,是映射的函数。消息映射的实质,是定义一个static数组,在WABC_END_MSG_MAP的时候,将定义的数组加入到main_wnd的映射链表。

WABC_BEGIN_MSG_MAP里的参数不是多余,它确保了所映射函数的对象,其类型是一样的。

WABC_END_MSG_MAP使用第一个映射槽,并假设this是一个wndbase对象(这意味着能接收消息)。除了WABC_END_MSG_MAP,还有WABC_END_MSG_MAPEX,起的作用和WABC_END_MSG_MAP一样,但可以做更多的控制。

在main_wnd::on_paint里,用一把黑色的刷子填充窗口:

dc.fill(rtClip, dc.black_brush());

black_brush是dc的属性,dc.black_brush()相当于调用HBRUSH(::GetStockObject(int(BLACK_BRUSH)))。由于这实现很简单,所以,编译器能将dc.black_brush() inline化,从而去掉调用函数的开销。关于wabc库里属性实现的原理,请查看“用c++模拟属性”一文。

dcclass有许多属性,这里不一一列举,具体请看"w_dc.h"

对于WM_CREATE和WM_DESTROY消息,wabc库会确保其映射的函数都会被调用,其它消息则不是这样。对于WM_CREATE消息,最先映射的函数会最先调用,而WM_DESTROY消息,最后映射的最先调用。具体原因请看“win32消息映射7-窗口的创建和注销”一文。

在wabc库,其映射函数的类型基本都是如下所示:

bool on_XXX(wabc::msg_XXX &msg);

但偶尔也有例外,如WM_PAINT对应的函数类型:

bool on_paint(dcclass &dc, wabc::rect &rtClip, wabc::msg_paint &msg);

映射消息的时候,映射的宏基本都会和相应的消息名称对应。如WM_CREATE对应WABC_ON_CREATE,WM_DESTROY对应WABC_ON_DESTROY等等。

映射的消息,其本质是一个static数组,必须保证,这数组按消息从小到大排序。在上面的例子里,因为WM_DESTROY<WM_PAINT,所以,先WABC_ON_DESTROY,后WABC_ON_PAINT。消息的大小可以查看‘w_msg.h’,所在行号越大,消息值越大。之所以要保证排序,是因为里面匹配消息的时候用到了二分查找法。若不能保证排序,在debug版本下会报错,在release版本下,会找不到对应的映射函数。

release版本的.exe文件,在笔者机器上大小为22k,这足以证明wabc库的小巧,发布的时候,并不需要另外的运行库。当windows编程入门以后,会发现,越简单的东西越好,很多时候,并不需要庞大的第三方库支持。用第三库,很多时候,只是需要它的消息映射机制,其它的,并不重要。‘wabc'库产生的原因在于此。消息映射的处理占了wabc库源码的一大部分,其它部分,都是为了方便的调用api。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值