IVsDropdownBarClient和GetEntryText:文本缓冲区的问题

时间:2015-02-11 15:56:21

标签: c# visual-studio-2013 visual-studio-extensions

在我的Visual Studio扩展程序中,我将阅读导航栏中的文本。因此我会监听窗口创建的事件,并从IVsCodeWindow对象中获取IVsDropdownBar以获取下拉栏中的当前选择。这很好用。然后,我使用以下代码段来提取当前选择的文本:

 string text;
 barClient.GetEntryText(MembersDropdown, curSelection, out text);
 if (hr == VSConstants.S_OK)
 {
    Debug.WriteLine("Text: " + text);
 } else  {
    Debug.WriteLine("No text found!");
 }

然而,这不起作用。我的扩展程序在代码段的第二行中以未处理的异常崩溃。我阅读了文档,可以找到以下注释:

  

ppszText中返回的文本缓冲区通常由   IVsDropdownBarClient对象和缓冲区必须持续生命   IVsDropdownBarClient对象。如果你正在实施这个   托管代码中的接口,您需要处理该字符串   通过调用者,实现IVsCoTaskMemFreeMyStrings接口   IVsDropdownBarClient接口。

我认为这是我的问题的一部分,但我无法理解我的代码中需要更改的内容才能使其正常工作。任何提示?

1 个答案:

答案 0 :(得分:0)

我现在很确定Visual Studio SDK Interop DLL有IVsDropDownbarClient.GetEntryText的错误编组信息,并且无法使用该接口调用该方法。

到目前为止,我找到的最佳解决方法是:

  1. 使用tlbimp工具为textmgr生成备用Interop DLL。 (您可以放心地忽略几十个警告,包括关于GetTextEntry的警告。)

    tlbimp" c:\ Program Files(x86)\ Microsoft Visual Studio 11.0 \ VSSDK \ VisualStudioIntegration \ Common \ Inc \ textmgr.tlb"

  2. (可选)如果您正在使用源代码管理,那么您可能希望将生成的文件(TextManagerInternal.dll)复制到扩展项目的子目录中,并将其作为外部项目进行检查依赖性。

  3. 在Visual Studio扩展项目中,添加对文件的引用(TextManagerInternal.dll)。

  4. 添加以下应正确处理字符串编组的方法。

    static public string HackHackGetEntryText(IVsDropdownBarClient client, int iCombo, int iIndex)
    {
        TextManagerInternal.IVsDropdownBarClient hackHackClient = (TextManagerInternal.IVsDropdownBarClient) client;
    
        string szText = null;
        IntPtr ppszText = IntPtr.Zero;
    
        try
        {
            ppszText = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(IntPtr)));
            if(ppszText == IntPtr.Zero)
                throw new Exception("Unable to allocate memory for IVsDropDownBarClient.GetTextEntry string marshalling.");
    
            hackHackClient.GetEntryText(iCombo, iIndex, ppszText);
    
            IntPtr pszText = Marshal.ReadIntPtr(ppszText);
    
            szText = Marshal.PtrToStringUni(pszText);
        }
        finally
        {
            if(ppszText != IntPtr.Zero)
                Marshal.FreeCoTaskMem(ppszText);
        }
    
        return szText;
    }
    

    }