您的位置:首页 > 编程语言 > Go语言

Golang与DLL交互

2017-12-09 13:30 155 查看

Golang与DLL交互

在系统级编程中,经常需要使用C/C++来编写模块给Go调用,目前官方支持这种调用,但是需要CGO做支撑。

这里研究了Golang与DLL进行数据交换的几种方式,(重点是:指针,结构体,回掉函数)并做以测试。

依赖条件:

C接口形式的DLL(这里使用了VS2015编写)

CGO依赖的GCC(这里使用Qt5.9自带的Minigw)

1. DLL代码

#include "stdafx.h"
#include <stdio.h>

#ifndef TM_ROBOT_API
#define TM_ROBOT_API extern "C" __declspec(dllexport)
#else
#define TM_ROBOT_API extern "C" __declspec(dllimport)
#endif

TM_ROBOT_API void fun1(int* pVal) {
char buff[128];
sprintf(buff, "fun1, val: %d -> 999\n", *pVal);
OutputDebugStringA(buff);
*pVal = 999;
}

struct MyStruct
{
int nVal1;
float nVal2;
};

typedef void(*CB_MY)(float nVal, float fVal);

TM_ROBOT_API void fun2(MyStruct* pVal) {
char buff[128];
sprintf(buff, "fun2, val: 1->%d, 2->%.4f -> 1,2\n", pVal->nVal1, pVal->nVal2);
OutputDebugStringA(buff);
pVal->nVal1 = 1;
pVal->nVal2 = 2.2;
}

TM_ROBOT_API void fun3(CB_MY pFun) {
char buff[128];
sprintf(buff, "fun3, val: %08X -> call it 10s\n", pFun);
OutputDebugStringA(buff);
for (int i=80;i<100;i++)
{
pFun(i*3.3, i*1.1);
Sleep(10);
}
}


注意,这里的调用约定为
extern "C" __declspec(dllexport)


2. Golang代码

package main

/*
// 依赖GCC
typedef struct _MyStruct
{
int nVal1;
float nVal2;
}MyStruct;

*/
import "C"
import (
"fmt"
"syscall"
"unsafe"
)

func cb_my(val1 float32, val2 float32) int32 {
fmt.Println("cb_my:", val1, val2)
return 0
}

func main() {
Handle := syscall.NewLazyDLL("gocTest.dll")
Fun3 := Handle.NewProc("fun3")
Fun2 := Handle.NewProc("fun2")
Fun1 := Handle.NewProc("fun1")
var aa int32 = 10 // var aa C.int = 10
Fun1.Call(uintptr(unsafe.Pointer(&aa)))
fmt.Println("########", aa)
var arg1 C.MyStruct // 使用Go的Struct会有问题
arg1.nVal1 = 11
arg1.nVal2 = 22.22
Fun2.Call(uintptr(unsafe.Pointer(&arg1)))
fmt.Println("************", arg1)
var fn = syscall.NewCallbackCDecl(cb_my) // 注意调用约定
Fun3.Call(fn)
fmt.Println("============")
}


3. 总结

fun1做简单的测试就能通过,如果时float等其他类型,尽量使用CGO模块类型。

fun2如果使用Golang的结构体,除了int32之外的参数都有问题,需要CGO模块类型。

fun3特别注意NewCallbackCDecl/NewCallback与回掉函数的约定,否则会出很多异常。

其他高阶混合编程,这里不做涉及。

参考

https://studygolang.com/articles/1424

http://lib.csdn.net/article/go/33766

类型转换对照表:

char -->  C.char -->  byte
signed char -->  C.schar -->  int8
unsigned char -->  C.uchar -->  uint8
short int -->  C.short -->  int16
short unsigned int -->  C.ushort -->  uint16
int -->  C.int -->  int
unsigned int -->  C.uint -->  uint32
long int -->  C.long -->  int32 or int64
long unsigned int -->  C.ulong -->  uint32 or uint64
long long int -->  C.longlong -->  int64
long long unsigned int -->  C.ulonglong -->  uint64
float -->  C.float -->  float32
double -->  C.double -->  float64
wchar_t -->  C.wchar_t  -->
void * -> unsafe.Pointer
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: