-
Notifications
You must be signed in to change notification settings - Fork 73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Struct support for Windows #237
Labels
enhancement
New feature or request
Comments
My comment applies here too |
Here is a first example of how it could look like: func RegisterNew(fptr any, handle uintptr, name string) {
if fptr == nil {
panic("argument is nil")
}
typ := reflect.TypeOf(fptr)
kind := typ.Kind()
if kind != reflect.Ptr {
panic("wrong kind " + kind.String())
}
typ = typ.Elem()
kind = typ.Kind()
if kind != reflect.Func {
panic("wrong kind " + kind.String())
}
numOut := typ.NumOut()
if numOut > 1 {
panic("at most one return value is supported")
}
numIn := typ.NumIn()
var outToIn bool
var outToUintptr bool
ptrPositions := make([]bool, numIn)
uintptrPositions := make([]bool, numIn)
outs := []reflect.Type{}
ins := []reflect.Type{}
uintptrTyp := reflect.TypeFor[uintptr]()
for i := 0; i < numOut; i++ {
out := typ.Out(i)
if out.Kind() == reflect.Struct {
if out.Size() > 8 {
out = reflect.PointerTo(out)
outToIn = true
ins = append(ins, out)
continue
}
outs = append(outs, uintptrTyp)
outToUintptr = true
continue
}
outs = append(outs, out)
}
for i := 0; i < numIn; i++ {
in := typ.In(i)
if in.Kind() == reflect.Struct {
if in.Size() > 8 {
in = reflect.PointerTo(in)
ptrPositions[i] = true
} else {
in = uintptrTyp
uintptrPositions[i] = true
}
}
ins = append(ins, in)
}
fnTyp := reflect.FuncOf(ins, outs, false)
fn := reflect.New(fnTyp)
purego.RegisterLibFunc(fn.Interface(), handle, name)
impl := reflect.MakeFunc(typ, func(args []reflect.Value) (results []reflect.Value) {
newArgs := make([]reflect.Value, 0, len(args))
var newResult reflect.Value
if outToIn {
newResult = reflect.New(ins[0].Elem())
newArgs = append(newArgs, newResult)
}
for i := 0; i < len(args); i++ {
if ptrPositions[i] {
value := reflect.New(args[i].Type())
value.Elem().Set(args[i])
newArgs = append(newArgs, value)
continue
} else if uintptrPositions[i] {
value := reflect.New(args[i].Type())
value.Elem().Set(args[i])
newArgs = append(newArgs, reflect.ValueOf(*(*uintptr)(value.UnsafePointer())))
continue
}
newArgs = append(newArgs, args[i])
}
res := fn.Elem().Call(newArgs)
if outToIn {
return []reflect.Value{newResult.Elem()}
} else if outToUintptr {
value := reflect.New(res[0].Type())
value.Elem().Set(res[0])
newValue := reflect.NewAt(typ.Out(0), value.UnsafePointer())
return []reflect.Value{newValue.Elem()}
}
return res
})
reflect.ValueOf(fptr).Elem().Set(impl)
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Operating System
What feature would you like to be added?
Support structs as return values and parameters of functions on Windows.
Why is this needed?
Technically purego already supports structs, but you have to make some weird stunts:
If the struct's size is less than or equal 8 bytes, you just can convert them into a uintptr. Same goes for return values. Example:
C:
Golang:
If the struct's size is lager then 8 bytes, you have to use a pointer as parameter. For return values you have to pass it as first argument. Here is another example from raylib-go:
C:
Golang:
The text was updated successfully, but these errors were encountered: