前置背景
VS带有菜单的插件具体如何开发请参照:http://blog.csdn.net/zgke/article/details/3041630。在我的工程中为了叙述方便(因为我用我的工程中的代码为例子),我把上述网站的例子中的父菜单——代码生成更改为Iava。
硬件环境
VS2008 + xp sp3
背景
最近正在开发一个VS2008的插件(带有菜单),具体什么功能我就不叙述了。在开发过程中遇到这样的一个问题:我无法卸载我的插件菜单。本片文章是记录我在开发过程中该如何去卸载我的插件菜单。
问题描述
现在假设我们开始开发菜单插件,
1. 当前系统有且仅有一个VS2008实例(插件工程,工程名称为IavaMenu),此时是没有安装插件,当前菜单(部分)如下图:
图一注:因为安装了VAssistX插件,所有有这个菜单项,对本例子中无影响。
2. 用以下的代码来制作插件菜单(代码一):
public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom) { BeginData.ApplicationObject = (DTE2)application; BeginData.AddInInstance = (AddIn)addInInst; if (connectMode == ext_ConnectMode.ext_cm_UISetup) { Commands2 commands = (Commands2)BeginData.ApplicationObject.Commands; string toolsMenuName = "Iava";//父菜单项的名称 Microsoft.VisualStudio.CommandBars.CommandBar menuBarCommandBar = ((Microsoft.VisualStudio.CommandBars.CommandBars)BeginData.ApplicationObject.CommandBars)["MenuBar"]; CommandBarControl toolsControl = null; try { ////这个是删除备份用的,也就是说当不想要此菜单的时候,可以通过这个方法给删除掉. //toolsControl = menuBarCommandBar.Controls[toolsMenuName]; //if (toolsControl != null) //{ // toolsControl.Delete(null); //} //return; //如果当前没有toolsMenuName菜单项,不会返回null,直接报错 toolsControl = menuBarCommandBar.Controls[toolsMenuName]; } catch { CommandBar menuObj = (CommandBar)BeginData.ApplicationObject.Commands.AddCommandBar("Iava(&I)", vsCommandBarType.vsCommandBarTypeMenu, ((Microsoft.VisualStudio.CommandBars.CommandBars)BeginData.ApplicationObject.CommandBars)["MenuBar"], 4); //4表示是第四个菜单项 toolsControl = menuBarCommandBar.Controls[toolsMenuName]; } CommandBarPopup toolsPopup = (CommandBarPopup)toolsControl; Factory.AddMenu(commands, toolsPopup); } }
3. 按F5运行后会启动第二个VS2008实例,该VS2008的菜单的效果是:
4. 终止插件工程,第二个VS2008实例将会自动结束。(3,4步可以重复操作)(这里必须要点击菜单中的按钮,让它激活,否则在第六步的时候不能正确的显示图二的效果,以下的类似步骤都需要有这个操作)
5. 关闭IavaMenu工程,此时系统中没有任何VS2008工程
6. 重新打开IavaMenu工程,此时VS2008的菜单的效果跟第三步中的图片一模一样。并且如果你修改代码中的任何地方,重新生成的时候,将会出现以下的错误:
无法将文件“obj\Debug\IavaMenu.dll”复制到“bin\IavaMenu.dll”。文件“bin\IavaMenu.dll”正由另一进程使用,因此该进程无法访问该文件。
为什么会出现这样了?我想主要是因为在第三步的时候,就相当于已经安装了我们自己开发的插件了,所以你再次启动任何一个VS2008的时候,就会加载我们自己的插件。实际上我们希望的是重新打开IavaMenu工程(或者启动一个VS2008实例)的菜单效果跟第一步是一样的,并且该IavaMenu正在被VS2008使用才导致上述的错误。这里有人会要疑惑为什么会有第5,6两个连续的步骤,可以不关闭工程,继续开发菜单,然后调试。实际的开发过程中,有可能我们需要花费数天去开发插件,而不是一天就能开发完成。所以5,6两步可以看成是第五步:当天关闭;第六步:第二天打开。
解决方法
目前我只有一个比较麻烦的解决方法,如果有人有好的解决方法请不吝赐教,谢谢。因为已经进行了问题描述中的前5步,我们从第六步开始重新描述,并且步骤序号从1重新开始:
1. 打开IavaMenu工程,详细描述见上述第六步
2. 关闭IavaMenu工程,找到IavaMenu\bin目录下的IavaMenu.dll,并删除掉,这个时候为什么可以删除?因为我已经把所有的VS2008实例关闭了。
3. 重新打开IavaMenu工程,此时的菜单项,依然是跟上述的第三步的菜单项一模一样,但是此时我们先不运行(编译)IavaMenu工程,我们把OnConnection函数修改如下(代码二):
public void OnConnection(object application,ext_ConnectMode connectMode,object addInInst,ref Array custom) { if (connectMode == ext_ConnectMode.ext_cm_UISetup) { Commands2commands = (Commands2)BeginData.ApplicationObject.Commands; stringtoolsMenuName = "Iava";//父菜单项的名称 Microsoft.VisualStudio.CommandBars.CommandBar menuBarCommandBar= ((Microsoft.VisualStudio.CommandBars.CommandBars)BeginData.ApplicationObject.CommandBars)["MenuBar"]; CommandBarControltoolsControl = null; try { //这个是删除备份用的,也就是说当不想要此菜单的时候,可以通过这个方法给删除掉. toolsControl = menuBarCommandBar.Controls[toolsMenuName]; if(toolsControl != null) { toolsControl.Delete(null); } return; } catch { } } }
然后按F5运行。启动第二个VS2008实例,该VS2008的菜单的效果是图一
Iava菜单消失了(上述代码的功劳)。这个时候为什么可以运行?因为我已经在第二步吧IavaMenu.dll给删除了。
4. 暂停IavaMenu工程,第二个VS2008实例将会自动关闭。
5. 关闭IavaMenu工程。
6. 重新打开IavaMenu工程。这个时候的菜单项如图一。这个是我们想要的菜单结果。但是如果我们在代码中作任何的修改,运行(编译)会出现上述问题第六步中的那个错误。
7. 操作同第二步
8. 重新打开IavaMenu工程,菜单是我们想要的结果,这个时候也可以进行正常的编译和运行了
注意:千万不能在第五步中就删除IavaMenu.dll,如果在第五步就删除dll文件时,在第六步将不会加载我们修改后的插件(删除菜单),所以依然会出现图二,而不能正确的得到图一的结果。
其他问题
在上述的2个执行顺序期间中,我没有启动第三个VS2008实例,如果启动第三个VS2008实例,有可能会出现其他的问题,有兴趣的朋友可以自己去观察观察。