比方说,我有一个在DLL上公开的函数的原型:
int CALLBACK worker (char* a_inBuf, int a_InLen,
char** a_pOutBuf, int* a_pOutLen,
char** a_pErrBuf, int* a_pErrLen)我确信从我的C#代码中调用该DLL函数非常容易,但它不适用于以下代码:
[DllImport("mydll.dll")]
public static extern int worker(
[In, MarshalAs(UnmanagedType.LPArray)] byte[] inBuf,
int inputLen,
[Out, MarshalAs(UnmanagedType.LPArray)] byte[] outBuf,
out int outputLen,
[Out, MarshalAs(UnmanagedType.LPArray)] byte[] errBuf,
out int errorLen);
...
int outputXmlLength = 0;
int errorXmlLength = 0;
byte[] outputXml = null;
byte[] errorXml = null;
worker(input, input.Length, output, out outputLength, error, out errorLength);当我要在我的非托管库中获取output和error的内存(因此取消引用传递的指针)时,我会遇到访问冲突:
*a_ppBuffer = (char*) malloc(size*sizeof(char));DLLIMPORT代码中为这个函数编写C#语句?a_pOutBuf和a_pErrBuf,而不是从worker中调用null (即使用真正的双指针)?发布于 2012-11-19 17:33:35
您当前的定义将无法工作。worker函数在函数内部分配内存并写入该内存。
P/调用层不支持以这种方式分配的封送处理C样式数组,因为它无法知道调用返回时数组的大小(不像SAFEARRAY)。
这也是为什么从API函数返回数组的指针通常是个坏主意,Windows API的编写方式使调用者处理内存分配。
尽管如此,您希望将worker的P/Invoke声明更改为:
[DllImport("mydll.dll")]
public static extern int worker(
[In, MarshalAs(UnmanagedType.LPArray)] byte[] inBuf,
int inputLen,
ref IntPtr outBuf,
ref int outputLen,
ref IntPtr errBuf,
ref int errorLen
);在执行此操作时,您将指示要手动封送数组(将为您设置outBuf和errBuf参数);您将传递对指针的引用(双间接,即您的char**),然后必须使用其他指示符进行边界检查(在本例中,是outputLen和errorLen参数)。
您将在返回时将数据从指针中封出,如下所示:
int outputXmlLength = 0;
int errorXmlLength = 0;
IntPtr output = IntPtr.Zero;
IntPtr error = IntPtr.Zero;
worker(
input,
input.Length,
ref output,
ref outputLength,
ref error,
ref errorLength
);
// Get the strings.
string outputString = Marshal.PtrToStringAnsi(
output,
outputLength
);
string errorString = Marshal.PtrToStringAnsi(
error,
errorLength
);尽管如此,你还有另外一个问题。因为内存是在函数中分配的,所以必须释放内存。由于使用malloc分配内存,因此需要将两个IntPtr实例传递回非托管代码,以便对它们进行free调用。
如果使用LocalAlloc或CoTaskMemAlloc在非托管代码中分配内存,则可以在班级上分别使用FreeHGlobal或FreeCoTaskMem方法来释放托管端的内存。
https://stackoverflow.com/questions/13457375
复制相似问题