通过索引获取(真实)监视器的句柄

时间:2015-04-02 12:24:38

标签: c++ windows winapi c++11

假设我有3台显示器。如何仅通过索引获取第二个句柄? EnumDisplayMonitors()将无法工作,因为它也枚举伪设备,EnumDisplayDevices()不会给我句柄。

3 个答案:

答案 0 :(得分:5)

您需要使用EnumDisplayMonitors()代替EnumDisplayDevices()来访问每个监视器的HMONITOR句柄。

但是,监视器不是由索引标识的。 GetMonitorInfo()可以告诉您哪个监视器是“主要的”,但这就是全部。无法知道哪个显示器是“秒”,“第三个”等等。并且您也不能使用显示器位置来确定,因为“第二个”显示器可以放置在与“主要”相关的任何位置监视器,然后“第三”监视器可以放置在与“第一”或“第二”监视器相关的任何位置。

所以你必须希望EnumDisplayMonitors()按照安装监视器的顺序进行枚举,然后你可以这样做:

struct sEnumInfo
{
    int iIndex;
    HMONITOR hMonitor;
};

BOOL CALLBACK GetMonitorByIndex(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{
    sEnumInfo *info = (sEnumInfo*) dwData;
    if (--info->iIndex < 0)
    {
        info->hMonitor = hMonitor;
        return FALSE;
    }
    return TRUE;
}

sEnumInfo info;
info.iIndex = 1;
info.hMonitor = NULL;

EnumDisplayMonitors(NULL, NULL, GetMonitorByIndex, (LPARAM)&info);
if (info.hMonitor != NULL)
{
    //...
}

答案 1 :(得分:1)

您可以排除主监视器,这是示例代码(样式可能有所不同):

如果DEVMODE dmPosition x == 0且y == 0,则它是主监视器。

  

仅对于显示设备,POINTL结构指示   显示设备相对于   桌面区域。主显示设备始终位于   坐标(0,0)。

选中x,y以定义第二或第三。

  LONG second_x=0;
  LONG second_y=0;

  DWORD deviceNum = 0;
  DISPLAY_DEVICE displayDevice;
  DEVMODE devMode;

  memset(&displayDevice, 0, sizeof(displayDevice));
  displayDevice.cb = sizeof(DISPLAY_DEVICE);
  while(EnumDisplayDevices(NULL, deviceNum, &displayDevice, 0))
  {
    EnumDisplaySettings(displayDevice.DeviceName, ENUM_CURRENT_SETTINGS, &devMode);
    if (devMode.dmPosition.x == 0 && devMode.dmPosition.y == 0)
    {
      // primary monitor
    }
    else
    {
      // second or third monitor
      second_x = devMode.dmPosition.x;
      second_y = devMode.dmPosition.y;
    }
    ++deviceNum;
  }

  m_pMainWnd->SetWindowPos(NULL,(int)second_x,(int)second_y,0,0,SWP_SHOWWINDOW | SWP_NOSIZE);

答案 2 :(得分:0)

您可以使用EnumDisplayMonitors()枚举设备并检查它是否为EnumDisplayDevices()

的伪监视器

使用GetMonitorInfo()迭代显示监视器时,您可以使用监视器设备的名称获取MONITORINFOEX

然后使用EnumDisplayDevices(),如果当前监视器是伪监视器(或者附加到桌面的情况下),则可以获取包含DISPLAY_DEVICE StateFlags的{​​{1}}

BOOL DispayEnumeratorProc(_In_ HMONITOR hMonitor, _In_ HDC hdcMonitor, _In_ LPRECT lprcMonitor, _In_ LPARAM dwData)
{
    TClass* self = (TClass*)dwData;
    if (self == nullptr)
        return FALSE;

    MONITORINFOEX monitorInfo;
    ::ZeroMemory(&monitorInfo, sizeof(monitorInfo));
    monitorInfo.cbSize = sizeof(monitorInfo);

    BOOL res = ::GetMonitorInfo(hMonitor, &monitorInfo);
    if (res == FALSE)
        return TRUE;

    DISPLAY_DEVICE displayDevice;
    ::ZeroMemory(&displayDevice, sizeof(displayDevice));
    displayDevice.cb = sizeof(displayDevice);

    res = ::EnumDisplayDevices(monitorInfo.szDevice, 0, &displayDevice, 0);
    if (res == FALSE)
        return TRUE;

    if (displayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)
        self->RegisterDisplay(monitorInfo);

    return TRUE;
}

void TClass::EnumerateDisplayMonitors()
{
    BOOL res = ::EnumDisplayMonitors(NULL, NULL, &DispayEnumeratorProc, (LPARAM)this);
    if (res == FALSE)
        Print("Failed");
}

您也可以通过迭代EnumDisplayDevices()

对显示器进行排序

如果您将NULL作为第一个参数传递给EnumDisplayDevices(),它将根据第二个参数返回适配器的信息。在这种情况下,您的设备将确定订单。

您可以将DeviceName中的DISPLAY_DEVICE与之前存储的szDevice中的MONITORINFOEX进行比较,以对HMONITORs

进行排序
void TClass::SortDisplayMonitors()
{
    DISPLAY_DEVICE displayDevice;
    ::ZeroMemory(&displayDevice, sizeof(displayDevice));
    displayDevice.cb = sizeof(displayDevice);

    std::map<std::string, DWORD> devices;
    for (DWORD iDevNum = 0; ::EnumDisplayDevices(NULL, iDevNum, &displayDevice, 0) != FALSE; ++iDevNum)
        devices.insert({displayDevice.DeviceName, iDevNum});

    auto compare = [&devices](MONITORINFOEX& l, MONITORINFOEX& r)
        {
            DWORD il = -1;
            DWORD ir = -1;

            auto foundL = devices.lower_bound(l.szDevice);
            if (foundL != devices.end())
                il = foundL->second;

            auto foundR = devices.lower_bound(r.szDevice);
            if (foundR != devices.end())
                ir = foundR->second;

            return (il < ir);
        };

    std::sort(m_monitors.begin(), m_monitors.end(), compare);
}

PS:你可以写
DWORD il = std :: numeric_limits&lt; DWORD&gt; :: max();
insted DWORD il = -1;
但在包含Windows.h之前不要忘记定义NOMINMAX