您的位置:知识库 » 其他分类

小T历险记

作者: taowen  发布时间: 2008-10-30 10:45  阅读: 1310 次  推荐: 0   原文链接   [收藏]  

 Prelude

小T今年刚从大学毕业。由于上学的时候不好好学习,毕业时候找工作非常困难。好在平时上C语言课帮女生写作业还积攒了一点经验值,好歹最后还是找到了一份写程序的工作。上班第一天,他接到一个任务,给一个word 2003的插件添加一个command bar,上面再添加一个command bar button。倒霉的小T,悲惨的生活从此拉开了序幕。

 Section 1

每一个新手,都应该感谢google。没有他,真不知道该怎么把事情搞定。小T也不例外。在一番寻找之后,不花多少力气。颇有基础的小T已经能够创建一个Command Bar了。代码虽然是Ctrl+C, Ctrl+V过来的,不过能用就行。

CommandBar commandBar = application.CommandBars.Add("TestCommandBar", MsoBarPosition.msoBarTop, falsetrue);

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;

恩,那Type.Missing是什么东西?哎,早知道用VBA写,可能会容易一些。接下来就是响应Click事件啦。

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的Bug Report,觉得很不是滋味。好吧,我多试试。点了N下。耶?真的诶,这是咋回事?放狗吧,搜了半天,没发现啥有用的。在网络和debugger之间耗费了接近一个下午之后,终于找到了一个同样悲惨的人在一篇blog的小字中提到了这个问题的原因。正确的写法麻烦多了:

private _CommandBarButtonEvents_ClickEventHandler handler;
private CommandBarButton commandBarButton;

private void InitializeCommandBar(Application application)
{
  CommandBar commandBar 
= application.CommandBars.Add("TestCommandBar", MsoBarPosition.msoBarTop, falsetrue);
  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第一反应是怎么可能,代码都是一样的,我又没判断当前是哪篇文档?难道他们是两个command bar?不过铁的事实摆在那里,还真有问题。小T的第一个怀疑就是,两篇word文档是两个word进程。然后有传说中的并发问题?怀疑很快被否定了,Word在大部分情况下只有一个进程(嘿嘿,大部分情况。。。)。那会是什么问题呢?哎,一早上的好心情就给它糟蹋了。放狗吧。这下就更加没有头绪了。你说我怎么把这个现象用关键字描述出来呢?找都不好找。等到快下班,功夫不负有心人。在一次无意的尝试之后,发现了问题的解决方案,那就是“一行代码”:

commandBarButton.Tag = "TestCommandBar";

 我KAO,居然这么简单……但是文档就是不写(MSDN唱到:就不告诉你,就不告诉你,就不告诉你~)

 Section 4

事情到这里还没完。一天BA告诉小T,需求有变化。客户说这按钮能不能加到我平常用的Command Bar上啊。那么多Command Bar我不喜欢。好吧,那就给它加到Standard Command Bar上吧。改一行代码就行,嘿嘿,知道什么叫Well-Design了吧:

CommandBar commandBar = application.CommandBars["Standard"];

嗯,挺好的。工作正常。咦?等我再试一下。shit!怎么有两个Test Command Bar Button出来?我KAO,又多了一个。。。无语。之前的代码咋就没问题呢?那就在添加之前判断一下吧,如果之前的button存在,就不添加了。

foreach (CommandBarControl ctrl in commandBar.Controls)
{
  
if (ctrl.Tag.Equals("TestCommandBar"))
  {
    
return;
  }
}

小T觉得很不爽。添加按钮的时候我不是说了是Temporary嘛:

CommandBarControl commandBarControl = commandBar.Controls.Add(MsoControlType.msoControlButton, Type.Missing, Type.Missing, Type.Missing, true);

 呵呵,谁让你相信MSDN的啊?真是天真的傻孩子。事实证明,Temporary的行为极其诡异。

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

难以伺候的客户又抱怨了。这个按钮为什么不能自定义啊。哦,我们伟大的word 2003,它有强大的用户自定义功能。小T写的按钮必须在Standard Command Bar上,拖到别的地方去下次又会创建出一个新的出来。公司的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干这个比较在行,所以第二个项目也是一个word 2003的插件。小T这次总结上次的经验,一开始就关注这卸载的问题。在无数个皓首穷经,不眠不休的夜晚之后,终于让小T找到了更可靠的使用word api的办法。那就是不用word api。word 2003的command bar的改动其实是存储在template和document上的。所以小T把之前添加一大堆代码浓缩成了一句话:

object install = true;
application.AddIns.Add(
@"c:\my_template.dot", ref install);

 这类型为ref object的函数参数实在是。。。(无语,[ref object]就更加牛x了。。。)。然后再结合FindControl,监听事件。齐活,小T终于感觉自己摸到了门道。

Section 8

新项目的需求中包括让不同文档窗口上的按钮状态独立。就像你按下B,当前输入的文字就粗体了那样。这下可把小T难住了。不过,不死的小T还是最终活下来了。其实也没几行代码,关键就是你知道不知道。word application有一个隐藏属性(其实没隐藏,只是文档上没说,官方说法是It is for internal use。。。)CustomizationContext。所以:

private void HandleNewDocument(Document document)
{
  application.CustomizationContext 
= document;
  InitializeCommandBar(application);
}

 

 小T这次真的有些得意了。这我都能搞定,太天才了。拥有多年开发经验的PM走过来,三击了一下word的快捷方式。瞬间启动了三个word窗口。僵死了半分钟之后,发现两个窗口上有command bar,一个没有。出错日志表明,word api抛出了ComException。。。小T,顿时觉得有一些无奈,word出错,我能怎么办?把CustomizationContext那行去掉,一切正常。。。

Conclusion

Command Bar的王道是用.dot加CustomizationContext。但是要认识到这一点,不写烂两三个项目是做不到的。小T的原型也就是本人,在写两个Outlook 2007插件,一个Outlook 2003插件,一个Excel 插件,N个PowerPoint插件,一个Word插件,然后再来写一个Word插件的时候才认识到这一点。。。也许只是我太笨了。

以上只是故事的很少一部分。关于command bar的故事还有很多,比如怎么样取消built-in command bar button的行为,OnAction有什么用,Command bar与Accessibility api的关系,以及著名的Outlook+Word+Command Bar问题。限于个人体力值有限,就不继续展开讲了。每个故事背后,都是无数人的心酸,血泪与青春。M$的东西一如既往地易学难精,而且没有道理。关键是最终你不能获得什么真本事,只能获得一堆“知识”。这些“知识”只对Office开发有用,如果不做office开发根本没有什么价值。在这里,奉劝大家,如果不能换一个项目的话,那就提早离职吧。不要把时间浪费在Office这个愚蠢的平台上了。如果你还真把它当做一个平台的话。

0
0
标签:Office开发

其他分类热门文章

    其他分类最新文章

      最新新闻

        热门新闻