go语言自带的jsonrpc 不支持http/websocket,而是使用tcp协议,
aardio中增加了一个库 wsock.tcp.jsonClient 支持与go语言进行jsonrpc调用。
先使用go语言编写一个exe文件( 当然你可以把后缀名改为 dll,下面的代码一样可以运行 )
go语言代码如下,注意 go里面{换行写是语法错误 :
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 
 | package main
 import (
 "fmt"
 "log"
 "net"
 "net/rpc"
 "net/rpc/jsonrpc"
 )
 
 type Args struct {
 X, Y int
 }
 
 var listener net.Listener
 
 type Calculator struct{}
 
 func (t *Calculator) Add(args *Args, reply *int) error {
 *reply = args.X + args.Y
 return nil
 }
 
 func (t *Calculator) Exit(args *int, reply *int) error {
 listener.Close()
 return nil
 }
 
 func main() {
 cal := new(Calculator)
 server := rpc.NewServer()
 server.Register(cal)
 
 listener, e := net.Listen("tcp", "localhost:0")
 if e != nil {
 fmt.Printf("error:%s\n", e)
 return
 } else {
 fmt.Printf("%s\n", listener.Addr().String())
 }
 
 for {
 if conn, err := listener.Accept(); err != nil {
 log.Fatal("error: " + err.Error())
 } else {
 go server.ServeCodec(jsonrpc.NewServerCodec(conn))
 }
 }
 }
 
 | 
假设上面用go语言生成的exe文件名为gotest.exe,并且是放在当前工程目录下,然后我们用下面的 aardio 代码调用这个 gotest.exe 里的go函数:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 
 | import win.ui;
 var winform = win.form(text="aardio调用go语言演示";right=759;bottom=469)
 winform.add(
 button={cls="button";text="调用Go语言的Calculator.Add函数";left=382;top=389;right=678;bottom=427;z=5};
 edit={cls="edit";left=19;top=12;right=732;bottom=352;edge=1;hscroll=1;multiline=1;vscroll=1;z=1};
 editX={cls="edit";text="2";left=109;top=392;right=185;bottom=424;edge=1;z=2};
 editY={cls="edit";text="3";left=238;top=392;right=320;bottom=420;edge=1;z=3};
 static={cls="static";text="+";left=198;top=395;right=230;bottom=420;align="center";transparent=1;z=4}
 )
 
 
 import wsock.tcp.jsonClient;
 import process.popen;
 
 
 var gofile = process.popen("/gotest.exe");
 if(!gofile) return winform.msgbox("启动go程序失败");
 
 
 var url = gofile.read();
 if( !url || string.startWith(url,"error:")  ) return winform.msgbox("启动go程序失败");
 
 
 var go = wsock.tcp.jsonClient(url)
 winform.edit.print("已连接到go程序",url);
 
 winform.button.oncommand = function(id,event){
 
 
 var rep = go.Calculator.Add({
 X = tonumber(winform.editX.text);
 Y = tonumber(winform.editY.text);
 } )
 
 if( rep[["result"]] ){
 winform.edit.print( "调用成功", rep.result )
 }
 else {
 winform.edit.print( rep[["error"]] )
 }
 }
 
 winform.show()
 win.loopMessage();
 
 
 go.Calculator.Exit(0);
 
 | 
附:调用Go语言编译器例子
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | import console;import golang;
 
 var go = golang();
 
 go.runCode("/hello.go",`
 package main
 import "fmt"
 func main() {
 fmt.Println("hello world")
 }`)
 
 console.pause();
 
 | 
最新版golang扩展库已支持自动下载配置Go编译器。
Go最新版已经支持调用生成DLL文件(需要调用gcc),在aardio中可以直接调用Go生成的DLL文件(使用cdecl调用约定),下面是调用Go编译器生成DLL的演示。  
下面看演示:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 
 | import console;import golang;
 
 
 var go = golang();
 
 
 string.save("/hello.go",`
 package main
 
 import "C"
 import "fmt"
 
 //export SayHello
 func SayHello(name string) {
 fmt.Printf("Go says: %s!\n", name)
 }
 
 func main() {
 //DLL入口函数,没有也要写个空的
 } `)
 
 
 go.buildShared("/hello.go","/hello.dll");
 
 
 var dll = raw.loadDll("/hello.dll",,"cdecl");
 
 
 console.open();
 var str = "必须在Go函数名前面加上 export 函数名的注释才能导出函数";
 dll.SayHello(str,#str);
 
 console.log( n )
 console.pause();
 
 | 
Go写DLL要注意一个特别的地方,Go导出函数前必须写一行注释声明导出函数,例如上面的 //export SayHello
Go语言里的字符串GoString是一个结构体,用aardio来表示是这样的:
| 12
 3
 4
 5
 6
 7
 8
 
 | class goString{ctor( str ){
 this.s = str;
 this.n = #str;
 };
 string s;
 addr n;
 }
 
 | 
如果是在API函数里传值,一个GoString展开为2个API参数来表示就可以了(一个字符串,后面跟一个字符串长度)
因为aardio传结构体都是传指针,如果用结构体,在Go里面要声明为指针,示例:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 
 | import console;import golang;
 
 
 var go = golang();
 
 
 string.save("/hello.go",`
 package main
 
 import "C"
 import "fmt"
 
 //export SayHello
 func SayHello(name *string) {
 fmt.Printf("Go says: %s!\n", *name)
 }
 
 func main() {
 //DLL入口函数,没有也要写个空的
 } `)
 
 
 go.buildShared("/hello.go","/hello.dll");
 
 
 var dll = raw.loadDll("/hello.dll",,"cdecl");
 
 class goString{
 ctor( str ){
 this.s = str;
 this.n = #str;
 };
 string s;
 addr n;
 }
 
 
 console.open();
 dll.SayHello( goString( "必须在Go函数名前面加上 export 函数名的注释才能导出函数") );
 
 console.log( n )
 console.pause();
 
 | 
需要先安装MinGW( GCC )
可以下载安装 MinGW-W64: https://sourceforge.net/projects/mingw-w64 这个只能安装在64位系统。
也可以下载安装 TDM-GCC: http://tdm-gcc.tdragon.net/download 这个提供支持32位、64位安装包。  
golang扩展库会自动搜索MinGW,MinGW-W64,TDM-GCC的安装位置,不需要手动配置。
当然也可以调用golang扩展库提供的addPath函数自己添加gcc.exe所在的目录。  
Go生成的文件很大,加上-ldflags "-s -w"参数会小一些,go.buildShared() 已经自动加上这些参数。
编译上面的代码生成的DLL只有1MB多一点,而且可以支持WinXP,不需要依赖外部运行库,还是非常不错的。
而且测试了一下,编译的DLL还能内存加载。