// Package interceptor 提供了动态加载和调用共享库函数的功能。 // 该包使用purego库实现跨平台的动态库加载,支持Windows的DLL和Linux的SO文件。 package interceptor import ( "fmt" "path/filepath" "reflect" "strings" "github.com/ebitengine/purego" ) // funcType 定义了函数的参数类型和返回值类型。 // 用于在动态加载库函数时指定函数签名。 type funcType struct { ParamTypes []string ReturnTypes []string } // typeMap 将字符串类型名映射到对应的Go reflect.Type。 // 支持基本数据类型如int、float、string等,以及特殊的"void"类型表示无返回值。 var typeMap = map[string]reflect.Type{ "int": reflect.TypeOf(int(0)), "int32": reflect.TypeOf(int32(0)), "int64": reflect.TypeOf(int64(0)), "uint": reflect.TypeOf(uint(0)), "float32": reflect.TypeOf(float32(0)), "float64": reflect.TypeOf(float64(0)), "string": reflect.TypeOf(""), "bool": reflect.TypeOf(false), "void": nil, // 用于表示无返回值 } // makeFuncType 根据给定的参数类型和返回值类型字符串列表,创建对应的函数类型。 // paramTypes: 函数参数类型的字符串列表 // returnTypes: 函数返回值类型的字符串列表 // 返回: 创建的函数类型和可能的错误 func makeFuncType(paramTypes, returnTypes []string) (reflect.Type, error) { var in, out []reflect.Type // 参数类型 for _, t := range paramTypes { rt, ok := typeMap[t] if !ok { return nil, fmt.Errorf("unknown parameter type: %s", t) } in = append(in, rt) } // 返回值类型 for _, t := range returnTypes { if t == "void" { continue // 无返回值 } rt, ok := typeMap[t] if !ok { return nil, fmt.Errorf("unknown return type: %s", t) } out = append(out, rt) } return reflect.FuncOf(in, out, false), nil } // loadLibrary 加载指定路径的动态库文件,并根据提供的函数映射表注册库中的函数。 // 如果库已经被加载过,则直接返回之前加载的实例。 // libPath: 动态库文件的路径 // libFuncMap: 库中函数名到函数类型的映射表 // 返回: 包含所有注册函数的接口实例 func (a *Ankointerceptor) loadLibrary(libPath string, libFuncMap map[string]funcType) interface{} { libName := filepath.Base(libPath) libName = strings.TrimSuffix(libName, filepath.Ext(".dll")) // 是不是so文件?libName里边是否包含.so if strings.Contains(libName, ".so") { soIndex := strings.Index(libName, ".so") libName = libName[0:soIndex] } libName = strings.TrimPrefix(libName, "lib") if _, ok := a.libMap[libName]; ok { return a.libMap[libName] // 如果已经加载过,直接返回 } lib, err := purego.Dlopen(libPath, purego.RTLD_LAZY) if err != nil { panic("Load library error") } a.liberalises = append(a.liberalises, lib) fnmap := make(map[string]interface{}) fileds := make([]reflect.StructField, 0, len(fnmap)) for name, types := range libFuncMap { ft, err := makeFuncType(types.ParamTypes, types.ReturnTypes) if err != nil { panic(err) } fn := reflect.New(ft).Elem().Addr().Interface() purego.RegisterLibFunc(fn, lib, name) //Get ft 指针类型 // ftp := reflect.PtrTo(ft) fileds = append(fileds, reflect.StructField{ Name: name, Type: ft, }) fnmap[name] = fn } // 根据fnmap构建一个匿名结构体,结构体的字段名为函数名,字段值为函数指针 libstruct := reflect.StructOf(fileds) // 创建一个匿名结构体的实例 libinstance := reflect.New(libstruct).Elem() for name, fn := range fnmap { // 将函数指针指向的函数设置到结构体实例的对应字段中 libinstance.FieldByName(name).Set(reflect.ValueOf(fn).Elem()) // libinstance.FieldByName(name).Set() } a.libMap[libName] = libinstance.Interface() return a.libMap[libName] } // Close 关闭所有已加载的动态库句柄,释放资源。 // 应在不再需要使用动态库时调用此方法。 func (a *Ankointerceptor) Close() { for _, lib := range a.liberalises { _ = purego.Dlclose(lib) } }