最近楼主学习了go语言,发现确实很方便,而且运行速度也不慢,官方自带的库也很好用,但是就是没有图形界面,所以就想使用C++写gui,然后网络什么的调用golang,于是开始尝试使用C++调用golang的dll
楼主系统是win10 64位的,使用MINGW编译C++,gcc版本64位的4.8.2,golang版本是64位的1.10.1,如果生成dll有问题可以升级下go版本
首先写一个main.go文件,包含json解析,http请求等C++写起来麻烦的方法,main函数中测试了golang结构体内存布局,发现和c++是一样的
详细我在注释里面都有写
package main
//
import "C"
import (
"encoding/json"
"fmt"
"github.com/axgle/mahonia"
"unsafe"
"net/http"
"strings"
"io/ioutil"
)
//export Sum
func Sum(a int, b int) int { //最简单的计算和
return a + b
}
//export Show
func Show(str string) { //显示传入的字符串
fmt.Print(str)
}
//export ToNewGBKCStr
func ToNewGBKCStr(str string, c **C.char) { //生成gbk字符串
enc := mahonia.NewEncoder("GBK")
output := enc.ConvertString(str)
*c = C.CString(output)
}
//export HttpGet
func HttpGet(url string,c **C.char){//http请求
//生成client 参数为默认
client := &http.Client{}
//提交请求
reqest, err := http.NewRequest("GET", url, strings.NewReader(""))
reqest.Header.Set("Content-Type", "application/x-www-form-urlencoded")
if err != nil {
fmt.Println(err)
return
}
//处理返回结果
response, err := client.Do(reqest)
if err != nil {
fmt.Println(err)
return
}
buf,err:=ioutil.ReadAll(response.Body)
if err != nil {
fmt.Println(err)
return
}
retstr:=string(buf)
ToNewGBKCStr(retstr,c)
}
//export SetMyPoint
func SetMyPoint(p uintptr) { //修改传入的结构体
mp := (*MyPoint)(unsafe.Pointer(p)) //将指针p强制转换为MyPoint类型
mp.Name = "名称:" + mp.Name
mp.X = 1 + mp.X
mp.Y = 2 + mp.Y
}
//export JsonToMyPoint
func JsonToMyPoint(str string, p uintptr) {
mp := (*MyPoint)(unsafe.Pointer(p))
json.Unmarshal([]byte(str), mp)
}
type MyPoint struct {
Name string `json:"name"`
X int `json:"x"`
Y int `json:"y"`
}
func main() {
//测试golang结构体内存布局
mp := MyPoint{Name: "测试", X: 1, Y: 2}
p := uintptr(unsafe.Pointer(&mp)) //强制转换为指针
name := *(*string)(unsafe.Pointer(p)) //将指针强制转换为string
fmt.Println(name)
//64位系统上string占16字节,前8字节是字符串的起始地址,后8字节为字符串占的字节数
p += unsafe.Sizeof(string(""))
x := *(*int)(unsafe.Pointer(p)) //将指针强制转换为int
fmt.Println(x)
p += unsafe.Sizeof(int(0)) //64位系统上int占8字节
y := *(*int)(unsafe.Pointer(p))
fmt.Println(y)
}
然后在这个文件目录下新建一个bat文件,输入
@echo off
set filepath=%1
set dllpath=%~dp1%~n1.dll
IF NOT EXIST "%filepath%" (
goto err
) ELSE (
goto make
)
:err
echo 文件不存在!
set/p exepath=请拖拽文件这里或输入文件路径然后按下回车
IF NOT EXIST "%filepath%" (
goto err
) ELSE (
goto make
)
:make
echo 编译 %~nx1 -^> %~n1.dll
call go build -ldflags "-s -w" -buildmode=c-shared -o "%dllpath%" "%filepath%"
echo 编译完成!按下回车关闭窗口
:end
pause
把main.go文件拖上去就会自动生成main.dll和main.h
接下来编写一个mian.cpp来调用这些函数
#include
#include
#include
#include "main.h"
struct MyPoint{//类型和顺序必须和go中的MyPoint对应
GoString Name;
long long X;
long long Y;
};
void dump(char *d, size_t len, const char* file) {
FILE *fp = nullptr;
fopen_s(&fp, file, "w+b");
fwrite(d, sizeof(char), len, fp);
fclose(fp);
}
void test(){
printf("Sum(1,2)=%d\n",Sum(1,2));
const char* str="测试字符串\n";
GoString gstr{str,(ptrdiff_t)strlen(str)};//就是go中的string类型
Show(gstr);
//char* cgstr = (char*)malloc(gstr.n + 1);
//if (!cgstr) { /* handle allocation failure */ }
//memcpy(cgstr, gstr.p, gstr.n);
//cgstr[gstr.n] = '\0';
//dump(cgstr,gstr.n,"1.txt");//dump出来用notepad++打发现是utf-8编码
//free(cgstr);
MyPoint mp{gstr,0,0};
SetMyPoint((GoUintptr)&mp);
printf("%d,%d\n",mp.X,mp.Y);
char* pname=nullptr;
ToNewGBKCStr(mp.Name,&pname);
printf("%s\n",pname);
free(pname);
pname=nullptr;
}
void testhttp(){
const char* str="http://www.baidu.com";
GoString gstr{str,(ptrdiff_t)strlen(str)};
char* res=nullptr;
HttpGet(gstr,&res);
printf("%s\n",res);
free(res);
res=nullptr;
}
void testjson(){
const char* str=R"_TWT_({"name":"来自json的点","x":100,"y":200})_TWT_";//C++11中的raw string,防止转义
GoString gstr{str,(ptrdiff_t)strlen(str)};
MyPoint mp;
JsonToMyPoint(gstr,(GoUintptr)&mp);
char* pname=nullptr;
ToNewGBKCStr(mp.Name,&pname);
printf("%s,%d,%d\n",pname,mp.X,mp.Y);
free(pname);
pname=nullptr;
}
int main(){
testhttp();
test();
testjson();
getchar();
return 0;
}
再编写一个bat,输入以下内容
call g++ -c main.cpp -o main.o -g -std=c++11
call g++ main.o main.dll -o 1.exe -g -std=c++11
call 1.exe
pause
双击即可一键编译运行
所有文件下载:https://github.com/sleepinging/StudyGolang/tree/master/Test/win32/DllTest
转载请注明出处:https://blog.csdn.net/rtduq/article/details/80340461