Migrated comctl32_windows.go to C.

This commit is contained in:
Pietro Gagliardi 2014-07-17 20:05:47 -04:00
parent 0adac4d3ca
commit 8fee588a1d
3 changed files with 76 additions and 64 deletions

63
redo/comctl32_windows.c Normal file
View File

@ -0,0 +1,63 @@
/* 17 july 2014 */
#include "winapi_windows.h"
static ULONG_PTR comctlManifestCookie;
static HMODULE comctl32;
DWORD initCommonControls(LPCWSTR manifest, char **errmsg)
{
ACTCTX actctx;
HANDLE ac;
INITCOMMONCONTROLSEX icc;
FARPROC f;
/* TODO does this take WINAPI? */
BOOL (*WINAPI ficc)(const LPINITCOMMONCONTROLSEX);
ZeroMemory(&actctx, sizeof (ACTCTX));
actctx.cbSize = sizeof (ACTCTX);
actctx.dwFlags = ACTCTX_FLAG_SET_PROCESS_DEFAULT;
actctx.lpSource = manifest;
ac = CreateActCtx(&actctx);
if (ac == INVALID_HANDLE_VALUE) {
*errmsg = "error creating activation context for synthesized manifest file";
return GetLastError();
}
if (ActivateActCtx(ac, &comctlManifestCookie) == FALSE) {
*errmsg = "error activating activation context for synthesized manifest file";
return GetLastError();
}
ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX));
icc.dwSize = sizeof (INITCOMMONCONTROLSEX);
icc.dwICC = ICC_PROGRESS_CLASS;
comctl32 = LoadLibraryW(L"comctl32.dll");
if (comctl32 == NULL) {
*errmsg = "error loading comctl32.dll";
return GetLastError();
}
/* GetProcAddress() only takes a multibyte string */
#define LOAD(fn) f = GetModuleHandle(comctl32, fn); \
if (f == NULL) { \
*errmsg = "error loading " fn "()"; \
return GetLastError(); \
}
LOAD("InitCommonControlsEx");
ficc = (BOOL (*WINAPI)(const LPINITCOMMONCONTROLSEX)) f;
LOAD("SetWindowSubclass");
fv_SetWindowSubclass = (BOOL (*WINAPI)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR)) f;
LOAD("RemoveWindowSubclass");
fv_RemoveWindowSubclass = (BOOL (*WINAPI)(HWND, SUBCLASSPROC, UINT_PTR)) f;
LOAD("DefSubclassProc");
fv_DefSubclassProc = (LRESULT (*WINAPI)(HWND, UINT, WPARAM, LPARAM)) f;
if ((*ficc)(&icc) == FALSE) {
*errmsg = "error initializing Common Controls (comctl32.dll)";
return GetLastError();
}
return 0;
}

View File

@ -11,10 +11,6 @@ import (
// pretty much every constant here except _WM_USER is from commctrl.h, except where noted // 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. 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. The only way to not require an external manifest is to synthesize the manifest ourselves.
@ -22,8 +18,9 @@ We can use the activation context API to load it at runtime.
References: References:
- http://stackoverflow.com/questions/4308503/how-to-enable-visual-styles-without-a-manifest - http://stackoverflow.com/questions/4308503/how-to-enable-visual-styles-without-a-manifest
- http://support.microsoft.com/kb/830033 - http://support.microsoft.com/kb/830033
The activation context code itself is in comctl32_windows.c.
*/ */
func forceCommonControls6() error { func initCommonControls() (err error) {
manifestfile, err := ioutil.TempFile("", "gouicomctl32v6manifest") manifestfile, err := ioutil.TempFile("", "gouicomctl32v6manifest")
if err != nil { if err != nil {
return fmt.Errorf("error creating synthesized manifest file: %v", err) return fmt.Errorf("error creating synthesized manifest file: %v", err)
@ -37,44 +34,12 @@ func forceCommonControls6() error {
// if ioutil.TempFile() ever changes so that the file is deleted when it is closed, this will need to change // if ioutil.TempFile() ever changes so that the file is deleted when it is closed, this will need to change
manifestfile.Close() manifestfile.Close()
var actctx s_ACTCTXW var errmsg *C.char
actctx.cbSize = uint32(unsafe.Sizeof(actctx)) errcode := C.initCommonControls(C.LPCWSTR(unsafe.Pointer(syscall.StringToUTF16Ptr(filename))), &errmsg)
// make this context the process default, just to be safe if errcode != 0 || errmsg != nil {
actctx.dwFlags = c_ACTCTX_FLAG_SET_PROCESS_DEFAULT return fmt.Errorf("error actually initializing comctl32.dll: %s: %v", C.GoString(errmsg), syscall.Errno(errcode))
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 return nil
} }
@ -84,29 +49,6 @@ const (
x_PROGRESS_CLASS = "msctls_progress32" 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"?> var manifest = []byte(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity <assemblyIdentity

View File

@ -25,3 +25,10 @@ extern void uimsgloop(void);
extern void issue(void *); extern void issue(void *);
extern HWND msgwin; extern HWND msgwin;
extern DWORD makemsgwin(char **); extern DWORD makemsgwin(char **);
/* comctl32_windows.c */
extern DWORD initCommonControls(LPCWSTR, char **);
/* TODO do any of these take WINAPI? */
extern BOOL (*WINAPI fv_SetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
extern BOOL (*WINAPI fv_RemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR);
extern LRESULT (*WINAPI fv_DefSubclassProc)(HWND, UINT, WPARAM, LPARAM);