@nimoxie/dsh-ui-tweaks 0.1.7 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DEVELOPMENT.md +147 -116
- package/LICENSE +21 -21
- package/README.md +157 -137
- package/cordis.patch.yml +7 -7
- package/lib/client.js +448 -30
- package/lib/window-helper.cs +195 -195
- package/lib/window-helper.ps1 +276 -276
- package/package.json +1 -1
package/lib/window-helper.cs
CHANGED
|
@@ -1,195 +1,195 @@
|
|
|
1
|
-
// dsh-ui-tweaks window-state helper (host half, compiled at plugin load).
|
|
2
|
-
//
|
|
3
|
-
// lib/index.js compiles this to window-helper.dll (csc /target:library) and
|
|
4
|
-
// lib/window-helper.ps1 loads it via Assembly.Load(byte[]) - in-process, no
|
|
5
|
-
// security prompt. A locally built exe was tried first and abandoned: unsigned
|
|
6
|
-
// exes trigger the "unknown publisher" dialog on every launch (and security
|
|
7
|
-
// software silently blocks them).
|
|
8
|
-
//
|
|
9
|
-
// DshWin exposes the Win32 surface the PowerShell orchestrator calls:
|
|
10
|
-
// WindowsOfPid / Alive / Visible / Placement / MoveTo / Maximize / Hide / Show /
|
|
11
|
-
// IsForeground / MaximizedState / IntersectsMonitor / ParentPid
|
|
12
|
-
// lib/window-helper.ps1 is the ONLY orchestrator (host discovery + restore/save loop).
|
|
13
|
-
// A Program.Main duplicating that orchestration existed for the earlier standalone-exe
|
|
14
|
-
// approach; deleted in 0.1.6 - it had drifted out of date and nothing called it.
|
|
15
|
-
//
|
|
16
|
-
// Client process tree (all one exe name):
|
|
17
|
-
// main -> --expose-internals -> spawn-bridge -> dsh runtime -> (helper)
|
|
18
|
-
// The host (Electron main, owns the window) is the TOPMOST "DeepSeek Harness"
|
|
19
|
-
// ancestor of the runtime, not the first match.
|
|
20
|
-
//
|
|
21
|
-
// NOTE: keep C# 5 compatible (OS-shipped legacy csc) and pure ASCII.
|
|
22
|
-
|
|
23
|
-
using System;
|
|
24
|
-
using System.Collections.Generic;
|
|
25
|
-
using System.Runtime.InteropServices;
|
|
26
|
-
using System.Text;
|
|
27
|
-
|
|
28
|
-
public class DshWin
|
|
29
|
-
{
|
|
30
|
-
[StructLayout(LayoutKind.Sequential)]
|
|
31
|
-
public struct RECT { public int Left, Top, Right, Bottom; }
|
|
32
|
-
|
|
33
|
-
[StructLayout(LayoutKind.Sequential)]
|
|
34
|
-
public struct POINT { public int X, Y; }
|
|
35
|
-
|
|
36
|
-
[StructLayout(LayoutKind.Sequential)]
|
|
37
|
-
public struct WINDOWPLACEMENT
|
|
38
|
-
{
|
|
39
|
-
public uint length, flags, showCmd;
|
|
40
|
-
public POINT ptMinPosition, ptMaxPosition;
|
|
41
|
-
public RECT rcNormalPosition;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
[StructLayout(LayoutKind.Sequential)]
|
|
45
|
-
public struct MONITORINFO
|
|
46
|
-
{
|
|
47
|
-
public uint cbSize;
|
|
48
|
-
public RECT rcMonitor, rcWork;
|
|
49
|
-
public uint dwFlags;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
[StructLayout(LayoutKind.Sequential)]
|
|
53
|
-
public struct PROCESS_BASIC_INFORMATION
|
|
54
|
-
{
|
|
55
|
-
public IntPtr Reserved1;
|
|
56
|
-
public IntPtr PebBaseAddress;
|
|
57
|
-
public IntPtr Reserved2_0;
|
|
58
|
-
public IntPtr Reserved2_1;
|
|
59
|
-
public IntPtr UniqueProcessId;
|
|
60
|
-
public IntPtr InheritedFromUniqueProcessId;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
public class WinInfo
|
|
64
|
-
{
|
|
65
|
-
public IntPtr Hwnd;
|
|
66
|
-
public string Title = "";
|
|
67
|
-
public string ClassName = "";
|
|
68
|
-
public RECT Rect;
|
|
69
|
-
public long Style;
|
|
70
|
-
public bool Visible;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
private delegate bool EnumProc(IntPtr hWnd, IntPtr lParam);
|
|
74
|
-
|
|
75
|
-
[DllImport("user32.dll")] private static extern bool EnumWindows(EnumProc cb, IntPtr lp);
|
|
76
|
-
[DllImport("user32.dll")] private static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);
|
|
77
|
-
[DllImport("user32.dll")] private static extern bool IsWindowVisible(IntPtr h);
|
|
78
|
-
[DllImport("user32.dll")] private static extern bool IsWindow(IntPtr h);
|
|
79
|
-
[DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern int GetClassName(IntPtr h, StringBuilder sb, int max);
|
|
80
|
-
[DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern int GetWindowText(IntPtr h, StringBuilder sb, int max);
|
|
81
|
-
[DllImport("user32.dll")] private static extern bool GetWindowRect(IntPtr h, out RECT r);
|
|
82
|
-
[DllImport("user32.dll")] private static extern int GetWindowLong(IntPtr h, int idx);
|
|
83
|
-
[DllImport("user32.dll")] private static extern bool GetWindowPlacement(IntPtr h, ref WINDOWPLACEMENT p);
|
|
84
|
-
[DllImport("user32.dll")] private static extern bool SetWindowPos(IntPtr h, IntPtr after, int x, int y, int w, int ht, uint flags);
|
|
85
|
-
[DllImport("user32.dll")] private static extern bool ShowWindow(IntPtr h, int cmd);
|
|
86
|
-
[DllImport("user32.dll")] private static extern IntPtr MonitorFromRect(ref RECT r, uint flags);
|
|
87
|
-
[DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow();
|
|
88
|
-
[DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern bool GetMonitorInfo(IntPtr hMon, ref MONITORINFO info);
|
|
89
|
-
[DllImport("ntdll.dll")] private static extern int NtQueryInformationProcess(IntPtr hProc, int pic, ref PROCESS_BASIC_INFORMATION pbi, int cb, out int pSize);
|
|
90
|
-
[DllImport("kernel32.dll")] private static extern IntPtr OpenProcess(uint access, bool inherit, uint pid);
|
|
91
|
-
[DllImport("kernel32.dll")] private static extern bool CloseHandle(IntPtr h);
|
|
92
|
-
|
|
93
|
-
public static WinInfo[] WindowsOfPid(uint pid)
|
|
94
|
-
{
|
|
95
|
-
var list = new List<WinInfo>();
|
|
96
|
-
EnumWindows(delegate(IntPtr h, IntPtr lp)
|
|
97
|
-
{
|
|
98
|
-
uint p;
|
|
99
|
-
GetWindowThreadProcessId(h, out p);
|
|
100
|
-
if (p != pid) return true;
|
|
101
|
-
var cn = new StringBuilder(256); GetClassName(h, cn, 256);
|
|
102
|
-
var t = new StringBuilder(512); GetWindowText(h, t, 512);
|
|
103
|
-
RECT r; GetWindowRect(h, out r);
|
|
104
|
-
var info = new WinInfo();
|
|
105
|
-
info.Hwnd = h;
|
|
106
|
-
info.Title = t.ToString();
|
|
107
|
-
info.ClassName = cn.ToString();
|
|
108
|
-
info.Rect = r;
|
|
109
|
-
info.Style = (long)GetWindowLong(h, -16);
|
|
110
|
-
info.Visible = IsWindowVisible(h);
|
|
111
|
-
list.Add(info);
|
|
112
|
-
return true;
|
|
113
|
-
}, IntPtr.Zero);
|
|
114
|
-
return list.ToArray();
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
public static bool Alive(IntPtr h) { return IsWindow(h); }
|
|
118
|
-
public static bool Visible(IntPtr h) { return IsWindowVisible(h); }
|
|
119
|
-
|
|
120
|
-
public static bool Placement(IntPtr h, out uint showCmd, out RECT normal)
|
|
121
|
-
{
|
|
122
|
-
WINDOWPLACEMENT wp = new WINDOWPLACEMENT();
|
|
123
|
-
wp.length = (uint)Marshal.SizeOf(typeof(WINDOWPLACEMENT));
|
|
124
|
-
showCmd = 0;
|
|
125
|
-
normal = new RECT();
|
|
126
|
-
if (!GetWindowPlacement(h, ref wp)) return false;
|
|
127
|
-
showCmd = wp.showCmd;
|
|
128
|
-
normal = wp.rcNormalPosition;
|
|
129
|
-
return true;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// SWP_NOZORDER(0x4) | SWP_NOACTIVATE(0x10)
|
|
133
|
-
public static bool MoveTo(IntPtr h, int x, int y, int w, int ht)
|
|
134
|
-
{
|
|
135
|
-
return SetWindowPos(h, IntPtr.Zero, x, y, w, ht, 0x14);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/// Maximized detection must accept both "currently maximized" and
|
|
139
|
-
/// "maximized then minimized": the latter reports showCmd SW_SHOWMINIMIZED (2)
|
|
140
|
-
/// but keeps WPF_RESTORETOMAXIMIZED (0x2) in flags. Checking showCmd == 3 alone
|
|
141
|
-
/// loses the maximized flag after maximize -> minimize -> close.
|
|
142
|
-
public static bool MaximizedState(IntPtr h)
|
|
143
|
-
{
|
|
144
|
-
WINDOWPLACEMENT wp = new WINDOWPLACEMENT();
|
|
145
|
-
wp.length = (uint)Marshal.SizeOf(typeof(WINDOWPLACEMENT));
|
|
146
|
-
if (!GetWindowPlacement(h, ref wp)) return false;
|
|
147
|
-
if (wp.showCmd == 3) return true; // SW_SHOWMAXIMIZED
|
|
148
|
-
if (wp.showCmd == 2) return (wp.flags & 0x2) != 0; // SW_SHOWMINIMIZED + WPF_RESTORETOMAXIMIZED
|
|
149
|
-
return false;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
public static bool Maximize(IntPtr h) { return ShowWindow(h, 3); } // SW_MAXIMIZE (also shows)
|
|
154
|
-
public static bool Restore(IntPtr h) { return ShowWindow(h, 9); } // SW_RESTORE (un-maximize)
|
|
155
|
-
|
|
156
|
-
// For the hide -> move -> show sandwich: moving a visible window makes the user
|
|
157
|
-
// watch it appear at the default spot and then jump; moving while hidden is
|
|
158
|
-
// nearly invisible. activate=false uses SW_SHOWNA so focus is not stolen.
|
|
159
|
-
public static bool Hide(IntPtr h) { return ShowWindow(h, 0); } // SW_HIDE
|
|
160
|
-
public static bool Show(IntPtr h, bool activate) { return ShowWindow(h, activate ? 5 : 8); }
|
|
161
|
-
|
|
162
|
-
public static bool IsForeground(IntPtr h)
|
|
163
|
-
{
|
|
164
|
-
return GetForegroundWindow() == h;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
public static bool IntersectsMonitor(int x, int y, int w, int ht)
|
|
168
|
-
{
|
|
169
|
-
RECT r = new RECT();
|
|
170
|
-
r.Left = x; r.Top = y; r.Right = x + w; r.Bottom = y + ht;
|
|
171
|
-
IntPtr m = MonitorFromRect(ref r, 0); // MONITOR_DEFAULTTONULL
|
|
172
|
-
if (m == IntPtr.Zero) return false;
|
|
173
|
-
MONITORINFO mi = new MONITORINFO();
|
|
174
|
-
mi.cbSize = (uint)Marshal.SizeOf(typeof(MONITORINFO));
|
|
175
|
-
return GetMonitorInfo(m, ref mi);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Parent PID via ntdll; no WMI round-trip (discovery must stay fast).
|
|
179
|
-
public static long ParentPid(long pid)
|
|
180
|
-
{
|
|
181
|
-
if (pid <= 0 || pid > uint.MaxValue) return -1;
|
|
182
|
-
IntPtr h = OpenProcess(0x0400, false, (uint)pid); // PROCESS_QUERY_INFORMATION
|
|
183
|
-
if (h == IntPtr.Zero) h = OpenProcess(0x1000, false, (uint)pid); // ..._LIMITED_INFORMATION
|
|
184
|
-
if (h == IntPtr.Zero) return -1;
|
|
185
|
-
try
|
|
186
|
-
{
|
|
187
|
-
PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION();
|
|
188
|
-
int size;
|
|
189
|
-
int st = NtQueryInformationProcess(h, 0, ref pbi, Marshal.SizeOf(typeof(PROCESS_BASIC_INFORMATION)), out size);
|
|
190
|
-
if (st != 0) return -1;
|
|
191
|
-
return pbi.InheritedFromUniqueProcessId.ToInt64();
|
|
192
|
-
}
|
|
193
|
-
finally { CloseHandle(h); }
|
|
194
|
-
}
|
|
195
|
-
}
|
|
1
|
+
// dsh-ui-tweaks window-state helper (host half, compiled at plugin load).
|
|
2
|
+
//
|
|
3
|
+
// lib/index.js compiles this to window-helper.dll (csc /target:library) and
|
|
4
|
+
// lib/window-helper.ps1 loads it via Assembly.Load(byte[]) - in-process, no
|
|
5
|
+
// security prompt. A locally built exe was tried first and abandoned: unsigned
|
|
6
|
+
// exes trigger the "unknown publisher" dialog on every launch (and security
|
|
7
|
+
// software silently blocks them).
|
|
8
|
+
//
|
|
9
|
+
// DshWin exposes the Win32 surface the PowerShell orchestrator calls:
|
|
10
|
+
// WindowsOfPid / Alive / Visible / Placement / MoveTo / Maximize / Hide / Show /
|
|
11
|
+
// IsForeground / MaximizedState / IntersectsMonitor / ParentPid
|
|
12
|
+
// lib/window-helper.ps1 is the ONLY orchestrator (host discovery + restore/save loop).
|
|
13
|
+
// A Program.Main duplicating that orchestration existed for the earlier standalone-exe
|
|
14
|
+
// approach; deleted in 0.1.6 - it had drifted out of date and nothing called it.
|
|
15
|
+
//
|
|
16
|
+
// Client process tree (all one exe name):
|
|
17
|
+
// main -> --expose-internals -> spawn-bridge -> dsh runtime -> (helper)
|
|
18
|
+
// The host (Electron main, owns the window) is the TOPMOST "DeepSeek Harness"
|
|
19
|
+
// ancestor of the runtime, not the first match.
|
|
20
|
+
//
|
|
21
|
+
// NOTE: keep C# 5 compatible (OS-shipped legacy csc) and pure ASCII.
|
|
22
|
+
|
|
23
|
+
using System;
|
|
24
|
+
using System.Collections.Generic;
|
|
25
|
+
using System.Runtime.InteropServices;
|
|
26
|
+
using System.Text;
|
|
27
|
+
|
|
28
|
+
public class DshWin
|
|
29
|
+
{
|
|
30
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
31
|
+
public struct RECT { public int Left, Top, Right, Bottom; }
|
|
32
|
+
|
|
33
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
34
|
+
public struct POINT { public int X, Y; }
|
|
35
|
+
|
|
36
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
37
|
+
public struct WINDOWPLACEMENT
|
|
38
|
+
{
|
|
39
|
+
public uint length, flags, showCmd;
|
|
40
|
+
public POINT ptMinPosition, ptMaxPosition;
|
|
41
|
+
public RECT rcNormalPosition;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
45
|
+
public struct MONITORINFO
|
|
46
|
+
{
|
|
47
|
+
public uint cbSize;
|
|
48
|
+
public RECT rcMonitor, rcWork;
|
|
49
|
+
public uint dwFlags;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
53
|
+
public struct PROCESS_BASIC_INFORMATION
|
|
54
|
+
{
|
|
55
|
+
public IntPtr Reserved1;
|
|
56
|
+
public IntPtr PebBaseAddress;
|
|
57
|
+
public IntPtr Reserved2_0;
|
|
58
|
+
public IntPtr Reserved2_1;
|
|
59
|
+
public IntPtr UniqueProcessId;
|
|
60
|
+
public IntPtr InheritedFromUniqueProcessId;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public class WinInfo
|
|
64
|
+
{
|
|
65
|
+
public IntPtr Hwnd;
|
|
66
|
+
public string Title = "";
|
|
67
|
+
public string ClassName = "";
|
|
68
|
+
public RECT Rect;
|
|
69
|
+
public long Style;
|
|
70
|
+
public bool Visible;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private delegate bool EnumProc(IntPtr hWnd, IntPtr lParam);
|
|
74
|
+
|
|
75
|
+
[DllImport("user32.dll")] private static extern bool EnumWindows(EnumProc cb, IntPtr lp);
|
|
76
|
+
[DllImport("user32.dll")] private static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);
|
|
77
|
+
[DllImport("user32.dll")] private static extern bool IsWindowVisible(IntPtr h);
|
|
78
|
+
[DllImport("user32.dll")] private static extern bool IsWindow(IntPtr h);
|
|
79
|
+
[DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern int GetClassName(IntPtr h, StringBuilder sb, int max);
|
|
80
|
+
[DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern int GetWindowText(IntPtr h, StringBuilder sb, int max);
|
|
81
|
+
[DllImport("user32.dll")] private static extern bool GetWindowRect(IntPtr h, out RECT r);
|
|
82
|
+
[DllImport("user32.dll")] private static extern int GetWindowLong(IntPtr h, int idx);
|
|
83
|
+
[DllImport("user32.dll")] private static extern bool GetWindowPlacement(IntPtr h, ref WINDOWPLACEMENT p);
|
|
84
|
+
[DllImport("user32.dll")] private static extern bool SetWindowPos(IntPtr h, IntPtr after, int x, int y, int w, int ht, uint flags);
|
|
85
|
+
[DllImport("user32.dll")] private static extern bool ShowWindow(IntPtr h, int cmd);
|
|
86
|
+
[DllImport("user32.dll")] private static extern IntPtr MonitorFromRect(ref RECT r, uint flags);
|
|
87
|
+
[DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow();
|
|
88
|
+
[DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern bool GetMonitorInfo(IntPtr hMon, ref MONITORINFO info);
|
|
89
|
+
[DllImport("ntdll.dll")] private static extern int NtQueryInformationProcess(IntPtr hProc, int pic, ref PROCESS_BASIC_INFORMATION pbi, int cb, out int pSize);
|
|
90
|
+
[DllImport("kernel32.dll")] private static extern IntPtr OpenProcess(uint access, bool inherit, uint pid);
|
|
91
|
+
[DllImport("kernel32.dll")] private static extern bool CloseHandle(IntPtr h);
|
|
92
|
+
|
|
93
|
+
public static WinInfo[] WindowsOfPid(uint pid)
|
|
94
|
+
{
|
|
95
|
+
var list = new List<WinInfo>();
|
|
96
|
+
EnumWindows(delegate(IntPtr h, IntPtr lp)
|
|
97
|
+
{
|
|
98
|
+
uint p;
|
|
99
|
+
GetWindowThreadProcessId(h, out p);
|
|
100
|
+
if (p != pid) return true;
|
|
101
|
+
var cn = new StringBuilder(256); GetClassName(h, cn, 256);
|
|
102
|
+
var t = new StringBuilder(512); GetWindowText(h, t, 512);
|
|
103
|
+
RECT r; GetWindowRect(h, out r);
|
|
104
|
+
var info = new WinInfo();
|
|
105
|
+
info.Hwnd = h;
|
|
106
|
+
info.Title = t.ToString();
|
|
107
|
+
info.ClassName = cn.ToString();
|
|
108
|
+
info.Rect = r;
|
|
109
|
+
info.Style = (long)GetWindowLong(h, -16);
|
|
110
|
+
info.Visible = IsWindowVisible(h);
|
|
111
|
+
list.Add(info);
|
|
112
|
+
return true;
|
|
113
|
+
}, IntPtr.Zero);
|
|
114
|
+
return list.ToArray();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
public static bool Alive(IntPtr h) { return IsWindow(h); }
|
|
118
|
+
public static bool Visible(IntPtr h) { return IsWindowVisible(h); }
|
|
119
|
+
|
|
120
|
+
public static bool Placement(IntPtr h, out uint showCmd, out RECT normal)
|
|
121
|
+
{
|
|
122
|
+
WINDOWPLACEMENT wp = new WINDOWPLACEMENT();
|
|
123
|
+
wp.length = (uint)Marshal.SizeOf(typeof(WINDOWPLACEMENT));
|
|
124
|
+
showCmd = 0;
|
|
125
|
+
normal = new RECT();
|
|
126
|
+
if (!GetWindowPlacement(h, ref wp)) return false;
|
|
127
|
+
showCmd = wp.showCmd;
|
|
128
|
+
normal = wp.rcNormalPosition;
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// SWP_NOZORDER(0x4) | SWP_NOACTIVATE(0x10)
|
|
133
|
+
public static bool MoveTo(IntPtr h, int x, int y, int w, int ht)
|
|
134
|
+
{
|
|
135
|
+
return SetWindowPos(h, IntPtr.Zero, x, y, w, ht, 0x14);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/// Maximized detection must accept both "currently maximized" and
|
|
139
|
+
/// "maximized then minimized": the latter reports showCmd SW_SHOWMINIMIZED (2)
|
|
140
|
+
/// but keeps WPF_RESTORETOMAXIMIZED (0x2) in flags. Checking showCmd == 3 alone
|
|
141
|
+
/// loses the maximized flag after maximize -> minimize -> close.
|
|
142
|
+
public static bool MaximizedState(IntPtr h)
|
|
143
|
+
{
|
|
144
|
+
WINDOWPLACEMENT wp = new WINDOWPLACEMENT();
|
|
145
|
+
wp.length = (uint)Marshal.SizeOf(typeof(WINDOWPLACEMENT));
|
|
146
|
+
if (!GetWindowPlacement(h, ref wp)) return false;
|
|
147
|
+
if (wp.showCmd == 3) return true; // SW_SHOWMAXIMIZED
|
|
148
|
+
if (wp.showCmd == 2) return (wp.flags & 0x2) != 0; // SW_SHOWMINIMIZED + WPF_RESTORETOMAXIMIZED
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
public static bool Maximize(IntPtr h) { return ShowWindow(h, 3); } // SW_MAXIMIZE (also shows)
|
|
154
|
+
public static bool Restore(IntPtr h) { return ShowWindow(h, 9); } // SW_RESTORE (un-maximize)
|
|
155
|
+
|
|
156
|
+
// For the hide -> move -> show sandwich: moving a visible window makes the user
|
|
157
|
+
// watch it appear at the default spot and then jump; moving while hidden is
|
|
158
|
+
// nearly invisible. activate=false uses SW_SHOWNA so focus is not stolen.
|
|
159
|
+
public static bool Hide(IntPtr h) { return ShowWindow(h, 0); } // SW_HIDE
|
|
160
|
+
public static bool Show(IntPtr h, bool activate) { return ShowWindow(h, activate ? 5 : 8); }
|
|
161
|
+
|
|
162
|
+
public static bool IsForeground(IntPtr h)
|
|
163
|
+
{
|
|
164
|
+
return GetForegroundWindow() == h;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
public static bool IntersectsMonitor(int x, int y, int w, int ht)
|
|
168
|
+
{
|
|
169
|
+
RECT r = new RECT();
|
|
170
|
+
r.Left = x; r.Top = y; r.Right = x + w; r.Bottom = y + ht;
|
|
171
|
+
IntPtr m = MonitorFromRect(ref r, 0); // MONITOR_DEFAULTTONULL
|
|
172
|
+
if (m == IntPtr.Zero) return false;
|
|
173
|
+
MONITORINFO mi = new MONITORINFO();
|
|
174
|
+
mi.cbSize = (uint)Marshal.SizeOf(typeof(MONITORINFO));
|
|
175
|
+
return GetMonitorInfo(m, ref mi);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Parent PID via ntdll; no WMI round-trip (discovery must stay fast).
|
|
179
|
+
public static long ParentPid(long pid)
|
|
180
|
+
{
|
|
181
|
+
if (pid <= 0 || pid > uint.MaxValue) return -1;
|
|
182
|
+
IntPtr h = OpenProcess(0x0400, false, (uint)pid); // PROCESS_QUERY_INFORMATION
|
|
183
|
+
if (h == IntPtr.Zero) h = OpenProcess(0x1000, false, (uint)pid); // ..._LIMITED_INFORMATION
|
|
184
|
+
if (h == IntPtr.Zero) return -1;
|
|
185
|
+
try
|
|
186
|
+
{
|
|
187
|
+
PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION();
|
|
188
|
+
int size;
|
|
189
|
+
int st = NtQueryInformationProcess(h, 0, ref pbi, Marshal.SizeOf(typeof(PROCESS_BASIC_INFORMATION)), out size);
|
|
190
|
+
if (st != 0) return -1;
|
|
191
|
+
return pbi.InheritedFromUniqueProcessId.ToInt64();
|
|
192
|
+
}
|
|
193
|
+
finally { CloseHandle(h); }
|
|
194
|
+
}
|
|
195
|
+
}
|