view Chronosv2/source/Interop/Win32Interop.cs @ 12:6a0449185449

SCC changed from TFS to HG
author stevenh7776 stevenhollidge@hotmail.com
date Tue, 21 Feb 2012 17:47:35 +0700
parents 443821e55f06
children 09d18d6e5f40
line wrap: on
line source

/*
The MIT License

Copyright (c) 2009-2010. Carlos Guzmán Álvarez. http://chronoswpf.codeplex.com/

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

using System;
using System.Runtime.InteropServices;
using System.Windows;

namespace Chronos.Interop
{
    /// <summary>
    /// Win32 Interop Functions
    /// </summary>
    /// <remarks>
    /// http://blogs.msdn.com/llobo/archive/2006/08/01/Maximizing-window-_2800_with-WindowStyle_3D00_None_2900_-considering-Taskbar.aspx
    /// http://social.msdn.microsoft.com/forums/en-US/wpf/thread/e77c3b58-41f6-4534-8a92-be0f8287b734/
    /// </remarks>
    public static class Win32Interop
    {
        #region · Consts ·

        /// <summary>
        /// Sets a new extended window style
        /// </summary>
        public static readonly Int32 GWL_EXSTYLE                = -20;
        
        /// <summary>
        /// Layered Windows
        /// </summary>
        public static readonly Int32 WS_EX_LAYERED              = 0x00080000;
        
        /// <summary>
        /// Transparent window
        /// </summary>
        public static readonly Int32 WS_EX_TRANSPARENT          = 0x00000020;
        
        private static readonly Int32 MONITOR_DEFAULTTONEAREST  = 0x00000002;

        /// <summary>
        /// Stop flashing. The system restores the window to its original state.
        /// </summary>
        public const UInt32 FLASHW_STOP = 0;

        /// <summary>
        /// Flash the window caption.
        /// </summary>
        public const UInt32 FLASHW_CAPTION = 1;

        /// <summary>
        /// Flash the taskbar button.
        /// </summary>
        public const UInt32 FLASHW_TRAY = 2;

        /// <summary>
        /// Flash both the window caption and taskbar button. 
        /// This is equivalent to setting the FLASHW_CAPTION | FLASHW_TRAY flags.
        /// </summary>
        public const UInt32 FLASHW_ALL = 3;

        /// <summary>
        /// Flash continuously, until the FLASHW_STOP flag is set.
        /// </summary>
        public const UInt32 FLASHW_TIMER = 4;

        /// <summary>
        /// Flash continuously until the window comes to the foreground.
        /// </summary>
        public const UInt32 FLASHW_TIMERNOFG = 12;

        #endregion

        #region · Inner Types ·

        [StructLayout(LayoutKind.Sequential)]
        private struct FLASHWINFO
        {
            public UInt32 cbSize;
            public IntPtr hwnd;
            public UInt32 dwFlags;
            public UInt32 uCount;
            public UInt32 dwTimeout;
        }

        // Struct we'll need to pass to the function
        [StructLayout(LayoutKind.Sequential)]
        private struct LASTINPUTINFO
        {
            public UInt32 cbSize;
            public UInt32 dwTime;
        }

        /// <summary>
        /// POINT aka POINTAPI
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            #region · Fields ·

            /// <summary>
            /// x coordinate of point.
            /// </summary>
            public int X;
            /// <summary>
            /// y coordinate of point.
            /// </summary>
            public int Y;

            #endregion

            #region · Constructors ·

            /// <summary>
            /// Construct a point of coordinates (x,y).
            /// </summary>
            public POINT(int x, int y)
            {
                this.X = x;
                this.Y = y;
            }

            #endregion
        }

        /// <summary>
        /// The MINMAXINFO structure contains information about a window's maximized size and 
        /// position and its minimum and maximum tracking size.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct MINMAXINFO
        {
            /// <summary>
            /// Reserved; do not use.
            /// </summary>
            public POINT ptReserved;

            /// <summary>
            /// Specifies the maximized width (POINT.x) and the maximized height (POINT.y) of the window. 
            /// For top-level windows, this value is based on the width of the primary monitor.
            /// </summary>
            public POINT ptMaxSize;

            /// <summary>
            /// Specifies the position of the left side of the maximized window (POINT.x) and 
            /// the position of the top of the maximized window (POINT.y). 
            /// For top-level windows, this value is based on the position of the primary monitor.
            /// </summary>
            public POINT ptMaxPosition;

            /// <summary>
            /// Specifies the minimum tracking width (POINT.x) and the minimum tracking height (POINT.y) of the window. 
            /// This value can be obtained programmatically from the system metrics SM_CXMINTRACK and SM_CYMINTRACK.
            /// </summary>
            public POINT ptMinTrackSize;

            /// <summary>
            /// Specifies the maximum tracking width (POINT.x) and the maximum tracking height (POINT.y) of the window. 
            /// This value is based on the size of the virtual screen and can be obtained programmatically from the 
            /// system metrics SM_CXMAXTRACK and SM_CYMAXTRACK.
            /// </summary>
            public POINT ptMaxTrackSize;
        };

        /// <summary>
        /// The MONITORINFO structure contains information about a display monitor.
        /// </summary>
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public class MONITORINFO
        {
            /// <summary>
            /// The size of the structure, in bytes.
            /// </summary>            
            public int cbSize = Marshal.SizeOf(typeof(MONITORINFO));

            /// <summary>
            /// A RECT structure that specifies the display monitor rectangle, expressed in virtual-screen coordinates. 
            /// Note that if the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.
            /// </summary>            
            public RECT rcMonitor = new RECT();

            /// <summary>
            /// A RECT structure that specifies the work area rectangle of the display monitor, expressed in virtual-screen coordinates. 
            /// Note that if the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.
            /// </summary>            
            public RECT rcWork = new RECT();

            /// <summary>
            /// A set of flags that represent attributes of the display monitor.
            /// </summary>            
            public int dwFlags = 0;
        }

        /// <summary> Win32 </summary>
        [StructLayout(LayoutKind.Sequential, Pack = 0)]
        public struct RECT
        {
            #region · Operators ·

            /// <summary> Determine if 2 RECT are equal (deep compare)</summary>
            public static bool operator ==(RECT rect1, RECT rect2)
            {
                return (rect1.left == rect2.left && rect1.top == rect2.top && rect1.right == rect2.right && rect1.bottom == rect2.bottom);
            }

            /// <summary> Determine if 2 RECT are different(deep compare)</summary>
            public static bool operator !=(RECT rect1, RECT rect2)
            {
                return !(rect1 == rect2);
            }

            #endregion

            #region · Static Members ·

            /// <summary> Win32 </summary>
            public static readonly RECT Empty = new RECT();

            #endregion

            #region · Public Fields ·

            /// <summary> Win32 </summary>
            public int left;
            /// <summary> Win32 </summary>
            public int top;
            /// <summary> Win32 </summary>
            public int right;
            /// <summary> Win32 </summary>
            public int bottom;

            #endregion

            #region · Properties ·

            /// <summary> Win32 </summary>
            public int Width
            {
                get { return Math.Abs(right - left); }  // Abs needed for BIDI OS
            }

            /// <summary> Win32 </summary>
            public int Height
            {
                get { return bottom - top; }
            }

            /// <summary> Win32 </summary>
            public bool IsEmpty
            {
                get
                {
                    // BUGBUG : On Bidi OS (hebrew arabic) left > right
                    return left >= right || top >= bottom;
                }
            }

            #endregion

            #region · Constructors ·

            /// <summary>
            /// Win32
            /// </summary>
            /// <param name="left">The left.</param>
            /// <param name="top">The top.</param>
            /// <param name="right">The right.</param>
            /// <param name="bottom">The bottom.</param>
            public RECT(int left, int top, int right, int bottom)
            {
                this.left = left;
                this.top = top;
                this.right = right;
                this.bottom = bottom;
            }

            /// <summary>
            /// Win32
            /// </summary>
            /// <param name="rcSrc">The rc SRC.</param>
            public RECT(RECT rcSrc)
            {
                this.left = rcSrc.left;
                this.top = rcSrc.top;
                this.right = rcSrc.right;
                this.bottom = rcSrc.bottom;
            }

            #endregion

            #region · Methods ·

            /// <summary>
            /// Return a user friendly representation of this struct
            /// </summary>
            /// <returns>
            /// A <see cref="System.String"/> that represents this instance.
            /// </returns>
            public override string ToString()
            {
                if (this == RECT.Empty)
                {
                    return "RECT {Empty}";
                }
                return "RECT { left : " + left + " / top : " + top + " / right : " + right + " / bottom : " + bottom + " }";
            }

            /// <summary>
            /// Determine if 2 RECT are equal (deep compare)
            /// </summary>
            /// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
            /// <returns>
            /// 	<c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
            /// </returns>
            public override bool Equals(object obj)
            {
                if (!(obj is Rect))
                {
                    return false;
                }

                return (this == (RECT)obj);
            }

            /// <summary>
            /// Return the HashCode for this struct (not garanteed to be unique)
            /// </summary>
            /// <returns>
            /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
            /// </returns>
            public override int GetHashCode()
            {
                return left.GetHashCode() + top.GetHashCode() + right.GetHashCode() + bottom.GetHashCode();
            }

            #endregion
        }

        #endregion

        #region · Static Methods ·

        public static void FlashWindow(IntPtr handle)
        {
            IntPtr      hWnd    = handle;
            FLASHWINFO  fInfo   = new FLASHWINFO();

            fInfo.cbSize    = Convert.ToUInt32(Marshal.SizeOf(fInfo));
            fInfo.hwnd      = hWnd;
            fInfo.dwFlags   = Win32Interop.FLASHW_ALL |
                              Win32Interop.FLASHW_TIMERNOFG |
                              Win32Interop.FLASHW_CAPTION;

            fInfo.uCount    = UInt32.MaxValue;
            fInfo.dwTimeout = 0;

            FlashWindowEx(ref fInfo);
        }

        /// <summary>
        /// Gets the application idle time
        /// </summary>
        /// <remarks>
        /// http://www.geekpedia.com/tutorial210_Retrieving-the-Operating-System-Idle-Time-Uptime-and-Last-Input-Time.html
        /// </remarks>
        /// <returns></returns>
        public static int GetIdleTime()
        {
            // Get the system uptime		
            int systemUptime = Environment.TickCount;
            // The tick at which the last input was recorded		
            int lastInputTicks = 0;
            // The number of ticks that passed since last input
            int idleTicks = 0;

            // Set the struct		
            LASTINPUTINFO lastInputInfo = new LASTINPUTINFO();
            lastInputInfo.cbSize = (uint)Marshal.SizeOf(lastInputInfo);
            lastInputInfo.dwTime = 0;

            // If we have a value from the function		
            if (GetLastInputInfo(ref lastInputInfo))
            {
                // Get the number of ticks at the point when the last activity was seen		
                lastInputTicks = (int)lastInputInfo.dwTime;
                // Number of idle ticks = system uptime ticks - number of ticks at last input		
                idleTicks = systemUptime - lastInputTicks;
            }

            return (idleTicks / 1000);
        }

        /// <summary>
        /// Window Proc
        /// </summary>
        /// <param name="hwnd">The HWND.</param>
        /// <param name="msg">The MSG.</param>
        /// <param name="wParam">The w param.</param>
        /// <param name="lParam">The l param.</param>
        /// <param name="handled">if set to <c>true</c> [handled].</param>
        /// <returns></returns>
        public static System.IntPtr WindowProc(
              System.IntPtr hwnd,
              int msg,
              System.IntPtr wParam,
              System.IntPtr lParam,
              ref bool handled)
        {
            switch (msg)
            {
                case 0x0024:/* WM_GETMINMAXINFO */
                    WmGetMinMaxInfo(hwnd, lParam);
                    handled = true;
                    break;
            }

            return (System.IntPtr)0;
        }

        /// <summary>
        /// Get the min max size of a window
        /// </summary>
        /// <param name="hwnd">The HWND.</param>
        /// <param name="lParam">The l param.</param>
        public static void WmGetMinMaxInfo(System.IntPtr hwnd, System.IntPtr lParam)
        {
            Win32Interop.MINMAXINFO mmi = (Win32Interop.MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(Win32Interop.MINMAXINFO));

            // Adjust the maximized size and position to fit the work area of the correct monitor
            System.IntPtr monitor = Win32Interop.MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);

            if (monitor != System.IntPtr.Zero)
            {
                Win32Interop.MONITORINFO monitorInfo = new Win32Interop.MONITORINFO();
                Win32Interop.GetMonitorInfo(monitor, monitorInfo);
                Win32Interop.RECT rcWorkArea = monitorInfo.rcWork;
                Win32Interop.RECT rcMonitorArea = monitorInfo.rcMonitor;

                mmi.ptMaxPosition.X = Math.Abs(rcWorkArea.left - rcMonitorArea.left);
                mmi.ptMaxPosition.Y = Math.Abs(rcWorkArea.top - rcMonitorArea.top);
                mmi.ptMaxSize.X = Math.Abs(rcWorkArea.right - rcWorkArea.left);
                mmi.ptMaxSize.Y = Math.Abs(rcWorkArea.bottom - rcWorkArea.top);
            }

            Marshal.StructureToPtr(mmi, lParam, true);
        }

        #endregion

        #region · P/Invoke Functions ·

        [DllImport("user32.dll")]
        static extern Int32 FlashWindowEx(ref FLASHWINFO pwfi);

        [DllImport("user32.dll")]
        static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);

        /// <summary>
        /// Gets information about a display monitor.
        /// </summary>
        /// <param name="hMonitor">The h monitor.</param>
        /// <param name="lpmi">The lpmi.</param>
        /// <returns></returns>
        [DllImport("user32")]
        internal static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi);

        /// <summary>
        /// Gets a handle to the display monitor that has the largest area of intersection with the bounding rectangle of a specified windo
        /// </summary>
        /// <param name="handle">The handle.</param>
        /// <param name="flags">The flags.</param>
        /// <returns></returns>
        [DllImport("User32")]
        internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags);

        /// <summary>
        /// Gets the cursor's position, in screen coordinates.
        /// </summary>
        /// <param name="pt"></param>
        /// <returns></returns>
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern bool GetCursorPos(out POINT pt);

        /// <summary>
        /// Gets information about the specified window. 
        /// The function also retrieves the 32-bit (long) value at the specified offset into the extra window memory.
        /// </summary>
        /// <param name="hWnd"></param>
        /// <param name="nIndex"></param>
        /// <returns></returns>
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern Int32 GetWindowLong(IntPtr hWnd, Int32 nIndex);

        /// <summary>
        /// Changes an attribute of the specified window.
        /// The function also sets the 32-bit (long) value at the specified offset into the extra window memory.
        /// </summary>
        /// <param name="hWnd"></param>
        /// <param name="nIndex"></param>
        /// <param name="newVal"></param>
        /// <returns></returns>
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern Int32 SetWindowLong(IntPtr hWnd, Int32 nIndex, Int32 newVal);

        #endregion
    }
}