/* Copyright (c) Cloud Software Group, Inc.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace XenAdmin.Core
{
///
/// Encapsulates window functions that aren't in the framework.
///
internal class Win32Window : IWin32Window
{
private readonly IntPtr _handle;
///
/// Initializes a new instance of the class.
///
/// The window handle.
public Win32Window(IntPtr handle)
{
_handle = handle;
}
///
/// Extract the window handle
///
public IntPtr Handle
{
get
{
return _handle;
}
}
///
/// Posts WM_CLOSE.
///
public void Close()
{
const int WM_CLOSE = 0x10;
PostMessage(WM_CLOSE, 0, 0);
}
///
/// Return true if this window is null
///
public bool IsNull
{
get
{
return _handle == IntPtr.Zero;
}
}
///
/// The children of this window
///
public ReadOnlyCollection Children
{
get
{
List windows = new List();
EnumChildWindows(_handle, delegate(IntPtr window, int i)
{
windows.Add(new Win32Window(window));
return true;
}, 0);
return new ReadOnlyCollection(windows);
}
}
public ReadOnlyCollection DirectChildren
{
get
{
List windows = new List();
foreach (Win32Window w in Children)
{
if (w.Parent._handle.ToInt32() == _handle.ToInt32())
{
windows.Add(w);
}
}
return new ReadOnlyCollection(windows);
}
}
///
/// Gets the first window that has the specified window text and matches the specified Predicate.
///
/// The text that the window must have.
/// The Predicate that the window must match.
/// The first window that has the specified window text and matches the specified Predicate.
public static Win32Window GetWindowWithText(string text, Predicate match = null)
{
if (match == null)
match = w => true;
Thread.Sleep(100);
foreach (Win32Window window in TopLevelWindows)
{
if (window.Text == text && match(window))
return window;
}
return null;
}
///
/// Gets a value indicating whether a form of the specified type is currently visible in this process.
///
public static bool ModalDialogIsVisible()
{
int currentProcess = Process.GetCurrentProcess().Id;
IntPtr mainWindowHandle = Process.GetCurrentProcess().MainWindowHandle;
bool output = false;
EnumWindows(delegate(IntPtr handle, int i)
{
Win32Window w = new Win32Window(handle);
if (w.ProcessId == currentProcess)
{
Form f = Form.FromHandle(w.Handle) as Form;
if (f != null && w.Handle != mainWindowHandle && f.GetType().Namespace.StartsWith("XenAdmin"))
{
output = true;
return false;
}
}
return true;
}, 0);
return output;
}
///
/// All top level windows
///
public static ReadOnlyCollection TopLevelWindows
{
get
{
List windows = new List();
EnumWindows(delegate(IntPtr handle, int i)
{
windows.Add(new Win32Window(handle));
return true;
}, 0);
return new ReadOnlyCollection(windows);
}
}
///
/// Return all windows of the current thread.
///
public static ReadOnlyCollection GetThreadWindows()
{
return GetThreadWindows(GetCurrentThreadId());
}
///
/// Return all windows of a given thread
///
/// The thread id
public static ReadOnlyCollection GetThreadWindows(int threadId)
{
List windows = new List();
EnumThreadWindows(threadId, delegate(IntPtr window, int i)
{
windows.Add(new Win32Window(window));
return true;
}, 0);
return new ReadOnlyCollection(windows);
}
///
/// The deskop window
///
public static Win32Window DesktopWindow
{
get
{
return new Win32Window(GetDesktopWindow());
}
}
///
/// The current foreground window
///
public static Win32Window ForegroundWindow
{
get
{
return new Win32Window(GetForegroundWindow());
}
}
///
/// Bring a window to the top
///
public void BringWindowToTop()
{
BringWindowToTop(_handle);
}
public void SetForegroundWindow()
{
SetForegroundWindow(_handle);
}
public void OpenIcon()
{
OpenIcon(_handle);
}
///
/// Find a child of this window
///
/// Name of the class, or null
/// Name of the window, or null
///
public Win32Window FindChild(string className, string windowName)
{
return new Win32Window(FindWindowEx(_handle, IntPtr.Zero, className, windowName));
}
///
/// Find a window by name or class
///
/// Name of the class, or null
/// Name of the window, or null
///
public static Win32Window FindWindow(string className, string windowName)
{
return new Win32Window(FindWindowEx(IntPtr.Zero, IntPtr.Zero, className, windowName));
}
///
/// Tests whether one window is a child of another
///
/// Parent window
/// Window to test
///
public static bool IsChild(Win32Window parent, Win32Window window)
{
return IsChild(parent._handle, window._handle);
}
///
/// Send a windows message to this window
///
///
///
///
///
public int SendMessage(int message, int wparam, int lparam)
{
return SendMessage(_handle, message, wparam, lparam);
}
///
/// Post a windows message to this window
///
///
///
///
///
public int PostMessage(int message, int wparam, int lparam)
{
return PostMessage(_handle, message, wparam, lparam);
}
///
/// Get the parent of this window. Null if this is a top-level window
///
public Win32Window Parent
{
get
{
return new Win32Window(GetParent(_handle));
}
}
///
/// Get the last (topmost) active popup
///
public Win32Window LastActivePopup
{
get
{
IntPtr popup = GetLastActivePopup(_handle);
if (popup == _handle)
return new Win32Window(IntPtr.Zero);
else
return new Win32Window(popup);
}
}
///
/// The text in this window
///
public string Text
{
get
{
int length = GetWindowTextLength(_handle);
StringBuilder sb = new StringBuilder(length + 1);
GetWindowText(_handle, sb, sb.Capacity);
return sb.ToString();
}
set
{
SetWindowText(_handle, value);
}
}
public string WindowClass
{
get
{
StringBuilder sb = new StringBuilder(1000);
GetClassName(_handle, sb, sb.Capacity);
return sb.ToString();
}
}
///
/// Get a long value for this window. See GetWindowLong()
///
///
///
public int GetWindowLong(int index)
{
return GetWindowLong(_handle, index);
}
///
/// Set a long value for this window. See SetWindowLong()
///
///
///
///
public int SetWindowLong(int index, int value)
{
return SetWindowLong(_handle, index, value);
}
///
/// The id of the thread that owns this window
///
public int ThreadId
{
get
{
return GetWindowThreadProcessId(_handle, IntPtr.Zero);
}
}
///
/// The id of the process that owns this window
///
public int ProcessId
{
get
{
int processId = 0;
GetWindowThreadProcessId(_handle, ref processId);
return processId;
}
}
///
/// Whether the window is minimized
///
public bool Minimized
{
get
{
return IsIconic(_handle);
}
set
{
const int SC_MINIMIZE = 0xF020;
const int WM_SYSCOMMAND = 0x0112;
PostMessage(WM_SYSCOMMAND, SC_MINIMIZE, 0);
}
}
///
/// Whether the window is maximized
///
public bool Maximized
{
get
{
return IsZoomed(_handle);
}
}
public bool MoveWindow(int X, int Y, int width, int height, bool repaint)
{
return MoveWindow(_handle, X, Y, width, height, repaint);
}
public Win32Window NextWindow
{
get
{
IntPtr h = GetNextWindow(_handle, 2);
if (h == IntPtr.Zero)
return null;
return new Win32Window(h);
}
}
///
/// Gets a value indicating whether there are pending message in the message queue.
///
/// true if the are messages pending; otherwise, false.
public bool MessagesPending
{
get
{
NativeMessage msg = new NativeMessage();
return PeekMessage(out msg, _handle, 0, 0, 0);
}
}
///
/// Turn this window into a tool window, so it doesn't show up in the Alt-tab list...
///
///
private const int GWL_EXSTYLE = -20;
private const int WS_EX_TOOLWINDOW = 0x00000080;
public void MakeToolWindow()
{
int windowStyle = GetWindowLong(GWL_EXSTYLE);
SetWindowLong(GWL_EXSTYLE, windowStyle | WS_EX_TOOLWINDOW);
}
[DllImport("user32.dll")]
private static extern bool BringWindowToTop(IntPtr window);
[DllImport("user32.dll")]
private static extern bool CloseWindow(IntPtr window);
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr window);
[DllImport("user32.dll")]
private static extern bool OpenIcon(IntPtr window);
[DllImport("user32.dll")]
private static extern IntPtr FindWindowEx(IntPtr parent, IntPtr childAfter, string className, string windowName);
[DllImport("user32.dll", EntryPoint = "FindWindow")]
private static extern IntPtr FindWindowWin32(string className, string windowName);
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr window, int message, int wparam, int lparam);
[DllImport("user32.dll")]
private static extern int PostMessage(IntPtr window, int message, int wparam, int lparam);
[DllImport("user32.dll")]
private static extern IntPtr GetParent(IntPtr window);
[DllImport("user32.dll")]
private static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern IntPtr GetLastActivePopup(IntPtr window);
[DllImport("user32.dll")]
private static extern int GetWindowText(IntPtr window, [In][Out] StringBuilder text, int copyCount);
[DllImport("user32.dll")]
private static extern bool SetWindowText(IntPtr window, string text);
[DllImport("user32.dll")]
private static extern int GetWindowTextLength(IntPtr window);
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr window, int index, int value);
[DllImport("user32.dll")]
private static extern int GetWindowLong(IntPtr window, int index);
[DllImport("user32.dll")]
private static extern int GetClassName(IntPtr window, [In][Out] StringBuilder text, int copyCount);
private delegate bool EnumWindowsProc(IntPtr window, int i);
[DllImport("user32.dll")]
private static extern bool EnumChildWindows(IntPtr window, EnumWindowsProc callback, int i);
[DllImport("user32.dll")]
private static extern bool EnumThreadWindows(int threadId, EnumWindowsProc callback, int i);
[DllImport("user32.dll")]
private static extern bool EnumWindows(EnumWindowsProc callback, int i);
[DllImport("user32.dll")]
private static extern int GetWindowThreadProcessId(IntPtr window, ref int processId);
[DllImport("user32.dll")]
private static extern int GetWindowThreadProcessId(IntPtr window, IntPtr ptr);
[DllImport("user32.dll")]
private static extern bool IsChild(IntPtr parent, IntPtr window);
[DllImport("user32.dll")]
private static extern bool IsIconic(IntPtr window);
[DllImport("user32.dll")]
private static extern bool IsZoomed(IntPtr window);
[DllImport("user32.dll")]
private static extern IntPtr GetWindowDC(IntPtr hwnd);
[DllImport("user32.dll")]
private static extern int ReleaseDC(IntPtr hwnd, IntPtr dc);
[DllImport("user32.dll")]
private static extern bool MoveWindow(IntPtr hwnd, int X, int Y, int width, int height, bool repaint);
[DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "GetWindow", SetLastError = true)]
private static extern IntPtr GetNextWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.U4)] int wFlag);
[DllImport("user32.dll")]
private static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
[DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
private static extern int GetCurrentThreadId();
///
/// The PeekMessage function dispatches incoming sent messages, checks the thread message queue for a posted message,
/// and retrieves the message (if any exist).
///
/// Pointer to an MSG structure that receives message information.
/// Handle to the window whose messages are to be retrieved. The window must belong to the current thread.
/// Specifies the value of the first message in the range of messages to be examined.
/// Specifies the value of the last message in the range of messages to be examined.
/// Specifies how messages are handled.
/// If a message is available, the return value is nonzero. If no messages are available, the return value is zero.
[SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool PeekMessage(out NativeMessage message, IntPtr handle, uint filterMin, uint filterMax, uint removeMsg);
[StructLayout(LayoutKind.Sequential)]
private struct NativeMessage
{
public IntPtr handle;
public uint msg;
public IntPtr wParam;
public IntPtr lParam;
public uint time;
public System.Drawing.Point p;
}
}
}