I ran across some interesting (read "unexpected") behavior the other day when writing a .NET WinForms control. This particular control has some logic that executes if and only if the host OS has visual themes enabled.
In order to check for the existence of enabled themes, I call a method called 'IsVisualStylesEnabled()' which is defined as below:
public static bool IsVisualStylesEnabled() {
bool isEnabled = false;
try {
OperatingSystem os = Environment.OSVersion;
// decide whether the OS even supports visual styles
bool isSupported = ( os.Platform == PlatformID.Win32NT )
&& ( ( ( os.Version.Major == 5 ) && ( os.Version.Minor >= 1 ) )
|| ( os.Version.Major > 5 ) );
if ( isSupported ) {
int majorDllVersion = getComCtlMajorVersion();
isEnabled = ( majorDllVersion > 5 ) && IsThemeActive() && IsAppThemed();
}
}
catch ( Exception ) {
// do nothing explicitly
}
return isEnabled;
}
private static int getComCtlMajorVersion() {
DLLVERSIONINFO dllVersion = new DLLVERSIONINFO { cbSize = Marshal.SizeOf(typeof( DLLVERSIONINFO )) };
DllGetVersion(ref dllVersion);
return dllVersion.dwMajorVersion;
}
[StructLayout(LayoutKind.Sequential)]
private struct DLLVERSIONINFO {
public int cbSize;
public int dwMajorVersion;
public int dwMinorVersion;
public int dwBuildNumber;
public int dwPlatformID;
}
[DllImport("comctl32.dll", CharSet = CharSet.Auto)]
private static extern int DllGetVersion(ref DLLVERSIONINFO version);
[DllImport("uxtheme.dll", CharSet = CharSet.Auto)]
private static extern bool IsThemeActive();
[DllImport("uxtheme.dll", CharSet = CharSet.Auto)]
private static extern bool IsAppThemed();
This code is pretty standard.
At design-time (i.e., within Visual Studio) my control would render properly. The problem, however, was evident when I executed the code - it would think that visual styles were disabled and degrade gracefully to the non-themed output.
After a little bit of debugging I discovered that the comctl32.dll version being loaded at design-time was version 6 (the desired version) whereas at runtime I was getting version 5. The first thing I tried was embedding a manifest into my executable to explicitly load version 6. No dice - I was still getting version 5.
Ultimately, however, I did discover the source of the issue: I was calling the IsVisualStylesEnabled() too early in the load process of my application. This was made apparent by placing my control on a form other than the start-up form - everything worked!
When initialized, my control began setting up UI components such as brushes, pens, etc and some of this logic was based on whether the themes were enabled. Most, if not all, of the setup logic occurs in the InitializeComponent() method which is called from the .ctor() of the control.
In order to guarantee that the proper version of comctl32.dll is loaded, you cannot call the GetDllVersion() method until at least the OnHandleCreated() method of your control. If you call it earlier, you effectively lock your application (and consequently the host application if your application is a visual component) into using version 5 whether or not the manifest dictates otherwise.
For my purposes, I had to wait until the OnPaintBackground() method to initialize the brushes and other auxiliary objects, but that at least happens after the OnHandleCreated().