using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace ConsoleApplication3
{
    static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MyForm());
        }




        #region Win32Class
        // a static class to expose needed win32 gdi functions.
        class Win32
        {
            public const Int32 ULW_COLORKEY = 0x00000001;
            public const Int32 ULW_ALPHA = 0x00000002;
            public const Int32 ULW_OPAQUE = 0x00000004;

            public const byte AC_SRC_OVER = 0x00;
            public const byte AC_SRC_ALPHA = 0x01;


            public enum Bool
            {
                False = 0,
                True
            };

            [StructLayout(LayoutKind.Sequential)]
            public struct Point
            {
                public Int32 x;
                public Int32 y;

                public Point(Int32 x, Int32 y) { this.x = x; this.y = y; }
            }


            [StructLayout(LayoutKind.Sequential)]
            public struct Size
            {
                public Int32 cx;
                public Int32 cy;

                public Size(Int32 cx, Int32 cy) { this.cx = cx; this.cy = cy; }
            }


            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            struct ARGB
            {
                public byte Blue;
                public byte Green;
                public byte Red;
                public byte Alpha;
            }


            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            public struct BLENDFUNCTION
            {
                public byte BlendOp;
                public byte BlendFlags;
                public byte SourceConstantAlpha;
                public byte AlphaFormat;
            }


            [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
            public static extern Bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags);

            #region DC About

            [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
            public static extern IntPtr GetDC(IntPtr hWnd);

            [DllImport("user32.dll", ExactSpelling = true)]
            public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

            [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
            public static extern IntPtr CreateCompatibleDC(IntPtr hDC);

            [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
            public static extern Bool DeleteDC(IntPtr hdc);

            [DllImport("gdi32.dll", ExactSpelling = true)]
            public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);

            [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
            public static extern Bool DeleteObject(IntPtr hObject);

            #endregion
        }

        #endregion


        #region PerPixelAlphaFormClass
        /**/
        /// <para>PerPixel forms should derive from this base class</para>
        /// <author><name>Rui Godinho Lopes</name><email>rui@ruilopes.com</email></author>
        class PerPixelAlphaForm : Form
        {
            /**/
            /// <para>Changes the current bitmap.</para>
            public void SetBitmap(Bitmap bitmap)
            {
                SetBitmap(bitmap, 255);
            }

            /**/
            /// <para>Changes the current bitmap with a custom opacity level. Here is where all happens!</para>
            public void SetBitmap(Bitmap bitmap, byte opacity)
            {
                if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
                    throw new ApplicationException("The bitmap must be 32ppp with alpha-channel.");

                // The ideia of this is very simple,
                // 1. Create a compatible DC with screen;
                // 2. Select the bitmap with 32bpp with alpha-channel in the compatible DC;
                // 3. Call the UpdateLayeredWindow.

                IntPtr screenDc = Win32.GetDC(IntPtr.Zero);
                IntPtr memDc = Win32.CreateCompatibleDC(screenDc);
                IntPtr hBitmap = IntPtr.Zero;
                IntPtr oldBitmap = IntPtr.Zero;

                try
                {
                    hBitmap = bitmap.GetHbitmap(Color.FromArgb(0)); // grab a GDI handle from this GDI+ bitmap
                    oldBitmap = Win32.SelectObject(memDc, hBitmap);//  select the newbitmap,return the oldbitmap

                    Win32.Size size = new Win32.Size(bitmap.Width, bitmap.Height);//create the size of LayeredWindow
                    Win32.Point pointSource = new Win32.Point(0, 0);
                    Win32.Point topPos = new Win32.Point(Left, Top);//LayeredWindow start position
                    Win32.BLENDFUNCTION blend = new Win32.BLENDFUNCTION();

                    /**/
                    /////????
                    blend.BlendOp = Win32.AC_SRC_OVER;
                    blend.BlendFlags = 0;
                    blend.SourceConstantAlpha = opacity;
                    blend.AlphaFormat = Win32.AC_SRC_ALPHA;

                    //the most important function
                    Win32.UpdateLayeredWindow(this.Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, Win32.ULW_ALPHA);
                }
                finally
                {
                    Win32.ReleaseDC(IntPtr.Zero, screenDc);
                    if (hBitmap != IntPtr.Zero)
                    {
                        Win32.SelectObject(memDc, oldBitmap);
                        //Windows.DeleteObject(hBitmap); // The documentation says that we have to use the Windows.DeleteObject    but since there is no such method I use the normal DeleteObject from Win32 GDI and it's working fine without any resource leak.
                        Win32.DeleteObject(hBitmap);
                    }
                    Win32.DeleteDC(memDc);
                }
            }

            protected override CreateParams CreateParams
            {
                //set form style
                get
                {
                    CreateParams cp = base.CreateParams;
                    cp.ExStyle |= 0x00080000; // This form has to have the WS_EX_LAYERED extended style
                    return cp;
                }
            }
        }

        #endregion


        #region MyPerPixelAlphaFormClass
        /**/
        /// <para>Our test form for this sample application. The bitmap will be displayed in this window.</para>
        class MyPerPixelAlphaForm : PerPixelAlphaForm
        {
            public MyPerPixelAlphaForm()
            {
                Text = "PerPixelAlpha Layered Form";
                TopMost = true;
                FormBorderStyle = FormBorderStyle.FixedDialog;
                MinimizeBox = false;
                MaximizeBox = false;
                ControlBox = false;
            }

            // Let Windows drag this window for us
            protected override void WndProc(ref Message m)
            {
                //Can move window
                if (m.Msg == 0x0084 /**//*WM_NCHITTEST*/)
                {
                    m.Result = (IntPtr)2; // HTCLIENT
                    return;
                }
                base.WndProc(ref m);
            }

        }
        #endregion


        #region MainFormClass
        /**/
        ///<para>The "controller" dialog box.</para>
        class MyForm : Form
        {
            public MyForm()
            {
                Font = new Font("tahoma", 8);
                Text = "perpixelalpha# - Sample application";
                FormBorderStyle = FormBorderStyle.FixedDialog;
                MinimizeBox = true;
                MaximizeBox = false;
                ClientSize = new Size(350, 160);
                StartPosition = FormStartPosition.CenterScreen;

                AllowDrop = true; // Because we want to be a drop target of windows explorer files.

                InitializeComponent();
            }

            /**/
            ///<para>Constructs and initializes all child controls of this dialog box.</para>
            private void InitializeComponent()
            {

                // Label with to display current opacity level
                Label Label1 = new Label();
                Label1.AutoSize = true;
                Label1.Location = new System.Drawing.Point(4, 8);
                Label1.Text = "1. Drag&&Drop an image file from windows explorer into this window.";
                Controls.Add(Label1);

                Label Label2 = new Label();
                Label2.AutoSize = true;
                Label2.Location = new System.Drawing.Point(4, 38);
                Label2.Text = "2. Play with the opacity level [0..255]:";
                Controls.Add(Label2);

                // Label with to display current opacity level
                LabelValue = new Label();
                LabelValue.AutoSize = true;
                LabelValue.Location = new System.Drawing.Point(195, 38);
                LabelValue.Text = "255";

                Controls.Add(LabelValue);

                // Trackbar to change opacity level
                Track = new TrackBar();

                Track.Location = new System.Drawing.Point(18, 58);
                Track.Size = new System.Drawing.Size(310, 0);
                Track.BeginInit();
                Track.Maximum = 255;
                Track.TickFrequency = 5;
                Track.TickStyle = TickStyle.TopLeft;
                Track.Value = 255;
                Track.EndInit();

                Track.ValueChanged += new EventHandler(Track_ValueChanged);

                Controls.Add(Track);


                Label Label3 = new Label();
                Label3.AutoSize = true;
                Label3.Location = new System.Drawing.Point(4, 108);
                Label3.Text = "3. Drag the layered window arround you desktop!";
                Controls.Add(Label3);


                // Label with two links to me! :)
                LinkLabel Link = new LinkLabel();

                Link.Location = new System.Drawing.Point(4, 140);
                Link.Size = new System.Drawing.Size(250, 80);
                Link.Text = "by Rui Lopes <rui@ruilopes.com>";
                Link.Links.Add(3, 9, "http://www.ruilopes.com");
                Link.Links.Add(14, 16, "mailto:rui@ruilopes.com");

                Link.LinkClicked += new LinkLabelLinkClickedEventHandler(Link_LinkClicked);

                Controls.Add(Link);

                // TestForm will containt the per-pixel-alpha dib
                TestForm = new MyPerPixelAlphaForm();
                TestForm.Show();

                this.DoubleClick += new EventHandler(MyForm_DoubleClick);
            }

            /**/
            ///<para>Frees our bitmap.</para>
            protected override void Dispose(bool disposing)
            {
                try
                {
                    if (disposing && bitmap != null)
                    {
                        bitmap.Dispose();
                        bitmap = null;
                    }
                }
                finally
                {
                    base.Dispose(disposing);
                }
            }

            /**/
            ///<para>Accepts only Drops of windows explorer files.</para>
            protected override void OnDragEnter(DragEventArgs e)
            {
                if (e.Data.GetDataPresent(DataFormats.FileDrop))
                    e.Effect = DragDropEffects.Copy;
                base.OnDragEnter(e);
            }

            /**/
            ///<para>Just loads the dropped file from windows explorer.</para>
            protected override void OnDragDrop(DragEventArgs e)
            {
                string[] files = e.Data.GetData(DataFormats.FileDrop) as string[];
                if (files != null)
                {
                    if (files.Length == 1)
                        SetPerPixelBitmapFilename(files[0]);
                    else
                        MessageBox.Show(this, "Please, drop only one image file.", "Too many files dropped", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                }
                base.OnDragDrop(e);
            }

            /**/
            ///<para>Just load a image file and display it on our test form.</para>
            private void SetPerPixelBitmapFilename(string fileName)
            {
                Bitmap newBitmap;

                try
                {

                    newBitmap = Image.FromFile(fileName) as Bitmap;
                    TestForm.SetBitmap(newBitmap, (byte)Track.Value);

                }
                catch (ApplicationException e)
                {
                    MessageBox.Show(this, e.Message, "Error with bitmap.", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
                catch (Exception e)
                {
                    MessageBox.Show(this, e.Message, "Could not open image file.", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                if (bitmap != null)
                    bitmap.Dispose();
                bitmap = newBitmap;
            }


            /**/
            ///<para>Change the opacity level of our test form.</para>
            private void Track_ValueChanged(object sender, EventArgs e)
            {
                byte opacity = (byte)Track.Value;
                LabelValue.Text = opacity.ToString();
                LabelValue.Refresh(); // We need this because on slow computers (mine!) the windows takes some time to update our label.

                if (bitmap != null)
                    TestForm.SetBitmap(bitmap, opacity);
            }

            /**/
            ///<para>Start the computer browser in the specified uri.</para>
            private void Link_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
            {
                e.Link.Visited = true;
                using (System.Diagnostics.Process.Start(e.Link.LinkData.ToString()))
                {
                }
            }


            // Our member varaibles:

            private Label LabelValue; // label with current opacity level
            private TrackBar Track; // trackbar to chabge opacity level
            private MyPerPixelAlphaForm TestForm; // our test form
            private Bitmap bitmap; // bitmap that is currently displaying on our test form

            //exit window
            private void MyForm_DoubleClick(object sender, EventArgs e)
            {
                this.Close();
            }
        }

        #endregion
    }
}


Posted on 2007-11-16 20:15  李通通  阅读(3015)  评论(5编辑  收藏  举报