[Transfer] MFC Thunder seven form special effects, using DWM to achieve Aero Glass effect

Starting with Windows Vista, the Aero Glass effect is applied to Home Premium and above systems (Home Basic does not have this effect). This effect is controlled by DWM (Desktop Window Manager). For general programs, this effect will be applied to the window border by default. But if we want more control, such as making part of the client area also have this effect, that’s also very simple. We don’t need to do any complicated algorithms in the program, we just need to adjust the API and let DWM do it.

1. Composition (window composition) and Non-client Rendering (non-client area rendering)

The non-client area usually includes the window title bar and window borders. By default, non-client areas are rendered with a frosted glass effect, which is also called composition. There are several functions that control how the system and current window are rendered. There are also Windows messages for accepting rendering mode changes.

1. Check whether Aero Glass is turned on in the system. Use the function DwmIsCompositionEnabled to detect whether the Aero Glass special effect is currently enabled on the system. It accepts a BOOL parameter and stores the current state into it. Function prototype: HRESULT DwmIsCompositionEnabled(BOOL *pfEnabled);

2. Turn on/off Aero Glass. Use the function DwmEnableComposition to turn on or off the system Aero Glass effect, pass in DWM_EC_ENABLECOMPOSITION to turn it on, and pass in DWM_EC_DISABLECOMPOSITION to turn it off.

3. Turn on/off non-client area rendering of the current window. The function DwmSetWindowAttribute is used to set window attributes. The attribute DWMWA_NCRENDERING_POLICY controls whether the current window uses non-client area rendering. DWMNCRP_ENABLED is on, DWMNCRP_DISABLED is off. The settings have no effect when the system’s Aero Glass is turned off. Correspondingly, the current window attributes can be detected using the function DwmGetWindowAttribute.

4. Respond to the system Aero Glass being turned on or off. When Aero Glass is turned on or off, Windows will send the message WM_DWMCOMPOSITIONCHANGED and use the function DwmIsCompositionEnabled to detect the status.

5. Respond to the opening or closing of non-client area rendering of the window. When the non-client area rendering of the current window is turned on or off, Windows will send the message WM_DWMNCRENDERINGCHANGED, wParam indicates the current status.

2. Transition (window animation) and ColorizationColor (theme color)

Transition controls whether to animate the minimization and restoration of windows. By using the function DwmSetWindowAttribute, set the attribute DWMWA_TRANSITIONS_FORCEDISABLED to turn on or off window animation. This setting is only effective for the current window.

When the user modifies the theme color through the control panel, Windows will send the message WM_DWMCOLORIZATIONCOLORCHANGED. The program uses the function DwmGetColorizationColor to obtain the current theme color and whether it is transparent. By responding to color changes, the color style of the program can change with the theme style.

3. Turn on the Aero Glass effect in the customer area

Function DwmEnableBlurBehindWindow turns on the Aero Glass effect in the client area. The first parameter is the window handle, and the second parameter is a DWM_BLURBEHIND structure. Among them, fEnable sets whether to enable the Glass effect in the client area. hRgnBlur sets the area of the Glass effect. Setting this to NULL will cause the entire client area to show the Glass effect. After setting it to a correct area, the area will show the Glass effect, while the outside area will be completely transparent. To render a transparent effect, the original color of the client area needs to be black. You can draw the client area in the WM_PAINT message. The following code uses GDI+ to draw the entire window as black when Aero Glass is on, and as gray when Aero Glass is off:

case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hDC = BeginPaint(hWnd, & amp;ps);
        //Do not create Graphics directly using the window handle, which will cause flickering
        Graphics graph(hDC);
        //Clear client area
        RECT rcClient;
        GetClientRect(hWnd, & amp;rcClient);
        BOOL bCompEnabled;
        DwmIsCompositionEnabled( & amp;bCompEnabled);
        SolidBrush br(bCompEnabled? Color::Black : Color::DarkGray);
        graph.FillRectangle( & amp;br, Rect(rcClient.left, rcClient.top,
            rcClient.right, rcClient.bottom));
        EndPaint(hWnd, & amp;ps);
    }
    break; 

Initialization and shutdown of GDI+ are still required:

//Initialize GDI+
ULONG_PTR token;
GdiplusStartupInput input;
GdiplusStartup( & amp;token, & amp;input, NULL);
//**********************************
//Close GDI+
GdiplusShutdown(token); 

The following code sets the entire client area to Glass effect:

DWM_BLURBEHIND bb = {<!-- -->0};
bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
bb.fEnable = true;
bb.hRgnBlur = NULL;
DwmEnableBlurBehindWindow(hWnd, & amp;bb); 

The following code sets an ellipse in the center of the client area to the Glass effect:

RECT rect;
GetWindowRect(hWnd, & amp;rect);
int width = 300, height = 200;
//Center the ellipse
HRGN hRgn = CreateEllipticRgn((rect.right - rect.left)/2 - width/2,
    (rect.bottom - rect.top)/2 - height/2, (rect.right - rect.left)/2 + width/2,
    (rect.bottom - rect.top)/2 + height/2);
DWM_BLURBEHIND bb = {<!-- -->0};
bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
bb.fEnable = true;
bb.hRgnBlur = hRgn;
DwmEnableBlurBehindWindow(hWnd, & amp;bb); 

4. The window border extends to the client area

In the above method, there is still a boundary between the non-client area and the client area. How to increase the range of Glass effects and eliminate boundaries? That is to extend the window frame to the client area, which is achieved by using the function DwmExtendFrameIntoClientArea. The function accepts a window handle and a parameter of type MARGINS. MARGINS specifies the range that extends in four directions: up, down, left, and right. If all four values are -1, expand to the entire client area.

MARGINS margins = {<!-- -->50, 50, 50, 50};
DwmExtendFrameIntoClientArea(hWnd, & amp;margins); 

MARGINS margins2 = {-1}; //Will expand to the entire client area
DwmExtendFrameIntoClientArea(hWnd, & amp;margins2); 

5. Draw graphics on the window

PNG images have an alpha channel and work well with Aero Glass. It is very convenient to use GDI + to display PNG images. The following code loads a PNG image into memory:

Bitmap bmp = Bitmap::FromFile(L"Ferrari.png", false); 

In the WM_PAINT message processing, after drawing the entire client area black, use GDI+ to draw the picture to the window client area:

//Draw graphics
int width = bmp->GetWidth();
int height = bmp->GetHeight();
Rect rc(30, 30, width, height);
graph.DrawImage(bmp, rc, 0, 0, width, height, UnitPixel); 

6. Text drawing

When the window is made transparent to a large extent, reading the text on the window becomes a problem. The Windows solution is to add a glowing effect to the text. This is the method used for the text in the title bar. We can use the DrawThemeTextEx function in our own program to draw glowing text. The prototype of this function is defined as follows:

HRESULT DrawThemeTextEx(HTHEME hTheme,
    HDC hdc,
    int iPartId,
    int iStateId,
    LPCWSTR pszText,
    int iCharCount,
    DWORD dwFlags,
    LPRECT pRect,
    const DTTOPTS *pOptions
); 

hTheme is a theme handle that can be obtained using OpenThemeData. The OpenThemeData function accepts a window handle and the name of the theme class. iPartId and iStateId represent Part and State in the theme class respectively. All available theme classes, Parts and states can be viewed in the SDK help document. pszText is the text to be drawn. iCharCount is the number of text, -1 means drawing all text. dwFlags specifies text format. pRect draws the text area. You can set the lighting, shadow and other effects of text in pOptions. HDC is a device context handle. In order to achieve a lighting effect similar to the text in the title bar, the handle obtained by BeginPaint cannot be used here. Instead, CreateCompatibleDC must be used to create a handle in memory, and a bitmap must be created through the memory. Handle draws text onto a bitmap. Then transfer the bitmap to the window. The following function encapsulates the process of drawing illuminated text:

//Draw luminous text
void DrawGlowingText(HDC hDC, LPWSTR szText, RECT & amp;rcArea,
    DWORD dwTextFlags = DT_LEFT | DT_VCENTER | DT_SINGLELINE, int iGlowSize = 10)
{
    //Get the topic handle
    HTHEME hThm = OpenThemeData(GetDesktopWindow(), L"TextStyle");
    //Create DIB
    HDC hMemDC = CreateCompatibleDC(hDC);
    BITMAPINFO bmpinfo = {<!-- -->0};
    bmpinfo.bmiHeader.biSize = sizeof(bmpinfo.bmiHeader);
    bmpinfo.bmiHeader.biBitCount = 32;
    bmpinfo.bmiHeader.biCompression = BI_RGB;
    bmpinfo.bmiHeader.biPlanes = 1;
    bmpinfo.bmiHeader.biWidth = rcArea.right - rcArea.left;
    bmpinfo.bmiHeader.biHeight = -(rcArea.bottom - rcArea.top);
    HBITMAP hBmp = CreateDIBSection(hMemDC, & amp;bmpinfo, DIB_RGB_COLORS, 0, NULL, 0);
    if (hBmp == NULL) return;
    HGDIOBJ hBmpOld = SelectObject(hMemDC, hBmp);
    //drawing options
    DTTOPTS dttopts = {<!-- -->0};
    dttopts.dwSize = sizeof(DTTOPTS);
    dttopts.dwFlags = DTT_GLOWSIZE | DTT_COMPOSITED;
    dttopts.iGlowSize = iGlowSize; //The size of the luminous range
    //draw text
    RECT rc = {<!-- -->0, 0, rcArea.right - rcArea.left, rcArea.bottom - rcArea.top};
    HRESULT hr = DrawThemeTextEx(hThm, hMemDC, TEXT_LABEL, 0, szText, -1, dwTextFlags, & amp;rc, & amp;dttopts);
    if(FAILED(hr)) return;
    BitBlt(hDC, rcArea.left, rcArea.top, rcArea.right - rcArea.left,
        rcArea.bottom - rcArea.top, hMemDC, 0, 0, SRCCOPY | CAPTUREBLT);
    //Clear
    SelectObject(hMemDC, hBmpOld);
    DeleteObject(hBmp);
    DeleteDC(hMemDC);
    CloseThemeData(hThm);
} 

After drawing the graphic, add the following code to draw a piece of text:

//Draw text
RECT rcText = {<!-- -->10, 10, 300, 40};
DrawGlowingText(hDC, L" a little Chinese and some english", rcText); 

Because the font glows, it looks better to leave a space to the left of the text. The effect is as follows:

7. Thumbnail association

There is another feature in the DWM API, thumbnail association. It allows us to display a thumbnail of a window into the client area of our own window. Thumbnails are different from screenshots in that they update in real time. The following code will display the thumbnail of the QQ video player in the window client area:

HRESULT hr = S_OK;
HTHUMBNAIL thumbnail = NULL;
HWND hWndSrc = FindWindow(_T("QQPlayer Window"), NULL);
hr = DwmRegisterThumbnail(hWnd, hWndSrc, & amp;thumbnail);
if (SUCCEEDED(hr))
{
    RECT rc;
    GetClientRect(hWnd, & amp;rc);
    DWM_THUMBNAIL_PROPERTIES dskThumbProps;
    dskThumbProps.dwFlags = DWM_TNP_RECTDESTINATION | DWM_TNP_VISIBLE | DWM_TNP_OPACITY;
    dskThumbProps.fVisible = TRUE;
    dskThumbProps.opacity = 200;
    dskThumbProps.rcDestination = rc;
    hr = DwmUpdateThumbnailProperties(thumbnail, & amp;dskThumbProps);
} 

First, find the source window handle through the window title, and then use DwmRegisterThumbnail to register the thumbnail association. After successful registration, update the thumbnail properties through DwmUpdateThumbnailProperties, which sets whether it is visible, transparent, and the target drawing area. Get the following effect:

Source code download

Original address: http://www.cnblogs.com/longle/archive/2011/11/14/2248991.html