说,我已经得到了上一个DLL公开的函数的原型是:
int CALLBACK worker (char* a_inBuf, int a_InLen,
char** a_pOutBuf, int* a_pOutLen,
char** a_pErrBuf, int* a_pErrLen)
我敢肯定,这是可笑容易调用该DLL函数从我的C#代码,但它不与此代码的工作:
[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
是可访问的,而不是null
从内部worker
(即使用一个真正的双指针)?
您当前的定义,将无法正常工作。 该worker
函数的函数中分配内存和写入内存。
的的P / Invoke层不支持封送处理以这种方式分配的C风格的数组,因为它无法知道数组将是多么大的是方式,当调用返回(不像比如说,一个SAFEARRAY
)。
这也是为什么在返回指针从API函数阵列通常是一个坏主意,和Windows API是写在这样一种方式,内存分配由主叫方处理。
这就是说,你要的的P / Invoke声明中更改worker
到这一点:
[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
分别对方法Marshal
类释放在管理方面的记忆。
文章来源: How do I call an unmanaged function that has a char[] as OUT parameter from C#?