我正在用C#构建一个Visual Studio2022扩展,目前正在使用VS API.我正在试着拨打IVsObjectList2.GetText()
,这是一个COM接口.然而,VS在try 这样做时崩溃了.我怀疑VS API中的编组定义是错误的.
第documentation个声明调用方应该释放GetText()
(字符串)的第三个参数NOT.即本机接口被定义为
HRESULT IVsObjectList2::GetText(
[in] ULONG Index,
[in] VSTREETEXTOPTIONS tto,
[out] const WCHAR **ppszText
);
而GetText()
的调用者不能释放ppszText
.然而,在C#代码的反编译过程中,我可以看到GetText()
被定义为
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
int GetText(
[In][ComAliasName("Microsoft.VisualStudio.OLE.Interop.ULONG")] uint index,
[In][ComAliasName("Microsoft.VisualStudio.Shell.Interop.VSTREETEXTOPTIONS")] VSTREETEXTOPTIONS tto,
[MarshalAs(UnmanagedType.LPWStr)] out string ppszText);
据我所知,default marshalling behavior导致CLR自动释放字符串参数ppszText
.我的理解正确吗?
如果我是正确的,因为这与API定义不一致,我可以以某种方式绕过这个问题吗?我的意思是,我能以某种方式在我自己的代码中纠正GetText()
的编组定义吗?(我认为第三个参数should be an IntPtr
instead?)例如,如果这是C++,我可能会对自己的定义做一个IVsObjectList2
的"represtrate_cast",然后这个定义是正确的;在C#中这样的事情可能吗?
调用C#代码:
IVsObjectManager2 objectManager2 = MyExtensionPackage.GetGlobalService(typeof(SVsObjectManager)) as IVsObjectManager2;
if (objectManager2.FindLibrary(new Guid(BrowseLibraryGuids80.VC), out IVsLibrary2 lib) == VSConstants.S_OK) {
var criteria = new VSOBSEARCHCRITERIA2();
if (lib.GetList2(
(uint)_LIB_LISTTYPE.LLT_CLASSES,
(uint)_LIB_LISTFLAGS.LLF_DONTUPDATELIST,
new[] { criteria },
out IVsObjectList2 list) == VSConstants.S_OK
&& list != null) {
if (list.GetItemCount(out uint count) == VSConstants.S_OK && count > 0) {
for (uint idx = 0; idx < count; ++idx) {
// The following crashes eventually.
list.GetText(idx, VSTREETEXTOPTIONS.TTO_PREFIX, out string prefix);
// Use "prefix"
}
}
}
}
list.GetText()
调用不会立即崩溃,但最终会崩溃,因为下面的调用堆栈出现了一些堆损坏:
ntdll.dll!RtlpBreakPointHeap()
ntdll.dll!RtlpValidateHeapEntry()
ntdll.dll!RtlValidateHeap()
AcLayers.dll!NS_FaultTolerantHeap::APIHook_RtlFreeHeap(void *,unsigned long,void *)
mscorlib.ni.dll!00007ffe31eb071f()
Microsoft.VisualStudio.Interop.ni.dll!00007ffe2d8bfc53()
Microsoft.VisualStudio.Interop.ni.dll!00007ffe2d8bfbe7()
[Managed to Native Transition]
My own code in C#, line with GetText()