tejashwi.io

Technology explored

author
Tejashwi Kalp Taru
Engineer, Tinkerer, Blogger
Reading time about 6 minutes

Changing Windows Aero color with Win32 programming


Changing Windows Aero color with Win32 programming

Windows Vista introduced the Desktop Window Manager (DWM), which uses hardware acceleration for the UI and enables the Aero glass effects. Each program writes to its own buffer, and DWM composites them into the final image. This requires a DirectX-compatible GPU with WDDM drivers.

Most ways to change the Aero color require either switching themes or restarting dwm.exe. But there’s another way.

Finding the Hidden APIs

While poking around, I found dwmapi.dll in the system32 folder. It handles all DWM-related API calls. Dumping the DLL revealed three functions of interest:

1
DwmIsCompositionEnabled() // Documented API, checks if DWM composition is enabled
1
DwmGetColorizationParameters() // At index 127, undocumented
1
DwmSetColorizationParameters() // At index 131, undocumented

The first function is documented. The other two aren’t officially supported, which means Microsoft could change or remove them anytime.

Loading the Functions

Since these are undocumented, we can’t use the dwmapi.h header directly. Instead, load the DLL at runtime:

1
2
3
4
5
HMODULE hDwmDLL = LoadLibrary("dwmapi.dll"); // Loads the DWM DLL
if (!hDwmDLL) {
  MessageBox(hWnd, "Unable to load DWM Library!", "Error", MB_ICONERROR);
  EndDialog(hWnd,0); // Close
}

Then get the function addresses. For the undocumented ones, use their index numbers:

1
2
3
4
5
6
7
8
9
10
11
// Needed Function from DWM Library
HRESULT (WINAPI *DwmIsCompositionEnabled)(BOOL *pfEnabled);
HRESULT (WINAPI *DwmSetColorizationParameters) (COLORIZATIONPARAMS *colorparam,UINT unknown);
HRESULT (WINAPI *DwmGetColorizationParameters) (COLORIZATIONPARAMS *colorparam);

// Everything is fine up to here, we can get function address
*(FARPROC *)&DwmIsCompositionEnabled = GetProcAddress(hDwmDLL,"DwmIsCompositionEnabled");

//Below two functions are undocumented thus load from there index
*(FARPROC *)&DwmGetColorizationParameters = GetProcAddress(hDwmDLL,(LPCSTR)127);
*(FARPROC *)&DwmSetColorizationParameters = GetProcAddress(hDwmDLL,(LPCSTR)131);

The Color Parameters Structure

The structure maps to registry values in HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM:

1
2
3
4
5
6
7
8
9
10
11
12
13
typedef struct COLORIZATIONPARAMS
{
	COLORREF         clrColor;          //ColorizationColor
	COLORREF         clrAftGlow;	   //ColorizationAfterglow
	UINT             nIntensity;	   //ColorizationColorBalance -> 0-100
	UINT             clrAftGlowBal;    //ColorizationAfterglowBalance
	UINT		 clrBlurBal;       //ColorizationBlurBalance
	UINT		 clrGlassReflInt;  //ColorizationGlassReflectionIntensity
	BOOL             fOpaque;
}DWMColor;

DWMColor dwmcolor;
COLORREF Restore; // This will be used to restore back the colors to default

Using the Functions

Always check if composition is enabled first, or the other calls will fail:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//Need to call DwmIsCompositionEnabled before calling the DwmSetColorizationParameters or it will fail.
DwmIsCompositionEnabled(&enabled);

// If glass composition is not enabled then close up
if(!enabled) {
  MessageBox(hWnd,"Composition is not enabled\nUnable to work!","Error",MB_ICONERROR);
  FreeLibrary(hDwmDLL);
  EndDialog(hWnd,0);
}

// The undocumented functions are not there, sorry
if(!DwmGetColorizationParameters && !DwmSetColorizationParameters) {
  MessageBox(hWnd,"Unable to find necessary functions in library","Error",MB_ICONERROR);
  FreeLibrary(hDwmDLL);
  EndDialog(hWnd,0);
} else {
  DwmGetColorizationParameters(&dwmcolor); // Get current values
  Restore = dwmcolor.clrColor; //Backup current color
}

Here’s a timer that changes the color randomly:

1
2
3
4
5
6
7
8
9
case WM_TIMER:
{
  R = (rand() % 256);
  G = (rand() % 256);
  B = (rand() % 256);
  dwmcolor.clrColor = RGB(R,G,B);
  DwmSetColorizationParameters(&dwmcolor,0);
}
return TRUE;

Restore the original color when closing:

1
2
dwmcolor.clrColor = Restore;
DwmSetColorizationParameters(&dwmcolor,0); // Restore color back

And free the DLL:

1
FreeLibrary(hDwmDLL); // Free the loaded DWM Library

You can download the complete source code here

What You Could Do With This

You could build an app that changes the Aero color based on temperature, or matches it to your wallpaper’s dominant color. The color changes immediately without restarting DWM.

comments powered by Disqus