安装gcc环境
运行环境:window10 64位
下载路径:http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/4.8.2/threads-posix/seh/x86_64-4.8.2-release-posix-seh-rt_v3-rev2.7z/download
解压缩到 C:\MinGW\mingw64 目录下, 还需要在 path 环境变量中增加 C:\MinGW\mingw64\bin 确保可以找到gcc。
编写需要生成dll的golang代码
plugin.go
package main import "C" import ( "fmt" ) //export DCall func DCall() int { return 2 } //export DCallWithParam func DCallWithParam(msg *C.char) *C.char { return msg } func main() { fmt.Println("goroute全部退出") }
执行命令生成dll文件:
go build -buildmode=c-shared -o plugin.dll plugin.go
会附带生成plugin.h文件
/* Code generated by cmd/cgo; DO NOT EDIT. */ /* package command-line-arguments */ #line 1 "cgo-builtin-export-prolog" #include <stddef.h> /* for ptrdiff_t below */ #ifndef GO_CGO_EXPORT_PROLOGUE_H #define GO_CGO_EXPORT_PROLOGUE_H #ifndef GO_CGO_GOSTRING_TYPEDEF typedef struct { const char *p; ptrdiff_t n; } _GoString_; #endif #endif /* Start of preamble from import "C" comments. */ /* End of preamble from import "C" comments. */ /* Start of boilerplate cgo prologue. */ #line 1 "cgo-gcc-export-header-prolog" #ifndef GO_CGO_PROLOGUE_H #define GO_CGO_PROLOGUE_H typedef signed char GoInt8; typedef unsigned char GoUint8; typedef short GoInt16; typedef unsigned short GoUint16; typedef int GoInt32; typedef unsigned int GoUint32; typedef long long GoInt64; typedef unsigned long long GoUint64; typedef GoInt64 GoInt; typedef GoUint64 GoUint; typedef __SIZE_TYPE__ GoUintptr; typedef float GoFloat32; typedef double GoFloat64; typedef float _Complex GoComplex64; typedef double _Complex GoComplex128; /* static assertion to make sure the file is being used on architecture at least with matching size of GoInt. */ typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1]; #ifndef GO_CGO_GOSTRING_TYPEDEF typedef _GoString_ GoString; #endif typedef void *GoMap; typedef void *GoChan; typedef struct { void *t; void *v; } GoInterface; typedef struct { void *data; GoInt len; GoInt cap; } GoSlice; #endif /* End of boilerplate cgo prologue. */ #ifdef __cplusplus extern "C" { #endif extern GoInt DCall(); extern char* DCallWithParam(char* p0); #ifdef __cplusplus } #endif
Golang代码调用
pluginLoad.go
package main import "C" import ( "fmt" "syscall" "unsafe" ) func main() { dll := syscall.NewLazyDLL("plugin.dll") f := dll.NewProc("DCall") res, _, _ := f.Call() fmt.Println(res) f2 := dll.NewProc("DCallWithParam") r, _, _ := f2.Call(uintptr(unsafe.Pointer(syscall.StringBytePtr("php2.cc")))) // 获取C返回的指针。 // 注意C返回的r为char*,对应的Go类型为*byte p := (*byte)(unsafe.Pointer(r)) // 定义一个[]byte切片,用来存储C返回的字符串 data := make([]byte, 0) // 遍历C返回的char指针,直到 '\0' 为止 for *p != 0 { data = append(data, *p) // 将得到的byte追加到末尾 r += unsafe.Sizeof(byte(0)) // 移动指针,指向下一个char p = (*byte)(unsafe.Pointer(r)) // 获取指针的值,此时指针已经指向下一个char } name := string(data) // 将data转换为字符串 fmt.Printf("Hello, %s!\n", name) }
域名命令:
go run pluginLoad.go