命令行窗口排列 https://share.weiyun.com/EykMqNix 密码:ydvrx5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright © 2022, 飞麦 <fitmap@qq.com>, All rights reserved.

#include <windows.h>
#include <tchar.h>
#include "Shlwapi.h"  // StrStrI
#pragma comment(lib, "ShLwApi.Lib")


struct HWND_RECT {
    HWND hwnd_part;  // 窗口句柄
    RECT rect_part;  // 窗口位置
};
static HWND_RECT hwnd_rect_a[MAX_PATH];  // 260:最多命令行窗口数
static int hwnd_num;  // 实际命令行窗口数
static LPCTSTR TITLE_A[] = {
    _T("\\Windows\\System32\\cmd.exe"),
    _T("Windows PowerShell"),
    _T("命令提示符"),
};


typedef const HWND_RECT* LP_HWND_RECT;
typedef void(__cdecl* WinDealFunc)(HWND& hwnd, RECT& rect);


// 根据窗口标题挑选命令行窗口
static bool is_cmd_window(LPCTSTR caption) {
    for (auto title : TITLE_A)
        if (StrStrI(caption, title))  // 是命令行窗口
            return true;
    return false;
}


// 获取窗口标题并筛选命令行窗口
static BOOL CALLBACK enum_child_proc(_In_ HWND hwnd, _In_ LPARAM lParam) {
    static TCHAR caption[MAX_PATH];
    if (GetWindowText(hwnd, caption, MAX_PATH) > 0)  // 获取窗口标题成功
        if (is_cmd_window(caption))  // 是命令行窗口
            if (hwnd_num < MAX_PATH)  // 未超过最大个数
                hwnd_rect_a[hwnd_num++].hwnd_part = hwnd;
    return TRUE;  // 表示继续枚举窗口
}

// 枚举桌面的所有子窗口
static void got_windows() {
    HWND hWndParent = GetDesktopWindow();
    WNDENUMPROC lpEnumFunc = enum_child_proc;
    LPARAM lParam = NULL;
    EnumChildWindows(hWndParent, lpEnumFunc, lParam);
}

// 获取桌面位置与大小
static RECT got_desk_rect() {
    HWND desk_hwnd = GetDesktopWindow();
    RECT desk_rect;
    GetWindowRect(desk_hwnd, &desk_rect);
    return desk_rect;
}

// 根据最左边的位置比较各命令行窗口的顺序
static int compare_left(LPCVOID a, LPCVOID b) {
    LP_HWND_RECT p_hwnd_rect_a = reinterpret_cast<LP_HWND_RECT>(a);
    LP_HWND_RECT p_hwnd_rect_b = reinterpret_cast<LP_HWND_RECT>(b);
    return p_hwnd_rect_a->rect_part.left - p_hwnd_rect_b->rect_part.left;
}

// 计算任务栏高度
static LONG calc_tray_height() {
    LPCTSTR lpClassName = _T("Shell_TrayWnd");  // 任务栏窗口类名
    LPCTSTR lpWindowName = NULL;  // 所有窗口名称都匹配
    HWND tray_hwnd = FindWindow(lpClassName, lpWindowName);
    RECT tray_rect;
    GetWindowRect(tray_hwnd, &tray_rect);
    LONG tray_height = tray_rect.bottom - tray_rect.top;
    return tray_height;
}

// 获取某命令行窗口的位置与大小
static void got_rects(HWND& hwnd, RECT& rect) {
    // SW_NORMAL:激活并显示窗口,如果窗口最小化、最大化或隐藏,系统会将其还原到其原始大小和位置
    ShowWindow(hwnd, SW_NORMAL);  // 窗口隐藏或最小化时无法获得其位置与大小
    GetWindowRect(hwnd, &rect);  // 获取命令行窗口位置与大小
}

// 对各命令行窗口排序(按照最左边的位置)
static void sort_windows() {
    qsort(hwnd_rect_a, hwnd_num, sizeof(HWND_RECT), compare_left);
}

// 计算各命令行窗口的合理位置与大小
static void calc_loc_size() {
    if (hwnd_num <= 0)
        return;
    RECT desk_rect = got_desk_rect();
    LONG desk_width = desk_rect.right - desk_rect.left;  // 计算桌面宽度
    LONG desk_height = desk_rect.bottom - desk_rect.top;  // 计算桌面高度
    LONG tray_height = calc_tray_height();
    RECT& rect = hwnd_rect_a[0].rect_part;  // 以首个命令行窗口为准
    LONG width = rect.right - rect.left;  // 计算命令行窗口统一宽度
    LONG rest_width = desk_width - width;  // 剩余宽度 = 桌面宽度 - 命令行窗口宽度
    LONG height = desk_height - 16 - tray_height;  // 各命令行窗口与桌面(除远程桌面栏及任务栏外)等高
    LONG top = desk_rect.top + 16;  // 各命令行窗口顶坐标与桌面(扣除远程桌面栏)相同
    LONG bottom = top + height;  // 各命令行窗口底位置
    for (auto i = 0; i < hwnd_num; i++) {
        RECT& rect = hwnd_rect_a[i].rect_part;
        // 左边坐标:如果有多个命令行窗口则均匀分布, 否则使命令行窗口位于中央
        rect.left = hwnd_num > 1 ? rest_width * i / (hwnd_num - 1) : rest_width / 2;
        rect.right = rect.left + width;
        rect.top = top;
        rect.bottom = bottom;
    }
}

// 设置某命令行窗口的位置与大小
static void chg_rects(HWND& hwnd, RECT& rect) {
    LONG width = rect.right - rect.left;
    LONG height = rect.bottom - rect.top;
    // HWND_TOP:将窗口置于 Z 顺序的顶部
    // SWP_ASYNCWINDOWPOS:如果调用线程和拥有窗口的线程附加到不同的输入队列,则系统会将请求发布到拥有窗口的线程
    SetWindowPos(hwnd, HWND_TOP, rect.left, rect.top, width, height, SWP_ASYNCWINDOWPOS);
}

// 枚举处理各命令行窗口
static void deal_windows(WinDealFunc func) {
    for (auto& hwnd_rect : hwnd_rect_a)
        func(hwnd_rect.hwnd_part, hwnd_rect.rect_part);
}

// 自动对多个命令行窗口设置位置与大小
int WINAPI _tWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ LPTSTR, _In_ int) {
    got_windows();
    deal_windows(got_rects);
    sort_windows();
    calc_loc_size();
    deal_windows(chg_rects);
    return 0;
}
posted @ 2024-01-22 17:29  飞麦  阅读(403)  评论(0编辑  收藏  举报