GoLang定义导出方法

通过指针传入函数方法参数

import "C"

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

//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)))
}

一定要加 “import “C”” 否则方法不能导出

编译成 DLL

#动态库
go build -buildmode=c-shared -o libmain32.dll main.go
//.dll 和 .so 名字而已,习惯而已
go build -buildmode=c-shared -o libmain32.so main.go
#静态库
go build -buildmode=c-archive -o libmain32.a main.go
c#调用DLL
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));
    }
}

通过指针将数据输出

C#适配 Any CPU

实现的基本思路为(x64和x86环境都装上,编译两种dll,根据运行环境选择dll)
分别导入x64和x86的函数 ,并添加后缀
判断当前进程是x64还是x86
呼叫与对应的函数

[DllImport("testdll32.dll", EntryPoint="add")
private static extern int add86(int a, intb);

[DllImport("testdll64.dll", EntryPoint="add")
private static extern int add64(int a, intb);
public static int add(int a, int b)
{
    if (Environment.Is64BitProcess)
        return add64(a,b);
    return add86(a,b);
}

x64运行挺好,但是在x86运行出现异常: 调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。请检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配

出现这个错误,可能
1.参数类型不匹配
难道char*不能用string来表示,IntPtr是一定可以的.将C++类型更改成int类型后测试,发现仍然出错,这样看来,不可能是参数类型不匹配了
2. 调用约定不匹配
DllImport还有一个CallingConvention的属性,默认值是CallingCovention.Stdcall, 此处更改成Cdecl(c/c++默认调用方式)就可以了

[DllImport("datalib.dll", EntryPoint = "test",CallingConvention=CallingConvention.Cdecl)]  
public static extern void test(string str);