你的第二种方法对我来说似乎是正确的。你在哪里:
FreePointerHandler(pointerToArray.ToPointer());
我认为你可以:
FreePointerHandler(pointerToArray);
我正在写一个测试并将发布一个编辑。
ref
对比out
至于ref
vs. out
,这并不完全映射到 C++ 参考。C#调用C#时,out
需要被调用的函数设置一个参数。对于互操作调用,这不能被强制执行,对于文档价值,我更喜欢out
在这种情况下。
真正的问题
真正的问题是,如果您没有使用 .Net pinvoke 的经验,那么在调用没有任何直接可见副作用的函数时很难有信心。
@Hans Passant 建议“通过调用它一百万次来测试它”,以使任何内存泄漏变得明显。虽然这种方法在这种情况下可能是最简单的,但它并不能推广到没有关联的内存资源并且如果它失败它不会提供任何额外信息的情况。如果我有 .dll 的源代码,我更喜欢通过 pinvoke 调用进行调试,如果没有,我更喜欢编写模拟 API 实现。这样,当您尝试新的 pinvoke 功能时,您可以准确地看到正在发生的事情。如果出现问题,调试器中的跟踪可以帮助您查看哪里出错了。
一个完整的 pinvoke 示例
这是基于原始问题的完整示例。没有记录返回值,也没有记录 myFunction 的详细信息。该示例仅使用 (0, 1, 2) 填充长度为 3 的已分配数组。
这是DLL的头文件:
// testlib.h
#ifdef TESTLIB_EXPORTS
#define TESTLIB_API __declspec(dllexport)
#else
#define TESTLIB_API __declspec(dllimport)
#endif
extern "C" {
TESTLIB_API int myFunction(int someNumber, int &arraySize, signed char *&array);
TESTLIB_API int freePointer(void* myPointer);
}
.DLL 的 .cpp 源文件:
// testlib.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "testlib.h"
#include <iostream>
using namespace std;
TESTLIB_API int myFunction(int someNumber, int &arraySize, signed char *&array)
{
#ifdef _DEBUG
cout << "myFunction enter " << someNumber << ", " << arraySize << ", 0x" << &array << endl;
#endif
arraySize = 3;
array = (signed char*)malloc(arraySize);
#ifdef _DEBUG
cout << "myFunction array: 0x" << (void *)array << endl;
#endif
for (int i = 0; i < arraySize; ++i)
{
array[i] = i;
}
#ifdef _DEBUG
cout << "myFunction exit " << someNumber << ", " << arraySize << ", 0x" << &array << endl;
#endif
return 0;
}
TESTLIB_API int freePointer(void* myPointer)
{
#ifdef _DEBUG
cout << "freePointer: 0x" << myPointer << endl;
#endif
free(myPointer);
return 0;
}
C# 源代码:
using System;
using System.Runtime.InteropServices;
namespace InteropTest
{
class InteropTest
{
[DllImport("testlib.dll")]
private static extern int myFunction(int someNumber, out int arraySize, out IntPtr array);
[DllImport("testlib.dll")]
public static extern int freePointer(IntPtr pointer);
public static byte[] myFunction(int myNumber)
{
int myArraySize;
IntPtr pointerToArray;
int iRet = myFunction(myNumber, out myArraySize, out pointerToArray);
// should check iRet and if needed throw exception
#if (DEBUG)
Console.WriteLine();
Console.WriteLine("InteropTest.myFunction myArraySize: {0}", myArraySize);
Console.WriteLine();
#endif
byte[] myArray = new byte[myArraySize];
Marshal.Copy(pointerToArray, myArray, 0, myArraySize);
freePointer(pointerToArray);
#if (DEBUG)
Console.WriteLine();
#endif
return myArray;
}
static void Main(string[] args)
{
#if (DEBUG)
Console.WriteLine("Start InteropTest");
Console.WriteLine();
#endif
int myNumber = 123;
byte[] myArray = myFunction(myNumber);
for (int i = 0; i < myArray.Length; ++i)
{
Console.WriteLine("InteropTest myArray[{0}] = {1}", i, myArray[i]);
}
}
}
}
调试版本打印状态消息。它们显示myFunction
的array
价值是传递给freePointer
.
我还为myFunction
. 当 pinvoke 调用很重要时,您通常希望一次性计算出细节并将其封装到一个函数中以供重用。