Added function generation to zwinconstgen.go. cgo uses DWARF to get function parameters, so we'll just specify them manually ourselves; see funcnames_windows.go.

This commit is contained in:
Pietro Gagliardi 2014-07-11 23:34:39 -04:00
parent 06c2f1b051
commit c55386f929
3 changed files with 127 additions and 10 deletions

View File

@ -0,0 +1,6 @@
// 11 july 2014
package ui
// wfunc kernel32 GetModuleHandleW *uint16 uintptr
// wfunc kernel32 GetStartupInfoW *s_STARTUPINFOW void

View File

@ -15,8 +15,8 @@ var (
)
func getWinMainParams() (err error) {
hInstance, err = f_GetModuleHandle(nil)
if err != nil {
hInstance, err = f_GetModuleHandleW(nil)
if hInstance == 0 {
return fmt.Errorf("error getting hInstance: %v", err)
}

View File

@ -22,7 +22,7 @@ func getPackage(path string) (pkg *ast.Package) {
filter := func(i os.FileInfo) bool {
return strings.HasSuffix(i.Name(), "_windows.go")
}
pkgs, err := parser.ParseDir(fileset, path, filter, parser.AllErrors)
pkgs, err := parser.ParseDir(fileset, path, filter, parser.AllErrors | parser.ParseComments)
if err != nil {
panic(err)
}
@ -57,8 +57,6 @@ func (w *walker) Visit(node ast.Node) ast.Visitor {
unknown[n.Name] = struct{}{}
}
}
case *ast.Comment: // function?
// TODO
}
return w
}
@ -72,7 +70,99 @@ func gatherNames(pkg *ast.Package) {
for _, d := range f.Decls {
ast.Walk(&walker{desired}, d)
}
for _, c := range f.Comments {
for _, cc := range c.List {
readComment(cc)
}
}
}
}
var funcs []string
var dlls = map[string]struct{}{}
// parse comments of the form "// wfunc dll Name argtypes {ret[,noerr]|void}"
// TODO clean this up
func readComment(c *ast.Comment) {
words := strings.Split(c.Text, " ")[1:] // strip leading //
if len(words) <= 0 || words[0] != "wfunc" {
return
}
dll := words[1]
dlls[dll] = struct{}{}
name := words[2]
args := make([]string, 0, len(words))
for i := 3; i < len(words) - 1; i++ {
args = append(args, words[i])
}
ret := words[len(words) - 1]
funcs = append(funcs, fmt.Sprintf("var fv_%s = %s.NewProc(%q)", name, dll, name))
r1 := "r1"
err := "err"
assign := ":="
r := rune('a')
argspec := ""
for _, t := range args {
argspec += fmt.Sprintf("%c %s, ", r, t)
r++
}
retspec := ""
if ret != "void" {
r := strings.Split(ret, ",")
retspec = "(" + r[0]
if len(r) > 1 && r[1] == "noerr" {
err = "_"
} else {
retspec += ", error"
}
retspec += ")"
} else {
r1 = "_"
err = "_"
assign = "="
}
funcs = append(funcs, fmt.Sprintf("func f_%s(%s) %s {", name, argspec, retspec))
call := fmt.Sprintf("\t%s, _, %s %s fv_%s.Call(", r1, err, assign, name)
r = rune('a')
for _, t := range args {
call += "uintptr("
if t[0] == '*' {
call += "unsafe.Pointer("
}
call += fmt.Sprintf("%c", r)
if t[0] == '*' {
call += ")"
}
call += "), "
r++
}
call += ")"
funcs = append(funcs, call)
if ret != "void" {
r := strings.Split(ret, ",")
retspec = "return (" + r[0] + ")("
if r[0][0] == '*' {
retspec += "unsafe.Pointer("
}
retspec += "r1"
if r[0][0] == '*' {
retspec += ")"
}
retspec += ")"
if len(r) > 1 && r[1] == "noerr" {
// do nothing
} else {
retspec += ", err"
}
funcs = append(funcs, retspec)
}
funcs = append(funcs, "}")
}
// for backwards compatibiilty reasons, Windows defines GetWindowLongPtr()/SetWindowLongPtr() as a macro which expands to GetWindowLong()/SetWindowLong() on 32-bit systems
@ -82,10 +172,6 @@ var gwlpNames = map[string]string{
"amd64": "etWindowLongPtrW",
}
func writeLine(f *os.File, line string) {
fmt.Fprintf(f, "%s\n", line)
}
const outTemplate = `package main
import (
"fmt"
@ -108,7 +194,7 @@ import (
// #include <commctrl.h>
// #include <stdint.h>
{{range .Consts}}// uintptr_t {{.}} = (uintptr_t) ({{noprefix .}});
{{end}}import "C"
{{end}}import "C" // notice the lack of newline in the template
// MinGW will generate handle pointers as pointers to some structure type under some conditions I don't fully understand; here's full overrides
var handleOverrides = []string{
"HWND",
@ -148,8 +234,16 @@ func winName(t reflect.Type) string {
func main() {
buf := new(bytes.Buffer)
fmt.Fprintln(buf, "package ui")
fmt.Fprintln(buf, "import (")
fmt.Fprintln(buf, "\t\"syscall\"")
fmt.Fprintln(buf, "\t\"unsafe\"")
fmt.Fprintln(buf, ")")
// constants
{{range .Consts}} fmt.Fprintf(buf, "const %s = %d\n", {{printf "%q" .}}, C.{{.}})
{{end}}
// structures
var t reflect.Type
{{range .Structs}} t = reflect.TypeOf(C.{{noprefix .}}{})
fmt.Fprintf(buf, "type %s struct {\n", {{printf "%q" .}})
@ -166,6 +260,14 @@ func main() {
fmt.Fprintf(buf, "type t_LPARAM %s\n", winName(reflect.TypeOf(C.LPARAM(0))))
fmt.Fprintf(buf, "type t_LRESULT %s\n", winName(reflect.TypeOf(C.LRESULT(0))))
// functions
{{range .Funcs}} fmt.Fprintf(buf, "%s\n", {{printf "%q" .}})
{{end}}
// DLLs
{{range .DLLs}} fmt.Fprintf(buf, "var %s = syscall.NewLazyDLL(%q)\n", {{printf "%q" .}}, {{printf "%s.dll" . | printf "%q"}})
{{end}}
// and finally done
res, err := format.Source(buf.Bytes())
if err != nil { panic(err.Error() + "\n" + string(buf.Bytes())) }
@ -176,6 +278,8 @@ func main() {
type templateArgs struct {
Consts []string
Structs []string
Funcs []string
DLLs []string
}
var templateFuncs = template.FuncMap{
@ -213,6 +317,7 @@ func main() {
// keep sorted for git
consts := make([]string, 0, len(unknown))
structs := make([]string, 0, len(unknown))
sorteddlls := make([]string, 0, len(dlls))
for ident, _ := range unknown {
if strings.HasPrefix(ident, "s_") {
structs = append(structs, ident)
@ -220,8 +325,12 @@ func main() {
}
consts = append(consts, ident)
}
for dll, _ := range dlls {
sorteddlls = append(sorteddlls, dll)
}
sort.Strings(consts)
sort.Strings(structs)
sort.Strings(sorteddlls)
// thanks to james4k in irc.freenode.net/#go-nuts
tmpdir, err := ioutil.TempDir("", "windowsconstgen")
@ -238,6 +347,8 @@ func main() {
err = t.Execute(f, &templateArgs{
Consts: consts,
Structs: structs,
Funcs: funcs,
DLLs: sorteddlls,
})
if err != nil {
panic(err)