如何从托管 C++ 调用 Foo(long[][]) (C#) (旧语法)?

发布于 2024-08-08 21:17:07 字数 1081 浏览 7 评论 0原文

我有签名为 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 参考自动生成的。

I've got existing C# code with signature of Foo(long[][] longs) which I need to call from Unmanaged C++ (not C++/CLI). I just can't seem to figure out the right combination of __gc[] and __gc* to make the compiler happy.

With C++/CLI, this is straight-forward:

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];
}

Edit: As I'm using Visual Studio 2008, the "simple" solution is to put the C++/CLI code in its own file and compile with /clr; of course, it would be easier if I didn't have to do this (e.g., other .h files with Managed C++). The C# code can't change as it's auto-generated from a web reference.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

记忆で 2024-08-15 21:17:07

从此更改签名
Foo(long[][]长整型)
对此:
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
如果您以前从未做过类似的事情,预计大约需要一周左右的时间才能完成此任务。

Change the signature from this
Foo(long[][] longs)
to this:
Foo(Array longs)

Then when you look at the resulting type library in OleView.exe, you should see:

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

From C++, that's fairly straight forward to call. You can just Win32 to create a SAFEARRAY, or I suggest include and then use the CComSafeArray wrapper class in ATL.

Even though both C# and C++ have richer array definitions, the interoperability between the two is typically done though the Type Library marshaller, 99% of which is legacy and based on what's "VB Compatible". The only array types that the Type Library marshaller supports is SAFEARRAY, so that's what you get when you follow the normal way of doing all this.

However, COM supports a richer array system (conformant arrays), which C# understands, it's harder to do, and you can't simply regasm your C# DLL and use the resulting type library in your unmanaged C++ program. Some of the techniques require tweaking the C# code with ILDASM. Others require you to keep two definitions of the interface, one in C++ and one in C#, and make sure they're in sync (no way to convert one to the other), then in the IDL for C++ adorn the parameter with size_is, and in C# with MarshalAs. It's kind of a mess and really the only type people do that is if they have an already published legacy interface that they cannot change. If this is your C# code, and you can define the interface, I wouldn't go there. Still, the technique is available. Here's a refernece: http://support.microsoft.com/kb/305990
Expect about a week or so to get through this if you've never done anything like this before.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文