using System;
using System.Collections;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using System.Runtime.InteropServices.ComTypes;
using ComTypes = System.Runtime.InteropServices.ComTypes;
namespace NativeHelpers
{
[Flags]
public enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VirtualMemoryOperation = 0x00000008,
VirtualMemoryRead = 0x00000010,
VirtualMemoryWrite = 0x00000020,
DuplicateHandle = 0x00000040,
CreateProcess = 0x000000080,
SetQuota = 0x00000100,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
QueryLimitedInformation = 0x00001000,
Synchronize = 0x00100000
}
public delegate bool EnumedWindow(IntPtr handleWindow, ref object lParam);
public enum GetAncestorFlags
{
/// <summary>
/// Retrieves the parent window. This does not include the owner, as it does with the GetParent function.
/// </summary>
GetParent = 1,
/// <summary>
/// Retrieves the root window by walking the chain of parent windows.
/// </summary>
GetRoot = 2,
/// <summary>
/// Retrieves the owned root window by walking the chain of parent and owner windows returned by GetParent.
/// </summary>
GetRootOwner = 3
}
[StructLayout(LayoutKind.Sequential)]
public struct TITLEBARINFO
{
public const int CCHILDREN_TITLEBAR = 5;
public uint cbSize;
public RECT rcTitleBar;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
public uint[] rgstate;
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left, Top, Right, Bottom;
public Rectangle ToRectangle()
{
return Rectangle.FromLTRB(Left, Top, Right, Bottom);
}
public override string ToString()
{
return "Rect: " + ToRectangle().ToString();
}
}
public enum TBBStates
{
STATE_SYSTEM_UNAVAILABLE = 0x1,
STATE_SYSTEM_PRESSED = 0x8,
STATE_SYSTEM_INVISIBLE = 0x8000,
STATE_SYSTEM_OFFSCREEN = 0x10000,
STATE_SYSTEM_FOCUSABLE = 0x100000
}
public enum WindowLongParam
{
/// <summary>Sets a new address for the window procedure.</summary>
/// <remarks>You cannot change this attribute if the window does not belong to the same process as the calling thread.</remarks>
GWL_WNDPROC = -4,
/// <summary>Sets a new application instance handle.</summary>
GWLP_HINSTANCE = -6,
GWLP_HWNDPARENT = -8,
/// <summary>Sets a new identifier of the child window.</summary>
/// <remarks>The window cannot be a top-level window.</remarks>
GWL_ID = -12,
/// <summary>Sets a new window style.</summary>
GWL_STYLE = -16,
/// <summary>Sets a new extended window style.</summary>
/// <remarks>See <see cref="ExWindowStyles"/>.</remarks>
GWL_EXSTYLE = -20,
/// <summary>Sets the user data associated with the window.</summary>
/// <remarks>This data is intended for use by the application that created the window. Its value is initially zero.</remarks>
GWL_USERDATA = -21,
/// <summary>Sets the return value of a message processed in the dialog box procedure.</summary>
/// <remarks>Only applies to dialog boxes.</remarks>
DWLP_MSGRESULT = 0,
/// <summary>Sets new extra information that is private to the application, such as handles or pointers.</summary>
/// <remarks>Only applies to dialog boxes.</remarks>
DWLP_USER = 8,
/// <summary>Sets the new address of the dialog box procedure.</summary>
/// <remarks>Only applies to dialog boxes.</remarks>
DWLP_DLGPROC = 4
}
[Flags]
public enum WindowStylesEx : uint
{
/// <summary>Specifies a window that accepts drag-drop files.</summary>
WS_EX_ACCEPTFILES = 0x00000010,
/// <summary>Forces a top-level window onto the taskbar when the window is visible.</summary>
WS_EX_APPWINDOW = 0x00040000,
/// <summary>Specifies a window that has a border with a sunken edge.</summary>
WS_EX_CLIENTEDGE = 0x00000200,
/// <summary>
/// Specifies a window that paints all descendants in bottom-to-top painting order using double-buffering.
/// This cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC. This style is not supported in Windows 2000.
/// </summary>
/// <remarks>
/// With WS_EX_COMPOSITED set, all descendants of a window get bottom-to-top painting order using double-buffering.
/// Bottom-to-top painting order allows a descendent window to have translucency (alpha) and transparency (color-key) effects,
/// but only if the descendent window also has the WS_EX_TRANSPARENT bit set.
/// Double-buffering allows the window and its descendents to be painted without flicker.
/// </remarks>
WS_EX_COMPOSITED = 0x02000000,
/// <summary>
/// Specifies a window that includes a question mark in the title bar. When the user clicks the question mark,
/// the cursor changes to a question mark with a pointer. If the user then clicks a child window, the child receives a WM_HELP message.
/// The child window should pass the message to the parent window procedure, which should call the WinHelp function using the HELP_WM_HELP command.
/// The Help application displays a pop-up window that typically contains help for the child window.
/// WS_EX_CONTEXTHELP cannot be used with the WS_MAXIMIZEBOX or WS_MINIMIZEBOX styles.
/// </summary>
WS_EX_CONTEXTHELP = 0x00000400,
/// <summary>
/// Specifies a window which contains child windows that should take part in dialog box navigation.
/// If this style is specified, the dialog manager recurses into children of this window when performing navigation operations
/// such as handling the TAB key, an arrow key, or a keyboard mnemonic.
/// </summary>
WS_EX_CONTROLPARENT = 0x00010000,
/// <summary>Specifies a window that has a double border.</summary>
WS_EX_DLGMODALFRAME = 0x00000001,
/// <summary>
/// Specifies a window that is a layered window.
/// This cannot be used for child windows or if the window has a class style of either CS_OWNDC or CS_CLASSDC.
/// </summary>
WS_EX_LAYERED = 0x00080000,
/// <summary>
/// Specifies a window with the horizontal origin on the right edge. Increasing horizontal values advance to the left.
/// The shell language must support reading-order alignment for this to take effect.
/// </summary>
WS_EX_LAYOUTRTL = 0x00400000,
/// <summary>Specifies a window that has generic left-aligned properties. This is the default.</summary>
WS_EX_LEFT = 0x00000000,
/// <summary>
/// Specifies a window with the vertical scroll bar (if present) to the left of the client area.
/// The shell language must support reading-order alignment for this to take effect.
/// </summary>
WS_EX_LEFTSCROLLBAR = 0x00004000,
/// <summary>
/// Specifies a window that displays text using left-to-right reading-order properties. This is the default.
/// </summary>
WS_EX_LTRREADING = 0x00000000,
/// <summary>
/// Specifies a multiple-document interface (MDI) child window.
/// </summary>
WS_EX_MDICHILD = 0x00000040,
/// <summary>
/// Specifies a top-level window created with this style does not become the foreground window when the user clicks it.
/// The system does not bring this window to the foreground when the user minimizes or closes the foreground window.
/// The window does not appear on the taskbar by default. To force the window to appear on the taskbar, use the WS_EX_APPWINDOW style.
/// To activate the window, use the SetActiveWindow or SetForegroundWindow function.
/// </summary>
WS_EX_NOACTIVATE = 0x08000000,
/// <summary>
/// Specifies a window which does not pass its window layout to its child windows.
/// </summary>
WS_EX_NOINHERITLAYOUT = 0x00100000,
/// <summary>
/// Specifies that a child window created with this style does not send the WM_PARENTNOTIFY message to its parent window when it is created or destroyed.
/// </summary>
WS_EX_NOPARENTNOTIFY = 0x00000004,
/// <summary>
/// The window does not render to a redirection surface.
/// This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual.
/// </summary>
WS_EX_NOREDIRECTIONBITMAP = 0x00200000,
/// <summary>Specifies an overlapped window.</summary>
WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
/// <summary>Specifies a palette window, which is a modeless dialog box that presents an array of commands.</summary>
WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
/// <summary>
/// Specifies a window that has generic "right-aligned" properties. This depends on the window class.
/// The shell language must support reading-order alignment for this to take effect.
/// Using the WS_EX_RIGHT style has the same effect as using the SS_RIGHT (static), ES_RIGHT (edit), and BS_RIGHT/BS_RIGHTBUTTON (button) control styles.
/// </summary>
WS_EX_RIGHT = 0x00001000,
/// <summary>Specifies a window with the vertical scroll bar (if present) to the right of the client area. This is the default.</summary>
WS_EX_RIGHTSCROLLBAR = 0x00000000,
/// <summary>
/// Specifies a window that displays text using right-to-left reading-order properties.
/// The shell language must support reading-order alignment for this to take effect.
/// </summary>
WS_EX_RTLREADING = 0x00002000,
/// <summary>Specifies a window with a three-dimensional border style intended to be used for items that do not accept user input.</summary>
WS_EX_STATICEDGE = 0x00020000,
/// <summary>
/// Specifies a window that is intended to be used as a floating toolbar.
/// A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font.
/// A tool window does not appear in the taskbar or in the dialog that appears when the user presses ALT+TAB.
/// If a tool window has a system menu, its icon is not displayed on the title bar.
/// However, you can display the system menu by right-clicking or by typing ALT+SPACE.
/// </summary>
WS_EX_TOOLWINDOW = 0x00000080,
/// <summary>
/// Specifies a window that should be placed above all non-topmost windows and should stay above them, even when the window is deactivated.
/// To add or remove this style, use the SetWindowPos function.
/// </summary>
WS_EX_TOPMOST = 0x00000008,
/// <summary>
/// Specifies a window that should not be painted until siblings beneath the window (that were created by the same thread) have been painted.
/// The window appears transparent because the bits of underlying sibling windows have already been painted.
/// To achieve transparency without these restrictions, use the SetWindowRgn function.
/// </summary>
WS_EX_TRANSPARENT = 0x00000020,
/// <summary>Specifies a window that has a border with a raised edge.</summary>
WS_EX_WINDOWEDGE = 0x00000100
}
// IShellLink Interface
[ComImport,
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("000214F9-0000-0000-C000-000000000046")]
public interface IShellLinkW
{
uint GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
uint GetIDList(out IntPtr ppidl);
uint SetIDList(IntPtr pidl);
uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
int cchMaxName);
uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
int cchMaxPath);
uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
int cchMaxPath);
uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
uint GetHotKey(out ushort pwHotkey);
uint SetHotKey(ushort wHotKey);
uint GetShowCmd(out int piShowCmd);
uint SetShowCmd(int iShowCmd);
uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
int cchIconPath, out int piIcon);
uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
uint dwReserved);
uint Resolve(IntPtr hwnd, uint fFlags);
uint SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
}
// ShellLink CoClass (ShellLink object)
[ComImport,
ClassInterface(ClassInterfaceType.None),
Guid("00021401-0000-0000-C000-000000000046")]
public class CShellLink { }
// WIN32_FIND_DATAW Structure
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
public struct WIN32_FIND_DATAW
{
public uint dwFileAttributes;
public ComTypes.FILETIME ftCreationTime;
public ComTypes.FILETIME ftLastAccessTime;
public ComTypes.FILETIME ftLastWriteTime;
public uint nFileSizeHigh;
public uint nFileSizeLow;
public uint dwReserved0;
public uint dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = NativeValues.MAX_PATH)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string cAlternateFileName;
}
// IPropertyStore Interface
[ComImport,
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
public interface IPropertyStore
{
uint GetCount([Out] out uint cProps);
uint GetAt([In] uint iProp, out PropertyKey pkey);
uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
uint Commit();
}
// PropertyKey Structure
// Narrowed down from PropertyKey.cs of Windows API Code Pack 1.1
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct PropertyKey
{
#region Fields
private Guid formatId; // Unique GUID for property
private Int32 propertyId; // Property identifier (PID)
#endregion
#region Public Properties
public Guid FormatId
{
get
{
return formatId;
}
}
public Int32 PropertyId
{
get
{
return propertyId;
}
}
#endregion
#region Constructor
public PropertyKey(Guid formatId, Int32 propertyId)
{
this.formatId = formatId;
this.propertyId = propertyId;
}
public PropertyKey(string formatId, Int32 propertyId)
{
this.formatId = new Guid(formatId);
this.propertyId = propertyId;
}
#endregion
}
// PropVariant Class (only for string value)
// Narrowed down from PropVariant.cs of Windows API Code Pack 1.1
// Originally from http://blogs.msdn.com/b/adamroot/archive/2008/04/11
// /interop-with-propvariants-in-net.aspx
[StructLayout(LayoutKind.Explicit)]
public sealed class PropVariant : IDisposable
{
#region Fields
[FieldOffset(0)]
ushort valueType; // Value type
// [FieldOffset(2)]
// ushort wReserved1; // Reserved field
// [FieldOffset(4)]
// ushort wReserved2; // Reserved field
// [FieldOffset(6)]
// ushort wReserved3; // Reserved field
[FieldOffset(8)]
IntPtr ptr; // Value
#endregion
#region Public Properties
// Value type (System.Runtime.InteropServices.VarEnum)
public VarEnum VarType
{
get { return (VarEnum)valueType; }
set { valueType = (ushort)value; }
}
// Whether value is empty or null
public bool IsNullOrEmpty
{
get
{
return (valueType == (ushort)VarEnum.VT_EMPTY ||
valueType == (ushort)VarEnum.VT_NULL);
}
}
// Value (only for string value)
public string Value
{
get
{
return Marshal.PtrToStringUni(ptr);
}
}
#endregion
#region Constructor
public PropVariant()
{ }
// Construct with string value
public PropVariant(string value)
{
if (value == null)
throw new ArgumentException("Failed to set value.");
valueType = (ushort)VarEnum.VT_LPWSTR;
ptr = Marshal.StringToCoTaskMemUni(value);
}
#endregion
#region Destructor
~PropVariant()
{
Dispose();
}
public void Dispose()
{
NativeCalls.PropVariantClear(this);
GC.SuppressFinalize(this);
}
#endregion
}
public static class NativeValues
{
public const int MAX_PATH = 260;
public const int INFOTIPSIZE = 1024;
public const int STGM_READ = 0x00000000; // STGM constants
public const int STGM_WRITE= 0x00000001; // STGM constants
public const int STGM_READWRITE = 0x00000002; // STGM constants
public const uint SLGP_UNCPRIORITY = 0x0002; // SLGP flags
// Name = System.AppUserModel.ID
// ShellPKey = PKEY_AppUserModel_ID
// FormatID = 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3
// PropID = 5
// Type = String (VT_LPWSTR)
public static readonly PropertyKey AppUserModelIDKey =
new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
public static readonly Guid IID_IPropertyStore = new Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99");
}
public static class NativeCalls
{
[DllImport("shell32.dll", SetLastError = true)]
public static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumWindows(EnumedWindow lpEnumFunc, ref object lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll", ExactSpelling = true)]
public static extern IntPtr GetAncestor(IntPtr hwnd, GetAncestorFlags flags);
[DllImport("user32.dll")]
public static extern IntPtr GetLastActivePopup(IntPtr hWnd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetTitleBarInfo(IntPtr hwnd, ref TITLEBARINFO pti);
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
public static string GetWindowTextManaged(IntPtr hWnd)
{
// Allocate correct string length first
int length = GetWindowTextLength(hWnd);
StringBuilder sb = new StringBuilder(length + 1);
GetWindowText(hWnd, sb, sb.Capacity);
return sb.ToString();
}
public static bool IsAltTabWindow(IntPtr hwnd)
{
TITLEBARINFO ti = new TITLEBARINFO();
if (!IsWindowVisible(hwnd)) return false;
IntPtr hwndWalk = IntPtr.Zero;
IntPtr hwndTry = GetAncestor(hwnd, GetAncestorFlags.GetRootOwner);
while (hwndTry != hwndWalk)
{
hwndWalk = hwndTry;
hwndTry = GetLastActivePopup(hwndWalk);
if (IsWindowVisible(hwndTry)) break;
}
if (hwndWalk != hwnd) return false;
// the following removes some task tray programs and "Program Manager"
ti.cbSize = (uint)Marshal.SizeOf(typeof(TITLEBARINFO));
GetTitleBarInfo(hwnd, ref ti);
if ((ti.rgstate[0] & (uint)TBBStates.STATE_SYSTEM_INVISIBLE) == (uint)TBBStates.STATE_SYSTEM_INVISIBLE) return false;
// Tool windows should not be displayed either, these do not appear in the
// task bar.
if (((WindowStylesEx)GetWindowLongPtr(hwnd, (int)WindowLongParam.GWL_EXSTYLE) & WindowStylesEx.WS_EX_TOOLWINDOW) == WindowStylesEx.WS_EX_TOOLWINDOW) return false;
return true;
}
[DllImport("Ole32.dll", PreserveSig = false)]
public extern static void PropVariantClear([In, Out] PropVariant pvar);
[DllImport("shell32.dll", SetLastError = true)]
public static extern int SHGetPropertyStoreForWindow(IntPtr handle, ref Guid riid, out IPropertyStore propertyStore);
// Verify if operation succeeded.
public static void VerifySucceeded(uint hresult)
{
if (hresult > 1)
throw new InvalidOperationException("Failed with HRESULT: " +
hresult.ToString("X"));
}
[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern Int32 GetApplicationUserModelId(IntPtr hProcess, ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
public static string GetApplicationUserModelIdManaged(IntPtr hProcess)
{
UInt32 size = 256;
StringBuilder sb = new StringBuilder((int)size);
VerifySucceeded((uint)GetApplicationUserModelId(hProcess, ref size, sb));
return sb.ToString();
}
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern Int32 GetCurrentApplicationUserModelId(ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
public static string GetCurrentApplicationUserModelIdManaged()
{
UInt32 size = 256;
StringBuilder sb = new StringBuilder((int)size);
VerifySucceeded((uint)GetCurrentApplicationUserModelId(ref size, sb));
return sb.ToString();
}
}
}