I had done this test with Calc a long time ago, which still works on my OS (Windows 10, 1909)
(Show Calc window and move it at 100, 100)
(can certainly be simplified...) =>
public partial class Form1 : Form
{
public enum HRESULT : int
{
S_OK = 0,
S_FALSE = 1,
E_NOINTERFACE = unchecked((int)0x80004002),
E_NOTIMPL = unchecked((int)0x80004001),
E_FAIL = unchecked((int)0x80004005)
}
public const int SW_HIDE = 0;
public const int SW_SHOWNORMAL = 1;
public const int SW_NORMAL = 1;
public const int SW_SHOWMINIMIZED = 2;
public const int SW_SHOWMAXIMIZED = 3;
public const int SW_MAXIMIZE = 3;
public const int SW_SHOWNOACTIVATE = 4;
public const int SW_SHOW = 5;
public const int SW_MINIMIZE = 6;
public const int SW_SHOWMINNOACTIVE = 7;
public const int SW_SHOWNA = 8;
public const int SW_RESTORE = 9;
public const int SW_SHOWDEFAULT = 10;
public const int SW_FORCEMINIMIZE = 11;
public const int SW_MAX = 11;
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, ref IntPtr lParam);
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumWindowsProc lpEnumFunc, ref IntPtr lParam);
public delegate bool EnumWindowsProc(IntPtr hWnd, ref IntPtr lParam);
public const long SYNCHRONIZE = (0x00100000L);
public const int STANDARD_RIGHTS_REQUIRED = (0x000F0000);
public const int PROCESS_VM_READ = (0x0010);
public const int PROCESS_VM_WRITE = (0x0020);
public const int PROCESS_DUP_HANDLE = (0x0040);
public const int PROCESS_CREATE_PROCESS = (0x0080);
public const int PROCESS_SET_QUOTA = (0x0100);
public const int PROCESS_SET_INFORMATION = (0x0200);
public const int PROCESS_QUERY_INFORMATION = (0x0400);
public const int PROCESS_SUSPEND_RESUME = (0x0800);
public const int PROCESS_QUERY_LIMITED_INFORMATION = (0x1000);
public const int PROCESS_SET_LIMITED_INFORMATION = (0x2000);
public const long PROCESS_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFFF);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool QueryFullProcessImageName(IntPtr hProcess, int dwFlags, StringBuilder lpExeName, ref uint lpdwSize);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool GetPackageFullName(IntPtr hProcess, ref uint packageFullNameLength, StringBuilder packageFullName);
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool IsWindowVisible(IntPtr hWnd);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
public const int SPI_GETWORKAREA = 0x0030;
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, [In, Out] ref RECT pvParam, uint fWinIni);
[DllImport("Shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern HRESULT SHGetPropertyStoreForWindow(IntPtr hwnd, ref Guid iid, [Out(), MarshalAs(UnmanagedType.Interface)] out IPropertyStore propertyStore);
public struct PROPERTYKEY
{
public PROPERTYKEY(Guid InputId, UInt32 InputPid)
{
fmtid = InputId;
pid = InputPid;
}
Guid fmtid;
uint pid;
};
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct PROPARRAY
{
public UInt32 cElems;
public IntPtr pElems;
}
[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct PROPVARIANT
{
[FieldOffset(0)]
public ushort varType;
[FieldOffset(2)]
public ushort wReserved1;
[FieldOffset(4)]
public ushort wReserved2;
[FieldOffset(6)]
public ushort wReserved3;
[FieldOffset(8)]
public byte bVal;
[FieldOffset(8)]
public sbyte cVal;
[FieldOffset(8)]
public ushort uiVal;
[FieldOffset(8)]
public short iVal;
[FieldOffset(8)]
public UInt32 uintVal;
[FieldOffset(8)]
public Int32 intVal;
[FieldOffset(8)]
public UInt64 ulVal;
[FieldOffset(8)]
public Int64 lVal;
[FieldOffset(8)]
public float fltVal;
[FieldOffset(8)]
public double dblVal;
[FieldOffset(8)]
public short boolVal;
[FieldOffset(8)]
public IntPtr pclsidVal; // GUID ID pointer
[FieldOffset(8)]
public IntPtr pszVal; // Ansi string pointer
[FieldOffset(8)]
public IntPtr pwszVal; // Unicode string pointer
[FieldOffset(8)]
public IntPtr punkVal; // punkVal (interface pointer)
[FieldOffset(8)]
public PROPARRAY ca;
[FieldOffset(8)]
public System.Runtime.InteropServices.ComTypes.FILETIME filetime;
}
[ComImport, Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPropertyStore
{
HRESULT GetCount([Out] out uint propertyCount);
HRESULT GetAt([In] uint propertyIndex, [Out, MarshalAs(UnmanagedType.Struct)] out PROPERTYKEY key);
HRESULT GetValue([In, MarshalAs(UnmanagedType.Struct)] ref PROPERTYKEY key, [Out, MarshalAs(UnmanagedType.Struct)] out PROPVARIANT pv);
HRESULT SetValue([In, MarshalAs(UnmanagedType.Struct)] ref PROPERTYKEY key, [In, MarshalAs(UnmanagedType.Struct)] ref PROPVARIANT pv);
HRESULT Commit();
}
public static PROPERTYKEY PKEY_AppUserModel_ID = new PROPERTYKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 5);
[DllImport("dwmapi.dll")]
private static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out IntPtr pvAttribute, int cbAttribute);
[DllImport("dwmapi.dll")]
private static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out RECT pvAttribute, int cbAttribute);
enum DWMWINDOWATTRIBUTE
{
DWMWA_NCRENDERING_ENABLED = 1,
DWMWA_NCRENDERING_POLICY,
DWMWA_TRANSITIONS_FORCEDISABLED,
DWMWA_ALLOW_NCPAINT,
DWMWA_CAPTION_BUTTON_BOUNDS,
DWMWA_NONCLIENT_RTL_LAYOUT,
DWMWA_FORCE_ICONIC_REPRESENTATION,
DWMWA_FLIP3D_POLICY,
DWMWA_EXTENDED_FRAME_BOUNDS,
DWMWA_HAS_ICONIC_BITMAP,
DWMWA_DISALLOW_PEEK,
DWMWA_EXCLUDED_FROM_PEEK,
DWMWA_CLOAK,
DWMWA_CLOAKED,
DWMWA_FREEZE_REPRESENTATION,
DWMWA_LAST
}
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool SwitchToThisWindow(IntPtr hWnd, Boolean fAltTab);
public const int SWP_NOSIZE = 0x0001;
public const int SWP_NOMOVE = 0x0002;
public const int SWP_NOZORDER = 0x0004;
public const int SWP_NOREDRAW = 0x0008;
public const int SWP_NOACTIVATE = 0x0010;
public const int SWP_FRAMECHANGED = 0x0020; /* The frame changed: send WM_NCCALCSIZE */
public const int SWP_SHOWWINDOW = 0x0040;
public const int SWP_HIDEWINDOW = 0x0080;
public const int SWP_NOCOPYBITS = 0x0100;
public const int SWP_NOOWNERZORDER = 0x0200; /* Don't do owner Z ordering */
public const int SWP_NOSENDCHANGING = 0x0400; /* Don't send WM_WINDOWPOSCHANGING */
public const int SWP_DRAWFRAME = SWP_FRAMECHANGED;
public const int SWP_NOREPOSITION = SWP_NOOWNERZORDER;
public const int SWP_DEFERERASE = 0x2000;
public const int SWP_ASYNCWINDOWPOS = 0x4000;
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
public static bool ListWindows(IntPtr hWnd, ref IntPtr lParam)
{
ENUMPARAM ep = (ENUMPARAM)Marshal.PtrToStructure(lParam, typeof(ENUMPARAM));
StringBuilder sbClassName = new StringBuilder(260);
string sClassName = null;
GetClassName(hWnd, sbClassName, (int)(sbClassName.Capacity));
sClassName = sbClassName.ToString();
// Minimized : "Windows.UI.Core.CoreWindow" top window
// Normal : "Windows.UI.Core.CoreWindow" child of "ApplicationFrameWindow"
if (sClassName == "Windows.UI.Core.CoreWindow")
{
int nPID = 0;
uint nThreadId = GetWindowThreadProcessId(hWnd, out nPID);
IntPtr hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, nPID);
string sPackage = string.Empty;
if (hProcess != IntPtr.Zero)
{
uint nSize = 260;
StringBuilder sPackageFullName = new StringBuilder((int)nSize);
GetPackageFullName(hProcess, ref nSize, sPackageFullName);
if (sPackageFullName.ToString().ToLower().Contains("calculator") && IsWindowVisible(hWnd))
{
nSize = 260;
StringBuilder sProcessImageName = new StringBuilder((int)nSize);
QueryFullProcessImageName(hProcess, 0, sProcessImageName, ref nSize);
//hWnd = FindWindow("ApplicationFrameWindow", "Calculatrice");
//ep.hWnd = hWnd;
ep.sExeName = sProcessImageName.ToString();
ep.nPID = nPID;
ep.nState = 1;
Marshal.StructureToPtr(ep, lParam, false);
if (ep.hWnd != IntPtr.Zero)
{
CloseHandle(hProcess);
return false;
}
}
CloseHandle(hProcess);
}
}
if (sClassName == "ApplicationFrameWindow")
{
// get real hWnd
IPropertyStore pPropertyStore;
Guid guid = new Guid("{886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99}");
HRESULT hr = SHGetPropertyStoreForWindow(hWnd, ref guid, out pPropertyStore);
//if (hr != HRESULT.S_OK)
// throw Marshal.GetExceptionForHR((int)hr);
if (hr == HRESULT.S_OK)
{
PROPVARIANT propVar = new PROPVARIANT();
hr = pPropertyStore.GetValue(ref PKEY_AppUserModel_ID, out propVar);
string sAUMID = Marshal.PtrToStringUni(propVar.pwszVal);
if (sAUMID != null && sAUMID.ToLower().Contains("calculator"))
{
RECT rect, rectWorkArea = new RECT();
GetWindowRect(hWnd, out rect);
IntPtr pRectWorkArea = IntPtr.Zero;
bool bRet = SystemParametersInfo(SPI_GETWORKAREA, 0, ref rectWorkArea, 0);
// maximized : out of SPI_GETWORKAREA
if (rect.left < rectWorkArea.left && rect.top < rectWorkArea.top && rect.right > rectWorkArea.right && rect.bottom > rectWorkArea.bottom)
ep.nState = 2;
ep.hWnd = hWnd;
Marshal.StructureToPtr(ep, lParam, false);
}
Marshal.ReleaseComObject(pPropertyStore);
}
IntPtr hWndFind = FindWindowEx(hWnd, IntPtr.Zero, "Windows.UI.Core.CoreWindow", null);
if (hWndFind != IntPtr.Zero)
{
int nPID = 0;
uint nThreadId = GetWindowThreadProcessId(hWndFind, out nPID);
IntPtr hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, nPID);
string sPackage = string.Empty;
if (hProcess != IntPtr.Zero)
{
uint nSize = 260;
StringBuilder sPackageFullName = new StringBuilder((int)nSize);
GetPackageFullName(hProcess, ref nSize, sPackageFullName);
if (sPackageFullName.ToString().ToLower().Contains("calculator") && IsWindowVisible(hWnd))
{
nSize = 260;
StringBuilder sProcessImageName = new StringBuilder((int)nSize);
QueryFullProcessImageName(hProcess, 0, sProcessImageName, ref nSize);
ep.hWnd = hWnd;
ep.sExeName = sProcessImageName.ToString();
ep.nPID = nPID;
Marshal.StructureToPtr(ep, lParam, false);
CloseHandle(hProcess);
return false;
}
CloseHandle(hProcess);
}
}
}
return true;
}
public Form1()
{
InitializeComponent();
}
private System.Windows.Forms.Button button1;
private void Form1_Load(object sender, EventArgs e)
{
this.button1 = new System.Windows.Forms.Button();
this.button1.Location = new System.Drawing.Point(105, 110);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 0;
this.button1.Text = "Find Calc";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 261);
this.Controls.Add(this.button1);
CenterToScreen();
}
private void button1_Click(object sender, EventArgs e)
{
EnumWindowsProc Callback = new EnumWindowsProc(ListWindows);
ENUMPARAM ep = new ENUMPARAM();
IntPtr plParam = Marshal.AllocHGlobal(Marshal.SizeOf(ep));
Marshal.StructureToPtr(ep, plParam, false);
EnumWindows(Callback, ref plParam);
ENUMPARAM epret = (ENUMPARAM)Marshal.PtrToStructure(plParam, typeof(ENUMPARAM));
Marshal.FreeHGlobal(plParam);
if (epret.hWnd != IntPtr.Zero)
{
// State can also be got with UI Automation and WindowVisualState
//string sState = (epret.nState == 1) ? "\n(state = minimized)" : "";
string sState = string.Empty;
switch (epret.nState)
{
case 0:
sState = "Normal";
break;
case 1:
sState = "Minimized";
break;
case 2:
sState = "Maximized";
break;
}
MessageBox.Show(string.Format("Window handle = 0x{0}\nPID = {1}\nExecutable = {2}\nState = {3}", epret.hWnd.ToString("X"), epret.nPID, epret.sExeName, sState), "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
MessageBox.Show("Calc not found", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
ShowWindow(epret.hWnd, SW_SHOWNORMAL);
SetWindowPos(epret.hWnd, new IntPtr(-1), 100, 100, 0, 0, SWP_NOSIZE);
}
[StructLayoutAttribute(LayoutKind.Sequential)]
private struct ENUMPARAM
{
public IntPtr hWnd;
public int nPID;
public string sExeName;
public int nState;
}
}