小T历险记
来源:互联网 发布:广域网优化设备 编辑:程序博客网 时间:2024/04/28 02:54
Prelude
小T今年刚从大学毕业。由于上学的时候不好好学习,毕业时候找工作非常困难。好在平时上C语言课帮女生写作业还积攒了一点经验值,好歹最后还是找到了一份写程序的工作。上班第一天,他接到一个任务,给一个word 2003的插件添加一个command bar,上面再添加一个commandbar button。倒霉的小T,悲惨的生活从此拉开了序幕。
Section 1
每一个新手,都应该感谢google。没有他,真不知道该怎么把事情搞定。小T也不例外。在一番寻找之后,不花多少力气。颇有基础的小T已经能够创建一个Command Bar了。代码虽然是Ctrl+C, Ctrl+V过来的,不过能用就行。
- CommandBar commandBar = application.CommandBars.Add("TestCommandBar", MsoBarPosition.msoBarTop, false, true);
- commandBar.Visible = true;
搞定了Command Bar,胜利还会远吗?我们小T还蛮仔细的,特意多启动了几次Word。确保每次它都在那,而且只有一个。小T暗自得意,并顺带对M$公司心生敬意。真是一个伟大的公司啊。设计的软件可扩展性这么好,简单易学。
继续放狗。不多时,Command Bar Button也搞定了。- CommandBarControl commandBarControl = commandBar.Controls.Add(MsoControlType.msoControlButton, Type.Missing, Type.Missing, Type.Missing, true);
- CommandBarButton commandBarButton = (CommandBarButton)commandBarControl;
- commandBarButton.Caption = "TestCommandBar";
- commandBarButton.Style = MsoButtonStyle.msoButtonCaption;
- commandBarButton.Visible = true;
- commandBarButton.Click += delegate {MessageBox.Show("Hello");};
我KAO!居然一次成功。可以用了,交差吧。小T走到QA面前,把程序给她装上。开心地去吃午饭了,准备庆祝一下这难得的开门红。
Section 2
午饭归来。QA就报了一个bug。这可能是小T从业以来处理的第一个Bug吧。恭喜,你的与虫斗其乐无穷的生活正式宣告开始了。Bug还蛮诡异的,就是你不停地点。到一定次数,MessageBox就不再出来了。小T心想,我KAO,这是什么鸟问题啊?好吧,我来试试。我点一下。我点两下。我点三下。。。。喂?玩我那?没问题啊。于是小T把Jira上的Bug Report标记为Can not reproduce。心中暗暗不爽,什么鸟QA嘛。
不多久,QA过来告诉他,重现啦,又重现啦。小T望着reopen的BugReport,觉得很不是滋味。好吧,我多试试。点了N下。耶?真的诶,这是咋回事?放狗吧,搜了半天,没发现啥有用的。在网络和debugger之间耗费了接近一个下午之后,终于找到了一个同样悲惨的人在一篇blog的小字中提到了这个问题的原因。正确的写法麻烦多了:
- private _CommandBarButtonEvents_ClickEventHandler handler;
- private CommandBarButton commandBarButton;
- private void InitializeCommandBar(Application application)
- {
- CommandBar commandBar = application.CommandBars.Add("TestCommandBar", MsoBarPosition.msoBarTop, false, true);
- commandBar.Visible = true;
- CommandBarControl commandBarControl = commandBar.Controls.Add(MsoControlType.msoControlButton, Type.Missing, Type.Missing, Type.Missing, true);
- commandBarButton = (CommandBarButton)commandBarControl;
- commandBarButton.Caption = "TestCommandBar";
- commandBarButton.Style = MsoButtonStyle.msoButtonCaption;
- commandBarButton.Visible = true;
- handler = new _CommandBarButtonEvents_ClickEventHandler(commandBarButton_Click);
- commandBarButton.Click += handler;
- }
- private void commandBarButton_Click(CommandBarButton Ctrl, ref bool CancelDefault)
- {
- MessageBox.Show("Hello");
- GC.Collect();
- }
好,这下就算强制GC也不会出问题了。写完这些代码,小T开始抱怨起来了。这么多人骂M$,那不是没有道理的啊。。。
Section 3
第二天早上。QA又报Bug了。创建一个新文档,在新创建的文档里,按钮不好使了。小T第一反应是怎么可能,代码都是一样的,我又没判断当前是哪篇文档?难道他们是两个commandbar?不过铁的事实摆在那里,还真有问题。小T的第一个怀疑就是,两篇word文档是两个word进程。然后有传说中的并发问题?怀疑很快被否定了,Word在大部分情况下只有一个进程(嘿嘿,大部分情况。。。)。那会是什么问题呢?哎,一早上的好心情就给它糟蹋了。放狗吧。这下就更加没有头绪了。你说我怎么把这个现象用关键字描述出来呢?找都不好找。等到快下班,功夫不负有心人。在一次无意的尝试之后,发现了问题的解决方案,那就是“一行代码”:- commandBarButton.Tag = "TestCommandBar";
Section 4
事情到这里还没完。一天BA告诉小T,需求有变化。客户说这按钮能不能加到我平常用的Command Bar上啊。那么多CommandBar我不喜欢。好吧,那就给它加到Standard Command Bar上吧。改一行代码就行,嘿嘿,知道什么叫Well-Design了吧:- CommandBar commandBar = application.CommandBars["Standard"];
- foreach (CommandBarControl ctrl in commandBar.Controls)
- {
- if (ctrl.Tag.Equals("TestCommandBar"))
- {
- return;
- }
- }
- CommandBarControl commandBarControl = commandBar.Controls.Add(MsoControlType.msoControlButton, Type.Missing, Type.Missing, Type.Missing, true);
Section 5
好日子似乎来临了。插件装在客户的机器上,一直良好。版本2.0就快要发布了。这个时候问题出现了。QA发现,V1.0卸载之后,按钮还在那里。嗯,这个问题我知道,小T心想。就是那个Temporary的问题嘛。看来不光是不能添加两遍,还得考虑怎么删掉它。那不如每次程序退出的时候就删了吧,省得夜长梦多。- ApplicationEvents4_Event events = application;
- events.Quit += delegate {
- CommandBar commandBar = application.CommandBars["Standard"];
- commandBar.Reset();
- };
但是。。。没有效果。有些时候,是没有解释的。看来只能写一个Uninstaller来卸载啦。
- public class Program
- {
- public static void Main(string[] args)
- {
- Application application = new Application();
- application.Visible = true;
- application.CommandBars["Standard"].Reset();
- }
- }
小T禁不住想问,为什么基本同样的代码在不同的地方执行就有不同的效果呢?
画外音:嗯,This is a good question~~这正式Office插件开发的奇妙之处啊。
这个时候,我们的小T已经不再是菜鸟了。但是你以为你已经知道了一切了吗?嘿嘿。。。
Section 6
难以伺候的客户又抱怨了。这个按钮为什么不能自定义啊。哦,我们伟大的word2003,它有强大的用户自定义功能。小T写的按钮必须在Standard CommandBar上,拖到别的地方去下次又会创建出一个新的出来。公司的UD人员看到了,en,这可用性太差啦。不行,得给我改。好吧,小T,心想,我真是命苦啊。改进后的代码,不再强制要求在Standard Command Bar下了。- CommandBarControl foundControl = application.CommandBars.FindControl(Type.Missing, Type.Missing, "TestCommandBar", Type.Missing);
- if (foundControl != null)
- {
- return;
- }
Section 7
小T在上一个项目干得不错。于是公司觉得小T干这个比较在行,所以第二个项目也是一个word2003的插件。小T这次总结上次的经验,一开始就关注这卸载的问题。在无数个皓首穷经,不眠不休的夜晚之后,终于让小T找到了更可靠的使用wordapi的办法。那就是不用word api。word 2003的commandbar的改动其实是存储在template和document上的。所以小T把之前添加一大堆代码浓缩成了一句话:
- object install = true;
- application.AddIns.Add(@"c:/my_template.dot", ref install);
Section 8
新项目的需求中包括让不同文档窗口上的按钮状态独立。就像你按下B,当前输入的文字就粗体了那样。这下可把小T难住了。不过,不死的小T还是最终活下来了。其实也没几行代码,关键就是你知道不知道。word application有一个隐藏属性(其实没隐藏,只是文档上没说,官方说法是Itis for internal use。。。)CustomizationContext。所以:
- private void HandleNewDocument(Document document)
- {
- application.CustomizationContext = document;
- InitializeCommandBar(application);
- }
小T这次真的有些得意了。这我都能搞定,太天才了。拥有多年开发经验的PM走过来,三击了一下word的快捷方式。瞬间启动了三个word窗口。僵死了半分钟之后,发现两个窗口上有command bar,一个没有。出错日志表明,wordapi抛出了ComException。。。小T,顿时觉得有一些无奈,word出错,我能怎么办?把CustomizationContext那行去掉,一切正常。。。
Conclusion
CommandBar的王道是用.dot加CustomizationContext。但是要认识到这一点,不写烂两三个项目是做不到的。小T的原型也就是本人,在写两个Outlook 2007插件,一个Outlook 2003插件,一个Excel插件,N个PowerPoint插件,一个Word插件,然后再来写一个Word插件的时候才认识到这一点。。。也许只是我太笨了。
- 小T历险记
- 小Tango梦游历险记
- 小老鼠历险记
- 小白历险记
- 100T核心数据库升级历险记
- \t\t小题目
- 【小白历险记】ELK日志系统安装部署指南
- 小明历险记:规则引擎drools教程一
- T-SQL 小介绍
- 小t的游戏
- 巨石强森还是成熟了——小评《巫山历险记》
- 爱情历险记
- 加班历险记
- 买房历险记
- MyBookWorld历险记
- Git历险记
- Git历险记
- git 历险记
- Disable select in Mozilla Firefox
- IIS与ASP什么关系
- oracle常用命令
- 使用规划求解进行优化计算
- Windows 找不到文件'(null)'.请确定文件名是否正确后,再试一下.要搜索文件
- 小T历险记
- DataShow:Microsoft SQL Server数据库建模工具正式发布
- Chrome浏览器下CSDN博客访问不太正常
- 当有U盘插入时,读取U盘中的所有文件
- JS 正则基础
- javascript实现的动态添加表单元素input,button等(appendChild)
- 英文之美
- 关于Orion服务器
- 10月杂响