【问题标题】:How do I call Foo(long[][]) (C#) from Managed C++ (old syntax)?如何从托管 C++(旧语法)调用 Foo(long[][]) (C#)?
【发布时间】:2009-10-16 20:08:42
【问题描述】:

我有签名为 Foo(long[][] longs) 的现有 C# 代码,我需要从 非托管 C++不是C++/CLI)调用它。我似乎无法找出 __gc[]__gc* 的正确组合来让编译器满意。

使用 C++/CLI,这很简单:

std::vector<__int64> evens;
evens.push_back(2); evens.push_back(4); evens.push_back(6); evens.push_back(8);
std::vector<__int64> odds;
odds.push_back(1); odds.push_back(3); odds.push_back(5); odds.push_back(7);
std::vector<std::vector<__int64> > ints;
ints.push_back(evens); ints.push_back(odds);

array<array<__int64>^>^ mgdInts = gcnew array<array<__int64>^>(ints.size());
for (size_t i = 0; i<ints.size(); ++i)
{
    const std::vector<__int64>& slice = ints[i];
    mgdInts[i] = gcnew array<__int64>(slice.size());
    for (size_t j=0; j<slice.size(); ++j)
        mgdInts[i][j] = slice[j];
}

编辑:当我使用 Visual Studio 2008 时,“简单”的解决方案是将 C++/CLI 代码放在它自己的文件中并使用 /clr 进行编译;当然,如果我不必这样做会更容易(例如,其他带有托管 C++ 的 .h 文件)。 C# 代码无法更改,因为它是从 Web 参考自动生成的。

【问题讨论】:

    标签: managed-c++


    【解决方案1】:

    从此更改签名 Foo(long[][] longs) 对此: Foo(Array longs)

    然后,当您查看 OleView.exe 中生成的类型库时,您应该会看到:

        HRESULT Foo([in] SAFEARRAY(int64) longs);
    

    从 C++ 开始,调用起来相当简单。你可以只用 Win32 创建一个 SAFEARRAY,或者我建议包含然后在 ATL 中使用 CComSafeArray 包装类。

    尽管 C# 和 C++ 都有更丰富的数组定义,但两者之间的互操作性通常是通过类型库编组器完成的,其中 99% 是遗留的并且基于“VB 兼容”。类型库编组器支持的唯一数组类型是 SAFEARRAY,所以当您按照正常方式执行所有这些操作时,您会得到这样的数组类型。

    但是,COM 支持更丰富的数组系统(一致性数组),C# 可以理解,但更难做到,而且您不能简单地重新加载 C# DLL 并在非托管 C++ 程序中使用生成的类型库。一些技术需要使用 ILDASM 调整 C# 代码。其他人则要求您保留接口的两个定义,一个在 C++ 中,一个在 C# 中,并确保它们同步(无法将一个转换为另一个),然后在 C++ 的 IDL 中使用 size_is 装饰参数,在 C# 中使用 MarshalAs。这有点乱,实际上人们这样做的唯一类型是如果他们已经发布了他们无法更改的遗留界面。如果这是您的 C# 代码,并且您可以定义接口,我不会去那里。尽管如此,该技术仍然可用。这是一个参考:http://support.microsoft.com/kb/305990 如果您以前从未做过类似的事情,预计大约需要一周左右的时间才能完成。

    【讨论】:

    • 是的。如果出于某种原因您根本不想要任何 C++/CLR 代码,那么解决它的另一种方法是创建另一个您 可以 控制的 C# 对象,该对象具有类型库兼容接口并包装原始代码。
    【解决方案2】:

    我想出的解决方案是使用List&lt;&gt;.ToArray():

    System::Collections::Generic::List<__int64 __gc[]>* mgdInts = new System::Collections::Generic::List<__int64 __gc[]>(ints.size());
    for (size_t i = 0; i<ints.size(); ++i)
    {
        const std::vector<__int64>& slice = ints[i];
        __int64 mgdSlice __gc[] = new __int64 __gc[slice.size()];
        for (size_t j=0; j<slice.size(); ++j)
            mgdSlice[j] = slice[j];
    
        mgdInts->Add(mgdSlice);
    }
    
    ClassLibrary1::Class1::Foo(mgdInts->ToArray());
    

    【讨论】:

      猜你喜欢
      • 2013-03-24
      • 1970-01-01
      • 1970-01-01
      • 2010-11-09
      • 1970-01-01
      • 2013-09-30
      • 1970-01-01
      • 2010-12-25
      相关资源
      最近更新 更多