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...
This commit is contained in:
parent
19f7b2946a
commit
51a3c0e379
|
@ -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>
|
||||||
|
`)
|
|
@ -39,3 +39,5 @@ package ui
|
||||||
// wfunc gdi32 SelectObject uintptr uintptr uintptr
|
// wfunc gdi32 SelectObject uintptr uintptr uintptr
|
||||||
// wfunc user32 ReleaseDC uintptr uintptr uintptr
|
// wfunc user32 ReleaseDC uintptr uintptr uintptr
|
||||||
// wfunc user32 IsChild uintptr uintptr uintptr,noerr
|
// wfunc user32 IsChild uintptr uintptr uintptr,noerr
|
||||||
|
// wfunc kernel32 CreateActCtxW *s_ACTCTXW uintptr
|
||||||
|
// wfunc kernel32 ActivateActCtx uintptr *t_ULONG_PTR uintptr
|
||||||
|
|
|
@ -20,6 +20,9 @@ func uiinit() error {
|
||||||
if err := initWindows(); err != nil {
|
if err := initWindows(); err != nil {
|
||||||
return fmt.Errorf("error initializing package ui on Windows: %v", err)
|
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 {
|
if err := makemsgwin(); err != nil {
|
||||||
return fmt.Errorf("error creating message-only window: %v", err)
|
return fmt.Errorf("error creating message-only window: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_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_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))))
|
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()
|
// and one for GetMessageW()
|
||||||
fmt.Fprintf(buf, "type t_BOOL %s\n", winName(reflect.TypeOf(C.BOOL(0))))
|
fmt.Fprintf(buf, "type t_BOOL %s\n", winName(reflect.TypeOf(C.BOOL(0))))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue