GUI/ShowDesktop.cs
author moel.mich
Tue, 30 Dec 2014 22:47:39 +0000
changeset 431 0e46e3ca812a
parent 179 a3530106314b
permissions -rw-r--r--
Fixed the following issue (present only on 32-bit systems):

Version: 0.7.0.0

System.NullReferenceException: Object reference not set to an instance of an object.
at OpenHardwareMonitor.GUI.MainForm.timer_Tick(Object sender, EventArgs e)
at System.Windows.Forms.Timer.OnTick(EventArgs e)
at System.Windows.Forms.Timer.TimerNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

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