2014-02-25 07:28:10 -06:00
// 25 february 2014
2014-03-12 20:55:45 -05:00
2014-02-25 07:28:10 -06:00
package ui
import (
"fmt"
2014-04-02 12:47:11 -05:00
"syscall"
2014-02-25 07:28:10 -06:00
"unsafe"
2014-04-02 12:47:11 -05:00
"io/ioutil"
2014-02-25 07:28:10 -06:00
)
2014-04-28 11:13:06 -05:00
// pretty much every constant here except _WM_USER is from commctrl.h, except where noted
2014-02-25 07:28:10 -06:00
2014-04-02 12:47:11 -05:00
var (
comctlManifestCookie uintptr
)
2014-03-12 17:53:57 -05:00
2014-02-25 07:28:10 -06:00
var (
2014-04-02 12:47:11 -05:00
_activateActCtx = kernel32 . NewProc ( "ActivateActCtx" )
_createActCtx = kernel32 . NewProc ( "CreateActCtxW" )
2014-02-25 07:28:10 -06:00
)
2014-04-02 12:47:11 -05:00
/ *
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
* /
func forceCommonControls6 ( ) ( 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 actctx struct {
cbSize uint32
dwFlags uint32
lpSource * uint16
wProcessorArchitecture uint16
wLangId uint16 // originally LANGID
lpAssemblyDirectory uintptr // originally LPCWSTR
lpResourceName uintptr // originally LPCWSTR
lpApplicationName uintptr // originally LPCWSTR
hModule _HANDLE // originally HMODULE
}
actctx . cbSize = uint32 ( unsafe . Sizeof ( actctx ) )
2014-06-04 18:29:37 -05:00
// make this context the process default, just to be safe
actctx . dwFlags = _ACTCTX_FLAG_SET_PROCESS_DEFAULT
2014-06-03 02:37:48 -05:00
actctx . lpSource = toUTF16 ( filename )
2014-04-02 12:47:11 -05:00
r1 , _ , err := _createActCtx . Call ( uintptr ( unsafe . Pointer ( & actctx ) ) )
2014-05-25 13:04:03 -05:00
// don't negConst() INVALID_HANDLE_VALUE; windowsconstgen was given a pointer by windows.h, and pointers are unsigned, so converting it back to signed doesn't work
if r1 == _INVALID_HANDLE_VALUE { // failure
2014-04-02 12:47:11 -05:00
return fmt . Errorf ( "error creating activation context for synthesized manifest file: %v" , err )
}
r1 , _ , err = _activateActCtx . Call (
r1 ,
uintptr ( unsafe . Pointer ( & comctlManifestCookie ) ) )
if r1 == uintptr ( _FALSE ) { // failure
return fmt . Errorf ( "error activating activation context for synthesized manifest file: %v" , err )
}
return nil
}
2014-02-25 07:28:10 -06:00
func initCommonControls ( ) ( err error ) {
var icc struct {
dwSize uint32
dwICC uint32
}
2014-04-02 12:47:11 -05:00
err = forceCommonControls6 ( )
if err != nil {
return fmt . Errorf ( "error forcing Common Controls version 6 (or newer): %v" , err )
}
2014-02-25 07:28:10 -06:00
icc . dwSize = uint32 ( unsafe . Sizeof ( icc ) )
icc . dwICC = _ICC_PROGRESS_CLASS
2014-04-02 12:47:11 -05:00
comctl32 = syscall . NewLazyDLL ( "comctl32.dll" )
r1 , _ , err := comctl32 . NewProc ( "InitCommonControlsEx" ) . Call ( uintptr ( unsafe . Pointer ( & icc ) ) )
2014-02-25 07:28:10 -06:00
if r1 == _FALSE { // failure
2014-04-28 20:32:49 -05:00
return fmt . Errorf ( "error initializing Common Controls (comctl32.dll); Windows last error: %v" , err )
2014-02-25 07:28:10 -06:00
}
return nil
}
// Common Controls class names.
const (
2014-05-25 11:39:53 -05:00
// x (lowercase) prefix to avoid being caught by the constants generator
x_PROGRESS_CLASS = "msctls_progress32"
2014-02-25 07:28:10 -06:00
)
2014-04-02 12:47:11 -05:00
var manifest = [ ] byte ( ` < ? xml version = "1.0" encoding = "UTF-8" standalone = "yes" ? >
< assembly xmlns = "urn:schemas-microsoft-com:asm.v1" manifestVersion = "1.0" >
< assemblyIdentity
version = "1.0.0.0"
processorArchitecture = "*"
name = "CompanyName.ProductName.YourApplication"
type = "win32"
/ >
< description > Your application description here . < / description >
< dependency >
< dependentAssembly >
< assemblyIdentity
type = "win32"
name = "Microsoft.Windows.Common-Controls"
version = "6.0.0.0"
processorArchitecture = "*"
publicKeyToken = "6595b64144ccf1df"
language = "*"
/ >
< / dependentAssembly >
< / dependency >
< / assembly >
` )