2014-08-14 09:42:10 -05:00
// 17 july 2014
2014-07-17 19:05:47 -05:00
# include "winapi_windows.h"
static ULONG_PTR comctlManifestCookie ;
static HMODULE comctl32 ;
2014-08-14 09:42:10 -05:00
// these are listed as WINAPI in both Microsoft's and MinGW's headers, but not on MSDN for some reason
2014-07-17 23:22:21 -05:00
BOOL ( * WINAPI fv_SetWindowSubclass ) ( HWND , SUBCLASSPROC , UINT_PTR , DWORD_PTR ) ;
BOOL ( * WINAPI fv_RemoveWindowSubclass ) ( HWND , SUBCLASSPROC , UINT_PTR ) ;
LRESULT ( * WINAPI fv_DefSubclassProc ) ( HWND , UINT , WPARAM , LPARAM ) ;
2014-08-16 13:02:00 -05:00
HIMAGELIST ( * WINAPI fv_ImageList_Create ) ( int , int , UINT , int , int ) ;
int ( * WINAPI fv_ImageList_Add ) ( HIMAGELIST , HBITMAP , HBITMAP ) ;
2014-08-25 15:53:47 -05:00
BOOL ( * WINAPI fv_ImageList_Destroy ) ( HIMAGELIST ) ;
2014-07-17 23:22:21 -05:00
2014-07-28 19:52:32 -05:00
# define wantedICCClasses ( \
ICC_PROGRESS_CLASS | /* progress bars */ \
ICC_TAB_CLASSES | /* tabs */ \
ICC_LISTVIEW_CLASSES | /* list views */ \
2014-10-28 14:46:13 -05:00
ICC_UPDOWN_CLASS | /* spinboxes */ \
2014-07-28 19:52:32 -05:00
0 )
2014-08-14 09:42:10 -05:00
// note that this is an 8-bit character string we're writing; see the encoding clause
2014-08-12 11:05:23 -05:00
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 )
2014-07-17 19:05:47 -05:00
{
2014-08-12 11:05:23 -05:00
WCHAR temppath [ MAX_PATH + 1 ] ;
WCHAR filename [ MAX_PATH + 1 ] ;
HANDLE file ;
DWORD nExpected , nGot ;
2014-07-17 19:05:47 -05:00
ACTCTX actctx ;
HANDLE ac ;
INITCOMMONCONTROLSEX icc ;
FARPROC f ;
2014-08-14 09:42:10 -05:00
// this is listed as WINAPI in both Microsoft's and MinGW's headers, but not on MSDN for some reason
2014-07-17 19:05:47 -05:00
BOOL ( * WINAPI ficc ) ( const LPINITCOMMONCONTROLSEX ) ;
2014-08-12 11:05:23 -05:00
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 ,
2014-08-14 09:42:10 -05:00
0 , // don't share while writing
2014-08-12 11:05:23 -05:00
NULL , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
if ( file = = NULL ) {
* errmsg = " error creating manifest file " ;
return GetLastError ( ) ;
}
2014-08-14 09:42:10 -05:00
nExpected = ( sizeof manifest / sizeof manifest [ 0 ] ) - 1 ; // - 1 to omit the terminating null character)
SetLastError ( 0 ) ; // catch errorless short writes
2014-08-12 11:05:23 -05:00
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 ( ) ;
}
2014-07-17 19:05:47 -05:00
ZeroMemory ( & actctx , sizeof ( ACTCTX ) ) ;
actctx . cbSize = sizeof ( ACTCTX ) ;
actctx . dwFlags = ACTCTX_FLAG_SET_PROCESS_DEFAULT ;
2014-08-12 11:05:23 -05:00
actctx . lpSource = filename ;
2014-07-17 19:05:47 -05:00
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 ) ;
2014-07-28 19:52:32 -05:00
icc . dwICC = wantedICCClasses ;
2014-07-17 19:05:47 -05:00
comctl32 = LoadLibraryW ( L " comctl32.dll " ) ;
if ( comctl32 = = NULL ) {
* errmsg = " error loading comctl32.dll " ;
return GetLastError ( ) ;
}
2014-08-14 09:42:10 -05:00
// GetProcAddress() only takes a multibyte string
2014-07-17 22:56:16 -05:00
# define LOAD(fn) f = GetProcAddress(comctl32, fn); \
2014-07-17 19:05:47 -05:00
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 ;
2014-08-16 13:02:00 -05:00
LOAD ( " ImageList_Create " ) ;
fv_ImageList_Create = ( HIMAGELIST ( * WINAPI ) ( int , int , UINT , int , int ) ) f ;
LOAD ( " ImageList_Add " ) ;
fv_ImageList_Add = ( int ( * WINAPI ) ( HIMAGELIST , HBITMAP , HBITMAP ) ) f ;
2014-08-25 15:53:47 -05:00
LOAD ( " ImageList_Destroy " ) ;
fv_ImageList_Destroy = ( BOOL ( * WINAPI ) ( HIMAGELIST ) ) f ;
2014-07-17 19:05:47 -05:00
if ( ( * ficc ) ( & icc ) = = FALSE ) {
* errmsg = " error initializing Common Controls (comctl32.dll) " ;
return GetLastError ( ) ;
}
return 0 ;
}