Added the hard drive firmware version to the report. This could be important if the SMART attribute layout changes with firmware versions on some drives.
     3   Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
     5   The contents of this file are subject to the Mozilla Public License Version
 
     6   1.1 (the "License"); you may not use this file except in compliance with
 
     7   the License. You may obtain a copy of the License at
 
     9   http://www.mozilla.org/MPL/
 
    11   Software distributed under the License is distributed on an "AS IS" basis,
 
    12   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
    13   for the specific language governing rights and limitations under the License.
 
    15   The Original Code is the Open Hardware Monitor code.
 
    17   The Initial Developer of the Original Code is 
 
    18   Michael Möller <m.moeller@gmx.ch>.
 
    19   Portions created by the Initial Developer are Copyright (C) 2010-2011
 
    20   the Initial Developer. All Rights Reserved.
 
    24   Alternatively, the contents of this file may be used under the terms of
 
    25   either the GNU General Public License Version 2 or later (the "GPL"), or
 
    26   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
    27   in which case the provisions of the GPL or the LGPL are applicable instead
 
    28   of those above. If you wish to allow use of your version of this file only
 
    29   under the terms of either the GPL or the LGPL, and not to allow others to
 
    30   use your version of this file under the terms of the MPL, indicate your
 
    31   decision by deleting the provisions above and replace them with the notice
 
    32   and other provisions required by the GPL or the LGPL. If you do not delete
 
    33   the provisions above, a recipient may use your version of this file under
 
    34   the terms of any one of the MPL, the GPL or the LGPL.
 
    40 using System.Drawing.Drawing2D;
 
    41 using System.Drawing.Text;
 
    42 using System.Reflection;
 
    43 using System.Runtime.InteropServices;
 
    44 using System.Windows.Forms;
 
    46 namespace OpenHardwareMonitor.GUI {
 
    48   public class GadgetWindow : NativeWindow, IDisposable {
 
    50     private bool visible = false;
 
    51     private bool lockPositionAndSize = false;
 
    52     private bool alwaysOnTop = false;
 
    53     private byte opacity = 255;
 
    54     private Point location = new Point(100, 100);
 
    55     private Size size = new Size(130, 84);
 
    56     private ContextMenu contextMenu = null;
 
    57     private MethodInfo commandDispatch;
 
    58     private IntPtr handleBitmapDC;
 
    59     private Size bufferSize;
 
    60     private Graphics graphics;
 
    62     public GadgetWindow() {
 
    64         typeof(Form).Assembly.GetType("System.Windows.Forms.Command");
 
    65       commandDispatch = commandType.GetMethod("DispatchID", 
 
    66         BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, 
 
    67         null, new Type[]{ typeof(int) }, null);
 
    69       this.CreateHandle(CreateParams);
 
    71       // move window to the bottom
 
    74       // prevent window from fading to a glass sheet when peek is invoked
 
    77         NativeMethods.DwmSetWindowAttribute(Handle,
 
    78           WindowAttribute.DWMWA_EXCLUDED_FROM_PEEK, ref value,
 
    79           Marshal.SizeOf(value));
 
    80       } catch (DllNotFoundException) { } catch (EntryPointNotFoundException) { }
 
    85     private void ShowDesktopChanged(bool showDesktop) {
 
    87         MoveToTopMost(Handle);
 
    93     private void MoveToBottom(IntPtr handle) {
 
    94       NativeMethods.SetWindowPos(handle, HWND_BOTTOM, 0, 0, 0, 0,
 
    95         SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
 
    98     private void MoveToTopMost(IntPtr handle) {
 
    99       NativeMethods.SetWindowPos(handle, HWND_TOPMOST, 0, 0, 0, 0,
 
   100         SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
 
   103     private void ShowContextMenu(Point position) {
 
   104       NativeMethods.TrackPopupMenuEx(contextMenu.Handle, 
 
   105         TPM_RIGHTBUTTON | TPM_VERTICAL, position.X,
 
   106         position.Y, Handle, IntPtr.Zero);
 
   109     protected virtual CreateParams CreateParams {
 
   111         CreateParams cp = new CreateParams();        
 
   116         cp.ExStyle = WS_EX_LAYERED | WS_EX_TOOLWINDOW;
 
   121     protected override void WndProc(ref Message message) {
 
   122       switch (message.Msg) {
 
   124             // need to dispatch the message for the context menu
 
   125             if (message.LParam == IntPtr.Zero)
 
   126               commandDispatch.Invoke(null, new object[] { 
 
   127               message.WParam.ToInt32() & 0xFFFF });
 
   130             message.Result = (IntPtr)HitResult.Caption;
 
   131             if (HitTest != null) {
 
   133                 Macros.GET_X_LPARAM(message.LParam) - location.X,
 
   134                 Macros.GET_Y_LPARAM(message.LParam) - location.Y
 
   136               HitTestEventArgs e = new HitTestEventArgs(p, HitResult.Caption);
 
   138               message.Result = (IntPtr)e.HitResult;
 
   141         case WM_NCLBUTTONDBLCLK: {
 
   142             if (MouseDoubleClick != null) {
 
   143               MouseDoubleClick(this, new MouseEventArgs(MouseButtons.Left, 2,
 
   144                 Macros.GET_X_LPARAM(message.LParam) - location.X,
 
   145                 Macros.GET_Y_LPARAM(message.LParam) - location.Y, 0));
 
   147             message.Result = IntPtr.Zero;
 
   149         case WM_NCRBUTTONDOWN: {
 
   150             message.Result = IntPtr.Zero;
 
   152         case WM_NCRBUTTONUP: {
 
   153             if (contextMenu != null)
 
   154               ShowContextMenu(new Point(
 
   155                 Macros.GET_X_LPARAM(message.LParam),
 
   156                 Macros.GET_Y_LPARAM(message.LParam)
 
   158             message.Result = IntPtr.Zero;
 
   160         case WM_WINDOWPOSCHANGING: {
 
   161             WindowPos wp = (WindowPos)Marshal.PtrToStructure(
 
   162               message.LParam, typeof(WindowPos));
 
   164             if (!lockPositionAndSize) {
 
   165               // prevent the window from leaving the screen
 
   166               if ((wp.flags & SWP_NOMOVE) == 0) {
 
   167                 Rectangle rect = Screen.GetWorkingArea(
 
   168                   new Rectangle(wp.x, wp.y, wp.cx, wp.cy));
 
   169                 const int margin = 16;
 
   170                 wp.x = Math.Max(wp.x, rect.Left - wp.cx + margin);
 
   171                 wp.x = Math.Min(wp.x, rect.Right - margin);
 
   172                 wp.y = Math.Max(wp.y, rect.Top - wp.cy + margin);
 
   173                 wp.y = Math.Min(wp.y, rect.Bottom - margin);
 
   176               // update location and fire event
 
   177               if ((wp.flags & SWP_NOMOVE) == 0) {
 
   178                 if (location.X != wp.x || location.Y != wp.y) {
 
   179                   location = new Point(wp.x, wp.y);
 
   180                   if (LocationChanged != null)
 
   181                     LocationChanged(this, EventArgs.Empty);
 
   185               // update size and fire event
 
   186               if ((wp.flags & SWP_NOSIZE) == 0) {
 
   187                 if (size.Width != wp.cx || size.Height != wp.cy) {
 
   188                   size = new Size(wp.cx, wp.cy);
 
   189                   if (SizeChanged != null)
 
   190                     SizeChanged(this, EventArgs.Empty);
 
   194               // update the size of the layered window
 
   195               if ((wp.flags & SWP_NOSIZE) == 0) {
 
   196                 NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero,
 
   197                   IntPtr.Zero, ref size, IntPtr.Zero, IntPtr.Zero, 0,
 
   201               // update the position of the layered window
 
   202               if ((wp.flags & SWP_NOMOVE) == 0) {
 
   203                 NativeMethods.SetWindowPos(Handle, IntPtr.Zero, 
 
   204                   location.X, location.Y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | 
 
   205                   SWP_NOZORDER | SWP_NOSENDCHANGING);
 
   209             // do not forward any move or size messages
 
   210             wp.flags |= SWP_NOSIZE | SWP_NOMOVE;
 
   212             // suppress any frame changed events
 
   213             wp.flags &= ~SWP_FRAMECHANGED;
 
   215             Marshal.StructureToPtr(wp, message.LParam, false);                      
 
   216             message.Result = IntPtr.Zero;
 
   219             base.WndProc(ref message);
 
   224     private BlendFunction CreateBlendFunction() {
 
   225       BlendFunction blend = new BlendFunction();
 
   226       blend.BlendOp = AC_SRC_OVER;
 
   227       blend.BlendFlags = 0;
 
   228       blend.SourceConstantAlpha = opacity;
 
   229       blend.AlphaFormat = AC_SRC_ALPHA;
 
   233     private void CreateBuffer() {      
 
   234       IntPtr handleScreenDC = NativeMethods.GetDC(IntPtr.Zero);
 
   235       handleBitmapDC = NativeMethods.CreateCompatibleDC(handleScreenDC);
 
   236       NativeMethods.ReleaseDC(IntPtr.Zero, handleScreenDC);
 
   239       BitmapInfo info = new BitmapInfo();
 
   240       info.Size = Marshal.SizeOf(info);
 
   241       info.Width = size.Width;
 
   242       info.Height = -size.Height;
 
   247       IntPtr hBmp = NativeMethods.CreateDIBSection(handleBitmapDC, ref info, 0, 
 
   248         out ptr, IntPtr.Zero, 0);
 
   249       IntPtr hBmpOld = NativeMethods.SelectObject(handleBitmapDC, hBmp);
 
   250       NativeMethods.DeleteObject(hBmpOld);
 
   252       graphics = Graphics.FromHdc(handleBitmapDC);
 
   254       if (Environment.OSVersion.Version.Major > 5) {
 
   255         this.graphics.TextRenderingHint = TextRenderingHint.SystemDefault;
 
   256         this.graphics.SmoothingMode = SmoothingMode.HighQuality;
 
   260     private void DisposeBuffer() {
 
   262       NativeMethods.DeleteDC(handleBitmapDC);
 
   265     public virtual void Dispose() {
 
   269     public PaintEventHandler Paint; 
 
   271     public void Redraw() {
 
   272       if (!visible || Paint == null)
 
   275       if (size != bufferSize) {
 
   281         new PaintEventArgs(graphics, new Rectangle(Point.Empty, size))); 
 
   283         Point pointSource = Point.Empty;
 
   284         BlendFunction blend = CreateBlendFunction();
 
   286         NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero, IntPtr.Zero,
 
   287           ref size, handleBitmapDC, ref pointSource, 0, ref blend, ULW_ALPHA);
 
   289         // make sure the window is at the right location
 
   290         NativeMethods.SetWindowPos(Handle, IntPtr.Zero,
 
   291           location.X, location.Y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE |
 
   292           SWP_NOZORDER | SWP_NOSENDCHANGING);
 
   295     public byte Opacity {
 
   300         if (opacity != value) {
 
   302           BlendFunction blend = CreateBlendFunction();
 
   303           NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero, IntPtr.Zero,
 
   304             IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, ref blend, ULW_ALPHA);
 
   309     public bool Visible {
 
   314         if (visible != value) {
 
   316           NativeMethods.SetWindowPos(Handle, IntPtr.Zero, 0, 0, 0, 0,
 
   317             SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER |
 
   318             (value ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
 
   321               ShowDesktop.Instance.ShowDesktopChanged += ShowDesktopChanged;
 
   324               ShowDesktop.Instance.ShowDesktopChanged -= ShowDesktopChanged;
 
   330     // if locked, the window can not be moved or resized
 
   331     public bool LockPositionAndSize {
 
   333         return lockPositionAndSize;
 
   336         lockPositionAndSize = value;
 
   340     public bool AlwaysOnTop {
 
   345         if (value != alwaysOnTop) {
 
   349               ShowDesktop.Instance.ShowDesktopChanged -= ShowDesktopChanged;
 
   350             MoveToTopMost(Handle);            
 
   352             MoveToBottom(Handle);
 
   354               ShowDesktop.Instance.ShowDesktopChanged += ShowDesktopChanged;
 
   367           NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero, IntPtr.Zero,
 
   368             ref size, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, 0);                    
 
   369           if (SizeChanged != null)
 
   370             SizeChanged(this, EventArgs.Empty);
 
   375     public event EventHandler SizeChanged;
 
   377     public Point Location {
 
   382         if (location != value) {
 
   384           NativeMethods.SetWindowPos(Handle, IntPtr.Zero, 
 
   385             location.X, location.Y, 0, 0, 
 
   386             SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING);          
 
   387           if (LocationChanged != null)
 
   388             LocationChanged(this, EventArgs.Empty);
 
   393     public event EventHandler LocationChanged;
 
   395     public ContextMenu ContextMenu {
 
   400         this.contextMenu = value;
 
   404     public event HitTestEventHandler HitTest;
 
   406     public event MouseEventHandler MouseDoubleClick;
 
   408     [StructLayout(LayoutKind.Sequential, Pack = 1)]
 
   409     private struct BlendFunction {
 
   411       public byte BlendFlags;
 
   412       public byte SourceConstantAlpha;
 
   413       public byte AlphaFormat;
 
   416     [StructLayout(LayoutKind.Sequential, Pack = 1)]
 
   417     private struct WindowPos {
 
   419       public IntPtr hwndInsertAfter;
 
   427     [StructLayout(LayoutKind.Sequential)]
 
   428     public struct BitmapInfo {
 
   433       public Int16 BitCount;
 
   434       public Int32 Compression;
 
   435       public Int32 SizeImage;
 
   436       public Int32 XPelsPerMeter;
 
   437       public Int32 YPelsPerMeter;
 
   438       public Int32 ClrUsed;
 
   439       public Int32 ClrImportant;
 
   443     public static readonly IntPtr HWND_BOTTOM = (IntPtr)1;
 
   444     public static readonly IntPtr HWND_TOPMOST = (IntPtr)(-1);
 
   446     public const int WS_EX_LAYERED = 0x00080000;
 
   447     public const int WS_EX_TOOLWINDOW = 0x00000080;
 
   449     public const uint SWP_NOSIZE = 0x0001;
 
   450     public const uint SWP_NOMOVE = 0x0002;
 
   451     public const uint SWP_NOACTIVATE = 0x0010;
 
   452     public const uint SWP_FRAMECHANGED = 0x0020;
 
   453     public const uint SWP_HIDEWINDOW = 0x0080;
 
   454     public const uint SWP_SHOWWINDOW = 0x0040;
 
   455     public const uint SWP_NOZORDER = 0x0004;
 
   456     public const uint SWP_NOSENDCHANGING = 0x0400;
 
   458     public const int ULW_COLORKEY = 0x00000001;
 
   459     public const int ULW_ALPHA = 0x00000002;
 
   460     public const int ULW_OPAQUE = 0x00000004;
 
   462     public const byte AC_SRC_OVER = 0x00;
 
   463     public const byte AC_SRC_ALPHA = 0x01;
 
   465     public const int WM_NCHITTEST = 0x0084;
 
   466     public const int WM_NCLBUTTONDBLCLK = 0x00A3;
 
   467     public const int WM_NCLBUTTONDOWN = 0x00A1;
 
   468     public const int WM_NCLBUTTONUP = 0x00A2;
 
   469     public const int WM_NCRBUTTONDOWN = 0x00A4;
 
   470     public const int WM_NCRBUTTONUP = 0x00A5;
 
   471     public const int WM_WINDOWPOSCHANGING = 0x0046;
 
   472     public const int WM_COMMAND = 0x0111;
 
   474     public const int TPM_RIGHTBUTTON = 0x0002;
 
   475     public const int TPM_VERTICAL = 0x0040;
 
   477     private enum WindowAttribute : int {
 
   478       DWMWA_NCRENDERING_ENABLED = 1,
 
   479       DWMWA_NCRENDERING_POLICY,
 
   480       DWMWA_TRANSITIONS_FORCEDISABLED,
 
   482       DWMWA_CAPTION_BUTTON_BOUNDS,
 
   483       DWMWA_NONCLIENT_RTL_LAYOUT,
 
   484       DWMWA_FORCE_ICONIC_REPRESENTATION,
 
   486       DWMWA_EXTENDED_FRAME_BOUNDS,
 
   487       DWMWA_HAS_ICONIC_BITMAP,
 
   489       DWMWA_EXCLUDED_FROM_PEEK,
 
   494     /// Some macros imported and converted from the Windows SDK
 
   496     private static class Macros {
 
   497       public static ushort LOWORD(IntPtr l) {
 
   498         return (ushort) ((ulong)l & 0xFFFF);
 
   501       public static UInt16 HIWORD(IntPtr l) {
 
   502         return (ushort) (((ulong)l >> 16) & 0xFFFF);
 
   505       public static int GET_X_LPARAM(IntPtr lp) {
 
   506         return (short) LOWORD(lp);
 
   509       public static int GET_Y_LPARAM(IntPtr lp) {
 
   510         return (short) HIWORD(lp);
 
   515     /// Imported native methods
 
   517     private static class NativeMethods {
 
   518       private const string USER = "user32.dll";
 
   519       private const string GDI = "gdi32.dll";
 
   520       public const string DWMAPI = "dwmapi.dll";
 
   522       [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
 
   523       [return: MarshalAs(UnmanagedType.Bool)]
 
   524       public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst,
 
   525         IntPtr pptDst, ref Size psize, IntPtr hdcSrc, IntPtr pprSrc,
 
   526         int crKey, IntPtr pblend, int dwFlags);
 
   528       [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
 
   529       [return: MarshalAs(UnmanagedType.Bool)]
 
   530       public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, 
 
   531         IntPtr pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, 
 
   532         int crKey, ref BlendFunction pblend, int dwFlags);
 
   534       [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
 
   535       [return: MarshalAs(UnmanagedType.Bool)]
 
   536       public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst,
 
   537         IntPtr pptDst, IntPtr psize, IntPtr hdcSrc, IntPtr pprSrc,
 
   538         int crKey, ref BlendFunction pblend, int dwFlags);  
 
   540       [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
 
   541       public static extern IntPtr GetDC(IntPtr hWnd);
 
   543       [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
 
   544       public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
 
   546       [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
 
   547       public static extern bool SetWindowPos(IntPtr hWnd,
 
   548         IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
 
   550       [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
 
   551       public static extern bool TrackPopupMenuEx(IntPtr hMenu, uint uFlags, 
 
   552         int x, int y, IntPtr hWnd, IntPtr tpmParams);
 
   554       [DllImport(GDI, CallingConvention = CallingConvention.Winapi)]
 
   555       public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
 
   557       [DllImport(GDI, CallingConvention = CallingConvention.Winapi)]
 
   558       public static extern IntPtr CreateDIBSection(IntPtr hdc, 
 
   559         [In] ref BitmapInfo pbmi, uint pila, out IntPtr ppvBits, 
 
   560         IntPtr hSection, uint dwOffset);
 
   562       [DllImport(GDI, CallingConvention = CallingConvention.Winapi)]
 
   563       [return: MarshalAs(UnmanagedType.Bool)]
 
   564       public static extern bool DeleteDC(IntPtr hdc);
 
   566       [DllImport(GDI, CallingConvention = CallingConvention.Winapi)]
 
   567       public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
 
   569       [DllImport(GDI, CallingConvention = CallingConvention.Winapi)]
 
   570       [return: MarshalAs(UnmanagedType.Bool)]
 
   571       public static extern bool DeleteObject(IntPtr hObject);
 
   573       [DllImport(DWMAPI, CallingConvention = CallingConvention.Winapi)]
 
   574       public static extern int DwmSetWindowAttribute(IntPtr hwnd,
 
   575         WindowAttribute dwAttribute, ref bool pvAttribute, int cbAttribute);
 
   579   public enum HitResult {
 
   595   public delegate void HitTestEventHandler(object sender, HitTestEventArgs e);
 
   597   public class HitTestEventArgs : EventArgs {
 
   598     public HitTestEventArgs(Point location, HitResult hitResult) {
 
   600       HitResult = hitResult;
 
   602     public Point Location { get; private set; }
 
   603     public HitResult HitResult { get; set; }