diff options
| author | Pietro Gagliardi <[email protected]> | 2014-07-17 20:05:47 -0400 |
|---|---|---|
| committer | Pietro Gagliardi <[email protected]> | 2014-07-17 20:05:47 -0400 |
| commit | 8fee588a1da781c8823dcb7d0538cf1ec7022b39 (patch) | |
| tree | 8f526ea3715e4d73e16f00ca7e392b273ed2a455 | |
| parent | 0adac4d3ca1ec91e6364fe11276323803418c2ff (diff) | |
Migrated comctl32_windows.go to C.
| -rw-r--r-- | redo/comctl32_windows.c | 63 | ||||
| -rw-r--r-- | redo/comctl32_windows.go | 70 | ||||
| -rw-r--r-- | redo/winapi_windows.h | 7 |
3 files changed, 76 insertions, 64 deletions
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 - - 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 + var errmsg *C.char - // 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) + 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)) } - 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(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity diff --git a/redo/winapi_windows.h b/redo/winapi_windows.h index 59b99fe..81bf271 100644 --- a/redo/winapi_windows.h +++ b/redo/winapi_windows.h @@ -25,3 +25,10 @@ extern void uimsgloop(void); extern void issue(void *); extern HWND msgwin; 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); |
