diff --git a/redo/funcnames_windows.go b/redo/funcnames_windows.go new file mode 100644 index 0000000..02b85ca --- /dev/null +++ b/redo/funcnames_windows.go @@ -0,0 +1,6 @@ +// 11 july 2014 + +package ui + +// wfunc kernel32 GetModuleHandleW *uint16 uintptr +// wfunc kernel32 GetStartupInfoW *s_STARTUPINFOW void diff --git a/redo/init_windows.go b/redo/init_windows.go index 9d83d50..4375cee 100644 --- a/redo/init_windows.go +++ b/redo/init_windows.go @@ -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) } diff --git a/redo/zwinconstgen.go b/redo/zwinconstgen.go index 39253f8..07c5959 100644 --- a/redo/zwinconstgen.go +++ b/redo/zwinconstgen.go @@ -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,9 +70,101 @@ 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 // we'll just simulate that here var gwlpNames = map[string]string{ @@ -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 // #include {{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)