455 lines
15 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Diagnostics;
using System.Web.Script.Serialization;
public class WindowManager
{
#region Win32 API
[DllImport("user32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
private static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
private static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);
[DllImport("user32.dll")]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")]
private static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
[DllImport("user32.dll")]
private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll")]
private static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool IsZoomed(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll")]
private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
private static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
private const uint SWP_NOMOVE = 0x0002;
private const uint SWP_NOSIZE = 0x0001;
private const uint WM_CLOSE = 0x0010;
private const int GWL_STYLE = -16;
private const int GWL_EXSTYLE = -20;
private const int WS_BORDER = 0x00800000;
private const int WS_CAPTION = 0x00C00000;
private const int WS_CHILD = 0x40000000;
private const int WS_POPUP = unchecked((int)0x80000000);
private const int WS_SYSMENU = 0x00080000;
private const int WS_MINIMIZEBOX = 0x00020000;
private const int WS_MAXIMIZEBOX = 0x00010000;
private const int WS_EX_TOPMOST = 0x00000008;
private const int WS_EX_TRANSPARENT = 0x00000020;
private const int WS_EX_TOOLWINDOW = 0x00000080;
private const int WS_EX_LAYERED = 0x00080000;
private const uint LWA_ALPHA = 0x2;
private const int SW_HIDE = 0;
private const int SW_SHOW = 5;
private const int SW_NORMAL = 1;
private const int SW_MAXIMIZE = 3;
private const int SW_MINIMIZE = 6;
private const int SW_RESTORE = 9;
private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
#endregion
public static void Main(string[] args)
{
if (args.Length == 0 || args[0] == "-h" || args[0] == "--help")
{
ShowHelp();
return;
}
string type = GetArgumentValue(args, "-type");
if (string.IsNullOrEmpty(type))
{
Console.Error.WriteLine("Error: 必须指定操作类型 (-type)");
return;
}
try
{
IntPtr hwnd = GetWindowHandle(args);
if (hwnd == IntPtr.Zero)
{
Console.Error.WriteLine("Error: 未找到目标窗口");
return;
}
switch (type.ToLower())
{
case "topmost":
bool isTopMost = bool.Parse(GetArgumentValue(args, "-value") ?? "true");
SetWindowPos(hwnd, isTopMost ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
break;
case "opacity":
int opacity = int.Parse(GetArgumentValue(args, "-value") ?? "100");
SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
SetLayeredWindowAttributes(hwnd, 0, (byte)(opacity * 2.55), LWA_ALPHA);
break;
case "rect":
string[] rectValues = (GetArgumentValue(args, "-value") ?? "").Split(',');
if (rectValues.Length == 4)
{
int x = int.Parse(rectValues[0]);
int y = int.Parse(rectValues[1]);
int width = int.Parse(rectValues[2]);
int height = int.Parse(rectValues[3]);
MoveWindow(hwnd, x, y, width, height, true);
}
break;
case "state":
string state = GetArgumentValue(args, "-value") ?? "normal";
int cmdShow = state == "maximize" ? SW_MAXIMIZE :
state == "minimize" ? SW_MINIMIZE : SW_NORMAL;
ShowWindow(hwnd, cmdShow);
break;
case "visible":
bool visible = bool.Parse(GetArgumentValue(args, "-value") ?? "true");
ShowWindow(hwnd, visible ? SW_SHOW : SW_HIDE);
break;
case "close":
PostMessage(hwnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
break;
case "focus":
if (IsIconic(hwnd))
{
ShowWindow(hwnd, SW_RESTORE);
}
SetForegroundWindow(hwnd);
break;
case "border":
bool hasBorder = bool.Parse(GetArgumentValue(args, "-value") ?? "true");
int style = GetWindowLong(hwnd, GWL_STYLE);
style = hasBorder ? style | WS_CAPTION : style & ~WS_CAPTION;
SetWindowLong(hwnd, GWL_STYLE, style);
break;
case "clickthrough":
bool isTransparent = bool.Parse(GetArgumentValue(args, "-value") ?? "true");
int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
exStyle |= WS_EX_LAYERED;
exStyle = isTransparent ? exStyle | WS_EX_TRANSPARENT : exStyle & ~WS_EX_TRANSPARENT;
SetWindowLong(hwnd, GWL_EXSTYLE, exStyle);
break;
case "info":
GetWindowInfo(hwnd);
break;
default:
Console.Error.WriteLine("Error: 不支持的操作类型");
break;
}
}
catch (Exception ex)
{
Console.Error.WriteLine(string.Format("Error: {0}", ex.Message));
}
}
private static IntPtr GetWindowHandle(string[] args)
{
string method = GetArgumentValue(args, "-method") ?? "title";
string value = GetArgumentValue(args, "-window") ?? "";
switch (method.ToLower())
{
case "handle":
return new IntPtr(long.Parse(value));
case "active":
return GetForegroundWindow();
default: // title
if (string.IsNullOrEmpty(value))
{
return IntPtr.Zero;
}
IntPtr foundWindow = IntPtr.Zero;
EnumWindows((hwnd, param) =>
{
StringBuilder title = new StringBuilder(256);
GetWindowText(hwnd, title, title.Capacity);
string windowTitle = title.ToString();
if (!string.IsNullOrEmpty(windowTitle) &&
windowTitle.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0)
{
foundWindow = hwnd;
return false; // 找到后停止枚举
}
return true;
}, IntPtr.Zero);
return foundWindow;
}
}
private static void GetWindowInfo(IntPtr hwnd)
{
var windowRect = new RECT();
GetWindowRect(hwnd, out windowRect);
var clientRect = new RECT();
GetClientRect(hwnd, out clientRect);
var titleText = new StringBuilder(256);
GetWindowText(hwnd, titleText, 256);
var className = new StringBuilder(256);
GetClassName(hwnd, className, 256);
uint processId = 0;
GetWindowThreadProcessId(hwnd, out processId);
string processName = "";
string processPath = "";
try
{
Process process = Process.GetProcessById((int)processId);
processName = process.ProcessName;
var startInfo = new ProcessStartInfo
{
FileName = "wmic",
Arguments = string.Format("process where ProcessId={0} get ExecutablePath /value", processId),
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
};
using (var proc = Process.Start(startInfo))
{
string output = proc.StandardOutput.ReadToEnd();
if (!string.IsNullOrEmpty(output))
{
string[] lines = output.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
foreach (string line in lines)
{
if (line.StartsWith("ExecutablePath="))
{
processPath = line.Substring("ExecutablePath=".Length);
break;
}
}
}
}
}
catch { }
int style = GetWindowLong(hwnd, GWL_STYLE);
int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
var data = new
{
handle = hwnd.ToInt64(),
processId = processId,
process = new
{
name = processName,
path = processPath
},
title = titleText.ToString(),
className = className.ToString(),
window = new
{
x = windowRect.Left,
y = windowRect.Top,
width = windowRect.Right - windowRect.Left,
height = windowRect.Bottom - windowRect.Top
},
client = new
{
width = clientRect.Right - clientRect.Left,
height = clientRect.Bottom - clientRect.Top
},
state = new
{
visible = IsWindowVisible(hwnd),
minimized = IsIconic(hwnd),
maximized = IsZoomed(hwnd),
focused = GetForegroundWindow() == hwnd
},
style = new
{
border = (style & WS_BORDER) != 0,
caption = (style & WS_CAPTION) != 0,
child = (style & WS_CHILD) != 0,
popup = (style & WS_POPUP) != 0,
sysmenu = (style & WS_SYSMENU) != 0,
minimizeBox = (style & WS_MINIMIZEBOX) != 0,
maximizeBox = (style & WS_MAXIMIZEBOX) != 0
},
exStyle = new
{
topmost = (exStyle & WS_EX_TOPMOST) != 0,
transparent = (exStyle & WS_EX_TRANSPARENT) != 0,
toolWindow = (exStyle & WS_EX_TOOLWINDOW) != 0,
layered = (exStyle & WS_EX_LAYERED) != 0
}
};
var serializer = new JavaScriptSerializer();
Console.WriteLine(serializer.Serialize(data));
}
private static string GetArgumentValue(string[] args, string key)
{
int index = Array.IndexOf(args, key);
if (index >= 0 && index < args.Length - 1)
{
return args[index + 1];
}
return null;
}
private static void ShowHelp()
{
string help = @"
Windows 窗口管理工具使用说明
==========================
基本语法:
window.exe -type <操作类型> [参数...]
操作类型:
--------
1. topmost - 设置窗口置顶
2. opacity - 设置窗口透明度
3. rect - 设置窗口位置和大小
4. state - 设置窗口状态
5. visible - 设置窗口可见性
6. close - 关闭窗口
7. focus - 设置窗口焦点
8. border - 设置窗口边框
9. clickthrough - 设置点击穿透
10. info - 获取窗口信息
通用参数:
--------
-method 窗口查找方式可选默认title
可选值title, handle, active
-window 窗口标题或句柄
示例:-window ""记事本""
-value 操作值,根据不同操作类型有不同含义
操作参数说明:
-----------
1. topmost:
-value true/false是否置顶
2. opacity:
-value 0-100透明度
3. rect:
-value x,y,width,height窗口位置和大小
4. state:
-value normal/maximize/minimize窗口状态
5. visible:
-value true/false是否可见
6. border:
-value true/false是否显示边框
7. clickthrough:
-value true/false是否点击穿透
使用示例:
--------
1. 设置窗口置顶:
window.exe -type topmost -window ""记事本"" -value true
2. 设置窗口透明度:
window.exe -type opacity -window ""记事本"" -value 80
3. 设置窗口位置和大小:
window.exe -type rect -window ""记事本"" -value ""100,100,800,600""
4. 最大化窗口:
window.exe -type state -window ""记事本"" -value maximize
5. 隐藏窗口:
window.exe -type visible -window ""记事本"" -value false
6. 关闭窗口:
window.exe -type close -window ""记事本""
7. 获取窗口信息:
window.exe -type info -window ""记事本""
返回值:
------
1. info操作返回JSON格式的窗口信息
2. 其他操作无返回值,执行失败时输出错误信息
注意事项:
--------
1. 窗口标题支持模糊匹配
2. handle方式查找窗口时需要提供正确的窗口句柄
3. active方式不需要提供window参数直接操作当前活动窗口
4. 某些操作可能需要管理员权限
";
Console.WriteLine(help);
}
}