Как использовать обратный вызов Go для DLL с минимальным 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)  // 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()
}

где обратный вызов определяется как

typedef void (*TCallbackString)(char*);

Но мне интересно, есть ли способ избежать использования CGO и просто передать функцию go в качестве параметра, не требуя ненужных привязок кода C... т.е.

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

Всегда ли требуется писать привязки C или как бы вы их ни называли, C-ссылки на код go, C-экспорты/экстерны, чтобы отправить обратный вызов в качестве параметра?

Нет способа просто сделать функцию go обратным вызовом, не сделав ее сначала C-ish?

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

person Another Prog    schedule 19.05.2017    source источник


Ответы (1)


Есть способ избежать приведения и упростить код обратного вызова.

// 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. Функция C.InitCallback похожа на C.SomeDLLFunc. Но она напрямую ссылается на goCallbackFunction без приведения, так как я перемещаю код из .go в .c.
  2. Это решение о обратном вызове для перехода из c dll. Нам нужно зарегистрировать только одну функцию go в dll. Пишем один C.InitCallback. Обратите внимание, что если мы используем решение C.SomeDLLFunc, мы должны написать пары (gocallback,dllfunc).
  3. Сохранение указателя функции экспорта в c dll — это нормально.
person 海牙客移库    schedule 25.08.2017