GUI/ShowDesktop.cs
author moel.mich
Sun, 27 May 2012 14:23:31 +0000
changeset 344 3145aadca3d2
parent 179 a3530106314b
permissions -rw-r--r--
Changed the license to the Mozilla Public License 2.0 and update the licensing information.
     1 /*
     2  
     3   This Source Code Form is subject to the terms of the Mozilla Public
     4   License, v. 2.0. If a copy of the MPL was not distributed with this
     5   file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  
     7   Copyright (C) 2010 Michael Möller <mmoeller@openhardwaremonitor.org>
     8 	
     9 */
    10 
    11 using System;
    12 using System.Runtime.InteropServices;
    13 using System.Windows.Forms;
    14 
    15 namespace OpenHardwareMonitor.GUI {
    16   public class ShowDesktop {
    17     private static ShowDesktop instance = new ShowDesktop();
    18 
    19     public delegate void ShowDesktopChangedEventHandler(bool showDesktop);
    20     
    21     private event ShowDesktopChangedEventHandler ShowDesktopChangedEvent;
    22 
    23     private System.Threading.Timer timer;
    24     private bool showDesktop = false;   
    25     private NativeWindow referenceWindow;
    26     private string referenceWindowCaption =
    27       "OpenHardwareMonitorShowDesktopReferenceWindow";
    28 
    29     private ShowDesktop() {
    30       // create a reference window to detect show desktop
    31       referenceWindow = new NativeWindow();
    32       CreateParams cp = new CreateParams();
    33       cp.ExStyle = GadgetWindow.WS_EX_TOOLWINDOW;
    34       cp.Caption = referenceWindowCaption;
    35       referenceWindow.CreateHandle(cp);
    36       NativeMethods.SetWindowPos(referenceWindow.Handle, 
    37         GadgetWindow.HWND_BOTTOM, 0, 0, 0, 0, GadgetWindow.SWP_NOMOVE | 
    38         GadgetWindow.SWP_NOSIZE | GadgetWindow.SWP_NOACTIVATE | 
    39         GadgetWindow.SWP_NOSENDCHANGING);
    40 
    41       // start a repeated timer to detect "Show Desktop" events 
    42       timer = new System.Threading.Timer(OnTimer, null,
    43         System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
    44     }
    45 
    46     private void StartTimer() {
    47       timer.Change(0, 200);
    48     }
    49 
    50     private void StopTimer() {
    51       timer.Change(System.Threading.Timeout.Infinite,
    52         System.Threading.Timeout.Infinite);
    53     }
    54 
    55     // the desktop worker window (if available) can hide the reference window
    56     private IntPtr GetDesktopWorkerWindow() {
    57       IntPtr shellWindow = NativeMethods.GetShellWindow();
    58       if (shellWindow == IntPtr.Zero)
    59         return IntPtr.Zero;
    60 
    61       int shellId;
    62       NativeMethods.GetWindowThreadProcessId(shellWindow, out shellId);
    63 
    64       IntPtr workerWindow = IntPtr.Zero;
    65       while ((workerWindow = NativeMethods.FindWindowEx(
    66           IntPtr.Zero, workerWindow, "WorkerW", null)) != IntPtr.Zero) {
    67 
    68         int workerId;
    69         NativeMethods.GetWindowThreadProcessId(workerWindow, out workerId);
    70         if (workerId == shellId) {
    71           IntPtr window = NativeMethods.FindWindowEx(
    72             workerWindow, IntPtr.Zero, "SHELLDLL_DefView", null);
    73           if (window != IntPtr.Zero) {
    74             IntPtr desktopWindow = NativeMethods.FindWindowEx(
    75               window, IntPtr.Zero, "SysListView32", null);
    76             if (desktopWindow != IntPtr.Zero)
    77               return workerWindow;
    78           }
    79         }
    80       }
    81       return IntPtr.Zero;
    82     }
    83 
    84     private void OnTimer(Object state) {
    85       bool showDesktopDetected;
    86 
    87       IntPtr workerWindow = GetDesktopWorkerWindow();
    88       if (workerWindow != IntPtr.Zero) {
    89         // search if the reference window is behind the worker window
    90         IntPtr reference = NativeMethods.FindWindowEx(
    91           IntPtr.Zero, workerWindow, null, referenceWindowCaption);
    92         showDesktopDetected = reference != IntPtr.Zero;
    93       } else {
    94         // if there is no worker window, then nothing can hide the reference
    95         showDesktopDetected = false;
    96       }
    97 
    98       if (showDesktop != showDesktopDetected) {
    99         showDesktop = showDesktopDetected;
   100         if (ShowDesktopChangedEvent != null) {
   101           ShowDesktopChangedEvent(showDesktop);
   102         }
   103       }
   104     }
   105 
   106     public static ShowDesktop Instance {
   107       get { return instance; }
   108     }
   109 
   110     // notify when the "show desktop" mode is changed
   111     public event ShowDesktopChangedEventHandler ShowDesktopChanged {
   112       add {
   113         // start the monitor timer when someone is listening
   114         if (ShowDesktopChangedEvent == null)           
   115           StartTimer();
   116         ShowDesktopChangedEvent += value;
   117       }
   118       remove {
   119         ShowDesktopChangedEvent -= value;
   120         // stop the monitor timer if nobody is interested
   121         if (ShowDesktopChangedEvent == null)
   122           StopTimer();
   123       }
   124     }
   125 
   126     private static class NativeMethods {
   127       private const string USER = "user32.dll";
   128 
   129       [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
   130       public static extern bool SetWindowPos(IntPtr hWnd,
   131         IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
   132 
   133       [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
   134       public static extern IntPtr FindWindowEx(IntPtr hwndParent,
   135         IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
   136 
   137       [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
   138       public static extern IntPtr GetShellWindow();
   139 
   140       [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
   141       public static extern int GetWindowThreadProcessId(IntPtr hWnd,
   142         out int processId);
   143     }  
   144   }
   145 }