簡體   English   中英

通過其索引獲取(實際)監視器的句柄

[英]get the handle of a (real) monitor by its index

假設我有3個監視器。 如何僅通過第二個索引獲取第二個的句柄? EnumDisplayMonitors()無法工作,因為它也枚舉了偽設備,而EnumDisplayDevices()卻沒有給我句柄。

您需要使用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)
{
    //...
}

您可以排除主監視器,這是示例代碼(樣式可能有所不同):

如果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);

您可以枚舉與設備EnumDisplayMonitors()並檢查它是否與偽顯示器EnumDisplayDevices()

在使用GetMonitorInfo()遍歷顯示監視器時,可以獲取帶有監視器設備名稱的MONITORINFOEX

然后,使用EnumDisplayDevices()可以獲取DISPLAY_DEVICE ,其中包含StateFlags和信息(如果當前監視器是偽監視器,則該信息(或者在連接到桌面的情況下)

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() ,它將基於第二個參數返回適配器的信息。 在這種情況下,您的設備將確定順序。

您可以將DISPLAY_DEVICE DeviceName與之前存儲的MONITORINFOEX中的szDevice進行比較,以對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 <DWORD> :: max();
裝的
DWORD il = -1;
但不要忘記在包含Windows.h之前先定義NOMINMAX

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM