As the topic says, the problem is as follows:
I can enumerate display adapters via EnumDisplayDevices. I can enumerate display outputs of a given display adapter via the same funcion. BUT the latter enumeration doesn't give display output's window (desktop) coordinates. It just gives you a name. The functions which give window coords are EnumDisplayMonitors or GetMonitorInfo, none of which take display output's name as one of its parameters. So how do I link the names of enumerated display outputs of a given adapter to their respective window/desktop coordinates? Let's say I have 2 adapters, 2 displays each (4 displays total). I want to get window coords of the first display of they second adapter.
Posted on 2010-07-05 12:25:25 by ti_mo_n
Hum... if you do EnumDisplayMonitors, you get the HMONITOR. You can then use GetMonitorInfo to get the adapter name (make sure you pass a MONITORINFOEX structure, the regular MONITORINFO doesn't have the name string).
Then you can compare that string to the one you got with EnumDisplayDevices, and you know which monitor belongs to which adapter... I think :)
Posted on 2010-07-05 14:49:44 by Scali
Apparently, it works! Thanks! :D
The only minor correction to the steps you proposed is that after you get MONITORINFOEX, you need to pass it through EnumDisplayDevices once more to get its "real" name.

If anyone with multiple adapters/display outputs could test the attached files, I would be grateful ^^


The relevant parts of the code, in C/C++, are as follows:

// monitor info
typedef struct _MONINF {
 RECT coords;
 TCHAR devname[32],
       dspname[128];
 BOOL isAttached;
} MONINF;

// helper struct
typedef struct _MYPARAMS {
 MONINF **displays;
 CONST UINT *dspcnts;
 MONITORINFOEX miex;
 DISPLAY_DEVICE dd;
 UINT adcnt;
} MYPARAMS;

// ---------------------------------------------------------------------------------------------------------

// get display devices
// we use this first time to enumerate adapters and subsequent times
// to enumerate displays on a particular adapter
static UINT getDevs(HANDLE hHeap, CONST TCHAR *dn, DISPLAY_DEVICE **oad) {
 DISPLAY_DEVICE *ad, *tmpad;
 UINT i, j, k;

 _tprintf(dbg01);
 if (hHeap) {
   if ((ad = (DISPLAY_DEVICE *)HeapAlloc(hHeap, 0, sizeof(DISPLAY_DEVICE)))) {
     j = 0;
     k = 0;
     ad->cb = sizeof(DISPLAY_DEVICE);
     while (EnumDisplayDevices(dn, j, ad, 0)) {
       j++;
       if (!(ad->StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)) k++;
       ad->cb = sizeof(DISPLAY_DEVICE);
     }

     if (k > 0) {
       tmpad = NULL;
       if ((k == 1) || (tmpad = (DISPLAY_DEVICE *)HeapReAlloc(hHeap, 0, ad, (sizeof(DISPLAY_DEVICE) * k)))) {
         if (tmpad) ad = tmpad;
         i = 0;
         j = 0;
         ad[0].cb = sizeof(DISPLAY_DEVICE);
         while ((j < k) && EnumDisplayDevices(dn, i, &(ad), 0)) {
           i++;
           if (!(ad->StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)) j++;
           if (j < k) ad.cb = sizeof(DISPLAY_DEVICE);
         }
         if (oad) (*oad) = ad;
         else HeapFree(hHeap, 0, oad);
         _tprintf(dbg02a);
         return k;
       }
     }
     HeapFree(hHeap, 0, ad);
   }
 }
 if (oad) (*oad) = NULL;
 _tprintf(dbg02b);
 return 0;
}

// returns all display outputs that belong to an adapter given by its name
static UINT getDisplays(HANDLE hHeap, CONST TCHAR *adnam, MONINF **odsp) {
 DISPLAY_DEVICE *dspinf;
 MONINF *dsp;
 UINT dspcnt, i;

 _tprintf(dbg03);
 if (hHeap && adnam) {
   dspcnt = getDevs(hHeap, adnam, &dspinf);
   if (dspcnt) {
     if ((dsp = (MONINF *)HeapAlloc(hHeap, 0, (sizeof(MONINF) * dspcnt)))) {
       for (i = 0; i < dspcnt; i++) {
         memcpy(&(dsp.devname), dspinf.DeviceName, (sizeof(TCHAR) << 5));
         memcpy(&(dsp.dspname), dspinf.DeviceString, (sizeof(TCHAR) << 7));
         dsp.isAttached = ((dspinf.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) ? TRUE : FALSE);
       }
       if (odsp) (*odsp) = dsp;
       else HeapFree(hHeap, 0, dsp);
       _tprintf(dbg04a);
       return dspcnt;
     }
   }
   if (dspinf) HeapFree(hHeap, 0, dspinf);
 }
 if (odsp) (*odsp) = NULL;
 _tprintf(dbg04b);
 return 0;
}

// the 'enumproc' which performs display name comparison and fills the coordinate data
static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
 MYPARAMS *mp = ((MYPARAMS *)dwData);
 UINT i, j, k, l;

 if (mp) {
   if (hMonitor) {
     mp->miex.cbSize = sizeof(MONITORINFOEX);
     if (GetMonitorInfo(hMonitor, &(mp->miex))) {
       mp->dd.cb = sizeof(DISPLAY_DEVICE);
       if (EnumDisplayDevices(mp->miex.szDevice, 0, &(mp->dd), 0)) {
         j = mp->adcnt;
         for (i = 0; i < j; i++) {
           l = mp->dspcnts;
           for (k = 0; k < l; k++) {
             if (!(lstrcmp(mp->dd.DeviceName, mp->displays.devname))) {
               mp->displays.coords = mp->miex.rcMonitor;
               return TRUE;
             }
           }
         }
       }
     }
   }
   return TRUE;
 }
 return FALSE;
}

// starter for the enumproc
static VOID fillDisplayCoords(HANDLE hHeap, UINT adcnt, CONST UINT *dspcnts, MONINF **displays) {
 MYPARAMS *mp;

 _tprintf(dbg05);
 if ((hHeap) && (adcnt > 0) && (dspcnts) && (displays)) {
   if ((mp = (MYPARAMS *)HeapAlloc(hHeap, 0, sizeof(MYPARAMS)))) {
     mp->displays = displays;
     mp->dspcnts = dspcnts;
     mp->adcnt = adcnt;
     EnumDisplayMonitors(NULL, NULL, &MonitorEnumProc, (LPARAM)mp);
     HeapFree(hHeap, 0, mp);
   }
 }
 _tprintf(dbg06);
}

// kinda self-explanatory...
static VOID presentDisplays(DISPLAY_DEVICE *adapters, UINT adcnt, MONINF **dsps, UINT *dspcnts) {
 UINT i, j, k, l;

 _tprintf(dbg07);
 if ((adcnt > 0) && (adapters) && (dsps) && (dspcnts)) {
   l = 0;
   _tprintf(dsprn);
   for (i = 0; i < adcnt; i++) {
     k = dspcnts;
     for (j = 0; j < k; j++) {
       if (dsps) {
         _tprintf(dspst, l, dsps.dspname, adapters.DeviceString, dsps.coords.left, dsps.coords.top, dsps.coords.right, dsps.coords.bottom);
         l++;
       }
     }
   }
   _tprintf(dsprn);
 }
 _tprintf(dbg08);
}

// the startup function
static INT mymain2(INT argc, _TCHAR* argv[]) {
 HANDLE hHeap;
 DISPLAY_DEVICE *adapters;
 MONINF **displays;
 UINT *dspcnts;
 UINT adcnt, i;

 displays = NULL;
 adapters = NULL;
 if (!(hHeap = GetProcessHeap())) return -1;

 adcnt = getDevs(hHeap, NULL, &adapters);
 
 if (adcnt > 0) {
   if ((dspcnts = (UINT *)HeapAlloc(hHeap, 0, (sizeof(UINT) * adcnt)))) {
     if ((displays = (MONINF **)HeapAlloc(hHeap, 0, (sizeof(MONINF *) * adcnt)))) {
       for (i = 0; i < adcnt; i++) {
         dspcnts = getDisplays(hHeap, adapters.DeviceName, &(displays));
       }
       fillDisplayCoords(hHeap, adcnt, dspcnts, displays);
     }
   }
 }


 if ((adapters) && (displays) && (dspcnts) && (adcnt > 0)) presentDisplays(adapters, adcnt, displays, dspcnts);


 if (dspcnts) HeapFree(hHeap, 0, dspcnts);
 if (displays) {
   for (i = 0; i < adcnt; i++) {
     if (displays) HeapFree(hHeap, 0, displays);
   }
   HeapFree(hHeap, 0, displays);
 }
 if (adapters) HeapFree(hHeap, 0, adapters);
 _tsystem(pscmd);
 return 0;
}
Posted on 2010-07-05 18:21:39 by ti_mo_n