diff options
Diffstat (limited to 'redo/comctl32_windows.go')
| -rw-r--r-- | redo/comctl32_windows.go | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/redo/comctl32_windows.go b/redo/comctl32_windows.go new file mode 100644 index 0000000..6b3d6e5 --- /dev/null +++ b/redo/comctl32_windows.go @@ -0,0 +1,132 @@ +// 25 february 2014 + +package ui + +import ( + "fmt" + "io/ioutil" + "syscall" + "unsafe" +) + +// pretty much every constant here except _WM_USER is from commctrl.h, except where noted + +var ( + comctlManifestCookie t_ULONG_PTR +) + +/* +Windows requires a manifest file to enable Common Controls version 6. +The only way to not require an external manifest is to synthesize the manifest ourselves. +We can use the activation context API to load it at runtime. +References: +- http://stackoverflow.com/questions/4308503/how-to-enable-visual-styles-without-a-manifest +- http://support.microsoft.com/kb/830033 +*/ +func forceCommonControls6() error { + manifestfile, err := ioutil.TempFile("", "gouicomctl32v6manifest") + if err != nil { + return fmt.Errorf("error creating synthesized manifest file: %v", err) + } + _, err = manifestfile.Write(manifest) + if err != nil { + return fmt.Errorf("error writing synthesized manifest file: %v", err) + } + filename := manifestfile.Name() + // we now have to close the file, otherwise ActivateActCtx() will complain that it's in use by another program + // if ioutil.TempFile() ever changes so that the file is deleted when it is closed, this will need to change + manifestfile.Close() + + var actctx s_ACTCTXW + + actctx.cbSize = uint32(unsafe.Sizeof(actctx)) + // make this context the process default, just to be safe + actctx.dwFlags = c_ACTCTX_FLAG_SET_PROCESS_DEFAULT + actctx.lpSource = syscall.StringToUTF16Ptr(filename) + + res, err := f_CreateActCtxW(&actctx) + if res == c_INVALID_HANDLE_VALUE { + return fmt.Errorf("error creating activation context for synthesized manifest file: %v", err) + } + res, err = f_ActivateActCtx(res, &comctlManifestCookie) + if res == c_FALSE { + return fmt.Errorf("error activating activation context for synthesized manifest file: %v", err) + } + return nil +} + +func initCommonControls() (err error) { + var icc s_INITCOMMONCONTROLSEX + + err = forceCommonControls6() + if err != nil { + return fmt.Errorf("error forcing Common Controls version 6 (or newer): %v", err) + } + + icc.dwSize = uint32(unsafe.Sizeof(icc)) + icc.dwICC = c_ICC_PROGRESS_CLASS + + // TODO call LoadLibraryW() directly + comctl32 := syscall.NewLazyDLL("comctl32.dll") + r1, _, err := comctl32.NewProc("InitCommonControlsEx").Call(uintptr(unsafe.Pointer(&icc))) + if r1 == c_FALSE { + return fmt.Errorf("error initializing Common Controls (comctl32.dll); Windows last error: %v", err) + } + fv_SetWindowSubclass = comctl32.NewProc("SetWindowSubclass") + fv_RemoveWindowSubclass = comctl32.NewProc("RemoveWindowSubclass") + fv_DefSubclassProc = comctl32.NewProc("DefSubclassProc") + return nil +} + +// Common Controls class names. +const ( + // x (lowercase) prefix to avoid being caught by the constants generator + x_PROGRESS_CLASS = "msctls_progress32" +) + +// this isn't generated by the constants generator because we need to load it from the correct version of comctl32.dll + +var ( + fv_SetWindowSubclass *syscall.LazyProc + fv_RemoveWindowSubclass *syscall.LazyProc + fv_DefSubclassProc *syscall.LazyProc +) + +func f_SetWindowSubclass(hwnd uintptr, subproc uintptr, id t_UINT_PTR, data t_DWORD_PTR) (uintptr, error) { + r1, _, err := fv_SetWindowSubclass.Call(hwnd, subproc, uintptr(id), uintptr(data)) + return r1, err +} + +func f_RemoveWindowSubclass(hwnd uintptr, subproc uintptr, id t_UINT_PTR) (uintptr, error) { + r1, _, err := fv_RemoveWindowSubclass.Call(hwnd, subproc, uintptr(id)) + return r1, err +} + +func f_DefSubclassProc(hwnd uintptr, uMsg t_UINT, wParam t_WPARAM, lParam t_LPARAM, id t_UINT_PTR, data t_DWORD_PTR) t_LRESULT { + r1, _, _ := fv_DefSubclassProc.Call(hwnd, uintptr(uMsg), uintptr(wParam), uintptr(lParam), uintptr(id), uintptr(data)) + return t_LRESULT(r1) +} + +var manifest = []byte(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> +<assemblyIdentity + version="1.0.0.0" + processorArchitecture="*" + name="CompanyName.ProductName.YourApplication" + type="win32" +/> +<description>Your application description here.</description> +<dependency> + <dependentAssembly> + <assemblyIdentity + type="win32" + name="Microsoft.Windows.Common-Controls" + version="6.0.0.0" + processorArchitecture="*" + publicKeyToken="6595b64144ccf1df" + language="*" + /> + </dependentAssembly> +</dependency> +</assembly> +`) |
