diff --git a/redo/comctl32_windows.c b/redo/comctl32_windows.c
index 09b9605..df1bdcd 100644
--- a/redo/comctl32_windows.c
+++ b/redo/comctl32_windows.c
@@ -16,8 +16,24 @@ LRESULT (*WINAPI fv_DefSubclassProc)(HWND, UINT, WPARAM, LPARAM);
ICC_LISTVIEW_CLASSES | /* list views */ \
0)
-DWORD initCommonControls(LPWSTR manifest, char **errmsg)
+/* note that this is an 8-bit character string we're writing; see the encoding clause */
+static const char manifest[] = "\n\n\nYour application description here.\n\n \n \n \n\n\n";
+
+/*
+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
+Because neither Go nor MinGW have ways to compile in resources like this (as far as I know), we have to do the work ourselves.
+*/
+DWORD initCommonControls(char **errmsg)
{
+ WCHAR temppath[MAX_PATH + 1];
+ WCHAR filename[MAX_PATH + 1];
+ HANDLE file;
+ DWORD nExpected, nGot;
ACTCTX actctx;
HANDLE ac;
INITCOMMONCONTROLSEX icc;
@@ -25,10 +41,45 @@ DWORD initCommonControls(LPWSTR manifest, char **errmsg)
/* this is listed as WINAPI in both Microsoft's and MinGW's headers, but not on MSDN for some reason */
BOOL (*WINAPI ficc)(const LPINITCOMMONCONTROLSEX);
+ if (GetTempPathW(MAX_PATH + 1, temppath) == 0) {
+ *errmsg = "error getting temporary path for writing manifest file";
+ return GetLastError();
+ }
+ if (GetTempFileNameW(temppath, L"manifest", 0, filename) == 0) {
+ *errmsg = "error getting temporary filename for writing manifest file";
+ return GetLastError();
+ }
+ file = CreateFileW(filename, GENERIC_WRITE,
+ 0, /* don't share while writing */
+ NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (file == NULL) {
+ *errmsg = "error creating manifest file";
+ return GetLastError();
+ }
+ nExpected = strlen(manifest); /* TODO make static */
+ SetLastError(0); /* catch errorless short writes */
+ if (WriteFile(file, manifest, nExpected, &nGot, NULL) == 0) {
+ *errmsg = "error writing manifest file";
+ return GetLastError();
+ }
+ if (nGot != nExpected) {
+ DWORD lasterr;
+
+ lasterr = GetLastError();
+ *errmsg = "short write to manifest file";
+ if (lasterr == 0)
+ *errmsg = "short write to manifest file without error code";
+ return lasterr;
+ }
+ if (CloseHandle(file) == 0) {
+ *errmsg = "error closing manifest file (this IS an error here because not doing so will prevent Windows from being able to use the manifest file in an activation context)";
+ return GetLastError();
+ }
+
ZeroMemory(&actctx, sizeof (ACTCTX));
actctx.cbSize = sizeof (ACTCTX);
actctx.dwFlags = ACTCTX_FLAG_SET_PROCESS_DEFAULT;
- actctx.lpSource = manifest;
+ actctx.lpSource = filename;
ac = CreateActCtx(&actctx);
if (ac == INVALID_HANDLE_VALUE) {
*errmsg = "error creating activation context for synthesized manifest file";
diff --git a/redo/comctl32_windows.go b/redo/comctl32_windows.go
deleted file mode 100644
index f4a7620..0000000
--- a/redo/comctl32_windows.go
+++ /dev/null
@@ -1,72 +0,0 @@
-// 25 february 2014
-
-package ui
-
-import (
- "fmt"
- "io/ioutil"
- "syscall"
-)
-
-// #include "winapi_windows.h"
-import "C"
-
-// TODO possibly rewrite the whole file access bits in C
-
-// pretty much every constant here except _WM_USER is from commctrl.h, except where noted
-
-/*
-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
-The activation context code itself is in comctl32_windows.c.
-*/
-func initCommonControls() (err 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 errmsg *C.char
-
- errcode := C.initCommonControls(toUTF16(filename), &errmsg)
- if errcode != 0 || errmsg != nil {
- return fmt.Errorf("error actually initializing comctl32.dll: %s: %v", C.GoString(errmsg), syscall.Errno(errcode))
- }
- return nil
-}
-
-var manifest = []byte(`
-
-
-Your application description here.
-
-
-
-
-
-
-`)
diff --git a/redo/uitask_windows.go b/redo/uitask_windows.go
index cd2d7dc..288b33f 100644
--- a/redo/uitask_windows.go
+++ b/redo/uitask_windows.go
@@ -21,8 +21,10 @@ func uiinit() error {
if errcode != 0 || errmsg != nil {
return fmt.Errorf("error initializing package ui on Windows: %s: %v", C.GoString(errmsg), syscall.Errno(errcode))
}
- if err := initCommonControls(); err != nil {
- return fmt.Errorf("error initializing comctl32.dll version 6: %v", err)
+ errmsg = nil
+ errcode = C.initCommonControls(&errmsg)
+ if errcode != 0 || errmsg != nil {
+ return fmt.Errorf("error initializing comctl32.dll: %s: %v", C.GoString(errmsg), syscall.Errno(errcode))
}
if err := makemsgwin(); err != nil {
return fmt.Errorf("error creating message-only window: %v", err)
diff --git a/redo/winapi_windows.h b/redo/winapi_windows.h
index 268caa3..ca27367 100644
--- a/redo/winapi_windows.h
+++ b/redo/winapi_windows.h
@@ -38,7 +38,7 @@ extern HWND msgwin;
extern DWORD makemsgwin(char **);
/* comctl32_windows.c */
-extern DWORD initCommonControls(LPWSTR, char **);
+extern DWORD initCommonControls(char **);
/* these are listed as WINAPI in both Microsoft's and MinGW's headers, but not on MSDN for some reason */
extern BOOL (*WINAPI fv_SetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
extern BOOL (*WINAPI fv_RemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR);