请选择 进入手机版 | 继续访问电脑版
设为首页收藏本站

【技术宅公社】数字艺术论坛   游戏开发 定格动画 动画论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

人人连接登陆

无需注册,直接登录

只需一步,轻松搞定

调查问卷
搜索
www.Exceedu.com视频站即将开放!欢迎投稿!论坛使用专用地址http://forum.exceedu.com/forum

ExceedU@学习圈子在线视频平台与论坛账号现在已经互通,在视频页面注册的朋友在论坛里需要激活!! 通过这个窗口,给我们提意见。我们的数字教程在持续研发当中,感谢大家的关注。

查看: 2721|回复: 15

【转】自己动手编写一个VS插件

[复制链接]
  • TA的每日心情
    开心
    2015-10-29 12:51
  • 签到天数: 13 天

    [LV.3]偶尔看看II

    发表于 2013-8-14 17:24:20 | 显示全部楼层 |阅读模式
    一键分享 一键分享

    作者:朱金灿

    来源:http://blog.csdn.net/clever101


             最近计划开发一个VS插件来帮助自己加快开发速度,研究了一下VS的插件开发。下面配合插图说明一下如何开发一个VS插件。


    第一步:创建插件工程,具体如下图:


               第二步不用干啥,如下图:


           第三步:选择开发语言,这里我选的是C++/ATL,因为这是我最拿手的,当然你也可以选择C#,这里不建议你选择C++/CLR,因为这个几乎冷僻得没人用,一般网上也找不到相关的例程,如下图:


            第四步选择调用程序,第一个是必选的,第二个可选可不选,选上也无妨,如下图:

    第五步输入插件名称和说明,如下图:


    第六步设置用户界面的调用方式,这里简单设置为在宿主应用程序启动时加载,如下图:


    第七步是填写关于信息,如下图:


    第八步是单击完成,如下图:


            由于所生成的插件是一个com组件,需要注册才能使用,因此需要设置一个生成后事件:regsvr32$(OutDir)/$(ProjectName).dll,具体如下图:




    回复

    使用道具 举报

  • TA的每日心情
    开心
    2015-10-29 12:51
  • 签到天数: 13 天

    [LV.3]偶尔看看II

    发表于 2013-8-14 17:28:47 | 显示全部楼层

       继续开发一个VS插件。首先认识一下通过插件向导生成的类和函数,大致弄清一下它们的含义。创建一个基于ATL的插件工程,都生成了一个CConnect类。现在我们看看CConnect类的一些重要接口:


    CConnect::OnConnection:这个接口可以说是插件的入口函数。只是这个入口函数会被调用几次,至于何时调用取决于这个函数的ConnectMode参数。

       

         一个插件有下面几种加载模式:

    • 在VS启动时,并且该插件并标记为随同VS启动时启动(所谓随同VS启动时启动请见图一),这时ConnectMode参数的值为ext_ConnectMode.ext_cm_Startup。

                      







              • 图一


    • 在用户需要时时被调用,就是说该插件并没有被标记为VS启动时启动但用户手动在外接程序管理器上给启动一栏打上勾上时,这时ConnectMode参数的值为ext_ConnectMode.ext_cm_AfterStartup。
    • 从命令行启动(使用devenv.exe去生成一个解决方案),这时ConnectMode参数的值为ext_ConnectMode.ext_cm_CommandLine。请注意这种情况在一些旧版本的Visual Studio会有一些bug并且看来只有在Visual Studio 2008才会正确运行(比VS 2008高的版本应该也可以)。
    • 当插件使用常驻的工具栏、命令栏和按钮(常驻意味着即使插件没有加载用户界面也会出现)同时Visual Studio要求插件去初始化常驻用户界面,这时ConnectMode参数的值为ext_ConnectMode.ext_cm_UISetup。这种连接模式必须不同于ext_ConnectMode.ext_cm_Startup和ext_ConnectMode.ext_cm_AfterStartup的情况下。
    • 假如你建的插件不是一个一般插件,而是一个和特定的解决方案相关的插件,当这个解决方案被加载时,这时ConnectMode参数的值为ext_ConnectMode.ext_cm_AfterStartup。

            所以,存在两种模式:ext_ConnectMode.ext_cm_Startup和ext_ConnectMode.ext_cm_AfterStartup。这意味着它们都以相同的方式处理因为在一般情况下插件在VS启动时自动加载还是过了一些时候手动加载它们并没有什么不同。所以你可以使用下面的代码:

    1. STDMETHODIMP CConnect::OnConnection(IDispatch *pApplication, ext_ConnectMode ConnectMode, IDispatch *pAddInInst, SAFEARRAY ** /*自定义*/ )
    2. {
    3.         HRESULT hr = S_OK;
    4.         pApplication->QueryInterface(__uuidof(DTE2), (LPVOID*)&m_pDTE);
    5.         pAddInInst->QueryInterface(__uuidof(AddIn), (LPVOID*)&m_pAddInInstance);
    6.        
    7.         switch(ConnectMode)
    8.         {
    9.         case ext_cm_Startup:
    10.         case ext_cm_AfterStartup:
    11.                 {
    12.                         // 初始化你的插件

    13.                         break;
    14.                 }
    15.         default:
    16.                 break;
    17.         }
    18.         return hr;
    19. }
    复制代码

       然而当插件在ext_ConnectMode.ext_cm_Startup模式加载(也就是在Visual Studio启动时加载),VisualStudio并没有完全初始化。所以这是很多插件可以正确初始化,但一些却会失败。比如当你的插件加载时需要显示一个工具窗口,当插件在VS启动时加载工具窗口却并不会显示,但在外接程序管理器手动加载这个插件时可以显示这个工具窗口。


           所以在VisualStudioz完全初始化之后再调用OnConnection函数会比较好。IDTExtensibility2接口提供了一个在VisualStudioz完全初始化后会被调用的叫OnStartupComplete的方法。所以正确的代码如下:

    1. STDMETHODIMP CConnect::OnStartupComplete (SAFEARRAY ** /*自定义*/ )
    2. {
    3.         // 初始化你的插件

    4.         return S_OK;
    5. }

    6. // CConnect
    7. STDMETHODIMP CConnect::OnConnection(IDispatch *pApplication, ext_ConnectMode ConnectMode, IDispatch *pAddInInst, SAFEARRAY ** /*自定义*/ )
    8. {
    9.         HRESULT hr = S_OK;
    10.         pApplication->QueryInterface(__uuidof(DTE2), (LPVOID*)&m_pDTE);
    11.         pAddInInst->QueryInterface(__uuidof(AddIn), (LPVOID*)&m_pAddInInstance);
    12.        
    13.         switch(ConnectMode)
    14.         {
    15.         case ext_cm_Startup:
    16.                 // 什么也不做,因为Visual Studio并没有完全初始化
    17.                 break;
    18.         case ext_cm_AfterStartup:
    19.                 {
    20.             OnStartupComplete(NULL);
    21.                         break;
    22.                 }
    23.         default:
    24.                 break;
    25.         }
    26.         return hr;
    27. }
    复制代码

    参考文献:


  • TA的每日心情
    开心
    2015-10-29 12:51
  • 签到天数: 13 天

    [LV.3]偶尔看看II

    发表于 2013-8-14 17:29:38 | 显示全部楼层

    让我们继续开发一个VS插件。上次我们谈论了OnConnection函数,这次我们实现如何在插件中创建一个工具栏。


             首先我们要弄明白VS是如何找到我们所建的插件的。VS插件本质上是一个com组件,其信息保存在注册表里。因此VS也是通过注册表来找到VS插件的。那个VS插件的信息保存在注册表的哪个位置呢?通过分析一些开源插件的源码(主要是分析工程里的AddIn.rgs文件),我发现VS插件的信息主要保存在注册表的下面两个位置(以VS2008为例)中的一个:

    HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\9.0\AddIns

    或者

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Addins


           二者的区别是第一个是当前用户才能使用,第二个是这个机器上所有用户都能使用。


            之前我们提到插件的信息都保存在AddIn.rgs文件。那么我们分析一下这个AddIn.rgs到底保存了哪些信息?


            下面是一个开源的插件工程的AddIn.rgs文件的内容:

    1. HKCR
    2. {
    3.         CppClean.Connect.1 = s 'Connect Class'
    4.         {
    5.                 CLSID = s '{9672D81E-B893-483E-A503-6C1A67D4290A}'
    6.         }
    7.         CppClean.Connect = s 'Connect Class'
    8.         {
    9.                 CLSID = s '{9672D81E-B893-483E-A503-6C1A67D4290A}'
    10.                 CurVer = s 'CppClean.Connect.1'
    11.         }
    12.         NoRemove CLSID
    13.         {
    14.                 ForceRemove '{9672D81E-B893-483E-A503-6C1A67D4290A}' = s 'Connect Class'
    15.                 {
    16.                         ProgID = s 'CppClean.Connect.1'
    17.                         VersionIndependentProgID = s 'CppClean.Connect'
    18.                         ForceRemove 'Programmable'
    19.                         InprocServer32 = s '%MODULE%'
    20.                         {
    21.                                 val ThreadingModel = s 'Apartment'
    22.                         }
    23.                         'TypeLib' = s '{134021C0-52F7-46A0-ADC2-C6230CFA3A95}'
    24.                 }
    25.         }
    26. }

    27. HKCU
    28. {
    29.         NoRemove 'SOFTWARE'
    30.         {
    31.                 NoRemove 'Microsoft'
    32.                 {
    33.                         NoRemove 'VisualStudio'
    34.                         {
    35.                                 NoRemove '9.0'
    36.                                 {
    37.                                         NoRemove 'AddIns'
    38.                                         {
    39.                                                 ForceRemove 'CppClean.Connect'
    40.                                                 {
    41.                                 val LoadBehavior = d 0
    42.                                 val CommandLineSafe = d 0
    43.                                 val CommandPreload = d 0
    44.                                 val FriendlyName = s 'CppClean AddIn'
    45.                                 val Description = s 'AddIn to pursue code high quality'
    46.                         val AboutBoxDetails = s 'Any question about CppClean, mailto:\r\noeichenwei@gmail.com\r\nCopyright (c) 2010 Wilson Chen.'
    47.                         val AboutBoxIcon = s '%MODULE%,1'
    48.                         val SatelliteDllName = s 'CppCleanUI.dll'
    49.                         val SatelliteDllPath = s '%MODULE_PATH%'
    50.                                                 }
    51.                                         }
    52.                                 }
    53.                         }
    54.                 }
    55.         }
    56. }
    复制代码
       初看之下这个rgs文件的内容是杂乱无章的,但是我们仔细分析一下发现还是有章可循的。这个rgs文件的内容大致可以分为两部分:HKCR和HKCU。我们可以看到HKCR部分不过是一般组件的注册信息(这个写过COM组件的同学都知道)。我们重点看看HKCU部分。我们看到HKCU部分的信息保存在HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\9.0\AddIns下面,那么结合注册表(下图),我们可以直观地看到它不过是定义了一些注册表项:



              这些注册表项大部分我们都可以通过搜索网上的资料得到其真实含义:

    LoadBehavior —— 加载行为,联系到上篇我们可以猜到它是在保存加载设置,是VS启动时加载还是单击其按钮时加载

    FriendlyName:可选的,为Add-In指定一个有意义的名称;

    Description:可选的,为Add-In指定有意义的描述信息;

    AboutBoxDetails:都是可选的,如果要在About对话框中显示Add-In的话,该节点用于指定其详细信息和图标;

    LoadBehavior:可选的,指定VS加载Add-In的方式,0表示VS不会自动加载,必须手工加载;1表示Add-in在VS启动的时候加载;4表示通过命令行方式加载;

    CommandPreload:可选的,指定Add-In应当预先加载;

    CommandLineSafe:可选的,指定Add-In是否是命令行安全的以及是否显示用户界面。


              SatelliteDllName和SatelliteDllPath这两个注册表项的含义我们下一篇介绍。这篇到此为止。


    参考文献:



  • TA的每日心情
    开心
    2015-10-29 12:51
  • 签到天数: 13 天

    [LV.3]偶尔看看II

    发表于 2013-8-14 17:30:04 | 显示全部楼层
    上次我们提到SatelliteDllName和SatelliteDllPath这两个注册表项。VS插件中所用到的资源如工具栏按钮之类的单独放在一个dll内,代码逻辑实现放在另一个dll,一般的命令惯例为代码逻辑实现的动态库为Logic.dll,资源动态库为LogicUI.dll。SatelliteDllName就是是指定VS插件中所用到资源dll的名字,SatelliteDllPath则是指定寻找资源dll的基本路径。寻找资源dll依照以下顺序来进行:

    1.      查找SatelliteDllPath\shell UI locale\SatelliteDllName是否存在
    2.      假如失败,寻找SatelliteDllPath\ User's preferred OS Locale \SatelliteDllName是否存在
    3.      假如失败,寻找SatelliteDllPath\ User's setup OS Locale \SatelliteDllName是否存在
    4.      假如失败,寻找SatelliteDllPath\ 1033 \SatelliteDllName是否存在
    5.      假如失败,寻找SatelliteDllPath \SatelliteDllName是否存在

           一般我们习惯在插件输出目录下新建一个1033的文件夹,资源dll就放在这个1033文件夹下。前面我们已经新建了DevHelper工程,下面我们就新建一个DevHelperUI工程作为它的资源dll。
    1. 新建一个DevHelperUI的Win 32项目

    2.单击下一步,如下图

    3. 类型选择DLL,附加选项为空项目,单击完成,如下图:

    4.输出路径设置输出到1033文件夹下,如下图:

    5. 将所需的资源添加到工程下,如下图:


                未完待续,敬请继续关注!

    参考文献:

    该用户从未签到

    发表于 2014-6-30 22:32:30 | 显示全部楼层
    谢谢楼主分享
  • TA的每日心情
    无聊
    2014-8-27 17:10
  • 签到天数: 1 天

    [LV.1]初来乍到

    发表于 2014-8-27 17:22:54 | 显示全部楼层
    谢谢楼主分享

    该用户从未签到

    发表于 2014-8-27 18:10:34 | 显示全部楼层
    非常感谢!楼主好人!

    该用户从未签到

    发表于 2014-10-8 00:48:15 | 显示全部楼层
    楼主好人,学习了

    该用户从未签到

    发表于 2014-12-1 21:30:10 | 显示全部楼层
    支持下,看看
    [发帖际遇]: guojiayu888 乐于助人,奖励 2 荣誉点数. 幸运榜 / 衰神榜
  • TA的每日心情
    开心
    2014-12-9 20:39
  • 签到天数: 1 天

    [LV.1]初来乍到

    发表于 2014-12-9 20:44:35 | 显示全部楼层
    好东西  收藏了
  • TA的每日心情
    无语
    2017-9-2 11:50
  • 签到天数: 351 天

    [LV.8]以坛为家I

    发表于 2015-1-22 22:13:36 | 显示全部楼层
    牛人。。学习了。。。。。。
    [发帖际遇]: 一个袋子砸在了 tianheww 头上,tianheww 赚了 2 工分. 幸运榜 / 衰神榜
  • TA的每日心情
    臭美
    2015-4-12 09:47
  • 签到天数: 1 天

    [LV.1]初来乍到

    发表于 2015-4-12 10:06:44 | 显示全部楼层
    支持一下,大神的东西
    [发帖际遇]: lin998776每日按时发帖,抽中奖励 2 荣誉点数. 幸运榜 / 衰神榜
  • TA的每日心情
    撞墙
    2015-5-14 14:22
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2015-5-13 21:00:13 | 显示全部楼层
    技术牛人,真不错!
  • TA的每日心情
    生病
    2015-9-8 16:22
  • 签到天数: 1 天

    [LV.1]初来乍到

    发表于 2015-9-8 16:35:06 | 显示全部楼层
    自制插件,从此妈妈再也不用担心我的学习了
    高级模式
    您需要登录后才可以回帖 登录 | 立即注册 人人连接登陆

    本版积分规则

    申请友链|小黑屋|手机版|ExceedU数字艺术 ( 沪ICP备14023054号  

    GMT+8, 2018-8-20 21:11

    Powered by Discuz! X3.2

    © 2001-2013 Comsenz Inc.

    快速回复 返回顶部 返回列表