如何在Windows中打开特定显示器上的窗口

How to open a window on a specific display in Windows?

本文关键字:显示器 窗口 Windows      更新时间:2023-10-16

我的任务是修改我们的一个c++产品,在Windows操作系统的特定显示上生成一个新窗口。这适用于需要能够配置平铺多显示可视化的客户端,其中每个显示都由单个计算机上的单独显卡驱动。

在linux中,我可以通过在每个显示器上启动一个X服务器,然后在适当设置display env var的情况下启动可视化软件的多个实例来轻松地做到这一点。然而,当涉及到在Windows中这样做时,我迷路了。任何指针/建议/例子吗?

您需要枚举所有监视器并检查它们在虚拟屏幕(MSDN)上的映射。

通过调用EnumDisplayMonitors (MSDN)枚举监视器。这将枚举一系列HMONITOR句柄,您可以将其传递给GetMonitorInfo (MSDN)以获得监视器在虚拟屏幕上的位置。

还有一个完整的多监视器支持指南,也值得一读。

关于多显示器(Windows) @ MSDN

一些注意事项:由于虚拟屏幕是用户控制的映射,因此没有什么可以阻止用户在虚拟坐标空间中放置显示器的相反物理侧设置显示器,反之亦然,以及任何其他奇怪的放置场景。此外,一些显示卡试图假定在插件检测时显示器的位置,从您的软件的角度来看,这可能是错误的,但可能是由于用户没有注意到哪个显示端口映射到左侧(如果它甚至被标记)。

您可以使用Win32 API中的EnumDisplayMonitors函数来获取每个显示器的信息。

一旦你有了你想要显示的矩形,你就知道该怎么做了=)

我很确定显示是按顺序列举的。但如果你是平铺,你可以得到所有显示矩形的矢量,然后对它们排序。

我有一个方便的包装器,我写了一会儿来获取所有的监视器信息:

声明

class CMonitorInfoEx : public MONITORINFOEX
{
public:
    CMonitorInfoEx();
    LPCRECT GetRect() const { return &rcMonitor; }
    LPCRECT GetWorkRect() const { return &rcWork; }
    LPCTSTR DeviceName() const { return szDevice; }
    bool IsPrimary() const { return (dwFlags & MONITORINFOF_PRIMARY) ? true : false; }
    int Width() const { return rcMonitor.right - rcMonitor.left; }
    int Height() const { return rcMonitor.bottom - rcMonitor.top; }
    int WorkWidth() const { return rcWork.right - rcWork.left; }
    int WorkHeight() const { return rcWork.bottom - rcWork.top; }
};

class CSysDisplays
{
public:
    CSysDisplays();
    void Update();
    int Count() const;
    const CMonitorInfoEx& Get( int i ) const;
private:
    std::vector<CMonitorInfoEx> mInfo;
};
实施

BOOL CALLBACK MonitorEnumProc( __in  HMONITOR hMonitor, __in  HDC hdcMonitor, __in  LPRECT lprcMonitor, __in  LPARAM dwData )
{
    std::vector<CMonitorInfoEx>& infoArray = *reinterpret_cast< std::vector<CMonitorInfoEx>* >( dwData );
    CMonitorInfoEx info;
    GetMonitorInfo( hMonitor, &info );
    infoArray.push_back( info );
    return TRUE;
}
CMonitorInfoEx::CMonitorInfoEx()
{
    cbSize = sizeof(MONITORINFOEX);
}

CSysDisplays::CSysDisplays()
{
    Update();
}

void CSysDisplays::Update()
{
    mInfo.clear();
    mInfo.reserve( ::GetSystemMetrics(SM_CMONITORS) );
    EnumDisplayMonitors( NULL, NULL, MonitorEnumProc, reinterpret_cast<LPARAM>(&mInfo) );
}

int CSysDisplays::Count() const
{
    return (int)mInfo.size();
}

const CMonitorInfoEx& CSysDisplays::Get( int i ) const
{
    return mInfo[i];
}