代码之家  ›  专栏  ›  技术社区  ›  IronicMuffin

如何正确地将char*从非托管dll返回到c_?

  •  3
  • IronicMuffin  · 技术社区  · 15 年前

    函数签名:

    char * errMessage(int err);
    

    我的代码:

    [DllImport("api.dll")]       
    internal static extern char[] errMessage(int err);
    ...
    char[] message = errMessage(err);
    

    这将返回一个错误:

    Cannot marshal 'return value': Invalid managed/unmanaged type combination.
    

    我做错什么了?谢谢你的帮助。

    5 回复  |  直到 15 年前
        1
  •  2
  •   scottm    15 年前

    试试这个:

    [DllImport("api.dll")]
    [return : MarshalAs(UnmanagedType.LPStr)]
    internal static extern string errMessage(int err);
    ...
    string message = errMessage(err);
    

    我相信C足够聪明来处理指针并返回一个字符串。

    编辑:添加了marshalas属性

        2
  •  7
  •   dtb    15 年前

    一种简单而健壮的方法是以c的形式分配缓冲区,如果a StringBuilder ,将其传递给非托管代码并填充到那里。

    例子:

    C

    #include <string.h>
    
    int foo(char *buf, int n) {
       strncpy(buf, "Hello World", n);
       return 0;
    }
    

    C.*

    [DllImport("libfoo", EntryPoint = "foo")]
    static extern int Foo(StringBuilder buffer, int capacity);
    
    static void Main()
    {
        StringBuilder sb = new StringBuilder(100);
        Foo(sb, sb.Capacity);
        Console.WriteLine(sb.ToString());
    }
    

    测试:

    Hello World
    
        3
  •  5
  •   Community CDub    7 年前

    this question . 总之,函数应该返回一个intptr,并且必须使用marshal.ptrtostring*将其转换为托管字符串对象。

        4
  •  5
  •   Hans Passant    15 年前

    这是一个可怕的函数签名,无法猜测字符串是如何分配的。也不能为字符串释放内存。如果在声明中将返回类型声明为“string”,则p/invoke封送拆收器将在指针上调用cotaskmemfree()。这不太可能是合适的。它将在XP中无声地失败,但在Vista和Win7中会使程序崩溃。

    在非托管程序中甚至不能可靠地调用函数。使用正确版本的free()的几率非常小。您所能做的就是将其声明为intptr,并使用marshal.ptrtostringansi()自己封送返回值。当您在taskmgr.exe中观察它时,一定要编写一个测试程序,它可以执行一百万次。如果程序的虚拟机大小没有限制地增长,则会出现无法插入的内存泄漏。

        5
  •  0
  •   Moshe Levi    15 年前

    尝试在托管端使用字符串。您也可以将字符集设置为ansi