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:
Pietro Gagliardi 2014-07-17 18:04:51 -04:00
parent 19f7b2946a
commit 51a3c0e379
4 changed files with 139 additions and 0 deletions

132
redo/comctl32_windows.go Normal file
View File

@ -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>
`)

View File

@ -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

View File

@ -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)
}

View File

@ -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))))