ITypeLib2.GetLibStatistics() 在 C# 中总是抛出 AccessViolationException

问题描述 投票:0回答:1

我正在尝试调用

GetLibStatistics
接口的
ITypeLib2
方法。我尝试了几种变体和技术,但它们都抛出
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();
c# .net com access-violation typelib
1个回答
0
投票

ITypeLib2::GetLibStatistics 方法在 C/C++ 中定义如下:

HRESULT GetLibStatistics(
  [out] ULONG *pcUniqueNames,
  [out] ULONG *pcchUniqueNames
);

文档规定了这一点:

[出] pcUniqueNames

唯一名称的计数。如果呼叫者不需要此信息, 设置为 NULL。

这就是 .NET 如此定义它的原因:

void GetLibStatistics(IntPtr pcUniqueNames, out int pcchUniqueNames);

所以第一个参数是一个指向32位无符号整数的指针。但显然,实际实现(在 OleAut32.dll 中)不喜欢空(IntPtr.Zero)指针,因此必须分配给某些东西,如下所示:

public static void GetLibStatisticsTest()
{
    LoadTypeLibEx(@"d:\temp\idl\machin.tlb", RegKind.None, out ITypeLib tlb);
    var tlb2 = tlb as ITypeLib2;
    if (tlb2 == null) return;

    var pcUniqueNames = Marshal.AllocCoTaskMem(Marshal.SizeOf<int>());
    try
    {
        tlb2.GetLibStatistics(pcUniqueNames, out int pcchUniqueNames); ;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
    finally
    {
        Marshal.FreeCoTaskMem(pcUniqueNames);
    }
}

PS:你不需要 CoInitialize,.NET 会为你调用它,并且它不应该由方法调用,而应该在线程(任何使用 COM 的线程)初始化时调用。

© www.soinside.com 2019 - 2024. All rights reserved.