/Platters/classes/genericLayeredForm.cs

http://skimpt.googlecode.com/ · C# · 428 lines · 307 code · 70 blank · 51 comment · 23 complexity · fce238b42f5a3542e28b1e9a3a2a563f MD5 · raw file

  1. #region "License Agreement"
  2. /* Skimpt, an open source screenshot utility.
  3. Copyright (C) <year> <name of author>
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. this program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  14. #endregion
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Drawing;
  18. using System.Windows.Forms;
  19. using System.Diagnostics;
  20. using System.ComponentModel;
  21. using System.Drawing.Imaging;
  22. using System.Runtime.InteropServices;
  23. public class LayeredForm : Form
  24. {
  25. [Category("Appearance"),
  26. Description("Occurs when the layered form needs repainting.")]
  27. protected event EventHandler<PaintLayerEventArgs> PaintLayer;
  28. #region Member Fields
  29. private bool freezePainting;
  30. private double layerOpacity = 1.0;
  31. #endregion
  32. #region Property Accessors
  33. public double LayerOpacity
  34. {
  35. get { return layerOpacity; }
  36. set
  37. {
  38. if (value > 1)
  39. value = 1;
  40. else if (value < 0)
  41. value = 0;
  42. layerOpacity = value;
  43. PaintLayeredWindow();
  44. }
  45. }
  46. private byte OpacityAsByte
  47. {
  48. get { return ((byte)(layerOpacity * 255)); }
  49. }
  50. protected bool FreezePainting
  51. {
  52. get { return freezePainting; }
  53. set
  54. {
  55. if (value == false)
  56. PaintLayeredWindow();
  57. freezePainting = value;
  58. }
  59. }
  60. #endregion
  61. #region .ctor
  62. protected LayeredForm()
  63. {
  64. FormBorderStyle = FormBorderStyle.None;
  65. ShowInTaskbar = false;
  66. StartPosition = FormStartPosition.Manual;
  67. }
  68. #endregion
  69. #region Painting Methods
  70. /// <summary>
  71. /// Raises the <see cref="PaintLayer"/> event.
  72. /// </summary>
  73. /// <param name="e">A <see cref="PaintLayerEventArgs"/> object containing the
  74. /// event data.</param>
  75. protected virtual void OnPaintLayer(PaintLayerEventArgs e)
  76. {
  77. EventHandler<PaintLayerEventArgs> handler = PaintLayer;
  78. if (!DesignMode && (handler != null))
  79. PaintLayer(this, e);
  80. }
  81. protected void PaintLayeredWindow()
  82. {
  83. if (Bounds.Size != Size.Empty)
  84. {
  85. using (Bitmap surface = new Bitmap(ClientRectangle.Width, ClientRectangle.Height, PixelFormat.Format32bppArgb))
  86. PaintLayeredWindow(surface, layerOpacity);
  87. }
  88. }
  89. protected void PaintLayeredWindow(Bitmap bitmap, double opacity)
  90. {
  91. if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
  92. throw new ArgumentException("The bitmap must be 32bpp with an alpha-channel.", "bitmap");
  93. layerOpacity = opacity;
  94. using (PaintLayerEventArgs args = new PaintLayerEventArgs(bitmap))
  95. {
  96. OnPaintLayer(args);
  97. PaintNative(bitmap, OpacityAsByte);
  98. }
  99. }
  100. private void PaintNative(Bitmap bitmap, byte opacity)
  101. {
  102. IntPtr hdcDestination = NativeMethods.GetDC(IntPtr.Zero);
  103. IntPtr hdcSource = NativeMethods.CreateCompatibleDC(hdcDestination);
  104. IntPtr hdcBitmap = IntPtr.Zero;
  105. IntPtr previousBitmap = IntPtr.Zero;
  106. try
  107. {
  108. hdcBitmap = bitmap.GetHbitmap(Color.FromArgb(0));
  109. previousBitmap = NativeMethods.SelectObject(hdcSource, hdcBitmap);
  110. NativeMethods.SIZE size = new NativeMethods.SIZE(bitmap.Width, bitmap.Height);
  111. NativeMethods.POINT source = new NativeMethods.POINT(0, 0);
  112. NativeMethods.POINT destination = new NativeMethods.POINT(Left, Top);
  113. NativeMethods.BLENDFUNCTION blend = new NativeMethods.BLENDFUNCTION();
  114. blend.BlendOp = NativeMethods.AC_SRC_OVER;
  115. blend.BlendFlags = 0;
  116. blend.SourceConstantAlpha = opacity;
  117. blend.AlphaFormat = NativeMethods.AC_SRC_ALPHA;
  118. NativeMethods.UpdateLayeredWindow(
  119. Handle,
  120. hdcDestination,
  121. ref destination,
  122. ref size,
  123. hdcSource,
  124. ref source,
  125. 0,
  126. ref blend,
  127. 2);
  128. }
  129. catch (Exception)
  130. {
  131. return;
  132. }
  133. finally
  134. {
  135. NativeMethods.ReleaseDC(IntPtr.Zero, hdcDestination);
  136. if (hdcBitmap != IntPtr.Zero)
  137. {
  138. NativeMethods.SelectObject(hdcSource, previousBitmap);
  139. NativeMethods.DeleteObject(hdcBitmap);
  140. }
  141. NativeMethods.DeleteDC(hdcSource);
  142. }
  143. }
  144. #endregion
  145. #region Method Overrides
  146. protected override void OnResize(EventArgs e)
  147. {
  148. if (!freezePainting)
  149. {
  150. PaintLayeredWindow();
  151. base.OnResize(e);
  152. }
  153. }
  154. #endregion
  155. #region Windows Message Handling
  156. protected override CreateParams CreateParams
  157. {
  158. get
  159. {
  160. CreateParams cParams = base.CreateParams;
  161. cParams.ExStyle |= NativeMethods.WS_EX_LAYERED;
  162. return cParams;
  163. }
  164. }
  165. #endregion
  166. protected override void OnPaintBackground(PaintEventArgs pevent)
  167. {
  168. // Eat event to prevent rendering error when WM_PAINT message
  169. // is sent.
  170. }
  171. }
  172. public class PaintLayerEventArgs : EventArgs, IDisposable
  173. {
  174. #region Member Fields
  175. private readonly Graphics graphics;
  176. private readonly Bitmap surface;
  177. private readonly Size size;
  178. #endregion
  179. #region Property Accessors
  180. /// <summary>
  181. /// Gets the bounds.
  182. /// </summary>
  183. /// <value>The bounds.</value>
  184. public Rectangle Bounds
  185. {
  186. get { return new Rectangle(Point.Empty, Size); }
  187. }
  188. /// <summary>
  189. /// Gets the size.
  190. /// </summary>
  191. /// <value>The size.</value>
  192. public Size Size
  193. {
  194. get { return size; }
  195. }
  196. /// <summary>
  197. /// Gets the graphics.
  198. /// </summary>
  199. /// <value>The graphics.</value>
  200. public Graphics Graphics
  201. {
  202. get { return graphics; }
  203. }
  204. /// <summary>
  205. /// Gets the image.
  206. /// </summary>
  207. /// <value>The image.</value>
  208. internal Bitmap Image
  209. {
  210. get { return surface; }
  211. }
  212. #endregion
  213. /// <summary>
  214. /// Initializes a new instance of the <see cref="PaintLayerEventArgs"/> class.
  215. /// </summary>
  216. public PaintLayerEventArgs() { }
  217. /// <summary>
  218. /// Initializes a new instance of the <see cref="PaintLayerEventArgs"/> class.
  219. /// </summary>
  220. /// <param name="bitmap">The bitmap.</param>
  221. internal PaintLayerEventArgs(Bitmap bitmap)
  222. {
  223. surface = bitmap;
  224. graphics = Graphics.FromImage(surface);
  225. //graphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
  226. size = new Size(bitmap.Width, bitmap.Height);
  227. }
  228. /// <summary>
  229. /// Disposes this instance.
  230. /// </summary>
  231. public void Dispose()
  232. {
  233. if (graphics != null)
  234. graphics.Dispose();
  235. if (surface != null)
  236. surface.Dispose();
  237. }
  238. }
  239. internal sealed class NativeMethods
  240. {
  241. //============== GDI32 CONSTANTS ===============
  242. public const Int32 CAPTUREBLT = 0x40000000;
  243. public const Int32 BLACKNESS = 0x42;
  244. public const Int32 DSTINVERT = 0x550009;
  245. public const Int32 MERGECOPY = 0xc000ca;
  246. public const Int32 MERGEPAINT = 0xbb0226;
  247. public const Int32 NOTSRCCOPY = 0x330008;
  248. public const Int32 NOTSRCERASE = 0x1100a6;
  249. public const Int32 PATCOPY = 0xf00021;
  250. public const Int32 PATINVERT = 0x5a0049;
  251. public const Int32 PATPAINT = 0xfb0a09;
  252. public const Int32 SRCAND = 0x8800c6;
  253. public const Int32 SRCCOPY = 0xcc0020;
  254. public const Int32 SRCERASE = 0x440328;
  255. public const Int32 SRCINVERT = 0x660046;
  256. public const Int32 SRCPAINT = 0xee0086;
  257. public const Int32 WHITENESS = 0xff0062;
  258. public const Int32 HORZRES = 8;
  259. public const Int32 VERTRES = 10;
  260. //===========================================
  261. private NativeMethods() { }
  262. [DllImport("user32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
  263. [return: MarshalAs(UnmanagedType.Bool)]
  264. internal static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vic);
  265. [DllImport("user32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
  266. [return: MarshalAs(UnmanagedType.Bool)]
  267. internal static extern bool UnregisterHotKey(IntPtr hWnd, int id);
  268. [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
  269. internal static extern ushort GlobalAddAtom(string lpString);
  270. [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
  271. internal static extern ushort GlobalDeleteAtom(ushort nAtom);
  272. [DllImport("gdi32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
  273. internal static extern IntPtr CreateCompatibleDC(IntPtr hdc);
  274. [DllImport("user32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
  275. internal static extern IntPtr GetDC(IntPtr hWnd);
  276. [DllImport("user32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
  277. internal static extern int ReleaseDC(IntPtr hWnd, IntPtr hdc);
  278. [DllImport("user32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
  279. [return: MarshalAs(UnmanagedType.Bool)]
  280. internal static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref POINT pptDst, ref SIZE psize, IntPtr hdcSrc, ref POINT pprSrc, int crKey, ref BLENDFUNCTION pblend, int dwFlags);
  281. [DllImport("gdi32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
  282. internal static extern IntPtr SelectObject(IntPtr hdc, IntPtr hObject);
  283. [DllImport("user32.dll", CharSet = CharSet.Ansi, SetLastError = false)]
  284. internal static extern int SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam);
  285. [DllImport("user32.dll", CharSet = CharSet.Ansi, SetLastError = false)]
  286. internal static extern int SendMessage(IntPtr hWnd, int msg, int wParam, string lParam);
  287. [DllImport("user32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
  288. internal static extern IntPtr GetWindow(IntPtr hwnd, int cmd);
  289. [DllImport("gdi32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
  290. [return: MarshalAs(UnmanagedType.Bool)]
  291. internal static extern bool DeleteDC(IntPtr hdc);
  292. [DllImport("gdi32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
  293. [return: MarshalAs(UnmanagedType.Bool)]
  294. internal static extern bool DeleteObject(IntPtr hObject);
  295. [DllImport("gdi32", SetLastError = true)]
  296. [return: MarshalAs(UnmanagedType.Bool)]
  297. public static extern bool BitBlt(IntPtr hdcDest, Int32 nXDest, Int32 nYDest, Int32 nWidth, Int32 nHeight, IntPtr hdcSrc, Int32 nXSrc, Int32 nYSrc, Int32 dwRop);
  298. internal const Int32 WM_SETICON = 0x80;
  299. internal const Int32 WM_SETTEXT = 0x000c;
  300. internal const Int32 GW_OWNER = 4;
  301. internal const Int32 ICON_SMALL = 0;
  302. internal const Int32 ICON_BIG = 1;
  303. internal const Int32 WS_EX_LAYERED = 0x80000;
  304. internal const Int32 WM_HOTKEY = 0x0312;
  305. internal const Byte AC_SRC_OVER = 0x00;
  306. internal const Byte AC_SRC_ALPHA = 0x01;
  307. [StructLayout(LayoutKind.Sequential, Pack = 1)]
  308. internal struct BLENDFUNCTION
  309. {
  310. public byte BlendOp;
  311. public byte BlendFlags;
  312. public byte SourceConstantAlpha;
  313. public byte AlphaFormat;
  314. }
  315. [StructLayout(LayoutKind.Sequential)]
  316. internal struct POINT
  317. {
  318. public int X;
  319. public int Y;
  320. public POINT(int x, int y)
  321. {
  322. X = x;
  323. Y = y;
  324. }
  325. public static explicit operator POINT(Point pt)
  326. {
  327. return new POINT(pt.X, pt.Y);
  328. }
  329. }
  330. [StructLayout(LayoutKind.Sequential)]
  331. internal struct SIZE
  332. {
  333. public int Width;
  334. public int Height;
  335. public SIZE(int w, int h)
  336. {
  337. Width = w;
  338. Height = h;
  339. }
  340. }
  341. internal static IntPtr GetTopLevelOwner(IntPtr hWnd)
  342. {
  343. IntPtr hwndOwner = hWnd;
  344. IntPtr hwndCurrent = hWnd;
  345. while (hwndCurrent != (IntPtr)0)
  346. {
  347. hwndCurrent = GetWindow(hwndCurrent, GW_OWNER);
  348. if (hwndCurrent != (IntPtr)0)
  349. {
  350. hwndOwner = hwndCurrent;
  351. }
  352. }
  353. return hwndOwner;
  354. }
  355. }