Mission accomplished.

30. décembre 2008

Ca c’est fait. Un mois et demi après la sortie de Warth Of The Lich King (extension de World of Warcraft), mon personnage dans le jeu est de niveau 80 avec toutes les réputations exaltées.

Pour les curieux qui voudraient voir (que dis-je admirer) la bête, ca se passe par ici.

tof

AHhhhhhhHhhh ce sentiment du travail bien fait! Je vais pouvoir recommencer à dormir.

WoW

Lancement de Dotnet-France

15. décembre 2008

suite à une légère pression d'un certain Oliver C., je vous propose de découvrir le site de Dotnet-France.

Comme je suis un grand reporter, je vous cite direct le communiqué de presse : "Dotnet-France ambitionne l’idée de devenir une des communautés les plus influentes auprès des étudiants et développeurs professionnels sur les technologies Microsoft".

.Net

Interop Win32 avec le Cross Fade Control

9. décembre 2008

Lors d'une super session à la PDC 2008, j'ai découvert une API Win32 utilisée dans la gestion des styles visuels nommée BufferedPaintRenderAnimation. Cette dernière est notamment utilisée dans les boutons sur Vista pour faire l'effet de fondu.

Je vous propose donc ici un petit contrôle .Net qui encapsule ce service:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1
{
    public partial class CrossFadeControl : Control
    {
        public enum FadeDirection
        {
            SourceDestination,
            DestinationSource
        }

        enum BP_ANIMATIONSTYLE
        {
            BPAS_NONE,
            BPAS_LINEAR,
            BPAS_CUBIC,
            BPAS_SINE
        }

        enum BP_BUFFERFORMAT
        {
            BPBF_COMPATIBLEBITMAP,
            BPBF_DIB,
            BPBF_TOPDOWNDIB,
            BPBF_TOPDOWNMONODIB
        }

        [StructLayout(LayoutKind.Sequential)]
        struct BP_ANIMATIONPARAMS
        {
            public int cbSize;
            public int dwFlags;
            public BP_ANIMATIONSTYLE style;
            public int dwDuration;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct BP_PAINTPARAMS
        {
            int cbSize;
            int dwFlags;
            IntPtr prcExclude;
            IntPtr pBlendFunction;
        }

        [DllImport("uxtheme.dll")]
        extern static int BufferedPaintInit();

        [DllImport("uxtheme.dll")]
        extern static int BufferedPaintUnInit();

        [DllImport("uxtheme.dll")]
        extern static int BufferedPaintRenderAnimation(IntPtr hWnd, IntPtr hDc);

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

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

        [DllImport("uxtheme.dll")]
        extern static int BufferedPaintStopAllAnimations(IntPtr handle);

        int animDuration = 0;
        int targetAnimationDuration = 500;
        Image source;
        Image destination;
        FadeDirection direction;

        public FadeDirection Direction
        {
            get { return direction; }
            set { direction = value; }
        }

        public Image Source
        {
            get { return source; }
            set { source = value; }
        }

        public Image Destination
        {
            get { return destination; }
            set { destination = value; }
        }

        public int TargetAnimationDuration
        {
            get { return targetAnimationDuration; }
            set { targetAnimationDuration = value; }
        }

        public CrossFadeControl()
        {
            InitializeComponent();
            BufferedPaintInit();
        }

        ~CrossFadeControl()
        {
            BufferedPaintUnInit();
        }

        public void StartAnimation()
        {
            animDuration = targetAnimationDuration;
            Invalidate();
        }

        Image GetSource()
        {
            switch (direction)
            {
                case FadeDirection.SourceDestination:
                    return source;
                case FadeDirection.DestinationSource:
                    return destination;
            }
            return source;
        }

        Image GetDestination()
        {
            switch (direction)
            {
                case FadeDirection.SourceDestination:
                    return destination;
                case FadeDirection.DestinationSource:
                    return source;
            }
            return destination;
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            if (source == null || destination == null)
            {
                base.OnPaint(pe);
                return;
            }

            IntPtr hdc = pe.Graphics.GetHdc();

            if (BufferedPaintRenderAnimation(Handle, hdc) == 0)
            {
                if (animDuration == 0)
                {
                    pe.Graphics.ReleaseHdc(hdc);
                    pe.Graphics.DrawImage(GetSource(), ClientRectangle);

                    return;
                }

                BP_ANIMATIONPARAMS animParams = new BP_ANIMATIONPARAMS();
                animParams.cbSize = Marshal.SizeOf(animParams);
                animParams.style = BP_ANIMATIONSTYLE.BPAS_LINEAR;
                animParams.dwDuration = animDuration;

                IntPtr hdcFrom, hdcTo;
                Rectangle rect = ClientRectangle;
                IntPtr hbpAnimation = BeginBufferedAnimation(Handle, hdc, ref rect, 
                    BP_BUFFERFORMAT.BPBF_COMPATIBLEBITMAP,
                     IntPtr.Zero, ref animParams, out hdcFrom, out hdcTo);

                if (hbpAnimation != IntPtr.Zero)
                {
                    if (hdcFrom != IntPtr.Zero)
                    {
                        Graphics gfx = Graphics.FromHdc(hdcFrom);
                        gfx.DrawImage(GetSource(), ClientRectangle);
                        gfx.Dispose();
                    }
                    if (hdcTo != IntPtr.Zero)
                    {
                        Graphics gfx = Graphics.FromHdc(hdcTo);
                        gfx.DrawImage(GetDestination(), ClientRectangle);
                        gfx.Dispose();
                    }
                    animDuration = 0;
                    EndBufferedAnimation(hbpAnimation, true);
                }
            }
            pe.Graphics.ReleaseHdc(hdc);
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            BufferedPaintStopAllAnimations(Handle);
            Invalidate();
        }
    }
}

 

Grâce aux propriétés Source et Destination, il est possible de fournir les images qui vont servir de source et de cible pour le fading. La propriété Direction permet de dire si l'on passe de la source à la destination ou inversement.

Finalement, la propriété TargetAnimationDuration donne, comme son nom l'indique, la durée de l'animation.

Amusez vous avec ce contrôle, cela fera plaisir aux développeurs Win32 chez Microsoft^^.

.Net, Win32