首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何调用具有char[]作为C#参数的非托管函数?

如何调用具有char[]作为C#参数的非托管函数?
EN

Stack Overflow用户
提问于 2012-11-19 15:52:44
回答 1查看 5K关注 0票数 7

比方说,我有一个在DLL上公开的函数的原型:

代码语言:javascript
复制
int CALLBACK worker (char* a_inBuf, int a_InLen,
                     char** a_pOutBuf, int* a_pOutLen,
                     char** a_pErrBuf, int* a_pErrLen)

我确信从我的C#代码中调用该DLL函数非常容易,但它不适用于以下代码:

代码语言:javascript
复制
[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的内存(因此取消引用传递的指针)时,我会遇到访问冲突:

代码语言:javascript
复制
*a_ppBuffer = (char*) malloc(size*sizeof(char));
  1. 如何在我的DLLIMPORT代码中为这个函数编写C#语句?
  2. 我如何实际调用该函数,以便可以访问a_pOutBufa_pErrBuf,而不是从worker中调用null (即使用真正的双指针)?
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-11-19 17:33:35

您当前的定义将无法工作。worker函数在函数内部分配内存并写入该内存。

P/调用层不支持以这种方式分配的封送处理C样式数组,因为它无法知道调用返回时数组的大小(不像SAFEARRAY)。

这也是为什么从API函数返回数组的指针通常是个坏主意,Windows API的编写方式使调用者处理内存分配。

尽管如此,您希望将worker的P/Invoke声明更改为:

代码语言:javascript
复制
[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参数)。

您将在返回时将数据从指针中封出,如下所示:

代码语言:javascript
复制
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方法来释放托管端的内存。

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13457375

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档