W
wujingping
Unregistered / Unconfirmed
GUEST, unregistred user!
终于找到了完美的透明窗口源代码,不过是c#的,有谁为大家造福,翻译成delphi!!<br>不过还是不支持98,调用了GDI+引擎,好像关键API是UpdateLayeredWindow。<br>本人不太懂C#,有哪位明白,不妨指教一下。<br><br>完整的zip 源文件在ftp://temp:temp@211.154.84.185/perpxalpha_sharp_src.zip<br>包含测试用的图片和成品exe文件。<br>源代码<br>//<br>// Copyright ?2002 Rui Godinho Lopes <rui@ruilopes.com><br>// All rights reserved.<br>//<br>// This source file(s) may be redistributed unmodified by any means<br>// PROVIDING they are not sold for profit without the authors expressed<br>// written consent, and providing that this notice and the authors name<br>// and all copyright notices remain intact.<br>//<br>// Any use of the software in source or binary forms, with or without<br>// modification, must include, in the user documentation ("About" box and<br>// printed documentation) and internal comments to the code, notices to<br>// the end user as follows:<br>//<br>// "Portions Copyright ?2002 Rui Godinho Lopes"<br>//<br>// An email letting me know that you are using it would be nice as well.<br>// That's not much to ask considering the amount of work that went into<br>// this.<br>//<br>// THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, <br>// EXPRESS OR IMPLIED. USE IT AT YOUT OWN RISK. THE AUTHOR ACCEPTS NO<br>// LIABILITY FOR ANY DATA DAMAGE/LOSS THAT THIS PRODUCT MAY CAUSE.<br>//<br><br>using System;<br>using System.Drawing;<br>using System.Drawing.Imaging;<br>using System.Windows.Forms;<br>using System.Runtime.InteropServices;<br><br><br>// a static class to expose needed win32 gdi functions.<br>class Win32 {<br><br> public enum Bool {<br> False= 0,<br> True<br> };<br><br> [StructLayout(LayoutKind.Sequential)]<br> public struct Point {<br> public Int32 x;<br> public Int32 y;<br><br> public Point(Int32 x, Int32 y) { this.x= x; this.y= y; }<br> }<br><br> [StructLayout(LayoutKind.Sequential)]<br> public struct Size {<br> public Int32 cx;<br> public Int32 cy;<br><br> public Size(Int32 cx, Int32 cy) { this.cx= cx; this.cy= cy; }<br> }<br><br> [StructLayout(LayoutKind.Sequential, Pack=1)]<br> struct ARGB {<br> public byte Blue;<br> public byte Green;<br> public byte Red;<br> public byte Alpha;<br> }<br><br> [StructLayout(LayoutKind.Sequential, Pack=1)]<br> public struct BLENDFUNCTION {<br> public byte BlendOp;<br> public byte BlendFlags;<br> public byte SourceConstantAlpha;<br> public byte AlphaFormat;<br> }<br><br><br> public const Int32 ULW_COLORKEY = 0x00000001;<br> public const Int32 ULW_ALPHA = 0x00000002;<br> public const Int32 ULW_OPAQUE = 0x00000004;<br><br> public const byte AC_SRC_OVER = 0x00;<br> public const byte AC_SRC_ALPHA = 0x01;<br><br><br> [DllImport("user32.dll", ExactSpelling=true, SetLastError=true)]<br> 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);<br><br> [DllImport("user32.dll", ExactSpelling=true, SetLastError=true)]<br> public static extern IntPtr GetDC(IntPtr hWnd);<br><br> [DllImport("user32.dll", ExactSpelling=true)]<br> public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);<br><br> [DllImport("gdi32.dll", ExactSpelling=true, SetLastError=true)]<br> public static extern IntPtr CreateCompatibleDC(IntPtr hDC);<br><br> [DllImport("gdi32.dll", ExactSpelling=true, SetLastError=true)]<br> public static extern Bool DeleteDC(IntPtr hdc);<br><br> [DllImport("gdi32.dll", ExactSpelling=true)]<br> public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);<br><br> [DllImport("gdi32.dll", ExactSpelling=true, SetLastError=true)]<br> public static extern Bool DeleteObject(IntPtr hObject);<br>}<br><br><br>/// <para>PerPixel forms should derive from this base class</para><br>/// <author><name>Rui Godinho Lopes</name><email>rui@ruilopes.com</email></author><br>class PerPixelAlphaForm : Form {<br><br> /// <para>Changes the current bitmap.</para><br> public void SetBitmap(Bitmap bitmap) {<br> SetBitmap(bitmap, 255);<br> }<br><br> /// <para>Changes the current bitmap with a custom opacity level. Here is where all happens!</para><br> public void SetBitmap(Bitmap bitmap, byte opacity) {<br> if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)<br> throw new ApplicationException("The bitmap must be 32ppp with alpha-channel.");<br><br> // The ideia of this is very simple,<br> // 1. Create a compatible DC with screen;<br> // 2. Select the bitmap with 32bpp with alpha-channel in the compatible DC;<br> // 3. Call the UpdateLayeredWindow.<br><br> IntPtr screenDc = Win32.GetDC(IntPtr.Zero);<br> IntPtr memDc = Win32.CreateCompatibleDC(screenDc);<br> IntPtr hBitmap = IntPtr.Zero;<br> IntPtr oldBitmap = IntPtr.Zero;<br><br> try {<br> hBitmap = bitmap.GetHbitmap(Color.FromArgb(0)); // grab a GDI handle from this GDI+ bitmap<br> oldBitmap = Win32.SelectObject(memDc, hBitmap);<br><br> Win32.Size size = new Win32.Size(bitmap.Width, bitmap.Height);<br> Win32.Point pointSource = new Win32.Point(0, 0);<br> Win32.Point topPos = new Win32.Point(Left, Top);<br> Win32.BLENDFUNCTION blend = new Win32.BLENDFUNCTION();<br> blend.BlendOp = Win32.AC_SRC_OVER;<br> blend.BlendFlags = 0;<br> blend.SourceConstantAlpha = opacity;<br> blend.AlphaFormat = Win32.AC_SRC_ALPHA;<br><br> Win32.UpdateLayeredWindow(Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, Win32.ULW_ALPHA);<br> }<br> finally {<br> Win32.ReleaseDC(IntPtr.Zero, screenDc);<br> if (hBitmap != IntPtr.Zero) {<br> Win32.SelectObject(memDc, oldBitmap);<br> //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.<br> Win32.DeleteObject(hBitmap);<br> }<br> Win32.DeleteDC(memDc);<br> }<br> }<br><br> protected override CreateParams CreateParams {<br> get {<br> CreateParams cp = base.CreateParams;<br> cp.ExStyle |= 0x00080000; // This form has to have the WS_EX_LAYERED extended style<br> return cp;<br> }<br> }<br>}<br><br><br><br><br><br><br><br>/// <para>Our test form for this sample application. The bitmap will be displayed in this window.</para><br>class MyPerPixelAlphaForm : PerPixelAlphaForm {<br><br> public MyPerPixelAlphaForm() {<br> Text = "PerPixelAlpha Layered Form";<br> TopMost = true;<br> FormBorderStyle = FormBorderStyle.FixedDialog;<br> MinimizeBox = false;<br> MaximizeBox = false;<br> ControlBox = false;<br> }<br><br> // Let Windows drag this window for us<br> protected override void WndProc(ref Message m) {<br> if (m.Msg == 0x0084 /*WM_NCHITTEST*/) {<br> m.Result= (IntPtr)2; // HTCLIENT<br> return;<br> }<br> base.WndProc(ref m);<br> }<br>}<br><br><br><br>///<para>The "controller" dialog box.</para><br>class MyForm : Form {<br><br> public MyForm() {<br> Font= new Font("tahoma", 8);<br> Text= "perpixelalpha# - Sample application";<br> FormBorderStyle = FormBorderStyle.FixedDialog;<br> MinimizeBox = false;<br> MaximizeBox = false;<br> ClientSize = new Size(350, 160);<br> StartPosition = FormStartPosition.CenterScreen;<br><br> AllowDrop = true; // Because we want to be a drop target of windows explorer files.<br><br> InitializeComponent();<br> }<br><br> ///<para>Constructs and initializes all child controls of this dialog box.</para><br> private void InitializeComponent() {<br><br> // Label with to display current opacity level<br> Label Label1 = new Label();<br> Label1.AutoSize = true;<br> Label1.Location = new System.Drawing.Point(4, 8);<br> Label1.Text = "1. Drag&&Drop an image file from windows explorer into this window.";<br> Controls.Add(Label1);<br><br> Label Label2 = new Label();<br> Label2.AutoSize = true;<br> Label2.Location = new System.Drawing.Point(4, 38);<br> Label2.Text = "2. Play with the opacity level [0..255]:";<br> Controls.Add(Label2);<br><br> // Label with to display current opacity level<br> LabelValue = new Label();<br> LabelValue.AutoSize = true;<br> LabelValue.Location = new System.Drawing.Point(195, 38);<br> LabelValue.Text = "255";<br><br> Controls.Add(LabelValue);<br><br><br><br> // Trackbar to change opacity level<br> Track = new TrackBar();<br><br> Track.Location = new System.Drawing.Point(18, 58);<br> Track.Size = new System.Drawing.Size(310, 0);<br> Track.BeginInit();<br> Track.Maximum = 255;<br> Track.TickFrequency = 5;<br> Track.TickStyle = TickStyle.TopLeft;<br> Track.Value = 255;<br> Track.EndInit();<br><br> Track.ValueChanged += new EventHandler(Track_ValueChanged);<br><br> Controls.Add(Track);<br><br> <br> Label Label3 = new Label();<br> Label3.AutoSize = true;<br> Label3.Location = new System.Drawing.Point(4, 108);<br> Label3.Text = "3. Drag the layered window arround you desktop!";<br> Controls.Add(Label3);<br><br><br> // Label with two links to me! <br> LinkLabel Link = new LinkLabel();<br><br> Link.Location = new System.Drawing.Point(4, 140);<br> Link.Size = new System.Drawing.Size(250, 80);<br> Link.Text = "by Rui Lopes <rui@ruilopes.com>";<br> Link.Links.Add(3, 9, "http://www.ruilopes.com");<br> Link.Links.Add(14, 16, "mailto:rui@ruilopes.com");<br><br> Link.LinkClicked += new LinkLabelLinkClickedEventHandler(Link_LinkClicked);<br><br> Controls.Add(Link);<br><br><br> // TestForm will containt the per-pixel-alpha dib<br> TestForm = new MyPerPixelAlphaForm();<br> TestForm.Show();<br> }<br><br> ///<para>Frees our bitmap.</para><br> protected override void Dispose(bool disposing) {<br> try {<br> if (disposing && bitmap != null) {<br> bitmap.Dispose();<br> bitmap = null;<br> }<br> } finally {<br> base.Dispose(disposing);<br> }<br> }<br><br> ///<para>Accepts only Drops of windows explorer files.</para><br> protected override void OnDragEnter(DragEventArgs e) {<br> if (e.Data.GetDataPresent(DataFormats.FileDrop))<br> e.Effect = DragDropEffects.Copy;<br> base.OnDragEnter(e);<br> }<br><br> ///<para>Just loads the dropped file from windows explorer.</para><br> protected override void OnDragDrop(DragEventArgs e) {<br> string[] files= e.Data.GetData(DataFormats.FileDrop) as string[];<br> if (files != null) {<br> if (files.Length == 1)<br> SetPerPixelBitmapFilename(files[0]);<br> else<br> MessageBox.Show(this, "Please, drop only one image file.", "Too many files dropped", MessageBoxButtons.OK, MessageBoxIcon.Stop);<br> }<br> base.OnDragDrop(e);<br> }<br><br> ///<para>Just load a image file and display it on our test form.</para><br> private void SetPerPixelBitmapFilename(string fileName) {<br> Bitmap newBitmap;<br><br> try {<br><br> newBitmap = Image.FromFile(fileName) as Bitmap;<br> TestForm.SetBitmap(newBitmap, (byte)Track.Value);<br><br> } catch (ApplicationException e) {<br> MessageBox.Show(this, e.Message, "Error with bitmap.", MessageBoxButtons.OK, MessageBoxIcon.Error);<br> return;<br> } catch (Exception e) {<br> MessageBox.Show(this, e.Message, "Could not open image file.", MessageBoxButtons.OK, MessageBoxIcon.Error);<br> return;<br> }<br><br> if (bitmap != null)<br> bitmap.Dispose();<br> bitmap = newBitmap;<br> }<br><br><br> ///<para>Change the opacity level of our test form.</para><br> private void Track_ValueChanged(object sender, EventArgs e) {<br> byte opacity = (byte)Track.Value;<br> LabelValue.Text = opacity.ToString();<br> LabelValue.Refresh(); // We need this because on slow computers (mine!) the windows takes some time to update our label.<br><br> if (bitmap != null)<br> TestForm.SetBitmap(bitmap, opacity); <br> }<br><br> ///<para>Start the computer browser in the specified uri.</para><br> private void Link_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) {<br> e.Link.Visited = true;<br> using (System.Diagnostics.Process.Start(e.Link.LinkData.ToString())) {<br> }<br> }<br><br><br> // Our member varaibles:<br><br> private Label LabelValue; // label with current opacity level<br> private TrackBar Track; // trackbar to chabge opacity level<br> private MyPerPixelAlphaForm TestForm; // our test form<br> private Bitmap bitmap; // bitmap that is currently displaying on our test form<br>}<br><br><br><br>// Our Great Application!<br>class TheApp {<br> [STAThread]<br> public static void Main() {<br> Application.Run(new MyForm());<br> }<br>}