C# IVsDropdownBarClient和GetEntryText:文本缓冲区存在问题

C# IVsDropdownBarClient和GetEntryText:文本缓冲区存在问题,c#,visual-studio-2013,visual-studio-extensions,C#,Visual Studio 2013,Visual Studio Extensions,在我的VisualStudio扩展中,我将阅读导航栏中的文本。因此,我监听窗口创建的事件,并从IVsCodeWindow对象中获取IVsDropdownBar以获取下拉栏中的当前选择。这个很好用。然后,我使用以下代码片段提取当前选择的文本: string text; barClient.GetEntryText(MembersDropdown, curSelection, out text); if (hr == VSConstants.S_OK) { Debug.WriteLi

在我的VisualStudio扩展中,我将阅读导航栏中的文本。因此,我监听窗口创建的事件,并从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对象的。如果您正在实施此功能 接口,您需要处理该字符串 由调用者在上实现ivscotaskmemfreeystrings接口 IVsDropdownBarClient接口


我假设这是我的问题的一部分,但我不能真正理解我必须在代码中修改什么才能让它工作。有什么提示吗?

我现在非常确定Visual Studio SDK Interop DLL具有错误的IVsDropDownbarClient.GetEntryText封送信息,并且无法使用该接口调用该方法

到目前为止,我发现最好的解决方法是:

使用tlbimp工具为textmgr生成备用互操作DLL。您可以安全地忽略几十个警告,包括关于GetExtentry的警告

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

如果使用源代码管理,则可能需要将生成的文件textmanagernal.dll复制到扩展项目的子目录中,并将其作为外部依赖项检入

在Visual Studio扩展项目中,添加对文件textmanagernal.dll的引用

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

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;
}
}