Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Changing Windows Aero Color

0.00/5 (No votes)
24 Jun 2013 1  
Ever wanted to change the Windows Aero color without restarting the DWM?

Introduction

From Windows Vista and above [till now], Windows introduced a new engine called Desktop Window Manager which enables the use of hardware acceleration to render the user interface. It is used to enable the new Windows Aero look and design which enables the glassy look, 3D view and switching. The Desktop Window Manager is a compositing window manager. This means that each program has a buffer that it writes data to, then it composites each buffer into final image and look. Hence it needs a DirectX compatible graphic device and WDDM drivers.

When the DWM was introduced, Windows introduced a colorful transparent UI called Aero. There are many ways to change the Aero color, mostly upon changing the Windows Aero enabled theme, the Aero color changes. The other ways need the restart of the DWM process that it dwm.exe.

Hence, when I tried to know more about this Aero color changing values, I found the DLL "dwmapi.dll", which can be found in system32 folder of the Windows installation directory. This DLL holds and serves all the needed API calls related to DWM. I tried to look the functions inside this DLL and I found 3 functions which can change the Aero colors.

Background

There are several API which are not documented in the Windows API lists. These undocumented APIs are private for Windows OS. To obtain these APIs, we can use Microsoft public symbol server. When dumped the dwmapi.dll, we can find three functions.

DwmIsCompositionEnabled() // Documented API,check if DWM composition is enabled or not
DwmGetColorizationParameters() // At index 127, undocumented API
DwmSetColorizationParameters() // At index 131, undocumented API

As I said, the first function is used to check whether DWM composition is enabled or not. If it's not enabled, then all calls to other functions will fail. So before using other functions, it's necessary that we check it. Next two functions are used to get and set the Aero color parameters respectively.

As the 2 functions are undocumented, Microsoft can modify or remove them back at anytime without notification.

Using the Code

As the 2 functions are undocumented, we cannot use the direct API call or header file "dwmapi.h". So I decided to load the "dwmapi.dll" at the runtime using the LoadLibrary() function. According to the MSDN, LoadLibrary() can load the DLL and using the GetProcAddress() function, we can load the address of the desired function. The GetProcAddress() can load the address of the function by either using the function name or the Index of the function. As we have the Index of those 2 undocumented APIs, we can load them too using GetProcAddress().

So first, let's load the "dwmapi.dll".

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
}

When we have loaded the DLL, now it's time to load the needed functions.

// 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 upto 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);

Now, we have to check the COLORIZATIONPARAMS used by the 2 undocumented APIs. Do find out the PARAMS, we can take a look at the registry key HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM.

The structure in C looks like below:

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

Now, when we know everything, it's time to use the needed functions. Let's take a look at the sample.

DwmIsCompositionEnabled(&enabled);//Need to call DwmIsCompositionEnabled 
				// before calling the DwmSetColorizationParameters or it will fail.
if(!enabled) // If glass composition is not enabled then close up
{
  MessageBox(hWnd,"Composition is not enabled\nUnable to work!","Error",MB_ICONERROR);
  FreeLibrary(hDwmDLL);
  EndDialog(hWnd,0);
}
if(!DwmGetColorizationParameters && 
	!DwmSetColorizationParameters) // The undocumented functions are not there, sorry
{
  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
}

To change the color at runtime, I have used the timer. We will generate the color automatically using random values and then set the color to the Aero.

case WM_TIMER:
{
  R = (rand() % 256);
  G = (rand() % 256);
  B = (rand() % 256);
  dwmcolor.clrColor = RGB(R,G,B);
  DwmSetColorizationParameters(&dwmcolor,0);
}
return TRUE;

Now, this will change the Windows Aero color without the need to restart the DWM. But, it's good if we set back the default color when we close this application. So at the start of the application, we will save the default Aero color and restore it back to the Aero on closing of the application.

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

And then finally, we will free the loaded DLL.

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

The complete source code, for this job, goes below:

#include <windows.h>
#include <stdlib.h>
#include <time.h>
#include "resource.h"

HMODULE hDwmDLL;
BOOL enabled = FALSE;
time_t t;
int R=0,G=0,B=0; // Colors
#define ID_TIMER 1 // Timer ID
 ypedef 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

// Needed Function from DWM Library
HRESULT (WINAPI *DwmIsCompositionEnabled)(BOOL *pfEnabled);
HRESULT (WINAPI *DwmSetColorizationParameters) (COLORIZATIONPARAMS *colorparam,UINT unknown);
HRESULT (WINAPI *DwmGetColorizationParameters) (COLORIZATIONPARAMS *colorparam);

BOOL CALLBACK DlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
	switch(message)
	{
		case WM_INITDIALOG:
			hDwmDLL = LoadLibrary("dwmapi.dll"); // Loads the DWM DLL
			if(!hDwmDLL)
			{
				MessageBox
				(hWnd,"Unable to load DWM Library!","Error",MB_ICONERROR);
				EndDialog(hWnd,0); // Close
			}
			else
			{
				// Everything is fine upto 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);
			}
			DwmIsCompositionEnabled(&enabled);//Need to call DwmIsCompositionEnabled 
					// before calling the DwmSetColorizationParameters or it will fail.
			if(!enabled) // If glass composition is not enabled then close up
			{
				MessageBox(hWnd,"Composition is not 
					enabled\nUnable to work!","Error",MB_ICONERROR);
				FreeLibrary(hDwmDLL);
				EndDialog(hWnd,0);
			}
			if(!DwmGetColorizationParameters && 
				!DwmSetColorizationParameters) // The undocumented functions are not there, sorry
			{
				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
				srand((unsigned) time(&t)); // seed for random number
			}
			return TRUE;
		case WM_TIMER:
			{
				R = (rand() % 256);
				G = (rand() % 256);
				B = (rand() % 256);
				dwmcolor.clrColor = RGB(R,G,B);
				DwmSetColorizationParameters(&dwmcolor,0);
			}
			return TRUE;
		case WM_COMMAND:
			switch(LOWORD(wParam))
			{
			case IDC_BUTTON1: //Stop
				KillTimer(hWnd,ID_TIMER);
				dwmcolor.clrColor = Restore;
				DwmSetColorizationParameters(&dwmcolor,0); // Restore color back
				break;
			case IDC_BUTTON2: //Start
				SetTimer(hWnd,ID_TIMER,300,NULL);
				break;
			}
			return TRUE;
		case WM_CLOSE:
			KillTimer(hWnd,ID_TIMER);
			dwmcolor.clrColor = Restore;
			DwmSetColorizationParameters(&dwmcolor,0); // Restore color back
			FreeLibrary(hDwmDLL); // Free the loaded DWM Library
			EndDialog(hWnd,0);
			return TRUE;
	}
	return FALSE;
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
{
	DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),NULL,DLGPROC(DlgProc),0);
}

Points of Interest

It is good to experiment with the internals of Windows. Suppose an application can change the Windows Aero color according to the current temperature or according to the average color of your wallpaper. Sounds interesting. This source code can be used to easily manipulate the Aero color and what's good is that you don't have to restart DWM.

History

  • Initial release: 1.0

NOTE: This will not work on Windows 10.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here