This topic has not yet been rated - Rate this topic

BeginBufferedAnimation function

Applies to: desktop apps only

Begins a buffered animation operation. The animation consists of a cross-fade between the contents of two buffers over a specified period of time.

Syntax

HANIMATIONBUFFER BeginBufferedAnimation(
  HWND hwnd,
  HDC hdcTarget,
  const RECT *rcTarget,
  BP_BUFFERFORMAT dwFormat,
  __in   BP_PAINTPARAMS *pPaintParams,
  __in   BP_ANIMATIONPARAMS *pAnimationParams,
  __out  HDC *phdcFrom,
  __out  HDC *phdcTo
);

Parameters

hwnd

Type: HWND

A handle to the window in which the animations play.

hdcTarget

Type: HDC

A handle of the target DC on which the buffer is animated.

rcTarget

Type: const RECT*

A pointer to a structure that specifies the area of the target DC in which to draw.

dwFormat

Type: BP_BUFFERFORMAT

The format of the buffer.

pPaintParams [in]

Type: BP_PAINTPARAMS*

A pointer to a structure that defines the paint operation parameters. This value can be NULL.

pAnimationParams [in]

Type: BP_ANIMATIONPARAMS*

A pointer to a structure that defines the animation operation parameters.

phdcFrom [out]

Type: HDC*

When this function returns, this value points to the handle of the DC where the application should paint the initial state of the animation, if not NULL.

phdcTo [out]

Type: HDC*

When this function returns, this value points to the handle of the DC where the application should paint the final state of the animation, if not NULL.

Return value

Type: HANIMATIONBUFFER

A handle to the buffered paint animation.

Remarks

BeginBufferedAnimation will take care of drawing the intermediate frames between those two states by generating multiple WM_PAINT messages.

BeginBufferedAnimation starts a timer that generates WM_PAINT messages on which BufferedPaintRenderAnimation should be called. During these messages, BufferedPaintRenderAnimation will return TRUE when it paints an intermediate frame, to signify that the application has no further painting to do.

If the animation duration is zero, then only phdcTo is returned and phdcFrom is set to NULL. In this case, the application should paint the final state using phdcTo to get the behavior similar to BeginBufferedPaint.

Examples

The following code example shows how to use this function.


#include <windows.h>
#include <tchar.h>
#include <uxtheme.h>

#pragma comment(lib, "uxtheme.lib")

#define WNDCLASSNAME L"BufferedPaintSample_WndClass"
#define ANIMATION_DURATION 500

bool g_fCurrentState = true;
bool g_fNewState = true;

void StartAnimation(HWND hWnd)
{
    g_fNewState = !g_fCurrentState;
    InvalidateRect(hWnd, NULL, TRUE);
}

void Paint(HWND hWnd, HDC hdc, bool state)
{
    RECT rc;
    GetClientRect(hWnd, &rc);
    FillRect(hdc, &rc, (HBRUSH)GetStockObject(WHITE_BRUSH));
    LPCTSTR pszIconId = state ? IDI_APPLICATION : IDI_ERROR;
    HICON hIcon = LoadIcon(NULL, pszIconId);
    if (hIcon)
    {
        DrawIcon(hdc, 10, 10, hIcon);
        DestroyIcon(hIcon);
    }
}

void OnPaint(HWND hWnd)
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd, &ps);
    if (hdc)
    {
        // See if this paint was generated by a soft-fade animation
        if (!BufferedPaintRenderAnimation(hWnd, hdc))
        {
            BP_ANIMATIONPARAMS animParams;
            ZeroMemory(&animParams, sizeof(animParams));
            animParams.cbSize = sizeof(BP_ANIMATIONPARAMS);
            animParams.style = BPAS_LINEAR;
            
            // Check if animation is needed. If not set dwDuration to 0
            animParams.dwDuration = (g_fCurrentState != g_fNewState ? ANIMATION_DURATION : 0);

            RECT rc;
            GetClientRect(hWnd, &rc);

            HDC hdcFrom, hdcTo;
            HANIMATIONBUFFER hbpAnimation = BeginBufferedAnimation(hWnd, hdc, &rc,
                BPBF_COMPATIBLEBITMAP, NULL, &animParams, &hdcFrom, &hdcTo);
            if (hbpAnimation)
            {
                if (hdcFrom)
                {
                    Paint(hWnd, hdcFrom, g_fCurrentState);
                }
                if (hdcTo)
                {
                    Paint(hWnd, hdcTo, g_fNewState);
                }

                g_fCurrentState = g_fNewState;
                EndBufferedAnimation(hbpAnimation, TRUE);
            }
            else
            {
                Paint(hWnd, hdc, g_fCurrentState);
            }
        }
        
        EndPaint(hWnd, &ps);
    }
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_LBUTTONDOWN:
        StartAnimation(hWnd);
        break;
    case WM_PAINT:
        OnPaint(hWnd);
        break;
    case WM_SIZE:
        BufferedPaintStopAllAnimations(hWnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

int WINAPI _tWinMain(HINSTANCE hInstance,
     HINSTANCE hPrevInstance,
     LPSTR     lpCmdLine,
     int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    if (SUCCEEDED(BufferedPaintInit()))
    {
        WNDCLASSEX wcex;
        ZeroMemory(&wcex, sizeof(wcex));
        wcex.cbSize = sizeof(WNDCLASSEX);
        wcex.style = CS_HREDRAW|CS_VREDRAW;
        wcex.lpfnWndProc = WndProc;
        wcex.hInstance = hInstance;
        wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
        wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        wcex.lpszClassName = WNDCLASSNAME;
        RegisterClassEx(&wcex);

        HWND hWnd = CreateWindow(WNDCLASSNAME, L"Buffered Paint Sample", 
            WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 
            CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

        if (hWnd)
        {
            ShowWindow(hWnd, nCmdShow);
            UpdateWindow(hWnd);

            MSG msg;
            while (GetMessage(&msg, NULL, 0, 0))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }

        BufferedPaintUnInit();
    }

    return 0;
}



void BufferedPaint(HDC hdc, const RECT *prcPaint)
{
    BP_PAINTPARAMS paintParams = {0};
    paintParams.cbSize = sizeof(paintParams);

    HDC hdcBuffer;
    HPAINTBUFFER hBufferedPaint = BeginBufferedPaint(hdc, prcPaint, 
        BPBF_COMPATIBLEBITMAP, &paintParams, &hdcBuffer);

    if (hBufferedPaint)
    {
        // Application specific painting code
        AppPaint(hdcBuffer, prcPaint);
        EndBufferedPaint(hBufferedPaint, TRUE);
    }
    else
    {
        // Error occurred, default to unbuffered painting
        AppPaint(hdc, prcPaint);
    }
}


Requirements

Minimum supported client

Windows Vista

Minimum supported server

Windows Server 2008

Header

Uxtheme.h

DLL

UxTheme.dll

 

 

Send comments about this topic to Microsoft

Build date: 3/6/2012

Did you find this helpful?
(1500 characters remaining)
Community Content Add
Annotations FAQ
BeginBufferedAnimation return NULL
"BeginBufferedAnimation" returns NULL if "BufferedPaintInit" is not called for the thread.
Must call BufferedPaintStopAllAnimations when window is being destroyed.
BufferedPaintStopAllAnimations must be called when a BeginBufferedAnimation hwnd is being destroyed (even if EndBufferedAnimation has been called).  The BufferedPaint code depends on window timers set on the BeginBufferedAnimation hwnd - if that window is being destroyed, the corresponding timers will be destroyed as well.  If one neglects to call BufferedPaintStopAllAnimations when a BeginBufferedAnimation window is destroyed, memory and GDI resource may be leaked.
Here's a C# implementation
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace BufferedAnimation
{
    public class BufferedAnimationControl : Control
    {
        public BufferedAnimationControl()
            : base()
        {
            this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
            BufferedPaintInit();
        }

        ~BufferedAnimationControl()
        {
            BufferedPaintStopAllAnimations(this.Handle);
            BufferedPaintUnInit();
        }

        protected override Size DefaultSize
        {
            get
            {
                return  Size.Add(SystemInformation.IconSize, new Size(20,20));
            }
        }

        bool g_fCurrentState = true;
        bool g_fNewState = true;

        void StartAnimation(IntPtr hWnd)
        {
            g_fNewState = !g_fCurrentState;
            this.Invalidate(true);
        }

        private void PaintAnimationState(IntPtr hdc, bool state)
        {
            Graphics g = Graphics.FromHdc(hdc);
            using (Brush brush = new SolidBrush(this.BackColor))
                g.FillRectangle(brush, this.ClientRectangle);
            Icon stateIcon = state ? SystemIcons.Application : SystemIcons.Error;
            g.DrawIcon(stateIcon, 10, 10);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            IntPtr hdc = e.Graphics.GetHdc();
            if (hdc != IntPtr.Zero)
            {
                // See if this paint was generated by a soft-fade animation
                if (!BufferedPaintRenderAnimation(this.Handle, hdc))
                {
                    BP_ANIMATIONPARAMS animParams = new BP_ANIMATIONPARAMS();
                    animParams.cbSize = Marshal.SizeOf(animParams);
                    animParams.style = BP_ANIMATIONSTYLE.BPAS_LINEAR;

                    // Check if animation is needed. If not set dwDuration to 0
                    animParams.dwDuration = (g_fCurrentState != g_fNewState ? ANIMATION_DURATION : 0);

                    RECT rc = new RECT(this.ClientRectangle);
                    IntPtr hdcFrom, hdcTo;
                    IntPtr hbpAnimation = BeginBufferedAnimation(this.Handle, hdc, ref rc, BP_BUFFERFORMAT.BPBF_COMPATIBLEBITMAP, IntPtr.Zero, ref animParams, out hdcFrom, out hdcTo);
                    if (hbpAnimation != IntPtr.Zero)
                    {
                        if (hdcFrom != IntPtr.Zero)
                        {
                            PaintAnimationState(hdcFrom, g_fCurrentState);
                        }
                        if (hdcTo != IntPtr.Zero)
                        {
                            PaintAnimationState(hdcTo, g_fNewState);
                        }
                        g_fCurrentState = g_fNewState;
                        EndBufferedAnimation(hbpAnimation, true);
                    }
                    else
                    {
                        PaintAnimationState(hdc, g_fCurrentState);
                    }
                }
                e.Graphics.ReleaseHdc(hdc);
            }
        }

        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            //base.OnPaintBackground(pevent);
        }

        protected override void OnClick(EventArgs e)
        {
            base.OnClick(e);
            StartAnimation(this.Handle);
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            BufferedPaintStopAllAnimations(this.Handle);
        }

        #region Interop

        [DllImport("uxtheme")]
        private static extern IntPtr BufferedPaintInit();

        [DllImport("uxtheme")]
        private static extern IntPtr BufferedPaintUnInit();

        [DllImport("uxtheme")]
        private static extern IntPtr BeginBufferedAnimation(IntPtr hwnd, IntPtr hdcTarget, ref RECT rcTarget, BP_BUFFERFORMAT dwFormat, IntPtr pPaintParams, ref BP_ANIMATIONPARAMS pAnimationParams, out IntPtr phdcFrom, out  IntPtr phdcTo);

        [DllImport("uxtheme")]
        private static extern IntPtr EndBufferedAnimation(IntPtr hbpAnimation, bool fUpdateTarget);

        [DllImport("uxtheme")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool BufferedPaintRenderAnimation(IntPtr hwnd, IntPtr hdcTarget);

        [DllImport("uxtheme")]
        private static extern IntPtr BufferedPaintStopAllAnimations(IntPtr hwnd);

        [StructLayout(LayoutKind.Sequential)]
        private struct RECT
        {
            public int left;
            public int top;
            public int right;
            public int bottom;
            public RECT(Rectangle rc)
            {
                left = rc.Left;
                top = rc.Top;
                right = rc.Right;
                bottom = rc.Bottom;
            }
        }
       
        [StructLayout(LayoutKind.Sequential)]
        private struct BP_ANIMATIONPARAMS
        {
            public Int32 cbSize, dwFlags;
            public BP_ANIMATIONSTYLE style;
            public Int32 dwDuration;
        }

        private enum BP_BUFFERFORMAT
        {
            BPBF_COMPATIBLEBITMAP,
            BPBF_DIB,
            BPBF_TOPDOWNDIB,
            BPBF_TOPDOWNMONODIB
        }
       
        [Flags]
        private enum BP_ANIMATIONSTYLE
        {
            BPAS_NONE = 0,
            BPAS_LINEAR = 1,
            BPAS_CUBIC = 2,
            BPAS_SINE = 3
        }

        private const int ANIMATION_DURATION = 500;

        #endregion
    }

}