first commit
This commit is contained in:
60
internal/codegen/templates/class.tmpl
Normal file
60
internal/codegen/templates/class.tmpl
Normal file
@ -0,0 +1,60 @@
|
||||
{{if not .IsAbstract}}
|
||||
const Signature{{.Name}} string = "{{.Signature}}"
|
||||
|
||||
type {{.Name}} struct {
|
||||
ole.IUnknown
|
||||
}
|
||||
|
||||
{{if .HasEmptyConstructor}}
|
||||
func New{{.Name}}() (*{{.Name}}, error) {
|
||||
inspectable, err := ole.RoActivateInstance("{{.FullyQualifiedName}}")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (*{{.Name}})(unsafe.Pointer(inspectable)), nil
|
||||
}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{$owner := .Name}}
|
||||
{{range .ImplInterfaces}}
|
||||
{{range .Funcs}}
|
||||
{{if not .Implement}}{{continue}}{{end}}
|
||||
func (impl *{{$owner}}) {{funcName .}} (
|
||||
{{- range .InParams -}}
|
||||
{{/*do not include out parameters, they are used as return values*/ -}}
|
||||
{{ if .IsOut }}{{continue}}{{ end -}}
|
||||
{{.GoVarName}} {{template "variabletype.tmpl" . }},
|
||||
{{- end -}}
|
||||
)
|
||||
|
||||
{{- /* return params */ -}}
|
||||
|
||||
( {{range .InParams -}}
|
||||
{{ if not .IsOut }}{{continue}}{{ end -}}
|
||||
{{template "variabletype.tmpl" . }},{{end -}}
|
||||
{{range .ReturnParams}}{{template "variabletype.tmpl" . }},{{end}} error )
|
||||
|
||||
{{- /* method body */ -}}
|
||||
|
||||
{
|
||||
itf := impl.MustQueryInterface(ole.NewGUID({{if .InheritedFrom.Namespace}}{{.InheritedFrom.Namespace}}.{{end}}GUID{{.InheritedFrom.Name}}))
|
||||
defer itf.Release()
|
||||
v := (*{{if .InheritedFrom.Namespace}}{{.InheritedFrom.Namespace}}.{{end}}{{.InheritedFrom.Name}})(unsafe.Pointer(itf))
|
||||
return v.{{funcName . -}}
|
||||
(
|
||||
{{- range .InParams -}}
|
||||
{{if .IsOut -}}
|
||||
{{continue -}}
|
||||
{{end -}}
|
||||
{{.GoVarName -}}
|
||||
,
|
||||
{{- end -}}
|
||||
)
|
||||
}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{range .ExclusiveInterfaces}}
|
||||
{{ template "interface.tmpl" .}}
|
||||
{{end}}
|
204
internal/codegen/templates/delegate.tmpl
Normal file
204
internal/codegen/templates/delegate.tmpl
Normal file
@ -0,0 +1,204 @@
|
||||
|
||||
const GUID{{.Name}} string = "{{.GUID}}"
|
||||
const Signature{{.Name}} string = "{{.Signature}}"
|
||||
|
||||
type {{.Name}} struct {
|
||||
ole.IUnknown
|
||||
sync.Mutex
|
||||
refs uintptr
|
||||
IID ole.GUID
|
||||
}
|
||||
|
||||
type {{.Name}}Vtbl struct {
|
||||
ole.IUnknownVtbl
|
||||
Invoke uintptr
|
||||
}
|
||||
|
||||
type {{.Name}}Callback func(instance *{{.Name}},{{- range .InParams -}}
|
||||
{{.GoVarName}} {{template "variabletype.tmpl" . }},
|
||||
{{- end -}})
|
||||
|
||||
var callbacks{{.Name}} = &{{.Name | toLower}}Callbacks {
|
||||
mu: &sync.Mutex{},
|
||||
callbacks: make(map[unsafe.Pointer]{{.Name}}Callback),
|
||||
}
|
||||
|
||||
var releaseChannels{{.Name}} = &{{.Name | toLower}}ReleaseChannels {
|
||||
mu: &sync.Mutex{},
|
||||
chans: make(map[unsafe.Pointer]chan struct{}),
|
||||
}
|
||||
|
||||
func New{{.Name}}(iid *ole.GUID, callback {{.Name}}Callback) *{{.Name}} {
|
||||
// create type instance
|
||||
size := unsafe.Sizeof(*(*{{.Name}})(nil))
|
||||
instPtr := kernel32.Malloc(size)
|
||||
inst := (*{{.Name}})(instPtr)
|
||||
|
||||
// get the callbacks for the VTable
|
||||
callbacks := delegate.RegisterCallbacks(instPtr, inst)
|
||||
|
||||
// the VTable should also be allocated in the heap
|
||||
sizeVTable := unsafe.Sizeof(*(*{{.Name}}Vtbl)(nil))
|
||||
vTablePtr := kernel32.Malloc(sizeVTable)
|
||||
|
||||
inst.RawVTable = (*interface{})(vTablePtr)
|
||||
|
||||
vTable := (*{{.Name}}Vtbl)(vTablePtr)
|
||||
vTable.IUnknownVtbl = ole.IUnknownVtbl{
|
||||
QueryInterface: callbacks.QueryInterface,
|
||||
AddRef: callbacks.AddRef,
|
||||
Release: callbacks.Release,
|
||||
}
|
||||
vTable.Invoke = callbacks.Invoke
|
||||
|
||||
// Initialize all properties: the malloc may contain garbage
|
||||
inst.IID = *iid // copy contents
|
||||
inst.Mutex = sync.Mutex{}
|
||||
inst.refs = 0
|
||||
|
||||
callbacks{{.Name}}.add(unsafe.Pointer(inst), callback)
|
||||
|
||||
// See the docs in the releaseChannels{{.Name}} struct
|
||||
releaseChannels{{.Name}}.acquire(unsafe.Pointer(inst))
|
||||
|
||||
inst.addRef()
|
||||
return inst
|
||||
}
|
||||
|
||||
func (r *{{.Name}}) GetIID() *ole.GUID {
|
||||
return &r.IID
|
||||
}
|
||||
|
||||
// addRef increments the reference counter by one
|
||||
func (r *{{.Name}}) addRef() uintptr {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
r.refs++
|
||||
return r.refs
|
||||
}
|
||||
|
||||
// removeRef decrements the reference counter by one. If it was already zero, it will just return zero.
|
||||
func (r *{{.Name}}) removeRef() uintptr {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
if r.refs > 0 {
|
||||
r.refs--
|
||||
}
|
||||
|
||||
return r.refs
|
||||
}
|
||||
|
||||
func (instance *{{.Name}}) Invoke(instancePtr, rawArgs0, rawArgs1, rawArgs2, rawArgs3, rawArgs4, rawArgs5, rawArgs6, rawArgs7, rawArgs8 unsafe.Pointer) uintptr {
|
||||
{{range $i, $arg := .InParams -}}
|
||||
{{- if $arg.Type.IsEnum -}}
|
||||
{{$arg.GoVarName}}Raw := ({{$arg.Type.UnderlyingEnumType}})(uintptr(rawArgs{{$i}}))
|
||||
{{- else -}}
|
||||
{{$arg.GoVarName}}Ptr := rawArgs{{$i}}
|
||||
{{- end}}
|
||||
{{end}}
|
||||
|
||||
// See the quote above.
|
||||
{{range .InParams -}}
|
||||
{{if .Type.IsEnum -}}
|
||||
{{.GoVarName}} := ({{template "variabletype.tmpl" . }})({{.GoVarName}}Raw)
|
||||
{{else -}}
|
||||
{{.GoVarName}} := ({{template "variabletype.tmpl" . }})({{.GoVarName}}Ptr)
|
||||
{{end -}}
|
||||
{{end -}}
|
||||
if callback, ok := callbacks{{.Name}}.get(instancePtr); ok {
|
||||
callback(instance, {{range .InParams}}{{.GoVarName}},{{end}})
|
||||
}
|
||||
return ole.S_OK
|
||||
}
|
||||
|
||||
func (instance *{{.Name}}) AddRef() uintptr {
|
||||
return instance.addRef()
|
||||
}
|
||||
|
||||
func (instance *{{.Name}}) Release() uintptr {
|
||||
rem := instance.removeRef()
|
||||
if rem == 0 {
|
||||
// We're done.
|
||||
instancePtr := unsafe.Pointer(instance)
|
||||
callbacks{{.Name}}.delete(instancePtr)
|
||||
|
||||
// stop release channels used to avoid
|
||||
// https://github.com/golang/go/issues/55015
|
||||
releaseChannels{{.Name}}.release(instancePtr)
|
||||
|
||||
kernel32.Free(unsafe.Pointer(instance.RawVTable))
|
||||
kernel32.Free(instancePtr)
|
||||
}
|
||||
return rem
|
||||
}
|
||||
|
||||
type {{.Name | toLower}}Callbacks struct {
|
||||
mu *sync.Mutex
|
||||
callbacks map[unsafe.Pointer]{{.Name}}Callback
|
||||
}
|
||||
|
||||
func (m *{{.Name | toLower}}Callbacks) add(p unsafe.Pointer, v {{.Name}}Callback) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
m.callbacks[p] = v
|
||||
}
|
||||
|
||||
func (m *{{.Name | toLower}}Callbacks) get(p unsafe.Pointer) ({{.Name}}Callback, bool) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
v, ok := m.callbacks[p]
|
||||
return v, ok
|
||||
}
|
||||
|
||||
func (m *{{.Name | toLower}}Callbacks) delete(p unsafe.Pointer) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
delete(m.callbacks, p)
|
||||
}
|
||||
|
||||
// typedEventHandlerReleaseChannels keeps a map with channels
|
||||
// used to keep a goroutine alive during the lifecycle of this object.
|
||||
// This is required to avoid causing a deadlock error.
|
||||
// See this: https://github.com/golang/go/issues/55015
|
||||
type {{.Name | toLower}}ReleaseChannels struct {
|
||||
mu *sync.Mutex
|
||||
chans map[unsafe.Pointer]chan struct{}
|
||||
}
|
||||
|
||||
func (m *{{.Name | toLower}}ReleaseChannels) acquire(p unsafe.Pointer) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
c := make(chan struct{})
|
||||
m.chans[p] = c
|
||||
|
||||
go func() {
|
||||
// we need a timer to trick the go runtime into
|
||||
// thinking there's still something going on here
|
||||
// but we are only really interested in <-c
|
||||
t := time.NewTimer(time.Minute)
|
||||
for {
|
||||
select {
|
||||
case <-t.C:
|
||||
t.Reset(time.Minute)
|
||||
case <-c:
|
||||
t.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (m *{{.Name | toLower}}ReleaseChannels) release(p unsafe.Pointer) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
if c, ok := m.chans[p]; ok {
|
||||
close(c)
|
||||
delete(m.chans, p)
|
||||
}
|
||||
}
|
6
internal/codegen/templates/enum.tmpl
Normal file
6
internal/codegen/templates/enum.tmpl
Normal file
@ -0,0 +1,6 @@
|
||||
type {{.Name}} {{.Type}}
|
||||
const Signature{{.Name}} string = "{{.Signature}}"
|
||||
|
||||
const ({{range .Values}}
|
||||
{{.Name}} {{$.Name}} = {{.Value}}{{end}}
|
||||
)
|
36
internal/codegen/templates/file.tmpl
Normal file
36
internal/codegen/templates/file.tmpl
Normal file
@ -0,0 +1,36 @@
|
||||
// Code generated by winrt-go-gen. DO NOT EDIT.
|
||||
|
||||
//go:build windows
|
||||
|
||||
//nolint:all
|
||||
package {{.Package}}
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
"github.com/go-ole/go-ole"
|
||||
"github.com/saltosystems/winrt-go"
|
||||
"github.com/saltosystems/winrt-go/internal/kernel32"
|
||||
{{range .Imports}}"{{.}}"
|
||||
{{end}}
|
||||
)
|
||||
|
||||
{{range .Interfaces}}
|
||||
{{template "interface.tmpl" .}}
|
||||
{{end}}
|
||||
|
||||
{{range .Classes}}
|
||||
{{template "class.tmpl" .}}
|
||||
{{end}}
|
||||
|
||||
{{range .Enums}}
|
||||
{{template "enum.tmpl" .}}
|
||||
{{end}}
|
||||
|
||||
{{range .Structs}}
|
||||
{{template "struct.tmpl" .}}
|
||||
{{end}}
|
||||
|
||||
{{range .Delegates}}
|
||||
{{template "delegate.tmpl" .}}
|
||||
{{end}}
|
30
internal/codegen/templates/func.tmpl
Normal file
30
internal/codegen/templates/func.tmpl
Normal file
@ -0,0 +1,30 @@
|
||||
{{if .Implement}}
|
||||
func {{if and .FuncOwner (not .RequiresActivation)}}
|
||||
(v *{{.FuncOwner}})
|
||||
{{- end -}}
|
||||
|
||||
{{funcName .}}
|
||||
|
||||
{{- /* in params */ -}}
|
||||
|
||||
(
|
||||
{{- range .InParams -}}
|
||||
{{/*do not include out parameters, they are used as return values*/ -}}
|
||||
{{ if .IsOut }}{{continue}}{{ end -}}
|
||||
{{.GoVarName}} {{template "variabletype.tmpl" . }},
|
||||
{{- end -}}
|
||||
)
|
||||
|
||||
{{- /* return params */ -}}
|
||||
|
||||
( {{range .InParams -}}
|
||||
{{ if not .IsOut }}{{continue}}{{ end -}}
|
||||
{{template "variabletype.tmpl" . }},{{end -}}
|
||||
{{range .ReturnParams}}{{template "variabletype.tmpl" . }},{{end}} error )
|
||||
|
||||
{{- /* method body */ -}}
|
||||
|
||||
{
|
||||
{{template "funcimpl.tmpl" .}}
|
||||
}
|
||||
{{end}}
|
86
internal/codegen/templates/funcimpl.tmpl
Normal file
86
internal/codegen/templates/funcimpl.tmpl
Normal file
@ -0,0 +1,86 @@
|
||||
{{if .RequiresActivation}}{{/*Activate class*/ -}}
|
||||
inspectable, err := ole.RoGetActivationFactory("{{.ExclusiveTo}}", ole.NewGUID(GUID{{.FuncOwner}}))
|
||||
if err != nil {
|
||||
return {{range .ReturnParams -}}
|
||||
{{.GoDefaultValue}}, {{end}}err
|
||||
}
|
||||
v := (*{{.FuncOwner}})(unsafe.Pointer(inspectable))
|
||||
|
||||
{{end -}}
|
||||
|
||||
{{- /* Declare out variables*/ -}}
|
||||
|
||||
{{range (concat .InParams .ReturnParams) -}}
|
||||
{{ if not .IsOut}}{{continue}}{{end -}}
|
||||
{{if eq .GoTypeName "string" -}}
|
||||
var {{.GoVarName}}HStr ole.HString
|
||||
{{ else -}}
|
||||
var {{.GoVarName}} {{template "variabletype.tmpl" . -}}
|
||||
{{if .Type.IsArray}} = make({{template "variabletype.tmpl" . -}}, {{.GoVarName}}Size){{end}}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
|
||||
{{- /* Convert in variables to winrt types */ -}}
|
||||
|
||||
{{range .InParams -}}
|
||||
{{ if .IsOut}}{{continue}}{{end -}}
|
||||
{{if eq .GoTypeName "string" -}}
|
||||
{{.GoVarName}}HStr, err := ole.NewHString({{.GoVarName}})
|
||||
if err != nil{
|
||||
return {{range $.InParams}}{{if .IsOut}}{{.GoDefaultValue}}, {{end}}{{end -}}
|
||||
{{range $.ReturnParams }}{{.GoDefaultValue}}, {{end}}err
|
||||
}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
hr, _, _ := syscall.SyscallN(
|
||||
v.VTable().{{funcName .}},
|
||||
uintptr(unsafe.Pointer(v)), // this
|
||||
{{range (concat .InParams .ReturnParams) -}}
|
||||
{{if .Type.IsArray -}}
|
||||
{{/* Arrays need to pass a pointer to their first element */ -}}
|
||||
uintptr(unsafe.Pointer(&{{.GoVarName}}[0])), // {{if .IsOut}}out{{else}}in{{end}} {{.GoTypeName}}
|
||||
{{else if .IsOut -}}
|
||||
{{if (or .Type.IsPrimitive .Type.IsEnum) -}}
|
||||
{{if eq .GoTypeName "string" -}}
|
||||
uintptr(unsafe.Pointer(&{{.GoVarName}}HStr)), // out {{.GoTypeName}}
|
||||
{{else -}}
|
||||
uintptr(unsafe.Pointer(&{{.GoVarName}})), // out {{.GoTypeName}}
|
||||
{{end -}}
|
||||
{{else -}}
|
||||
uintptr(unsafe.Pointer(&{{.GoVarName}})), // out {{.GoTypeName}}
|
||||
{{end -}}
|
||||
{{else if .Type.IsPointer -}}
|
||||
uintptr(unsafe.Pointer({{.GoVarName}})), // in {{.GoTypeName}}
|
||||
{{else if (or .Type.IsPrimitive .Type.IsEnum) -}}
|
||||
{{ if eq .GoTypeName "bool" -}}
|
||||
uintptr(*(*byte)(unsafe.Pointer(&{{.GoVarName}}))), // in {{.GoTypeName}}
|
||||
{{ else if eq .GoTypeName "string" -}}
|
||||
uintptr({{.GoVarName}}HStr), // in {{.GoTypeName}}
|
||||
{{else -}}
|
||||
uintptr({{.GoVarName}}), // in {{.GoTypeName}}
|
||||
{{end -}}
|
||||
{{else if .Type.IsGeneric -}}
|
||||
uintptr({{.GoVarName}}), // in {{.GoTypeName}}
|
||||
{{else -}}
|
||||
uintptr(unsafe.Pointer(&{{.GoVarName}})), // in {{.GoTypeName}}
|
||||
{{end -}}
|
||||
{{end -}}
|
||||
)
|
||||
|
||||
if hr != 0 {
|
||||
return {{range .InParams}}{{if .IsOut}}{{.GoDefaultValue}}, {{end}}{{end -}}
|
||||
{{range .ReturnParams }}{{.GoDefaultValue}}, {{end}}ole.NewError(hr)
|
||||
}
|
||||
|
||||
{{range (concat .InParams .ReturnParams) -}}
|
||||
{{ if not .IsOut}}{{continue}}{{end -}}
|
||||
{{if eq .GoTypeName "string" -}}
|
||||
{{.GoVarName}} := {{.GoVarName}}HStr.String()
|
||||
ole.DeleteHString({{.GoVarName}}HStr)
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
|
||||
|
||||
return {{range .InParams}}{{if .IsOut}}{{.GoVarName}}, {{end}}{{end -}}
|
||||
{{range .ReturnParams }}{{.GoVarName}},{{end}} nil
|
||||
{{- /* remove trailing white space*/ -}}
|
22
internal/codegen/templates/interface.tmpl
Normal file
22
internal/codegen/templates/interface.tmpl
Normal file
@ -0,0 +1,22 @@
|
||||
const GUID{{.Name}} string = "{{.GUID}}"
|
||||
const Signature{{.Name}} string = "{{.Signature}}"
|
||||
|
||||
type {{.Name}} struct {
|
||||
ole.IInspectable
|
||||
}
|
||||
|
||||
type {{.Name}}Vtbl struct {
|
||||
ole.IInspectableVtbl
|
||||
|
||||
{{range .Funcs}}
|
||||
{{funcName .}} uintptr
|
||||
{{- end}}
|
||||
}
|
||||
|
||||
func (v *{{.Name}}) VTable() *{{.Name}}Vtbl {
|
||||
return (*{{.Name}}Vtbl)(unsafe.Pointer(v.RawVTable))
|
||||
}
|
||||
|
||||
{{range .Funcs}}
|
||||
{{template "func.tmpl" .}}
|
||||
{{end}}
|
7
internal/codegen/templates/struct.tmpl
Normal file
7
internal/codegen/templates/struct.tmpl
Normal file
@ -0,0 +1,7 @@
|
||||
const Signature{{.Name}} string = "{{.Signature}}"
|
||||
|
||||
type {{.Name}} struct {
|
||||
{{range .Fields}}
|
||||
{{.GoVarName}} {{.GoTypeName}}
|
||||
{{end}}
|
||||
}
|
5
internal/codegen/templates/variabletype.tmpl
Normal file
5
internal/codegen/templates/variabletype.tmpl
Normal file
@ -0,0 +1,5 @@
|
||||
{{if .Type.IsArray}}[]{{end -}}
|
||||
{{if .Type.IsPointer}}*{{end -}}
|
||||
{{.GoTypeName -}}
|
||||
|
||||
{{- /*remove trailing whitespace*/ -}}
|
Reference in New Issue
Block a user