diff options
| author | Pietro Gagliardi <[email protected]> | 2014-07-02 22:53:03 -0400 |
|---|---|---|
| committer | Pietro Gagliardi <[email protected]> | 2014-07-02 22:53:03 -0400 |
| commit | 8a81650b3da7ce00725336df9e03b38e935c5a65 (patch) | |
| tree | 08af843f0460e7226f305cf7162021ef54e8c3f7 /comctl_windows.go | |
| parent | 4dd5ceb11d62bd6b9af4847936314a9d8c45707f (diff) | |
Moved it all back; the preemptive multitaksing during an event handler kills us on all platforms. Going to have to restrict ALL GUI accss to happening from one t hread, so going to need to drop uitask entirely and have just a start() callback for startup code and a post() function for posting requests to windows (like channel sends but into a perpetual buffer).
Diffstat (limited to 'comctl_windows.go')
| -rw-r--r-- | comctl_windows.go | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/comctl_windows.go b/comctl_windows.go new file mode 100644 index 0000000..56a7bfb --- /dev/null +++ b/comctl_windows.go @@ -0,0 +1,126 @@ +// 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 uintptr +) + +var ( + _activateActCtx = kernel32.NewProc("ActivateActCtx") + _createActCtx = kernel32.NewProc("CreateActCtxW") +) + +/* +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() (err 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 struct { + cbSize uint32 + dwFlags uint32 + lpSource *uint16 + wProcessorArchitecture uint16 + wLangId uint16 // originally LANGID + lpAssemblyDirectory uintptr // originally LPCWSTR + lpResourceName uintptr // originally LPCWSTR + lpApplicationName uintptr // originally LPCWSTR + hModule _HANDLE // originally HMODULE + } + + actctx.cbSize = uint32(unsafe.Sizeof(actctx)) + // make this context the process default, just to be safe + actctx.dwFlags = _ACTCTX_FLAG_SET_PROCESS_DEFAULT + actctx.lpSource = toUTF16(filename) + + r1, _, err := _createActCtx.Call(uintptr(unsafe.Pointer(&actctx))) + // don't negConst() INVALID_HANDLE_VALUE; windowsconstgen was given a pointer by windows.h, and pointers are unsigned, so converting it back to signed doesn't work + if r1 == _INVALID_HANDLE_VALUE { // failure + return fmt.Errorf("error creating activation context for synthesized manifest file: %v", err) + } + r1, _, err = _activateActCtx.Call( + r1, + uintptr(unsafe.Pointer(&comctlManifestCookie))) + if r1 == uintptr(_FALSE) { // failure + return fmt.Errorf("error activating activation context for synthesized manifest file: %v", err) + } + return nil +} + +func initCommonControls() (err error) { + var icc struct { + dwSize uint32 + dwICC uint32 + } + + 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 = _ICC_PROGRESS_CLASS + + comctl32 = syscall.NewLazyDLL("comctl32.dll") + r1, _, err := comctl32.NewProc("InitCommonControlsEx").Call(uintptr(unsafe.Pointer(&icc))) + if r1 == _FALSE { // failure + return fmt.Errorf("error initializing Common Controls (comctl32.dll); Windows last error: %v", err) + } + return nil +} + +// Common Controls class names. +const ( + // x (lowercase) prefix to avoid being caught by the constants generator + x_PROGRESS_CLASS = "msctls_progress32" +) + +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> +`) |
