summaryrefslogtreecommitdiff
path: root/redo/comctl32_windows.go
diff options
context:
space:
mode:
Diffstat (limited to 'redo/comctl32_windows.go')
-rw-r--r--redo/comctl32_windows.go132
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>
+`)