求助:使用生成的Golang DLL返回字符串或* C.Char

我一直试图遵循z505/goDLL的方法,但遇到了一个大问题。该方法无法返回字符串,我无法读取结果的输出变量。

这是我目前使用的代码(Go)(完整代码https://play.golang.org/p/Yfg85DCeMLh):

//export PrintHello2
func PrintHello2(Input *C.char, Output **C.char) int32 {
    fmt.Println(C.GoString(Input))
    *Output = C.CString(fmt.Sprintf("From DLL: Hello, %s!
", C.GoString(Input)))
    fmt.Println("Message: ", C.GoString(*Output))
    return 1
}

//export PrintHello3
func PrintHello3(Input *C.char, Output *int32) int32 {
    fmt.Println(C.GoString(Input))
    *Output = 3
    fmt.Println("Value: ", *Output)
    return 0
}

C# 测试代码:

class Program
{
    [DllImport("goDLL.dll", CharSet = CharSet.Unicode)]
    public static extern int PrintHello2(byte[] data, ref byte[] output);

    [DllImport("goDLL.dll", CharSet = CharSet.Unicode)]
    public static extern int PrintHello3(byte[] data, ref int output);

    static void Main(string[] args)
    {
        string res = "demo";
        byte[] output = null;
        Int32 refVal = 0;

        Console.WriteLine("PrintHello3 Returns: " + PrintHello3(Encoding.UTF8.GetBytes(res), ref refVal));
        Console.WriteLine("Ref Val changed to: " + refVal + "
");
        Console.WriteLine("PrintHello2 Returns: " + PrintHello2(Encoding.UTF8.GetBytes(res), ref output));
        Console.WriteLine("Ref Val changed to: " + Encoding.UTF8.GetString(output) + "
");
    }
}

预期产出结果:

C:\tmp\DLL>ConsoleApp.exe
demo
Value:  3
PrintHello3 Returns: 0
Ref Val changed to: 3

demo
Message:  From DLL: Hello, demo!
PrintHello2 Returns: 1
Ref Val changed to: From DLL: Hello, demo!

实际结果:

C:\tmp\DLL>ConsoleApp.exe
demo
Value:  3
PrintHello3 Returns: 0
Ref Val changed to: 3

demo
Message:  From DLL: Hello, demo!

我没有发现错误。

dozc58418381
dozc58418381 我不确定C#中的类型将是什么,但是google占用了大量资源。其中一些可能会有所帮助:gist.github.com/esskar/3779066、social.msdn.microsoft.com/Forums/vstudio/en-US/…、stackoverflow.com/questions/39987435/…等。
2 年多之前 回复
dongshun1884
dongshun1884 确实是我的想法,但是即使不接受字符串,您会建议使用什么呢?
2 年多之前 回复
dongqiaogouk86049
dongqiaogouk86049 我对C#并不是很熟悉,但是我怀疑byte[]是否可以透明地用作**C.char。
2 年多之前 回复
dryk50495
dryk50495 按建议完成编辑,谢谢
2 年多之前 回复
doudao1950
doudao1950 更新问题,显示所需的输出以及遇到的错误。如果是堆栈跟踪,请准确指出引起恐慌的是哪一行。请参阅“如何提问”以及如何创建最小的可复制示例。
2 年多之前 回复
dongnaota6386
dongnaota6386 因为我也在使用cgoc代码,所以不确定是否相关:github.com/z505/goDLL/blob/master/goDLL.c
2 年多之前 回复
duanchai0028
duanchai0028 您似乎拥有C#和Go代码。为什么使用C语言标记?
2 年多之前 回复
douqing0713
douqing0713 使用**C.char进行代码:play.golang.org/p/B_FwFjsaWt0C#代码:pastebin.com/jZk0sEw5
2 年多之前 回复
dswg47377
dswg47377 请显示调用这两个函数的代码。
2 年多之前 回复
doubei5310
doubei5310 请显示实际的错误输出以及您期望发生的情况。在PrintHello2中,“消息:”行是否未显示任何输出?如果您期望Output*C.char更改在函数外部可见,则需要传递**C.char,否则您将覆盖函数范围内的指针值。
2 年多之前 回复
dongqiulei1987
dongqiulei1987 在打印“消息:...”之后的PrintHello1上,该函数似乎很紧急,没有任何错误。它导致C#应用程序退出而没有任何返回值。对于PrintHello2,我期望Output变量具有字符串,该字符串为空。例如对于PrintHello3不会发生这种情况,例如以下示例中实际发挥预期作用的示例。golang.org/p/F5PNcwHnXj4
2 年多之前 回复
doucan2102
doucan2102 您“只能从C#读取的是指针地址”是什么意思?会发生什么?PrintHello1中的什么“根本不起作用”?
2 年多之前 回复

1个回答



无论如何,经过一段时间尝试并错误“ ing”,这是解决方案</ p>

< strong>开始</ strong> </ p>

  //导出PrintHello2 
func PrintHello2(输入* C.char,输出** C.char)int32 {
输出= C .CString(fmt.Sprintf(“来自DLL:您好,%s!
”,C.GoString(输入)))
返回int32(len(C.GoString(
Output)))
}
\ n // export PrintHello4
func PrintHello4(输入* C.char)* C.char {
返回C.CString(fmt.Sprintf(“来自DLL:Hello,%s!
”,C.GoString(输入) ))
}
</ code> </ pre>

C#</ strong> </ p>

  class Program 
{\ n [DllImport(“ goDLL.dll”,CharSet = CharSet.Unicode,CallingConvention = CallingConvention.StdCall)]
公共静态外部int PrintHello2([In]个byte []数据,参考IntPtr输出);

[DllImport (“ goDLL.dll”,CharSet = CharSet.Unicode,CallingConvention = CallingConvention.StdCall)]
公共静态外部IntPtr PrintHello4(byte []数据);

静态void Main(string [] args)
{

字符串res =“ demo”;
IntPtr输出= IntPtr.Zero;
var a = PrintHello4(Encoding.UTF8.GetBytes(res));

Console.WriteLine(“ PrintHello4返回:” + Marshal.PtrToStringAnsi (a));
var i = PrintHello2(Encoding.UTF8.GetBytes(res),ref输出);

Console.WriteLine(“ PrintHello2返回:” + i);
Console.WriteLine(“ Ref Val更改为:“ + Marshal.PtrToStringAnsi(output,i));
}
}
</ code> </ pre>

它可能会被许多其他可能使用的 </ p>

感谢JimB的技巧和耐心</ p>
</ div>

展开原文

原文

Anyway, after some time trying and error"ing", this is the solution

Go

//export PrintHello2
func PrintHello2(Input *C.char, Output **C.char) int32 {
    *Output = C.CString(fmt.Sprintf("From DLL: Hello, %s!
", C.GoString(Input)))
    return int32(len(C.GoString(*Output)))
}

//export PrintHello4
func PrintHello4(Input *C.char) *C.char{
    return C.CString(fmt.Sprintf("From DLL: Hello, %s!
", C.GoString(Input)))
}

C#

class Program
{
    [DllImport("goDLL.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
    public static extern int PrintHello2([In] byte[] data, ref IntPtr output);

    [DllImport("goDLL.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
    public static extern IntPtr PrintHello4(byte[] data);

    static void Main(string[] args)
    {
        string res = "demo";
        IntPtr output= IntPtr.Zero;
        var a = PrintHello4(Encoding.UTF8.GetBytes(res));

        Console.WriteLine("PrintHello4 Returns: " + Marshal.PtrToStringAnsi(a));
        var i = PrintHello2(Encoding.UTF8.GetBytes(res), ref output);

        Console.WriteLine("PrintHello2 Returns: " + i);
        Console.WriteLine("Ref Val changed to: " + Marshal.PtrToStringAnsi(output, i));
    }
}

It will probably be used by many others that might be trying to accomplish the same as i am.

Thanks for the tips and pacience JimB

douxin8749
douxin8749 是的,但是这种情况只是关于共享内存地址以传递值的测试。 您将需要返回de value而不是指针本身。 所示示例效率不高,没有任何适当的验证。 您最好创建一个体面的包装,并以正确的方式实施它。
大约一年之前 回复
dst2017
dst2017 谢谢! 通过创建go对象以包装分配的内存,它将在gc时自动释放c mem。 但是在这种情况下,mem用作返回值。 当调用方仍在使用mem,但goc中出现gc时,这似乎是一个致命错误。
大约一年之前 回复
dpikoto468637
dpikoto468637 我相信您指的是这篇文章stackoverflow.com/questions/9537948/garbage-collection-and-cgo
大约一年之前 回复
duanjianl183188
duanjianl183188 是否有必要为C.CString调用C.free()?
大约一年之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问