【问题标题】:Invoke .NET method via COM, with a ref array通过 COM 调用 .NET 方法,使用 ref 数组
【发布时间】:2020-10-13 19:57:05
【问题描述】:

我有一个 .NET DLL,它在 C# 中公开了一个类似这样的方法:

void TestMethod(ref TestClass[] parameter)

TestClass 是一个普通的 C# 类,它有一个 COM 可见的接口,我应该用一个包含一个元素的数组来调用该方法。​我不知道如何从 C++ 程序通过 COM 调用它。

该参数变为 SAFEARRAY**。目前,我正在这样做,其中 m_Object 是指向具有 TestMethod 的类的智能指针:

VARIANT* current = NULL;
HRESULT hrx = SafeArrayAccessData(ret, (LPVOID*)&current);
ITestClassPtr item;
item.CreateInstance(__uuidof(TestClass));
current->vt = VT_UNKNOWN;
current->punkVal = item.GetInterfacePtr();
SafeArrayUnaccessData(ret);
HRESULT hr = (*m_Object)->TestMethod(&ret);

​这会导致0x80131533“数组的运行时类型与元数据中记录的子类型不匹配”。

我也试过了:

ITestClassPtr 项;
item.CreateInstance(__uuidof(TestClass));
长 i = 0;
SafeArrayPutElement(ret, &i, item);
HRESULT hr = (*m_Object)->TestMethod(&ret);

这会导致无用的 0x80131600。

我也尝试过使用 CComSafeArray,但我得到了相同的结果(无论如何它只是 SAFEARRAY 的一个包装器)。

我没有 DLL 的源代码,也无法对其进行调试。我在网上搜索过,我可以找到很多关于如何通过 COM 调用 C# DLL 的示例,但没有一个具体涵盖如何将类的 ref 数组从 C++ 传递到 C#。

有什么想法吗?

【问题讨论】:

  • 只有当参数是 object[] 时,第一个 sn-p 才合适。第二个sn-p没有错。 0x80131600 告诉您 C# 代码引发了 ApplicationException。这是一种糟糕的做法,可以追溯到 .NET 1.x 时代。告诉您,任何人都不太可能接听您需要拨打的电话以获得您需要的帮助。你肯定会考虑投资一个好的反汇编程序。
  • @HansPassant 听起来我可能用第二种方法做的一切都是正确的,至少在 COM 对象传递方面。谢谢,很有用。

标签: c# c++ com


【解决方案1】:

假设你有这些 C# 类:

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class TestClass1
{
    public void SayHello()
    {
        Console.WriteLine("Hello 1");
    }

    public void TestMethod(ref TestClass2[] parameter)
    {
        parameter[0].SayHello();
    }
}

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class TestClass2
{
    public void SayHello()
    {
        Console.WriteLine("Hello 2");
    }
}

您可以使用这样的命令行注册它并创建类型库:

%windir%\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe ClassLibrary1.dll /codebase /tlb

如果您查看使用OleView from Windows SDK 创建的类型库,TestMethod 的声明如下:

[id(0x60020005)]
HRESULT TestMethod([in, out] SAFEARRAY(_TestClass2*)* parameter);

所以它是 SAFEARRAY_TestClass2 指针(IUnknown-derived),您可以像这样创建和使用它(假设 Visual Studio 支持):

...
#import "c:\mypath\ClassLibrary1.tlb" raw_interfaces_only

using namespace ClassLibrary1;


int main()
{
  CoInitialize(NULL);
  {
    // warning: all error checks omitted

    CComPtr<_TestClass1> tc1;
    tc1.CoCreateInstance(__uuidof(TestClass1));
    tc1.SayHello(); // outputs "Hello 1"

    CComPtr<_TestClass2> tc2;
    tc2.CoCreateInstance(__uuidof(TestClass2));

    SAFEARRAY* psa = SafeArrayCreateVector(VT_UNKNOWN, 0, 1);

    LONG index = 0;
    // note this will call AddRef on tc2 so it's safe
    SafeArrayPutElement(psa, &index, (_TestClass2*)tc2);

    tc1->TestMethod(&psa); // Outputs "Hello 2"

    SafeArrayDestroy(psa);
  }

  CoUninitialize();
  return 0;
}

【讨论】:

  • 谢谢。在这一点上,我认为我的问题一定是在 DLL 内部,而不是 COM...
猜你喜欢
  • 2010-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多