summaryrefslogtreecommitdiff
path: root/redo/comctl32_windows.c
diff options
context:
space:
mode:
authorPietro Gagliardi <[email protected]>2014-08-12 12:05:23 -0400
committerPietro Gagliardi <[email protected]>2014-08-12 12:05:23 -0400
commit995fbb2b8fca47d1d7a4eac98ce24f58f1960ac3 (patch)
tree889ded410bf6d286ae0cda1acb0daca7d7f87147 /redo/comctl32_windows.c
parent1873b72d49c2dabbbffc556f8e45c8b8828343f1 (diff)
Migrated all Common Controls version 6 initialization on the Windows backend to C.
Diffstat (limited to 'redo/comctl32_windows.c')
-rw-r--r--redo/comctl32_windows.c55
1 files changed, 53 insertions, 2 deletions
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[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n<assemblyIdentity\n version=\"1.0.0.0\"\n processorArchitecture=\"*\"\n name=\"CompanyName.ProductName.YourApplication\"\n type=\"win32\"\n/>\n<description>Your application description here.</description>\n<dependency>\n <dependentAssembly>\n <assemblyIdentity\n type=\"win32\"\n name=\"Microsoft.Windows.Common-Controls\"\n version=\"6.0.0.0\"\n processorArchitecture=\"*\"\n publicKeyToken=\"6595b64144ccf1df\"\n language=\"*\"\n />\n </dependentAssembly>\n</dependency>\n</assembly>\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";