moel@202: /*
moel@344:  
moel@344:   This Source Code Form is subject to the terms of the Mozilla Public
moel@344:   License, v. 2.0. If a copy of the MPL was not distributed with this
moel@344:   file, You can obtain one at http://mozilla.org/MPL/2.0/.
moel@344:  
moel@344:   Copyright (C) 2010-2011 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@344: 	Copyright (C) 2010 Paul Werelds <paul@werelds.net>
moel@176: 
moel@176: */
moel@176: 
moel@176: using System;
moel@176: using System.Drawing;
moel@302: using System.Drawing.Drawing2D;
moel@302: using System.Drawing.Text;
moel@176: using System.Reflection;
moel@176: using System.Runtime.InteropServices;
moel@176: using System.Windows.Forms;
moel@176: 
moel@176: namespace OpenHardwareMonitor.GUI {
moel@183: 
moel@302:   public class GadgetWindow : NativeWindow, IDisposable {
moel@176: 
moel@176:     private bool visible = false;
moel@183:     private bool lockPositionAndSize = false;
moel@176:     private bool alwaysOnTop = false;
moel@176:     private byte opacity = 255;
moel@176:     private Point location = new Point(100, 100);
moel@176:     private Size size = new Size(130, 84);
moel@176:     private ContextMenu contextMenu = null;
moel@176:     private MethodInfo commandDispatch;
moel@302:     private IntPtr handleBitmapDC;
moel@302:     private Size bufferSize;
moel@302:     private Graphics graphics;
moel@176: 
moel@176:     public GadgetWindow() {
moel@176:       Type commandType = 
moel@176:         typeof(Form).Assembly.GetType("System.Windows.Forms.Command");
moel@176:       commandDispatch = commandType.GetMethod("DispatchID", 
moel@176:         BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, 
moel@176:         null, new Type[]{ typeof(int) }, null);
moel@176: 
moel@176:       this.CreateHandle(CreateParams);
moel@176: 
moel@176:       // move window to the bottom
moel@176:       MoveToBottom(Handle);
moel@176: 
moel@176:       // prevent window from fading to a glass sheet when peek is invoked
moel@176:       try {
moel@176:         bool value = true;
moel@202:         NativeMethods.DwmSetWindowAttribute(Handle,
moel@176:           WindowAttribute.DWMWA_EXCLUDED_FROM_PEEK, ref value,
moel@176:           Marshal.SizeOf(value));
moel@176:       } catch (DllNotFoundException) { } catch (EntryPointNotFoundException) { }
moel@302: 
moel@302:       CreateBuffer();
moel@176:     }
moel@176: 
moel@176:     private void ShowDesktopChanged(bool showDesktop) {
moel@176:       if (showDesktop) {
moel@176:         MoveToTopMost(Handle);
moel@176:       } else {
moel@176:         MoveToBottom(Handle);
moel@176:       }
moel@176:     }
moel@176: 
moel@176:     private void MoveToBottom(IntPtr handle) {
moel@176:       NativeMethods.SetWindowPos(handle, HWND_BOTTOM, 0, 0, 0, 0,
moel@176:         SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
moel@176:     }
moel@176: 
moel@176:     private void MoveToTopMost(IntPtr handle) {
moel@176:       NativeMethods.SetWindowPos(handle, HWND_TOPMOST, 0, 0, 0, 0,
moel@176:         SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
moel@176:     }
moel@176: 
moel@176:     private void ShowContextMenu(Point position) {
moel@176:       NativeMethods.TrackPopupMenuEx(contextMenu.Handle, 
moel@176:         TPM_RIGHTBUTTON | TPM_VERTICAL, position.X,
moel@176:         position.Y, Handle, IntPtr.Zero);
moel@176:     }
moel@176: 
moel@176:     protected virtual CreateParams CreateParams {
moel@176:       get {
moel@183:         CreateParams cp = new CreateParams();        
moel@183:         cp.Width = 4096;
moel@183:         cp.Height = 4096;
moel@176:         cp.X = location.X;
moel@176:         cp.Y = location.Y;
moel@176:         cp.ExStyle = WS_EX_LAYERED | WS_EX_TOOLWINDOW;
moel@176:         return cp;
moel@176:       }
moel@176:     }
moel@176: 
moel@176:     protected override void WndProc(ref Message message) {
moel@176:       switch (message.Msg) {
moel@183:         case WM_COMMAND: {
moel@183:             // need to dispatch the message for the context menu
moel@183:             if (message.LParam == IntPtr.Zero)
moel@183:               commandDispatch.Invoke(null, new object[] { 
moel@183:               message.WParam.ToInt32() & 0xFFFF });
moel@183:           } break;
moel@183:         case WM_NCHITTEST: {
moel@183:             message.Result = (IntPtr)HitResult.Caption;
moel@183:             if (HitTest != null) {
moel@183:               Point p = new Point(
paulwerelds@208:                 Macros.GET_X_LPARAM(message.LParam) - location.X,
paulwerelds@208:                 Macros.GET_Y_LPARAM(message.LParam) - location.Y
paulwerelds@208:               );
moel@183:               HitTestEventArgs e = new HitTestEventArgs(p, HitResult.Caption);
moel@183:               HitTest(this, e);
moel@183:               message.Result = (IntPtr)e.HitResult;
moel@183:             }
moel@183:           } break;
moel@183:         case WM_NCLBUTTONDBLCLK: {
moel@244:             if (MouseDoubleClick != null) {
moel@244:               MouseDoubleClick(this, new MouseEventArgs(MouseButtons.Left, 2,
moel@244:                 Macros.GET_X_LPARAM(message.LParam) - location.X,
moel@244:                 Macros.GET_Y_LPARAM(message.LParam) - location.Y, 0));
moel@244:             }
moel@183:             message.Result = IntPtr.Zero;
moel@183:           } break;
moel@183:         case WM_NCRBUTTONDOWN: {
moel@183:             message.Result = IntPtr.Zero;
moel@183:           } break;
moel@183:         case WM_NCRBUTTONUP: {
moel@183:             if (contextMenu != null)
moel@183:               ShowContextMenu(new Point(
paulwerelds@209:                 Macros.GET_X_LPARAM(message.LParam),
paulwerelds@209:                 Macros.GET_Y_LPARAM(message.LParam)
paulwerelds@209:               ));
moel@183:             message.Result = IntPtr.Zero;
moel@183:           } break;
moel@183:         case WM_WINDOWPOSCHANGING: {
moel@183:             WindowPos wp = (WindowPos)Marshal.PtrToStructure(
moel@183:               message.LParam, typeof(WindowPos));
moel@183:             
moel@183:             if (!lockPositionAndSize) {
moel@183:               // prevent the window from leaving the screen
moel@183:               if ((wp.flags & SWP_NOMOVE) == 0) {
moel@243:                 Rectangle rect = Screen.GetWorkingArea(
moel@243:                   new Rectangle(wp.x, wp.y, wp.cx, wp.cy));
moel@183:                 const int margin = 16;
moel@183:                 wp.x = Math.Max(wp.x, rect.Left - wp.cx + margin);
moel@183:                 wp.x = Math.Min(wp.x, rect.Right - margin);
moel@183:                 wp.y = Math.Max(wp.y, rect.Top - wp.cy + margin);
moel@183:                 wp.y = Math.Min(wp.y, rect.Bottom - margin);
moel@183:               }
moel@176: 
moel@183:               // update location and fire event
moel@183:               if ((wp.flags & SWP_NOMOVE) == 0) {
moel@183:                 if (location.X != wp.x || location.Y != wp.y) {
moel@183:                   location = new Point(wp.x, wp.y);
moel@183:                   if (LocationChanged != null)
moel@183:                     LocationChanged(this, EventArgs.Empty);
moel@183:                 }
moel@183:               }
moel@176: 
moel@183:               // update size and fire event
moel@183:               if ((wp.flags & SWP_NOSIZE) == 0) {
moel@183:                 if (size.Width != wp.cx || size.Height != wp.cy) {
moel@183:                   size = new Size(wp.cx, wp.cy);
moel@183:                   if (SizeChanged != null)
moel@183:                     SizeChanged(this, EventArgs.Empty);
moel@183:                 }
moel@183:               } 
moel@176: 
moel@183:               // update the size of the layered window
moel@183:               if ((wp.flags & SWP_NOSIZE) == 0) {
moel@183:                 NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero,
moel@183:                   IntPtr.Zero, ref size, IntPtr.Zero, IntPtr.Zero, 0,
moel@183:                   IntPtr.Zero, 0);                
moel@183:               }
moel@183: 
moel@183:               // update the position of the layered window
moel@183:               if ((wp.flags & SWP_NOMOVE) == 0) {
moel@183:                 NativeMethods.SetWindowPos(Handle, IntPtr.Zero, 
moel@183:                   location.X, location.Y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | 
moel@183:                   SWP_NOZORDER | SWP_NOSENDCHANGING);
moel@183:               }
moel@176:             }
moel@183:             
moel@183:             // do not forward any move or size messages
moel@243:             wp.flags |= SWP_NOSIZE | SWP_NOMOVE;
moel@243: 
moel@243:             // suppress any frame changed events
moel@243:             wp.flags &= ~SWP_FRAMECHANGED;
moel@243: 
moel@183:             Marshal.StructureToPtr(wp, message.LParam, false);                      
moel@183:             message.Result = IntPtr.Zero;
moel@183:           } break;
moel@183:         default: {
moel@183:             base.WndProc(ref message);
moel@183:           } break;
moel@176:       }      
moel@176:     }
moel@176: 
moel@176:     private BlendFunction CreateBlendFunction() {
moel@176:       BlendFunction blend = new BlendFunction();
moel@176:       blend.BlendOp = AC_SRC_OVER;
moel@176:       blend.BlendFlags = 0;
moel@176:       blend.SourceConstantAlpha = opacity;
moel@176:       blend.AlphaFormat = AC_SRC_ALPHA;
moel@176:       return blend;
moel@176:     }
moel@176: 
moel@302:     private void CreateBuffer() {      
moel@302:       IntPtr handleScreenDC = NativeMethods.GetDC(IntPtr.Zero);
moel@302:       handleBitmapDC = NativeMethods.CreateCompatibleDC(handleScreenDC);
moel@302:       NativeMethods.ReleaseDC(IntPtr.Zero, handleScreenDC);
moel@302:       bufferSize = size;
moel@176: 
moel@302:       BitmapInfo info = new BitmapInfo();
moel@302:       info.Size = Marshal.SizeOf(info);
moel@302:       info.Width = size.Width;
moel@302:       info.Height = -size.Height;
moel@302:       info.BitCount = 32;
moel@302:       info.Planes = 1;
moel@302: 
moel@302:       IntPtr ptr;
moel@302:       IntPtr hBmp = NativeMethods.CreateDIBSection(handleBitmapDC, ref info, 0, 
moel@302:         out ptr, IntPtr.Zero, 0);
moel@302:       IntPtr hBmpOld = NativeMethods.SelectObject(handleBitmapDC, hBmp);
moel@302:       NativeMethods.DeleteObject(hBmpOld);
moel@302:       
moel@302:       graphics = Graphics.FromHdc(handleBitmapDC);
moel@302: 
moel@302:       if (Environment.OSVersion.Version.Major > 5) {
moel@302:         this.graphics.TextRenderingHint = TextRenderingHint.SystemDefault;
moel@302:         this.graphics.SmoothingMode = SmoothingMode.HighQuality;
moel@302:       } 
moel@302:     }
moel@302: 
moel@302:     private void DisposeBuffer() {
moel@302:       graphics.Dispose();
moel@302:       NativeMethods.DeleteDC(handleBitmapDC);
moel@302:     }
moel@302: 
moel@302:     public virtual void Dispose() {
moel@302:       DisposeBuffer();
moel@302:     } 
moel@302: 
moel@302:     public PaintEventHandler Paint; 
moel@302: 
moel@302:     public void Redraw() {
moel@302:       if (!visible || Paint == null)
moel@302:         return;
moel@302: 
moel@302:       if (size != bufferSize) {
moel@302:         DisposeBuffer();
moel@302:         CreateBuffer();
moel@302:       }
moel@302: 
moel@302:       Paint(this, 
moel@302:         new PaintEventArgs(graphics, new Rectangle(Point.Empty, size))); 
moel@176: 
moel@176:         Point pointSource = Point.Empty;
moel@183:         BlendFunction blend = CreateBlendFunction();
moel@176: 
moel@302:         NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero, IntPtr.Zero,
moel@302:           ref size, handleBitmapDC, ref pointSource, 0, ref blend, ULW_ALPHA);
moel@183: 
moel@183:         // make sure the window is at the right location
moel@302:         NativeMethods.SetWindowPos(Handle, IntPtr.Zero,
moel@302:           location.X, location.Y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE |
moel@183:           SWP_NOZORDER | SWP_NOSENDCHANGING);
moel@176:     }
moel@176: 
moel@176:     public byte Opacity {
moel@176:       get {
moel@176:         return opacity;
moel@176:       }
moel@176:       set {
moel@176:         if (opacity != value) {
moel@176:           opacity = value;
moel@176:           BlendFunction blend = CreateBlendFunction();
moel@176:           NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero, IntPtr.Zero,
moel@176:             IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, ref blend, ULW_ALPHA);
moel@176:         }
moel@176:       }
moel@176:     }
moel@176: 
moel@176:     public bool Visible {
moel@176:       get {
moel@176:         return visible;
moel@176:       }
moel@176:       set {
moel@176:         if (visible != value) {
moel@176:           visible = value;
moel@176:           NativeMethods.SetWindowPos(Handle, IntPtr.Zero, 0, 0, 0, 0,
moel@176:             SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER |
moel@176:             (value ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
moel@180:           if (value) {
moel@180:             if (!alwaysOnTop)
moel@180:               ShowDesktop.Instance.ShowDesktopChanged += ShowDesktopChanged;
moel@180:           } else {
moel@180:             if (!alwaysOnTop)
moel@180:               ShowDesktop.Instance.ShowDesktopChanged -= ShowDesktopChanged;
moel@180:           }
moel@176:         }
moel@176:       }
moel@176:     }
moel@176: 
moel@183:     // if locked, the window can not be moved or resized
moel@183:     public bool LockPositionAndSize {
moel@176:       get {
moel@183:         return lockPositionAndSize;
moel@176:       }
moel@176:       set {
moel@183:         lockPositionAndSize = value;
moel@176:       }
moel@176:     }
moel@176: 
moel@176:     public bool AlwaysOnTop {
moel@176:       get {
moel@176:         return alwaysOnTop;
moel@176:       }
moel@176:       set {
moel@176:         if (value != alwaysOnTop) {
moel@176:           alwaysOnTop = value;
moel@176:           if (alwaysOnTop) {
moel@180:             if (visible)
moel@180:               ShowDesktop.Instance.ShowDesktopChanged -= ShowDesktopChanged;
moel@176:             MoveToTopMost(Handle);            
moel@176:           } else {
moel@176:             MoveToBottom(Handle);
moel@180:             if (visible)
moel@180:               ShowDesktop.Instance.ShowDesktopChanged += ShowDesktopChanged;
moel@176:           }
moel@176:         }
moel@176:       }
moel@176:     }
moel@176: 
moel@176:     public Size Size {
moel@176:       get {
moel@176:         return size; 
moel@176:       }
moel@176:       set {
moel@176:         if (size != value) {
moel@176:           size = value;
moel@183:           NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero, IntPtr.Zero,
moel@183:             ref size, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, 0);                    
moel@183:           if (SizeChanged != null)
moel@183:             SizeChanged(this, EventArgs.Empty);
moel@176:         }
moel@176:       }
moel@176:     }
moel@176: 
moel@183:     public event EventHandler SizeChanged;
moel@183: 
moel@176:     public Point Location {
moel@176:       get {
moel@176:         return location;
moel@176:       }
moel@176:       set {
moel@183:         if (location != value) {
moel@183:           location = value;
moel@183:           NativeMethods.SetWindowPos(Handle, IntPtr.Zero, 
moel@183:             location.X, location.Y, 0, 0, 
moel@183:             SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING);          
moel@183:           if (LocationChanged != null)
moel@183:             LocationChanged(this, EventArgs.Empty);
moel@183:         }
moel@176:       }
moel@176:     }
moel@176: 
moel@176:     public event EventHandler LocationChanged;
moel@176: 
moel@176:     public ContextMenu ContextMenu {
moel@176:       get {
moel@176:         return contextMenu;
moel@176:       }
moel@176:       set {
moel@176:         this.contextMenu = value;
moel@176:       }
moel@176:     }
moel@176: 
moel@183:     public event HitTestEventHandler HitTest;
moel@183: 
moel@244:     public event MouseEventHandler MouseDoubleClick;
moel@244: 
moel@176:     [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@176:     private struct BlendFunction {
moel@176:       public byte BlendOp;
moel@176:       public byte BlendFlags;
moel@176:       public byte SourceConstantAlpha;
moel@176:       public byte AlphaFormat;
moel@176:     }
moel@176: 
moel@176:     [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@176:     private struct WindowPos {
moel@176:       public IntPtr hwnd;
moel@176:       public IntPtr hwndInsertAfter;
moel@176:       public int x;
moel@176:       public int y;
moel@176:       public int cx;
moel@176:       public int cy;
moel@176:       public uint flags;
moel@176:     }
moel@176: 
moel@302:     [StructLayout(LayoutKind.Sequential)]
moel@302:     public struct BitmapInfo {
moel@302:       public Int32 Size;
moel@302:       public Int32 Width;
moel@302:       public Int32 Height;
moel@302:       public Int16 Planes;
moel@302:       public Int16 BitCount;
moel@302:       public Int32 Compression;
moel@302:       public Int32 SizeImage;
moel@302:       public Int32 XPelsPerMeter;
moel@302:       public Int32 YPelsPerMeter;
moel@302:       public Int32 ClrUsed;
moel@302:       public Int32 ClrImportant;
moel@302:       public Int32 Colors;
moel@302:     }
moel@302: 
moel@176:     public static readonly IntPtr HWND_BOTTOM = (IntPtr)1;
moel@176:     public static readonly IntPtr HWND_TOPMOST = (IntPtr)(-1);
moel@176: 
moel@176:     public const int WS_EX_LAYERED = 0x00080000;
moel@176:     public const int WS_EX_TOOLWINDOW = 0x00000080;
moel@176: 
moel@176:     public const uint SWP_NOSIZE = 0x0001;
moel@176:     public const uint SWP_NOMOVE = 0x0002;
moel@176:     public const uint SWP_NOACTIVATE = 0x0010;
moel@243:     public const uint SWP_FRAMECHANGED = 0x0020;
moel@176:     public const uint SWP_HIDEWINDOW = 0x0080;
moel@176:     public const uint SWP_SHOWWINDOW = 0x0040;
moel@176:     public const uint SWP_NOZORDER = 0x0004;
moel@176:     public const uint SWP_NOSENDCHANGING = 0x0400;
moel@176: 
moel@176:     public const int ULW_COLORKEY = 0x00000001;
moel@176:     public const int ULW_ALPHA = 0x00000002;
moel@176:     public const int ULW_OPAQUE = 0x00000004;
moel@176: 
moel@176:     public const byte AC_SRC_OVER = 0x00;
moel@176:     public const byte AC_SRC_ALPHA = 0x01;
moel@176: 
moel@176:     public const int WM_NCHITTEST = 0x0084;
moel@176:     public const int WM_NCLBUTTONDBLCLK = 0x00A3;
moel@176:     public const int WM_NCLBUTTONDOWN = 0x00A1;
moel@176:     public const int WM_NCLBUTTONUP = 0x00A2;
moel@176:     public const int WM_NCRBUTTONDOWN = 0x00A4;
moel@176:     public const int WM_NCRBUTTONUP = 0x00A5;
moel@176:     public const int WM_WINDOWPOSCHANGING = 0x0046;
moel@176:     public const int WM_COMMAND = 0x0111;
moel@176: 
moel@176:     public const int TPM_RIGHTBUTTON = 0x0002;
moel@176:     public const int TPM_VERTICAL = 0x0040;
moel@176: 
moel@176:     private enum WindowAttribute : int {
moel@176:       DWMWA_NCRENDERING_ENABLED = 1,
moel@176:       DWMWA_NCRENDERING_POLICY,
moel@176:       DWMWA_TRANSITIONS_FORCEDISABLED,
moel@176:       DWMWA_ALLOW_NCPAINT,
moel@176:       DWMWA_CAPTION_BUTTON_BOUNDS,
moel@176:       DWMWA_NONCLIENT_RTL_LAYOUT,
moel@176:       DWMWA_FORCE_ICONIC_REPRESENTATION,
moel@176:       DWMWA_FLIP3D_POLICY,
moel@176:       DWMWA_EXTENDED_FRAME_BOUNDS,
moel@176:       DWMWA_HAS_ICONIC_BITMAP,
moel@176:       DWMWA_DISALLOW_PEEK,
moel@176:       DWMWA_EXCLUDED_FROM_PEEK,
moel@176:       DWMWA_LAST
moel@176:     }
moel@176: 
paulwerelds@208:     /// <summary>
paulwerelds@208:     /// Some macros imported and converted from the Windows SDK
paulwerelds@208:     /// </summary>
paulwerelds@208:     private static class Macros {
paulwerelds@210:       public static ushort LOWORD(IntPtr l) {
paulwerelds@210:         return (ushort) ((ulong)l & 0xFFFF);
paulwerelds@208:       }
paulwerelds@208:       
paulwerelds@208:       public static UInt16 HIWORD(IntPtr l) {
paulwerelds@210:         return (ushort) (((ulong)l >> 16) & 0xFFFF);
paulwerelds@208:       }
paulwerelds@208: 
paulwerelds@208:       public static int GET_X_LPARAM(IntPtr lp) {
paulwerelds@210:         return (short) LOWORD(lp);
paulwerelds@208:       }
paulwerelds@208: 
paulwerelds@208:       public static int GET_Y_LPARAM(IntPtr lp) {
paulwerelds@210:         return (short) HIWORD(lp);
paulwerelds@208:       }
paulwerelds@208:     }
paulwerelds@208: 
paulwerelds@208:     /// <summary>
paulwerelds@208:     /// Imported native methods
paulwerelds@208:     /// </summary>
moel@176:     private static class NativeMethods {
moel@176:       private const string USER = "user32.dll";
moel@176:       private const string GDI = "gdi32.dll";
moel@176:       public const string DWMAPI = "dwmapi.dll";
moel@176: 
moel@176:       [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
moel@176:       [return: MarshalAs(UnmanagedType.Bool)]
moel@183:       public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst,
moel@183:         IntPtr pptDst, ref Size psize, IntPtr hdcSrc, IntPtr pprSrc,
moel@183:         int crKey, IntPtr pblend, int dwFlags);
moel@183: 
moel@183:       [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
moel@183:       [return: MarshalAs(UnmanagedType.Bool)]
moel@176:       public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, 
moel@183:         IntPtr pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, 
moel@176:         int crKey, ref BlendFunction pblend, int dwFlags);
moel@176: 
moel@176:       [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
moel@176:       [return: MarshalAs(UnmanagedType.Bool)]
moel@176:       public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst,
moel@176:         IntPtr pptDst, IntPtr psize, IntPtr hdcSrc, IntPtr pprSrc,
moel@176:         int crKey, ref BlendFunction pblend, int dwFlags);  
moel@176: 
moel@176:       [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
moel@176:       public static extern IntPtr GetDC(IntPtr hWnd);
moel@176: 
moel@176:       [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
moel@176:       public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
moel@176: 
moel@176:       [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
moel@176:       public static extern bool SetWindowPos(IntPtr hWnd,
moel@176:         IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
moel@176: 
moel@176:       [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
moel@176:       public static extern bool TrackPopupMenuEx(IntPtr hMenu, uint uFlags, 
moel@176:         int x, int y, IntPtr hWnd, IntPtr tpmParams);
moel@176: 
moel@176:       [DllImport(GDI, CallingConvention = CallingConvention.Winapi)]
moel@176:       public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
moel@176: 
moel@176:       [DllImport(GDI, CallingConvention = CallingConvention.Winapi)]
moel@302:       public static extern IntPtr CreateDIBSection(IntPtr hdc, 
moel@302:         [In] ref BitmapInfo pbmi, uint pila, out IntPtr ppvBits, 
moel@302:         IntPtr hSection, uint dwOffset);
moel@302: 
moel@302:       [DllImport(GDI, CallingConvention = CallingConvention.Winapi)]
moel@176:       [return: MarshalAs(UnmanagedType.Bool)]
moel@176:       public static extern bool DeleteDC(IntPtr hdc);
moel@176:       
moel@176:       [DllImport(GDI, CallingConvention = CallingConvention.Winapi)]
moel@176:       public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
moel@176: 
moel@176:       [DllImport(GDI, CallingConvention = CallingConvention.Winapi)]
moel@176:       [return: MarshalAs(UnmanagedType.Bool)]
moel@176:       public static extern bool DeleteObject(IntPtr hObject);
moel@176: 
moel@176:       [DllImport(DWMAPI, CallingConvention = CallingConvention.Winapi)]
moel@176:       public static extern int DwmSetWindowAttribute(IntPtr hwnd,
moel@176:         WindowAttribute dwAttribute, ref bool pvAttribute, int cbAttribute);
moel@176:     }    
moel@176:   }
moel@183: 
moel@183:   public enum HitResult {
moel@183:     Transparent = -1,
moel@183:     Nowhere = 0,
moel@183:     Client = 1,
moel@183:     Caption = 2,
moel@183:     Left = 10,
moel@183:     Right = 11,
moel@183:     Top = 12,
moel@183:     TopLeft = 13,
moel@183:     TopRight = 14,
moel@183:     Bottom = 15,
moel@183:     BottomLeft = 16,
moel@183:     BottomRight = 17,
moel@183:     Border = 18
moel@183:   }
moel@183: 
moel@183:   public delegate void HitTestEventHandler(object sender, HitTestEventArgs e);
moel@183: 
moel@183:   public class HitTestEventArgs : EventArgs {
moel@183:     public HitTestEventArgs(Point location, HitResult hitResult) {
moel@183:       Location = location;
moel@183:       HitResult = hitResult;
moel@183:     }
moel@183:     public Point Location { get; private set; }
moel@183:     public HitResult HitResult { get; set; }
moel@183:   }
moel@176: }