diff --git a/redo/funcnames_windows.go b/redo/funcnames_windows.go deleted file mode 100644 index 35685db..0000000 --- a/redo/funcnames_windows.go +++ /dev/null @@ -1,43 +0,0 @@ -// 11 july 2014 - -package ui - -// wfunc kernel32 GetModuleHandleW *uint16 uintptr -// wfunc kernel32 GetStartupInfoW *s_STARTUPINFOW void -// wfunc user32 LoadIconW uintptr uintptr uintptr -// wfunc user32 LoadCursorW uintptr uintptr uintptr -// wfunc user32 GetMessageW *s_MSG uintptr t_UINT t_UINT t_BOOL - -// these two don't technically return void but let's pretend they do since their return values are irrelevant/not indicative of anything useful -// wfunc user32 TranslateMessage *s_MSG void -// wfunc user32 DispatchMessageW *s_MSG void - -// wfunc user32 PostMessageW uintptr t_UINT t_WPARAM t_LPARAM uintptr -// wfunc user32 RegisterClassW *s_WNDCLASSW uintptr - -// TODO narrow down argument types -// wfunc user32 CreateWindowExW uintptr *uint16 *uint16 uintptr uintptr uintptr uintptr uintptr uintptr uintptr uintptr unsafe.Pointer uintptr - -// wfunc user32 DefWindowProcW uintptr t_UINT t_WPARAM t_LPARAM t_LRESULT,noerr - -// this one doesn't technically return void but let's pretend it does since its return value is irrelevant/not indicative of anything useful -// wfunc user32 ShowWindow uintptr uintptr void - -// wfunc user32 SendMessageW uintptr t_UINT t_WPARAM t_LPARAM t_LRESULT,noerr -// wfunc user32 UpdateWindow uintptr uintptr -// wfunc user32 DestroyWindow uintptr uintptr -// wfunc user32 PostQuitMessage uintptr void -// wfunc user32 GetClientRect uintptr *s_RECT uintptr -// wfunc user32 SetParent uintptr uintptr uintptr -// wfunc gdi32 GetTextMetricsW uintptr *s_TEXTMETRICW uintptr - -// TODO int here will be wrong on 64-bit systems -// wfunc kernel32 MulDiv int int int int,noerr -// wfunc user32 MoveWindow uintptr int int int int t_BOOL uintptr - -// wfunc user32 GetDC uintptr uintptr -// wfunc gdi32 SelectObject uintptr uintptr uintptr -// wfunc user32 ReleaseDC uintptr uintptr uintptr -// wfunc user32 IsChild uintptr uintptr uintptr,noerr -// wfunc kernel32 CreateActCtxW *s_ACTCTXW uintptr -// wfunc kernel32 ActivateActCtx uintptr *t_ULONG_PTR uintptr diff --git a/redo/zregen.sh b/redo/zregen.sh deleted file mode 100755 index 790d6ff..0000000 --- a/redo/zregen.sh +++ /dev/null @@ -1 +0,0 @@ -go run zwinconstgen.go . 386 "$@" && go run zwinconstgen.go . amd64 "$@" diff --git a/redo/zwinconstgen.go b/redo/zwinconstgen.go deleted file mode 100644 index 07a113c..0000000 --- a/redo/zwinconstgen.go +++ /dev/null @@ -1,414 +0,0 @@ -// +build ignore - -// 24 may 2014 -package main - -import ( - "fmt" - "os" - "strings" - "go/token" - "go/ast" - "go/parser" - "sort" - "io/ioutil" - "path/filepath" - "text/template" - "os/exec" -) - -func getPackage(path string) (pkg *ast.Package) { - fileset := token.NewFileSet() // parser.ParseDir() actually writes to this; not sure why it doesn't return one instead - filter := func(i os.FileInfo) bool { - return strings.HasSuffix(i.Name(), "_windows.go") - } - pkgs, err := parser.ParseDir(fileset, path, filter, parser.AllErrors | parser.ParseComments) - if err != nil { - panic(err) - } - if len(pkgs) != 1 { - panic("more than one package found") - } - for k, _ := range pkgs { // get the sole key - pkg = pkgs[k] - } - return pkg -} - -type walker struct { - desired func(string) bool -} - -var known = map[string]string{} -var unknown = map[string]struct{}{} - -func (w *walker) Visit(node ast.Node) ast.Visitor { - switch n := node.(type) { - case *ast.Ident: // constant or structure? - if w.desired(n.Name) { - if n.Obj != nil { - delete(unknown, n.Name) - kind := n.Obj.Kind.String() - if known[n.Name] != "" && known[n.Name] != kind { - panic(n.Name + "(" + kind + ") already known to be a " + known[n.Name]) - } - known[n.Name] = kind - } else if _, ok := known[n.Name]; !ok { // only if not known - unknown[n.Name] = struct{}{} - } - } - } - return w -} - -func gatherNames(pkg *ast.Package) { - desired := func(name string) bool { - return strings.HasPrefix(name, "c_") || // constants - strings.HasPrefix(name, "s_") // structs - } - for _, f := range pkg.Files { - 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{ - "386": "etWindowLongW", - "amd64": "etWindowLongPtrW", -} - -// in reality these use LONG_PTR for the actual values; LONG_PTR is a signed value, but for our use case it doesn't really matter -func genGetSetWindowLongPtr(targetarch string) { - name := gwlpNames[targetarch] - - funcs = append(funcs, fmt.Sprintf("var fv_GetWindowLongPtrW = user32.NewProc(%q)", "G" + name)) - funcs = append(funcs, "func f_GetWindowLongPtrW(hwnd uintptr, which uintptr) uintptr {") - funcs = append(funcs, "\tres, _, _ := fv_GetWindowLongPtrW.Call(hwnd, which)") - funcs = append(funcs, "\treturn res") - funcs = append(funcs, "}") - - funcs = append(funcs, fmt.Sprintf("var fv_SetWindowLongPtrW = user32.NewProc(%q)", "S" + name)) - funcs = append(funcs, "func f_SetWindowLongPtrW(hwnd uintptr, which uintptr, value uintptr) {") - funcs = append(funcs, "\tfv_SetWindowLongPtrW.Call(hwnd, which, value)") - funcs = append(funcs, "}") -} - -const outTemplate = `package main -import ( - "fmt" - "bytes" - "reflect" - "go/format" - "strings" -) -// #define UNICODE -// #define _UNICODE -// #define STRICT -// #define STRICT_TYPED_ITEMIDS -// /* get Windows version right; right now Windows XP */ -// #define WINVER 0x0501 -// #define _WIN32_WINNT 0x0501 -// #define _WIN32_WINDOWS 0x0501 /* according to Microsoft's winperf.h */ -// #define _WIN32_IE 0x0600 /* according to Microsoft's sdkddkver.h */ -// #define NTDDI_VERSION 0x05010000 /* according to Microsoft's sdkddkver.h */ -// #include -// #include -// #include -{{range .Consts}}// uintptr_t {{.}} = (uintptr_t) ({{noprefix .}}); -{{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", - "HINSTANCE", - "HICON", - "HCURSOR", - "HBRUSH", - "HMENU", - // These are all pointers to functions; handle them identically to handles. - "WNDPROC", -} -func winName(t reflect.Type) string { - for _, s := range handleOverrides { - if strings.Contains(t.Name(), s) { - return "uintptr" - } - } - switch t.Kind() { - case reflect.UnsafePointer: - return "uintptr" - case reflect.Ptr: - return "*" + winName(t.Elem()) - case reflect.Struct: - // the t.Name() will be the cgo-mangled name; get the original name out - parts := strings.Split(t.Name(), "_") - part := parts[len(parts) - 1] - // many Windows API types have struct tagXXX as their declarator - // if you wonder why, see http://blogs.msdn.com/b/oldnewthing/archive/2008/03/26/8336829.aspx?Redirected=true - if strings.HasPrefix(part, "tag") { - part = part[3:] - } - return "s_" + part - case reflect.Array: - return fmt.Sprintf("[%d]%s", t.Len(), winName(t.Elem())) - } - return t.Kind().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" .}}) - for i := 0; i < t.NumField(); i++ { - fmt.Fprintf(buf, "\t%s %s\n", t.Field(i).Name, winName(t.Field(i).Type)) - } - fmt.Fprintf(buf, "}\n") -{{end}} - - // let's generate names for window procedure types - fmt.Fprintf(buf, "\n") - fmt.Fprintf(buf, "type t_UINT %s\n", winName(reflect.TypeOf(C.UINT(0)))) - fmt.Fprintf(buf, "type t_WPARAM %s\n", winName(reflect.TypeOf(C.WPARAM(0)))) - 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)))) - fmt.Fprintf(buf, "type t_UINT_PTR %s\n", winName(reflect.TypeOf(C.UINT_PTR(0)))) - fmt.Fprintf(buf, "type t_DWORD_PTR %s\n", winName(reflect.TypeOf(C.DWORD_PTR(0)))) - // and one for initCommonControls() - fmt.Fprintf(buf, "type t_ULONG_PTR %s\n", winName(reflect.TypeOf(C.ULONG_PTR(0)))) - // and one for GetMessageW() - fmt.Fprintf(buf, "type t_BOOL %s\n", winName(reflect.TypeOf(C.BOOL(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())) } - fmt.Printf("%s", res) -} -` - -type templateArgs struct { - Consts []string - Structs []string - Funcs []string - DLLs []string -} - -var templateFuncs = template.FuncMap{ - "noprefix": func(s string) string { - return s[2:] - }, -} - -func main() { - if len(os.Args) < 3 { - panic("usage: " + os.Args[0] + " path goarch [go-command-options...]") - } - pkgpath := os.Args[1] - targetarch := os.Args[2] - if _, ok := gwlpNames[targetarch]; !ok { - panic("unknown target windows/" + targetarch) - } - goopts := os.Args[3:] // valid if len(os.Args) == 3; in that case this will just be a slice of length zero - - pkg := getPackage(pkgpath) - gatherNames(pkg) - - // if we still have some known, I didn't clean things up completely - if len(known) > 0 { - knowns := "" - for ident, kind := range known { - if kind != "var" && kind != "const" { - continue - } - knowns += "\n" + ident + " (" + kind + ")" - } - panic("error: the following are still known!" + knowns) // has a newline already - } - - // 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) - continue - } - consts = append(consts, ident) - } - for dll, _ := range dlls { - sorteddlls = append(sorteddlls, dll) - } - sort.Strings(consts) - sort.Strings(structs) - sort.Strings(sorteddlls) - - // and finally - genGetSetWindowLongPtr(targetarch) - - // thanks to james4k in irc.freenode.net/#go-nuts - tmpdir, err := ioutil.TempDir("", "windowsconstgen") - if err != nil { - panic(err) - } - genoutname := filepath.Join(tmpdir, "gen.go") - f, err := os.Create(genoutname) - if err != nil { - panic(err) - } - - t := template.Must(template.New("winconstgenout").Funcs(templateFuncs).Parse(outTemplate)) - err = t.Execute(f, &templateArgs{ - Consts: consts, - Structs: structs, - Funcs: funcs, - DLLs: sorteddlls, - }) - if err != nil { - panic(err) - } - - cmd := exec.Command("go", "run") - cmd.Args = append(cmd.Args, goopts...) // valid if len(goopts) == 0; in that case this will just be a no-op - cmd.Args = append(cmd.Args, genoutname) - f, err = os.Create(filepath.Join(pkgpath, "zconstants_windows_" + targetarch + ".go")) - if err != nil { - panic(err) - } - defer f.Close() - cmd.Stdout = f - cmd.Stderr = os.Stderr - // we need to preserve the environment EXCEPT FOR the variables we're overriding - // thanks to raggi and smw in irc.freenode.net/#go-nuts - for _, ev := range os.Environ() { - if strings.HasPrefix(ev, "GOOS=") || - strings.HasPrefix(ev, "GOARCH=") || - strings.HasPrefix(ev, "CGO_ENABLED=") { - continue - } - cmd.Env = append(cmd.Env, ev) - } - cmd.Env = append(cmd.Env, - "GOOS=windows", - "GOARCH=" + targetarch, - "CGO_ENABLED=1") // needed as it's not set by default in cross-compiles - err = cmd.Run() - if err != nil { - // TODO find a way to get the exit code - os.Exit(1) - } - - // TODO remove the temporary directory -}