summaryrefslogtreecommitdiff
path: root/redo
diff options
context:
space:
mode:
authorPietro Gagliardi <[email protected]>2014-07-17 18:04:51 -0400
committerPietro Gagliardi <[email protected]>2014-07-17 18:04:51 -0400
commit51a3c0e3797bee6276f6e8945e53a9b12e2901a4 (patch)
tree12e308ba564f4165107873e4c3c74074acd1ba40 /redo
parent19f7b2946a6198862f860b1f7c5798c0d66b8fc1 (diff)
Migrated the comctl32.dll code and added all the window subclassing stuff. Starting to consider just doing what I'm doing with the Mac OS X backend and just using cgo...
Diffstat (limited to 'redo')
-rw-r--r--redo/comctl32_windows.go132
-rw-r--r--redo/funcnames_windows.go2
-rw-r--r--redo/uitask_windows.go3
-rw-r--r--redo/zwinconstgen.go2
4 files changed, 139 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>
+`)
diff --git a/redo/funcnames_windows.go b/redo/funcnames_windows.go
index 005607f..35685db 100644
--- a/redo/funcnames_windows.go
+++ b/redo/funcnames_windows.go
@@ -39,3 +39,5 @@ package ui
// 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/uitask_windows.go b/redo/uitask_windows.go
index 8e8187a..15f4048 100644
--- a/redo/uitask_windows.go
+++ b/redo/uitask_windows.go
@@ -20,6 +20,9 @@ func uiinit() error {
if err := initWindows(); err != nil {
return fmt.Errorf("error initializing package ui on Windows: %v", err)
}
+ if err := initCommonControls(); err != nil {
+ return fmt.Errorf("error initializing comctl32.dll version 6: %v", err)
+ }
if err := makemsgwin(); err != nil {
return fmt.Errorf("error creating message-only window: %v", err)
}
diff --git a/redo/zwinconstgen.go b/redo/zwinconstgen.go
index c0e2171..07a113c 100644
--- a/redo/zwinconstgen.go
+++ b/redo/zwinconstgen.go
@@ -278,6 +278,8 @@ func main() {
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))))