How to use a Go callback for a DLL with minimal Cgo?

huangapple go评论113阅读模式
英文:

How to use a Go callback for a DLL with minimal Cgo?

问题

一种将回调函数设置为传递给DLL函数参数的方法是使用CGO...

package main

/*
#cgo LDFLAGS: -L${SRCDIR} -lsomelib

#include "somelib.h"

extern void CallbackString(char* s);
*/
import "C"

import (
	"unsafe"
	"fmt"
)

//export CallbackString
func CallbackString(s *C.char) {
	gostr := C.GoString(s)  // 转换为Go语言字符串
	fmt.Println("从DLL(或DSO)中获取的字符串:", gostr)
}

func Example() {
	// 通过调用需要回调参数的DLL中的函数来设置回调
	C.SomeDLLFunc(x, y,
		(C.TCallbackString)(unsafe.Pointer(C.CallbackString)),
		other,
		params)
}


func main() {
	Example()
}

其中回调函数定义为

typedef void (*TCallbackString)(char*);

但我想知道是否有一种方法可以避免使用CGO,只需将go函数作为参数传递而不需要不必要的C代码绑定,即

C.SomeDLLFunc(x, y,
	CallbackString, // 如何将go函数作为回调发送?
	other,
	params)

是否总是需要编写C绑定或类似的东西,C链接到go代码,C导出/外部,以便将回调作为参数发送?

是否没有办法直接将go函数作为回调,而不需要先将其变为C风格?

C.SomeDLLFunc(x, y,
	WhatCastIsNeeded(CallbackString), // 将常规的go函数作为回调?
	other,
	params)
英文:

One way to setup a callback function to be passed in to a parameter to a DLL function is to use CGO...

package main

/*
#cgo LDFLAGS: -L${SRCDIR} -lsomelib

#include "somelib.h"

extern void CallbackString(char* s);
*/
import "C"

import (
	"unsafe"
	"fmt"
)

//export CallbackString
func CallbackString(s *C.char) {
	gostr := C.GoString(s)  // convert to golang string
	fmt.Println("Got string from dll (or dso): ", gostr)
}

func Example() {
	// setup a callback by calling a function in
	// the DLL requiring callback param
	C.SomeDLLFunc(x,y,
		(C.TCallbackString)(unsafe.Pointer(C.CallbackString)),
	 	other,
		params)
}


func main() {
	Example()
}

where the callback is defined as

typedef void (*TCallbackString)(char*);

But I am wondering if there is a way to avoid using CGO and just pass the go function in as a parameter without requiring needless C code bindings.. i.e.

C.SomeDLLFunc(x,y,
	CallbackString, // how to send the go function in as a callback?
 	other,
	params)

Does it always require writing C bindings or whatever you call them, C links to the go code, C exports/externs, in order to send a callback as a param?

There is no way to just make a go function a callback without making it C-ish first?

C.SomeDLLFunc(x,y,
	WhatCastIsNeeded(CallbackString), // regular go function as a callback?
 	other,
	params)

答案1

得分: 2

有一种方法可以避免类型转换并简化回调代码。

// 在dll中的cgo.h文件
typedef void (Callback)(int kind,void arg);
void SetCallback(Callback func);

// 在dll中的cgo.c文件
Callback Gfunc;
void SetCallback(Callback func){
Gfunc=func;
}

// 在go项目中的cgocb.h文件
void InitCallback();
extern void goCallbackFunction(int kind,void* arg);

// 在go项目中的cgocb.c文件
void InitCallback(){
SetCallback(goCallbackFunction);
}

// 在go项目中的cgocb.go文件
// export goCallbackFunction
func goCallbackFunction(kind C.int,arg unsafe.Pointer){
switch kind{
case C.AKind:
arg:=(*C.AKind)(arg)
AkindCallback(arg)
}
}

  1. C.InitCallback函数类似于C.SomeDLLFunc,但是它直接引用了goCallbackFunction,而不需要类型转换,因为我将代码从.go文件移动到了.c文件中。
  2. 这是一种从C DLL回调到Go的解决方案。我们只需要向DLL注册一个Go函数。我们编写了一个C.InitCallback函数。请注意,如果我们使用C.SomeDLLFunc解决方案,我们必须编写(gocallback,dllfunc)对。
  3. 在C DLL中保持一个导出的Go函数指针是可以的。
英文:

There is some way to avoid the cast and simplify callback code.

// cgo.h in dll  
typedef void (*Callback)(int kind,void* arg);
void SetCallback(Callback func);

// cgo.c in dll
Callback Gfunc;
void SetCallback(Callback func){
    Gfunc=func;
}

// cgocb.h in go project
void InitCallback();
extern void goCallbackFunction(int kind,void* arg);

// cgocb.c in go project
void InitCallback(){
    SetCallback(goCallbackFunction);
}

// cgocb.go in go project
// export goCallbackFunction
func goCallbackFunction(kind C.int,arg unsafe.Pointer){
    switch kind{
    case C.AKind:
        arg:=(*C.AKind)(arg)
        AkindCallback(arg)
    }
}
  1. The C.InitCallback function is similar to C.SomeDLLFunc.But it references goCallbackFunction directly without cast,since I move the code from .go to .c.
  2. This is a solution about callback to go from c dll. We need to register only one go function to the dll. We write one C.InitCallback. Note that if we use the C.SomeDLLFunc solution, we must write (gocallback,dllfunc) pairs.
  3. Keeping an export go function pointer in c dll is ok.

huangapple
  • 本文由 发表于 2017年5月20日 05:37:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/44079364.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定