From 8fee588a1da781c8823dcb7d0538cf1ec7022b39 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Thu, 17 Jul 2014 20:05:47 -0400 Subject: [PATCH] Migrated comctl32_windows.go to C. --- redo/comctl32_windows.c | 63 ++++++++++++++++++++++++++++++++++++ redo/comctl32_windows.go | 70 ++++------------------------------------ redo/winapi_windows.h | 7 ++++ 3 files changed, 76 insertions(+), 64 deletions(-) create mode 100644 redo/comctl32_windows.c diff --git a/redo/comctl32_windows.c b/redo/comctl32_windows.c new file mode 100644 index 0000000..d621d2a --- /dev/null +++ b/redo/comctl32_windows.c @@ -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; +} diff --git a/redo/comctl32_windows.go b/redo/comctl32_windows.go index 282d721..a28da69 100644 --- a/redo/comctl32_windows.go +++ b/redo/comctl32_windows.go @@ -11,10 +11,6 @@ import ( // 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. @@ -22,8 +18,9 @@ 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 +The activation context code itself is in comctl32_windows.c. */ -func forceCommonControls6() error { +func initCommonControls() (err error) { manifestfile, err := ioutil.TempFile("", "gouicomctl32v6manifest") if err != nil { 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 manifestfile.Close() - var actctx s_ACTCTXW + var errmsg *C.char - 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) + errcode := C.initCommonControls(C.LPCWSTR(unsafe.Pointer(syscall.StringToUTF16Ptr(filename))), &errmsg) + if errcode != 0 || errmsg != nil { + return fmt.Errorf("error actually initializing comctl32.dll: %s: %v", C.GoString(errmsg), syscall.Errno(errcode)) } - 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 } @@ -84,29 +49,6 @@ const ( 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(`