-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathunmarshal_windows.go
83 lines (71 loc) · 2.12 KB
/
unmarshal_windows.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
//go:build windows
package goinvoke
import (
"github.com/hashicorp/go-multierror"
"github.com/jamesits/goinvoke/utils"
"golang.org/x/sys/windows"
"reflect"
"strconv"
)
// Unmarshal loads the DLL into memory, then fills all struct fields with type *windows.LazyProc with exported functions.
func Unmarshal(path string, v any) error {
var err error
var syntheticErr = ErrorUnmarshalFailed
var errorOccurred = false
ld := newLazyDLL(path)
err = ld.Load()
if err != nil {
errorOccurred = true
syntheticErr = multierror.Append(syntheticErr, err)
return syntheticErr
}
d := unLazy(ld)
// https://stackoverflow.com/a/46354875
valueReference := reflect.ValueOf(v).Elem()
typeReference := valueReference.Type()
fieldCount := typeReference.NumField()
for i := 0; i < fieldCount; i++ {
// try to get a function name from tag first, then by attribute name
typeField := typeReference.Field(i)
procName := utils.GetStructTag(typeField, "func")
if procName == "" {
procName = typeField.Name
}
// get a reference of current attribute's value
valueField := valueReference.Field(i)
if !valueField.IsValid() || !valueField.CanSet() || procName == "" {
continue
}
if utils.CompatibleType(valueField, typeOfLazyProc) {
// LazyProc only supports loading by name
proc := ld.NewProc(procName)
// try to load the proc now
err = proc.Find()
if err != nil {
errorOccurred = true
syntheticErr = multierror.Append(syntheticErr, err)
continue
}
utils.Set(valueField, proc)
} else if utils.CompatibleType(valueField, typeOfProc) {
// Windows specific: ordinal
ordinal, ordinalParsingError := strconv.ParseInt(utils.GetStructTag(typeField, "ordinal"), 10, 64)
var proc *windows.Proc
if ordinalParsingError == nil { // we have a valid ordinal
proc, err = d.FindProcByOrdinal(uintptr(ordinal))
} else { // fallback to matching by name
proc, err = d.FindProc(procName)
}
if err != nil {
errorOccurred = true
syntheticErr = multierror.Append(syntheticErr, err)
continue
}
utils.Set(valueField, proc)
}
}
if errorOccurred {
return syntheticErr
}
return nil
}