随笔-3  评论-4  文章-0  trackbacks-0
  2005年11月10日
以前VC6的代码,从xml文件中读取属性文字(中文),返回BSTR类型,用OLE2T转换,然后显示,一直工作很正常,用来做本地化,比修改Res文件要方便的多。

同样的代码,在VS2003里面居然不能工作了,调试,发现BSTR返回正常,而通过OLE2T转换居然就全转成“???”了,晕。

做了无数尝试,发现用unicode编译就正常。可是原来的VC6项目不论是否Unicode编译都正常的,要把一个项目全部转成Unicode还是有相当工作量的,似乎也并没有必要。

寻找解决方法,看了一堆ATL的代码,ATL7提供了OLE2T的代替品COLE2T,用一个重载是COLE2T(bstr, codepage),发现给把第二个参数设置成CP_ACP,即ANSI code page就转换正常了。原来是codepage的问题,ATL搞了一大堆代码来获取转换用的codepage,看得人晕,而我要的只是ANSI code page。

继续找,终于找到了,ATL的代码通过一条宏定义进行了分支。如果定义了宏_CONVERSION_DONT_USE_THREAD_LOCALE,则对当前code page的请求简单返回CP_ACP,否则,就搞了一大堆代码从当前线程中查询。那么我们要做的就是定义这个宏就可以了。试了一下,果然如此

最终解决方案,在stdafx.h的所有包含文件前面加上:
#define _CONVERSION_DONT_USE_THREAD_LOCALE


搞定
posted @ 2005-11-10 09:43 章鱼 阅读(731) | 评论 (1)编辑 收藏
  2005年9月20日

起因

上次完成了CAppBar的代码后,就一直想在标题栏的关闭按钮前面加一个按钮,来控制自动隐藏的设置。在标题栏上加按钮并不算特别麻烦,主要是控制WM_NCPAINT,把想要的效果画上去。当然,原理不复杂,要实现的好却不容易。上网搜了一下,有一些简单的例子用来讲述原理,没有找到比较好的实现,更谈不上可复用的代码了,那么只好自己实现了。

原理

首选必须明白原理,想在标题栏上创建CButton这样窗口按钮的努力是徒劳的。标题栏属于Non-Client区域,不能在其上创建子窗口,唯一的方法就是响应WM_NCPAINT消息,通过Window DC画上去,当然,还需要处理一些其他的鼠标消息以得到按钮的效果。这样,实现的思路就和CAppBar差不多了,再创建一个模板类,于是,CCaptionButton<T>就诞生了。 先看看效果

按钮图片

因为是画上去的按钮,我们需要准备一些按钮图片。一个按钮至少需要3个图片来表示3个状态:

  • 正常状态
  • 按下状态
  • 鼠标停留状态
另外,如果需要下面两种额外状态,就需要一共提供5个按钮图片
  • Checked状态
  • Disabled状态

我们通过一个ImageList来组织这些按钮图片。一幅象下面这样的图片资源可以产生一个按钮需要的ImageList,当然也可以通过其他方式实现。

当添加一个标题栏按钮时,我们需要这些按钮图片,参数的类型是HIMAGELIST

添加标题栏按钮

我们需要支持多个标题栏按钮,因此在CCaptionButton类中,通过一个vector来维护所有按钮的信息。具体实现不多说了,就讲怎么使用吧,添加按钮的方法就是:

 int AddButton(UINT uID, int cx, int cy, HIMAGELIST himl, LPCTSTR lpszHint=NULL);

其中,uID是按钮的ID,当按钮被点击时,会有一个WM_COMMAND消息发送给窗口,uID为参数。因此,处理标题栏按钮点击的方法和处理普通按钮完全相同。cx和cy定义了按钮的宽度和高度,这个尺寸必须和按钮图片相符。himl则包含了3-5幅图片,表示按钮不同状态下的样子。最后,lpszHint是按钮的tooltip提示文字。

控制按钮位置

加入的按钮显示在标题栏的什么地方呢?自动控制按钮的位置似乎是一个可重用的类应该完成的任务。在类的实现中,我尝试自动计算标题栏上的空白区域,让我们添加的标题栏按钮靠窗口右边已有按钮排列。然而,我发现,由于存在许多不同的窗口样式,如是否有最小化按钮,是否有问号按钮,是否窄标题栏(即ToolWindow),自动计算很容易产生错误。不如让继承类来决定如何排放按钮位置。因此,提供了下面这个函数供继承类重载:

 POINT GetButtonPos(int index);

CCaptionButton为这个函数提供了一个默认的实现,但是,这个实现比较简单,只有在窗口为ToolWindow,并且没有任何系统按钮的情况下才能正常显示。通过重载GetButtonPos函数,实际上我们得到了比自动计算强的多的功能,即我们可以在任意位置显示按钮,甚至可以控制按钮水平或者垂直排列,就象例子程序中看到的那样。

使用方法

总结一下使用方法

  • 把CCaptionButton作为一个父类继承
  • 使用CHAIN_MSG_MAP把消息传递到CCaptionButton类
  • 调用AddButton函数添加一个或多个按钮
  • 重载GetButtonPos函数提供每个按钮的显示位置
  • 处理标题栏按钮产生的Command消息
  • 可以调用CheckButton改变按钮的Check状态
  • 可以调用EnableButton改变按钮的Enable状态

示例程序

示例程序中使用了5个标题按钮,并配合使用了CAppBar类,以实现桌面停靠的功能。5个标题按钮的排列使用了普通方式和垂直排列的方式,通过继承GetButtonPos函数实现。其中图钉按钮控制AppBar窗口的自动隐藏设置;其他4个按钮使窗口停靠到桌面的一边;并且把停靠到底部的按钮设置成Disabled,可以看到不同的效果

下载示例程序

posted @ 2005-09-20 11:07 章鱼 阅读(2223) | 评论 (1)编辑 收藏
  2005年9月15日
关于Docking Window的文章有很多,基本都是讲主程序内部的工具栏小窗口的Docking,看看代码,一般都很复杂。关于桌面Docking的文章并不多见。实际上从Windows95开始,Win32 API就提供了一个叫做SHAppBarMessage的函数,用于实现完全等同于Windows Task Bar的功能。即可以停靠在屏幕在任意一边,并把自己排除到桌面空间之外。当其他应用程序窗口最大化的时候,不占据Task Bar的空间。同时,也可以设置成自动隐藏,让出所有的桌面空间。这样的窗口,就称为AppBar。

象QQ这样的程序可以停靠在窗口的一边,也可以自动隐藏,但似乎和AppBar的行为还是有不少差距的。本文提供的是对标准AppBar的一个实现。

利用SHAppBarMessage函数实现一个AppBar并不困难,这篇文章介绍了几乎所有实现细节,但所提供的例子却是SDK风格的代码,基本没有实际使用价值。但是对于SDK文档是一个很好的补充,很多SDK中没有说清楚的问题在文中给出了解释。

另一个问题是,SHAppBarMessage函数并没有提供我想当然认为应该实现的功能。比如对拖动的支持,比如自动隐藏窗口的隐藏和出现功能都必须额外的代码实现。SHAppBarMessage函数所做的主要工作似乎是划分屏幕,使其他窗口不会占用AppBar的空间。当然,能实现这个也足够了,毕竟,没有SHAppBarMessage函数,其他功能肯定都可以实现,而这个划分屏幕的功能我不知道该怎么做。

写一个可重用的AppBar基础类的愿望马上出现在我头脑中。WTL由于其超低的耦合性成为我必然的选择。模板类CAppBar<T>就是工作的结果。这个类不只是对SHAppBarMessage函数的简单封装,同时提供了通过拖动实现停靠或脱离屏幕的功能,并提供自动隐藏的实现。

任何从CWindowImpl直接或间接继承的弹出式窗口类都可以使用CAppBar。使用的方法很简单:
    1、把CAppBar作为一个父类继承
    2、使用CHAIN_MSG_MAP把消息传递给CAppBar
    3、在窗口创建时调用InitAppBar函数,参数可选
这样,这个窗口就具备了AppBar的功能了,下面你就可以通过拖动把它停靠在屏幕边上了。
当然,也可以通过调用DockAppBar停靠或脱离;或者调用SetAutoHide改变自动隐藏的设置。
如果在停靠状态改变时需要有特殊操作,可以重载OnDockingChanged函数。

基本就是这样,代码很简单,就象其他WTL类一样。希望下一版的WTL可以收录它

下载例子程序
posted @ 2005-09-15 09:42 章鱼 阅读(1157) | 评论 (2)编辑 收藏
仅列出标题