英文:
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)
}
}
C.InitCallback
函数类似于C.SomeDLLFunc
,但是它直接引用了goCallbackFunction
,而不需要类型转换,因为我将代码从.go文件移动到了.c文件中。- 这是一种从C DLL回调到Go的解决方案。我们只需要向DLL注册一个Go函数。我们编写了一个
C.InitCallback
函数。请注意,如果我们使用C.SomeDLLFunc
解决方案,我们必须编写(gocallback,dllfunc)对。 - 在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)
}
}
- The
C.InitCallback
function is similar toC.SomeDLLFunc
.But it referencesgoCallbackFunction
directly without cast,since I move the code from .go to .c. - 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 theC.SomeDLLFunc
solution, we must write (gocallback,dllfunc) pairs. - Keeping an export go function pointer in c dll is ok.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论