影子
刚回到学校,一时半会没有安定下来,呆在学校无事。走在武汉街道上,处处飘着桂花香,想起“八月桂花遍地开”歌声。前人总结的规律总是那么准确,自然忆起父辈经常在耳边的唠叨:不听老人言,吃亏在眼前。思想在钢枪铁炮的西方思潮和大刀长矛的中国传统的熏染下,人不免变得浮躁、善变,左右摇摆,骑墙观望。
前一段时间一个朋友一直叨念着让我给他做一个插件系统,他抱怨插件的消息传递不畅通,无法下手构建属于自己plugin system。我告诉他应该怎么去研究,他非要我动手给他demo一个,并且指明要“Eclipse”那样的。我没有那么好设计思想,也没有很强的技术,对Eclipse更是知之甚少,一直走在Microsoft大道上,深受billgate庇护,省去了Java开发的一堆环境配置问题。
第一次走进公司到现在有两年零几天了,作为一个学生我清楚在公司应该如何。一直没有偏离自己理想,在痛苦中成长,体会到痛并快乐着的滋味。在做系统的时候,由于对mfc知识掌握不足,dll封装UI的时候经常出现资源切换问题,Debug和Release下也会出现不同行为,就连非dll里面模态对话框的支持都是麻烦(还是资源问题)。有一个同事采用CLocalResource解决资源切换麻烦,当然大部分情况下是没有好用的,然而在两个dll互相调用有UI参与的时候还是一样回出现句柄非法。这一切让我明白,好的框架设计和软件职能分解是最只要的。于是我不遗余力的追逐plugin技术,思考软件行为,加强编程技巧。其间受到一位对我影响很大的人的帮助,我感慨万千,人生际遇很重要。
设计技术
UI技巧和算法技巧同等重要。追求过跨平台的UI库(QT、wxWidget),爱慕过小巧的UI库(WTL、fox),甚至冲动的想用Win32写框架、用ATL编写控件库。在项目里,我用ATL写对话框的时候,我尝尽了苦头,没有DDX机制,API麻烦的调用、字符串处理困难等。要解决这些问题,不得不引入其他库,考虑一下:你用的库别人熟悉吗?你用的库别人容易用吗?每个人都要引入库会不会冗余?当加入所有这些支持,恐怕比MFC不会小到那里(这里意思不是反对使用其他库而鼓吹MFC)。实际的项目很少是一人所为,所以应该选择大家都熟悉的库(是什么?)。也曾经嫌弃过MFC,现在不了,而是想如何充分利用他所有机制。
涉及到的技术有:idl、ATL、MFC。用idl文件定义系统接口,形成system的脉络。ATL制作插件,实现system的必须接口。MFC提供system的UI基础设施(Toolbar Frame Doc/View ......)。
目标
实现一般界面元素的plugin扩展支持,依次实现Toolbar plugin、menu plugin、statusbar plugin、dockbar plugin、Doc/View plugin,通过XML配置描述插件实现UI。
技术思路
一个灵活的系统必须有清晰的结构,为扩展提供必要的内建支持设施。结构的清晰保证插件可以合理操纵系统的编程点,内建支持保证插件扩展的简单性、UI统一性、UI多样性(只需系统内部修改UI样式即可实现不同风格UI)。
看几个结构模型:DOM模型、VBA、.NET的CodeDOM。
(DOM)
(.NET CodeDOM)
(VBA)
通过上面的图形,我们可以清楚看到他们都有一个顶级对象,通过该顶级对象可以获取模型中的一切可编程对象。而作为一个外界插件,需要了解系统只需获取该顶级对象即可,该顶级对象在插件加载的时候传递给插件。
框架设计
系统通过一个顶级对象IApplication可以获取所有内部对象。加载插件的时候传递该对象,插件通过该对象了解系统模型,创建UI、设置命令接口。系统拥有插件的命令接口驱动插件,插件拥有系统模型调用系统功能,彼此间互相了解,正常通信。
接口设计
[
object
,
uuid(D6424B18
-
886A
-
47c8
-
8D10
-
A8A977C1DBF4),
helpstring(
"
IApplication Interface
"
),
pointer_default(unique)
]
interface
IApplication : IUnknown
{
[id(
1
), helpstring(
"
method GetMainFrame
"
), hidden] HRESULT GetMainFrame([
out
, retval]IMainFrame
**
ppMainFrame);
}
;
[
object
,
uuid(D59C6E9F
-
70F6
-
44b0
-
8358
-
5AA0BB6DB1D1),
helpstring(
"
IMainFrame Interface
"
),
pointer_default(unique)
]
interface
IMainFrame : IUnknown
{
[id(
1
), helpstring(
"
method CreateToolBar
"
), hidden] HRESULT CreateToolBar([
in
]BSTR bstrCaption, [
out
, retval]IWLWToolBar
**
ppToolBar);
[id(
2
), helpstring(
"
method GetMainWnd
"
), hidden] HRESULT GetMainWnd([
out
, retval]LONG
*
pMainWnd);
}
;
[
object
,
uuid(687ACF1C
-
1EC0
-
4808
-
B04C
-
9455B97D3D6D),
helpstring(
"
IAddin Interface
"
),
pointer_default(unique)
]
interface
IWLWAddin : IUnknown
{
[id(
1
), helpstring(
"
method OnConnect
"
), hidden] HRESULT OnConnect([
in
]IApplication
*
pApp);
[id(
2
), helpstring(
"
method OnDisconnect
"
), hidden] HRESULT OnDisconnect();
}
;
[
object
,
uuid(1ED92132
-
09BF
-
409b
-
951D
-
EEE68706C67C),
helpstring(
"
IToolBar Interface
"
),
pointer_default(unique)
]
interface
IWLWToolBar : IUnknown
{
[id(
1
), helpstring(
"
method SetToolbarInfo
"
), hidden] HRESULT SetToolbarInfo(
[
in
]LONG lInstance, [
in
]IWLWCommand
*
pICommand,
[
in
]LONG lBitmapResource);
[id(
2
), helpstring(
"
method AddCommand
"
), hidden] HRESULT AddCommand(
[
in
]BSTR bstrCommand, [
in
]BSTR bstrTooltip,
[
in
]BSTR bstrMessage, [
in
]LONG lBitmapOffset);
[id(
3
), helpstring(
"
method FinishAdd
"
), hidden] HRESULT FinishAdd();
}
;
[
object
,
uuid(
05393789
-
A95B
-
4172
-
941A
-
E532DF38F4E4),
helpstring(
"
ICommand Interface
"
),
pointer_default(unique)
]
interface
IWLWCommand : IUnknown
{
[id(
1
), helpstring(
"
method OnCommand
"
), hidden] HRESULT OnCommand([
in
]BSTR bstrCommand, [
in
]LONG wParam, [
in
]LONG lParam);
[id(
2
), helpstring(
"
method Enable
"
), hidden] HRESULT Enable([
in
]BSTR bstrCommand, [
in
]LONG wParam, [
in
]LONG lParam, [
out
, retval]VARIANT_BOOL
*
pbEnable);
}
;
目前实现
工具栏插件基本实现,通过文本文件加载插件。处理工具栏按钮tooltip、状态栏提示、消息响应、UI状态处理。
修改意见:添加下拉式按钮、添加控件到工具栏、添加Rebar风格工具栏、定制工具栏。
插件文本:
界图:
代码下载 内含说明
学习同时谢谢提出意见
posted on 2006-10-13 14:30
万连文 阅读(2418)
评论(4) 编辑 收藏 引用 所属分类:
小作品