自己动手编写一个VS插件(五)

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.youkuaiyun.com/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

作者:朱金灿

来源:http://blog.youkuaiyun.com/clever101

 

        继续编写VisualStudio插件。这次我编写的插件叫DevAssist(意思是开发助手)。在看了前面的文章之后你知道了一个VisualStudio插件一般是由两个工程组成的:功能dll和资源dll。首先我们先建一个功能dll——DevAssist,具体过程请参考第一篇:自己动手编写一个VS插件(一)。然后我们再建一个资源dll——DevAssistUI。

 

编译一下DevAssistUI工程,结果出错:

generalerror c1010070: Failed to load and parse the manifest

   上网查了下,发现编译一个空工程会出现这个错误,于是把一个位图资源导入进去再编译就没有这个错误了。再编译DevAssistUI工程,还有错误:

 

1>------已启动生成: 项目: DevAssistUI, 配置: Debug Win32 ------

1>正在链接...

1>LINK: error LNK2001: 无法解析的外部符号 __DllMainCRTStartup@12

1>E:\PIE3_src\outdir/Debug/1033\DevAssistUI.dll: fatal error LNK1120: 1 个无法解析的外部命令

1>生成日志保存在“file://E:\PIE3_src\Intdir\Debug\DevAssistUI\BuildLog.htm”

1>DevAssistUI - 2 个错误,0 个警告

========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========

 

       在工程设置里把该工程改为无入口点即可,如下图: 

     

      现在我们开始实现创建一个工具栏并把它显示出来。首先需要在AddIn.rgs中指定资源dll,具体是在HKCU段添加SatelliteDllName和SatelliteDllPath两个变量,具体如下:

HKCU

{

    NoRemove 'SOFTWARE'

    {

       NoRemove 'Microsoft'

       {

           NoRemove 'VSA'

           {

              NoRemove '9.0'

              {

                  NoRemove 'AddIns'

                  {

                     ForceRemove'DevAssist.Connect'

                      {

                         valLoadBehavior = d 1

                         valCommandLineSafe = d 0

                         valCommandPreload = d 0

                         valFriendlyName = s 'DevAssist -开发助手。'

                         valDescription = s 'DevAssist - 用于辅助开发。'

                         valAboutBoxDetails = s '有关DevAssist的详细信息,请参见DevAssist 站点\r\nhttp://blog.youkuaiyun.com/clever101\r\n关于客户支持,请致电: 1-800-xxx-xxxx。\r\n版权所有(C) 2013 DreamStudio Inc.'

                         valAboutBoxIcon = s '%MODULE%,1'

                         val SatelliteDllName = s 'DevAssistUI.dll'

                         valSatelliteDllPath = s '%MODULE_PATH%'

                     }

                  }

              }

           }

       }

    }

    NoRemove 'SOFTWARE'

    {

       NoRemove 'Microsoft'

       {

           NoRemove 'VisualStudio'

           {

              NoRemove '9.0'

              {

                  NoRemove 'AddIns'

                  {

                     ForceRemove'DevAssist.Connect'

                     {

                         valLoadBehavior = d 1

                         valCommandLineSafe = d 0

                         valCommandPreload = d 0

                         valFriendlyName = s 'DevAssist -开发助手。'

                         valDescription = s 'DevAssist - 用于辅助开发。'

                         valAboutBoxDetails = s '有关DevAssist的详细信息,请参见DevAssist 站点\r\nhttp://blog.youkuaiyun.com/clever101\r\n关于客户支持,请致电: 1-800-xxx-xxxx。\r\n版权所有(C) 2013 DreamStudio Inc.'

                         valAboutBoxIcon = s '%MODULE%,1'

                         val SatelliteDllName = s 'DevAssistUI.dll'

                         valSatelliteDllPath = s '%MODULE_PATH%'

                     }

                  }

              }

           }

       }

    }

}

然后开始添加创建工具栏的代码:

// 按钮信息结构体struct stCommandInfo{ LPCTSTR m_name; // 按钮名字 LPCTSTR m_strTip; // 按钮提示 BOOL    m_hasIcon; // 是否有图标 UINT   m_bitmapID; // 对应的位图ID UINT   m_cmdID; // 命令ID};HRESULT CConnect::FindToolbarByName( _CommandBars* pCommandBars, LPCWSTR szToolbarName, CommandBar** pOut ){ if(pCommandBars == NULL || pOut == NULL)  return E_FAIL; CComVariant varToolbarName(szToolbarName)int nToolBars = 0; HRESULT hr = pCommandBars->get_Count(&nToolBars); for(int idx = 1; idx <= nToolBars; idx++) {  CComPtr<CommandBar> pCommandBar;  hr = pCommandBars->get_Item(CComVariant(idx), &pCommandBar);  if(FAILED(hr))   continue;  BSTR bsName = NULL;  if(pCommandBar != NULL)   pCommandBar->get_Name(&bsName);  if(CComVariant(bsName) == varToolbarName)  {   *pOut = pCommandBar;   (*pOut)->AddRef();   break;  }  SysFreeString(bsName);  hr = E_FAIL; } return hr;}// When run, the Add-in wizard prepared the registry for the Add-in.// At a later time, if the Add-in becomes unavailable for reasons such as://   1) You moved this project to a computer other than which is was originally created on.//   2) You chose 'Yes' when presented with a message asking if you wish to remove the Add-in.//   3) Registry corruption.// you will need to re-register the Add-in by building the MyAddin21Setup project // by right clicking the project in the Solution Explorer, then choosing install.void UnregisterCommand(CComPtr<EnvDTE::Commands>& pCommands, LPCWSTR commandName){ CComPtr<EnvDTE::Command> pCommand; // // COMMAND_NAME_FULL must be the module name plus the COMMAND_NAME. // For this case, the module name can be found at the CvsInVC7.rgs and // CvsInVC8.rgs files. // WCHAR item[256]; wcscpy_s(item, 256, MODULE_NAME); wcscat_s(item, 256, commandName); HRESULT hr = pCommands->Item(CComVariant(item), -1, &pCommand); if (SUCCEEDED(hr)) {  pCommand->Delete(); }}// CConnectSTDMETHODIMP CConnect::OnConnection(IDispatch *pApplication, ext_ConnectMode ConnectMode, IDispatch *pAddInInst, SAFEARRAY ** /*自定义*/ ){ HRESULT hr = S_OK; pApplication->QueryInterface(__uuidof(DTE2), (LPVOID*)&m_pDTE); pAddInInst->QueryInterface(__uuidof(EnvDTE::AddIn), (LPVOID*)&m_pAddInInstance); if(ConnectMode == AddInDesignerObjects::ext_cm_CommandLine) {  ::MessageBox(GetActiveWindow(),_T("CConnect::OnConnection, CommandLine Mode"),_T("DevAssist"),MB_OK);  return S_OK; } CComPtr<IDispatch> pDisp; CComPtr<EnvDTE::Commands> pCommands; CComPtr<Commands2> pCommands2; CComQIPtr<_CommandBars> pCommandBars; CComPtr<CommandBar> pCommandBar; IfFailGoCheck(m_pDTE->get_Commands(&pCommands), pCommands); pCommands2 = pCommands; // Get the set of command bars for the application. IfFailGoCheck(m_pDTE->get_CommandBars(&pDisp), pDisp); pCommandBars = pDisp; // See if the toolbar has been created. BOOL bRecreateToolbar = FALSE; hr = FindToolbarByName(pCommandBars, TOOLBAR_NAME, &pCommandBar); if (SUCCEEDED(hr)) {  CComPtr<CommandBarControls> pCommandBarControls;  pCommandBar->get_Controls(&pCommandBarControls);  int count = 0;  pCommandBarControls->get_Count(&count);  if (count == 0)  {           bRecreateToolbar = true;  }  pCommandBar = NULL; } else {  bRecreateToolbar = TRUE; } if(ConnectMode == 5 || bRecreateToolbar) //5 == ext_cm_UISetup {  // See if the CodeLib toolbar has been created.  hr = FindToolbarByName(pCommandBars, TOOLBAR_NAME, &pCommandBar);  if(FAILED(hr))  {   pDisp = NULL;   // The toolbar hasn't been created yet.  Add it.   hr = pCommands->AddCommandBar(CComBSTR(TOOLBAR_NAME),    EnvDTE::vsCommandBarTypeToolbar,    NULL,    1,    &pDisp);   // Yes, this code is unnecessary, but it serves to prove that   // the command bar creation actually worked.   hr = FindToolbarByName(pCommandBars, TOOLBAR_NAME, &pCommandBar);  }  int curToolbarPosition = 1;  int nMaxCommand = sizeof(s_commandList)/sizeof(s_commandList[0]);  for(int curCommand = 0; curCommand < nMaxCommand; ++curCommand)  {   CComPtr<EnvDTE::Command> pCreatedCommand;   const stCommandInfo* commandInfo = &s_commandList[curCommand];   UnregisterCommand(pCommands, commandInfo->m_name);   HRESULT hr2 = pCommands2->AddNamedCommand2(m_pAddInInstance,    CComBSTR(commandInfo->m_name),    CComBSTR(commandInfo->m_name),    CComBSTR(commandInfo->m_strTip),    VARIANT_FALSE,    CComVariant(commandInfo->m_bitmapID),    NULL,    (EnvDTE::vsCommandStatusSupported + EnvDTE::vsCommandStatusEnabled),    EnvDTE80::vsCommandStylePict,    EnvDTE80::vsCommandControlTypeButton,    &pCreatedCommand);   if(SUCCEEDED(hr2) && (pCreatedCommand) &&  commandInfo->m_hasIcon)   {    //Add the control:    pDisp = NULL;    IfFailGoCheck(pCreatedCommand->AddControl(pCommandBar, curToolbarPosition, &pDisp),pDisp);    curToolbarPosition++;   }  } }Error: return hr;}

     编译运行工程,工具栏出来了,但是按钮都是灰的。到网上找了个插件工程参考,发现需要修改CConnect类的基类,具体如下:

//class ATL_NO_VTABLE CConnect : // public CComObjectRootEx<CComSingleThreadModel>,// public CComCoClass<CConnect, &CLSID_Connect>,// public IDispatchImpl<_IDTExtensibility2, &IID__IDTExtensibility2, &LIBID_AddInDesignerObjects, 1, 0>class ATL_NO_VTABLE CConnect :  public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CConnect, &CLSID_Connect>, public IDispatchImpl<EnvDTE::IDTCommandTarget, &__uuidof(EnvDTE::IDTCommandTarget), &EnvDTE::LIBID_EnvDTE, 8, 0>, public IDispatchImpl<_IDTExtensibility2, &IID__IDTExtensibility2, &LIBID_AddInDesignerObjects, 1, 0>

 

修改后工具栏按钮都亮了。

 

遇到的一些问题及解决办法:

 

a. error+C2872:+“ULONG_PTR”:+不明确的符号

 

1>Connect.cpp

1>d:\programfiles\microsoft visual studio 9.0\vc\atlmfc\include\cstringt.h(2253) : errorC2872: “ULONG_PTR”: 不明确的符号

1>        可能是“c:\program files\microsoftsdks\windows\v6.0a\include\basetsd.h(139) : __w64 unsigned long ULONG_PTR”

1>        或      “e:\pie3_src\intdir\debug\devassist\dte80a.tlh(464) :EnvDTE::ULONG_PTR”

1>        d:\program files\microsoft visual studio9.0\vc\atlmfc\include\cstringt.h(2250): 编译类 模板 成员函数“boolATL::CStringT<BaseType,StringTraits>::CheckImplicitLoad(const void *)”时

1>        with

1>        [

1>            BaseType=wchar_t,

1>           StringTraits=ATL::StrTraitATL<wchar_t,ATL::ChTraitsCRT<wchar_t>>

1>        ]

1>        d:\program files\microsoft visualstudio 9.0\vc\atlmfc\include\cstringt.h(2686): 参见对正在编译的类 模板 实例化“ATL::CStringT<BaseType,StringTraits>”的引用

1>        with

1>        [

1>            BaseType=wchar_t,

1>            StringTraits=ATL::StrTraitATL<wchar_t,ATL::ChTraitsCRT<wchar_t>>

1>        ]

1>        d:\program files\microsoft visualstudio 9.0\vc\atlmfc\include\atlstr.h(1139): 参见对正在编译的类 模板 实例化“ATL::CStringElementTraits<T>”的引用

1>        with

1>        [

1>            T=ATL::CAtlStringW

1>        ]

1>正在生成代码...

 

原因分析:对于ULONG_PTR类型,VS2008的类型库和windowsSDK出现重定义。解决办法是:在导入VS2008的类型库时重命名ULONG_PTR类型(LONG_PTR也有类似问题),如下:

 #import "libid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2" version("8.0") lcid("0") raw_interfaces_only named_guids rename("ULONG_PTR","ULONG_PTRDTE") rename("LONG_PTR","LONG_PTRDTE")

b. 链接器工具错误 LINK : fatal error LNK1168: 无法打开..\outdir\Debug\DevAssist.dll 进行写入。

 

解决办法:

在VS里的外接程序管理器里把启动去掉,如下图:

   然后编译如果还要错误就重启VS,如果还有错误就打开任务管理器,杀死所有explorer.exe,然后新建一个explorer进程。

 

c.修改工具栏按钮的位图资源或提示,但是工具栏总是不更新。

   在工具栏的自定义对话框中将工具栏删掉,如下:

      然后重启VS再启动插件即可看到工具栏的更新状态。






           

给我老师的人工智能教程打call!http://blog.youkuaiyun.com/jiangjunshow
这里写图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值