基本方式:将 Go 程序编译成 DLL 供 C# 调用。html
注意:代码中 export 的注释是定义的入口描述不能省略git
package main import "C" import "fmt" func main() { fmt.Println(Test()) } var _count = 0 //Test : //export Test func Test() int { _count++ return _count }
在 LiteIDE 中将编译配置的 BUILDARGS
自定义值为 --buildmode=c-shared -o Test.dll
,从而造成如下编译语句。github
go build --buildmode=c-shared -o Test.dll
[DllImport("Test.dll", EntryPoint = "Test")] extern static int Test();
生成 DLL 依赖于 gcc,没有 gcc 环境时,会报如下错误:golang
"gcc": executable file not found in %PATH%c#
GCC下载:Windows 64位版本 || Windows 32位版本,也能够从从云盘下载。
下载以后,解压后确保 gcc 命令在搜索路径(Path)中。
更多信息可参考:http://www.javashuo.com/article/p-yswharqc-w.htmlwindows
在 LiteIDE 中,能够经过配置 win32.env
和 win64.env
来指定不一样的 gcc 环境路径达到生成指定系统的 DLL 文件。ui
在 c# 中判断操做系统是否 64 位,能够使用如下语句。操作系统
bool is64 = Environment.Is64BitOperatingSystem;
为了在不一样的操做系统下,加载不一样的 DLL,采起如下步骤来进行组织。
(1)将 32 位的版本命名为 Test32.dll,将 64 位的版本命名为 Test64.dll
(2)定义 ITest 接口,将 DLL 将要调用的方法定义为接口方法
(3)分别为ITest接口实现 Test32 与 Test64 类,在类中加载相应的 DLL
(4)经过判断操做系统类型,实例化一个 ITest 的具体实现类实例来使用
具体接口与类实现代码以下:.net
public interface ITest { int Test(); } public class Test32 : ITest { class TestDLL { const string DLL_NAME = "Test32.dll"; [DllImport(DLL_NAME, EntryPoint = "Test")] public extern static int Test(); } public int Test() { return TestDLL.Test(); } } public class Test64 : ITest { class TestDLL { const string DLL_NAME = "Test64.dll"; [DllImport(DLL_NAME, EntryPoint = "Test")] public extern static int Test(); } public int Test() { return TestDLL.Test(); } }
实例化与调用:调试
ITest test = Environment.Is64BitOperatingSystem ? (ITest)new Test64() : (ITest)new Test32(); int result = test.Test();
//Hello : //export Hello func Hello(name *C.char) string { return fmt.Sprintf("hello %s", C.GoString(name)) }
C# GoString struct 定义
public struct GoString { public IntPtr p; public int n; public GoString(IntPtr n1, int n2) { p = n1; n = n2; } }
C# DllImport 声明
[DllImport(DLL_NAME, EntryPoint = "Hello", CallingConvention = CallingConvention.Cdecl)] public extern static GoString Hello(byte[] name);
C# GoString struct 转 String
public string GoStringToCSharpString(GoString goString) { byte[] bytes = new byte[goString.n]; for (int i = 0; i < goString.n; i++) { bytes[i] = Marshal.ReadByte(goString.p, i); } string result = Encoding.UTF8.GetString(bytes); return result; }
C# 调用示例
GoString goResult = test.Hello(Encoding.UTF8.GetBytes("张三")); Debug.WriteLine(GoStringToCSharpString(goResult));
CallingConvention
在声明中加入 CallingConvention = CallingConvention.Cdecl
避免未知异常。
[DllImport("Test.dll", CallingConvention = CallingConvention.Cdecl)]
程序崩溃甚至异常提示都没有,可在加载 DLL 以前:
Environment.SetEnvironmentVariable("GODEBUG", "cgocheck=0");