在多显示器的Windows工作场景下,有时候需要把某个程序固定到指定的显示器上,可是系统并没有提供简单的方法,本文将介绍使用C++代码和批处理文件实现将指定程序窗口固定到指定显示屏的方法。

准备工作

首先需要准备以下软件和库:

  • Visual Studio 2017(或其他C++ IDE)
  • WinAPI

编写程序

在IDE中创建一个新的Console Application项目,然后按照以下方式编写C++程序:

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
#include <Windows.h>
#include <iostream>
#include <vector>

BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{
std::vector<MONITORINFOEX>* monitors = reinterpret_cast<std::vector<MONITORINFOEX>*>(dwData);

// 获取显示器信息
MONITORINFOEX monitorInfo = {};
monitorInfo.cbSize = sizeof(MONITORINFOEX);

if (GetMonitorInfo(hMonitor, &monitorInfo))
{
monitors->push_back(monitorInfo);
}
return TRUE;
}

int main(int argc, char **argv)
{
// 接收到的参数格式错误直接返回
if (argc < 3 || argc > 4) {
std::cout << "参数错误" << std::endl;
//终止返回错误码
std::exit(EXIT_FAILURE);
}


std::vector<MONITORINFOEX> monitors; // 存储所有显示器信息

// 枚举所有显示器
if (!EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, reinterpret_cast<LPARAM>(&monitors)))
{
std::cout << "Failed to enum monitors." << std::endl;
std::exit(EXIT_FAILURE);;
}


// 获取输入的程序句柄
HWND hwnd = FindWindowA(NULL, argv[1]);

if (hwnd != NULL)
{
// 获取输入的屏幕句柄
int i = atoi(argv[2]);
if (monitors.size() > i)
{
//存在第三个参数全屏显示,不存在则正常显示
if (argv[3])
{
// 将窗口移到指定屏幕上并设置全屏
SetWindowPos(hwnd, NULL, monitors[i].rcMonitor.left, monitors[i].rcMonitor.top,
monitors[i].rcMonitor.right - monitors[i].rcMonitor.left, monitors[i].rcMonitor.bottom - monitors[i].rcMonitor.top, 0);
}
else
{
// 获取原窗口矩形区域
RECT rect;
GetWindowRect(hwnd, &rect);

int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
// 将窗口移到指定屏幕上并设置原位置原大小
SetWindowPos(hwnd, NULL, monitors[i].rcMonitor.left, monitors[i].rcMonitor.top, width, height, 0);
}
}
else
{
std::cout << "显示器不存在" << std::endl;
}
}
else
{
std::cout << "进程未启动或进程名称错误" << std::endl;
}
return 0;
}

以上代码使用WinAPI库中的一些函数来实现将指定窗口移动到指定屏幕的功能。最后一步是将程序编译为MoveExe.exe可执行文件。

运行调试

在 Visual Studio 项目中,可以通过以下步骤来设置需要传递的参数:

  1. 在 Visual Studio 中右键单击主程序文件,并选择“属性”选项。
  2. 在“属性页”窗口中,选择“调试”选项卡。
  3. 在“命令参数”文本框中输入需要传递的参数。

编写批处理文件

接下来需要编写一个批处理文件(例如MoveExe.bat),使得使用该文件可以方便地将指定程序移动到指定屏幕。以下是示例代码:

1
2
:: 调用程序并传入参数,参数中包含空格需要用双引号包含住
MoveExe.exe "微信" 2

以上代码表示把微信窗口移动到第2个显示器上,其中第一个参数为需要移动的程序名称,第二个参数为目标屏幕的编号。在执行命令时,批处理文件将启动MoveExe.exe程序并传递命令行参数。

部分窗口需要管理员用户启动执行方可移动,可采用下列代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@echo off
:: 关闭回显

:: 检查系统是否为 64 位系统,如果是,则将 SysWOW64 目录添加到环境变量 path
if exist "%SystemRoot%\SysWOW64" path %path%;%windir%\SysNative;%SystemRoot%\SysWOW64;%~dp0

:: 使用 bcdedit 命令来测试当前用户是否拥有管理员权限(因为该命令需要管理员权限才能运行)
bcdedit >nul

:: 如果命令返回成功,则说明当前用户已经是管理员身份,否则需要以管理员身份重新运行该脚本
if '%errorlevel%' NEQ '0' (goto UACPrompt) else (goto UACAdmin)

:UACPrompt
:: 请求管理员权限
%1 start "" mshta vbscript:createobject("shell.application").shellexecute("""%~0""","::",,"runas",1)(window.close)&exit
:: 终止当前脚本
exit /B

:UACAdmin
cd /d "%~dp0"
:: 调用程序并传入参数,参数中包含空格需要用双引号包含住
MoveExe.exe "微信" 2

运行程序

最后,双击MoveExe.bat文件并等待程序运行即可。如果一切正常,程序将把指定的程序窗口移动到指定显示屏上。如果出现错误,程序将输出错误日志。

结尾

本文介绍了使用C++代码和批处理文件实现把指定程序窗口固定到指定屏幕上的方法。这个方法可以在多显示器的Windows系统上提高工作效率。在实际使用中,根据需要可以修改C++程序和批处理文件使其满足自己的需求。