如何调用具有一个char []从C#OUT参数的非托管函数?(How do I call an un

2019-08-02 22:36发布

说,我已经得到了上一个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);

我收到的时候我要取的内存访问冲突outputerror我的非托管库中(因此取消引用传递的指针):

*a_ppBuffer = (char*) malloc(size*sizeof(char));
  1. 我怎样写DLLIMPORT此功能在我的C#代码语句?

  2. 实际上,我怎么调用函数,这样a_pOutBufa_pErrBuf是可访问的,而不是null从内部worker (即使用一个真正的双指针)?

Answer 1:

您当前的定义,将无法正常工作。 该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);

在这一过程中,就表示你要手动元帅阵列(在outBuferrBuf参数会为你进行设置); 你传递的参考指针(双间接,那是你char** ),然后从他们阅读使用其他指标进行边界检查(在这种情况下, outputLenerrorLen参数)。

你会在像这样的回报名帅出指针的数据:

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叫上他们。

如果你在非托管代码中使用分配内存LocalAllocCoTaskMemAlloc ,那么你可以使用FreeHGlobalFreeCoTaskMem分别对方法Marshal类释放在管理方面的记忆。



文章来源: How do I call an unmanaged function that has a char[] as OUT parameter from C#?