Migrated comctl32_windows.go to C.
This commit is contained in:
parent
0adac4d3ca
commit
8fee588a1d
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue