Invoke整理VARIANT数组

Invoke整理VARIANT数组

本文介绍了使用P/Invoke整理VARIANT数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

情况:我有一个托管(C#,.NET 2.0)应用程序,该应用程序使用P/Invoke使用非托管(C ++)DLL.与简单"方法(POD参数/返回值)一起,还需要将boost :: variant值数组传递给代码.原因是这些方法传递报告数据(类似于Excel单元格,可以是任何类型). C#代码将它们接受为装箱的对象".

Situation:I have a managed (C#, .NET 2.0) application which uses an unmanaged (C++) DLL using P/Invoke. Along with the "simple" methods (POD arguments/return value) there's a requirement to pass a boost::variant value arrays to the code. The reason for it is that these methods pass report data (similar to Excel cells, which can be of any type). C# code accepts them as boxed "object"'s.

以前的实现要求使用COM VARIANT的SafeArray.但是,由于编码不佳/未对其进行测试,因此编组被证明是内存泄漏.现在,我必须找到封送数据的另一种选择.

The previous implementation called for use of SafeArray of COM VARIANT's. However, due to poor coding/not testing it, the marshalling turned out to be leaking memory. Now I have to find another option for marshalling the data.

先前的实现如下所示: C ++:

Previous implementation looked like this:C++:

extern "C" __declspec(dllexport) void GetReport(VARIANT& output) {
    // ... here a SafeArray of VARIANT values was created
    output.vt = VT_VARIANT | VT_ARRAY;
    output.parray = safeArray;
}

C#

[DllImport("CppLibrary.dll")]
private static extern void GetReport(out object output);

//....
object data;
GetReport(data);
object rows = data as object[];

此特定实现通过不释放互操作结构来泄漏内存.

This specific implementation leaks memory by not freeing up the interop structures.

我试图通过包含SafeArray编组指令来更改原型:

I've tried to change the prototypes by including SafeArray marshalling directives:

C ++

extern "C" __declspec(dllexport) void GetReport(SAFEARRAY output) { // Also tried SAFEARRAY*, SAFEARRAY&, VARIANT, VARIANT&, VARIANT*
    // Internal stuff
}

C#

private static extern void GetReport([Out, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)]ref object[] output);

但是,我唯一要做的就是要么得到一个空的结果对象,要么由于内存损坏/堆栈溢出而崩溃.

However, the only things I've achieved were either an empty resulting object(s), or crash due to memory corruption/stack overflow.

问题:如何正确地将此类数据类型(VARIANT类型的结构的数组)编组到C#?我可以使C ++ DLL成为COM之一,但这将需要重写大量代码.有没有更简单的方法可以解决这种情况?也许我想念一些东西.

Problem:How to correctly marshal such data type (array of VARIANT-typed structures) to C#?I can make the C++ DLL a COM one, but this will require rewriting quite a handful of code. Is there any simpler way out of the situation? Maybe I'm missing something.

推荐答案

有以下示例:"> http://limbioliong.wordpress.com/2011/03/20/c-interop-how-to-return-a-来自非托管功能的变体/

最后,他们直接使用IntPtr(它们将其用作返回值,您必须将其用作out IntPtr),然后从C#中使用Marshal.GetObjectForNativeVariant()VariantClear()Marshal.FreeCoTaskMem()方面,而在C/C ++方面,VARIANT被分配了CoTaskMemAlloc().

In the end they use directly an IntPtr (they use it as a return value, you would have to use it as a out IntPtr), then Marshal.GetObjectForNativeVariant(), VariantClear() and Marshal.FreeCoTaskMem() from the C# side, while on the C/C++ side the VARIANT was allocated with CoTaskMemAlloc().

[DllImport("MyDLL.dll", CallingConvention = CallingConvention.StdCall)]
static extern void MyFunction(out IntPtr ptr);

[DllImport("oleaut32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
static extern Int32 VariantClear(IntPtr pvarg);

IntPtr pVariant;
MyFunction(out pVariant);

object objRet = Marshal.GetObjectForNativeVariant(pVariant);

VariantClear(pVariant);
Marshal.FreeCoTaskMem(pVariant);

pVariant = IntPtr.Zero;

很显然,您可以在dll中公开另一个C函数,以释放VARIANT(在库中公开Free方法始终是正确的,以便调用者可以使用它们,而不会问自己我应该如何释放此内存" ?")

Clearly you could expose another C function in your dll that frees the VARIANT (it's always correct to expose Free methods in your library, so that caller can use them and not ask himself "how should I free this memory?")

这篇关于使用P/Invoke整理VARIANT数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-23 07:22