andlabs-ui/redo/comctl32_windows.go

133 lines
4.2 KiB
Go
Raw Normal View History

// 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) t_LRESULT {
r1, _, _ := fv_DefSubclassProc.Call(hwnd, uintptr(uMsg), uintptr(wParam), uintptr(lParam))
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>
`)