我正在try 调用ITypeLib2接口的GetLibStatistics方法.我try 了几种变种和技巧,但都投了System.AccessViolationException: Attempted to read or write protected memory分.

我能够在C++的本机COM中成功执行该方法,因此我知道我使用的.tlb文件没有问题.

在这一点上,我的猜测是GetLibStatistics不是用C#实现的.请指点一下.

public static void GetLibStatisticsTest()
{
    CoInitialize(IntPtr.Zero);

    ITypeLib tlb;
    LoadTypeLibEx(@"C:\Sample.tlb", RegKind.None, out tlb);

    var tlb2 = tlb as ITypeLib2;
    if (tlb2 == null ) { return; }

    try
    {
        IntPtr pcUniqueNames = IntPtr.Zero;
        int pcchUniqueNames;

        // This always throws `System.AccessViolationException`. Why??
        tlb2.GetLibStatistics(pcUniqueNames, out pcchUniqueNames);;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
    finally
    {
        CoUninitialize();
    }
}

[DllImport("ole32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int CoInitialize(IntPtr pvReserved);

[DllImport("oleaut32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int LoadTypeLibEx(string szFile, RegKind regKind, out ITypeLib pptlib);

[DllImport("ole32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern void CoUninitialize();

推荐答案

由.NET定义的ITypeLib2"完全"是错误的.它在C/C++中定义如下:

ITypeLib2 : public ITypeLib
{
public:
    virtual HRESULT STDMETHODCALLTYPE GetCustData(REFGUID guid, VARIANT *pVarVal) = 0;
    virtual HRESULT STDMETHODCALLTYPE GetLibStatistics(ULONG *pcUniqueNames, ULONG *pcchUniqueNames) = 0;
    virtual HRESULT STDMETHODCALLTYPE GetDocumentation2(INT index, LCID lcid, BSTR *pbstrHelpString, DWORD *pdwHelpStringContext, BSTR *pbstrHelpStringDll) = 0;
    virtual HRESULT STDMETHODCALLTYPE GetAllCustData(CUSTDATA *pCustData) = 0;
}

在.NET中就像这样

public interface ITypeLib2 : ITypeLib
{
    ... ITypeLib ...

    void GetCustData(ref Guid guid, out object pVarVal);
    void GetDocumentation2(int index, out string pbstrHelpString, out int pdwHelpStringContext, out string pbstrHelpStringDll);
    void GetLibStatistics(IntPtr pcUniqueNames, out int pcchUniqueNames);
    void GetAllCustData(IntPtr pCustData);
}

因此,GetDocumentation2GetLibStatistics已经被切换,而你调用的是GetDocumentation2,而不是明显错误的参数(REQ).😱

这可以在调试器中判断:

enter image description here

所以你必须在代码中重新定义ITypeLib2,这样:

[ComImport, Guid("00020411-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ITypeLib2 : ITypeLib
{
    [PreserveSig]
    new int GetTypeInfoCount();
    new void GetTypeInfo(int index, out ITypeInfo ppTI);
    new void GetTypeInfoType(int index, out System.Runtime.InteropServices.ComTypes.TYPEKIND pTKind);
    new void GetTypeInfoOfGuid(ref Guid guid, out ITypeInfo ppTInfo);
    new void GetLibAttr(out IntPtr ppTLibAttr);
    new void GetTypeComp(out ITypeComp ppTComp);
    new void GetDocumentation(int index, out string strName, out string strDocString, out int dwHelpContext, out string strHelpFile);
    new bool IsName([MarshalAs(UnmanagedType.LPWStr)] string szNameBuf, int lHashVal);
    new void FindName([MarshalAs(UnmanagedType.LPWStr)] string szNameBuf, int lHashVal, [Out][MarshalAs(UnmanagedType.LPArray)] ITypeInfo[] ppTInfo, [Out][MarshalAs(UnmanagedType.LPArray)] int[] rgMemId, ref short pcFound);
    [PreserveSig]
    new void ReleaseTLibAttr(IntPtr pTLibAttr);

    void GetCustData(ref Guid guid, out object pVarVal);
    void GetLibStatistics(IntPtr pcUniqueNames, out int pcchUniqueNames);
    void GetDocumentation2(int index, out string pbstrHelpString, out int pdwHelpStringContext, out string pbstrHelpStringDll);
    void GetAllCustData(IntPtr pCustData);
}

而且它会奏效的.

我已经为这https://github.com/dotnet/runtime/issues/99946个人创造了一个问题,

Csharp相关问答推荐

ASP.NET Core 8 Cors标题未显示

Blazor:类型或命名空间名称Components在命名空间中不存在''

如何使用C#中的图形API更新用户配置文件图像

在. NET Core 8 Web API中,当为服务总线使用通用消费者时,如何防止IServiceProvider被释放或空?"

ASP.NET核心结果.文件vs结果.流

一种安全的方式来存储SSH凭证(MAUI/C#应用程序)

如何修改中间件或其注册以正确使用作用域服务?

如何定义EFCore中的多个穿透

如何使用C#中的主构造函数功能使用多个构造函数?

如何将此方法参数化并使其更灵活?

try 使用C#ASP.NET收集WMI信息时访问被拒绝,但在PowerShell中工作

如何在C#中转换泛型包装类内部的派生类

LINQ to Entities中的加权平均值

Regex字母数字校验

为什么我的伺服电机不动,下面的代码?

在C#中,当输入一个方法/局部函数时,我的IEnumerator被重置/重新创建.为什么?

如何使用.NET Aspire从Blazor应用程序与GRPC API通信?

如何使用IHostedService添加数据种子方法

避免在特定区域中设置Visual Studio代码的自动格式

将文本从剪贴板粘贴到RichTextBox时,新文本不会在RichTextBox ForeColor中着色