How do I get a handle to the primary monitor?


There are various ways of getting a monitor. You can get the monitor from a point, from a rectangle, or from a window. But how do you get the primary monitor?

The primary monitor is defined to be the one which has (0, 0) as its origin. Therefore, one solution is

HMONITOR GetPrimaryMonitor()
{
 POINT ptZero = { 0, 0 };
 return MonitorFromPoint(ptZero,
                         MONITOR_DEFAULTTOPRIMARY);
}

The desktop window by convention is deemed to reside primarily on the primary monitor, so you could also use this:

HMONITOR GetPrimaryMonitor()
{
 return MonitorFromWindow(GetDesktopWindow(),
                          MONITOR_DEFAULTTOPRIMARY);
}

Or you could just pass the null window handle. This is technically an illegal parameter, but by specifying MONITOR_DEFAULT­TO­PRIMARY, you are saying, "If anything goes wrong, give me the primary monitor."

HMONITOR GetPrimaryMonitor()
{
 return MonitorFromWindow(nullptr,
                          MONITOR_DEFAULTTOPRIMARY);
}

In this case, we are intentionally going astray because we want to kick in the MONITOR_DEFAULT­TO­PRIMARY behavior.

Comments (21)
  1. Joshua says:

    Amusingly, GetWindowRect(GetDeskopWindow(), &r) returns the bounds of the primary monitor. Took me a bit to find the API to get the desktop size (bounding box of all monitors).

  2. Rob says:

    @Joshua: Likely because a RECT can't describe the shape of a nonuniform multi-monitor system (for example, my home PC has monitors of sizes 2560x1440 and 1920x1200).  It can't capture a region, so back-compat concerns kick in...

  3. Brian_EE says:

    Likewise, even multiple displays of the same resolution might not make a rectangle. I have 4 displays. They can be arranged all in a horizontal row, a vertical column, a "square" 2x2, or in a J, L or T shape.

  4. Joshua Ganes says:

    You've provided three quick examples that should work well. I can imagine that there are infinitely more convoluted implementations that happen to return the correct result in the end. (e.g. Calculate the Ackermann function A( 10, 10 ) and provide the result to a function f( x ) = 0 to calculate your x,y point coordinates.)

    Are there any clear benefits, drawbacks, or trade-offs here? Which implementation would you recommend?

  5. Joshua says:

    @Brian_EE, Rob: Apparently neither of you got "bounding box". The smallest rectangle encompassing any finite set of finite rectangles always exists.

  6. Sven2 says:

    I wonder why we're still stuck with rectangular monitors anyway. Elliptical screens would be much more natural and allow for some fancy user interface designs.

    There are some cell phones with circular displays, but they kinda died when smartphones arrived :(

  7. Gabe says:

    Kythyria: How do you arrange it so there is no monitor at (0, 0)?

  8. Kythyria says:

    @Joshua: The desktop bounding box is not as useful as it looks: I've encountered a number of programs that can't quite grasp the concept of (0,0) *not* being on any monitor and so become incorrectly positioned. In the end I put another couple of books under a monitor so that something would be there.

  9. Count Zero says:

    @Gabe - He can't. Since (0,0) is by definition on the primary monitor it would only be possible if he has a monitor with a vertical resolution under 0 lines. (Yet another occasion where italic text would have been useful.) Also the described problem exists. I used to use my laptop with one of my 24'' HDMI displays attached when I was at home, but lately I have simply gave up on that.

    Some applications tend to "remember" their last position even it is not on the screen. I have written a tiny program that detects if a form is fully outside of the viewable area of the desktop (or if its title bar is outside of the viewable area of the desktop), and moves all forms onto the "real" desktop, but there are programs that don't let themselves  be moved for some reason. They identify the sender of WM_MOVE and does not move if its an other application (except explorer.exe). This practice is more common then you would think and has no logical reason.

  10. GWO says:

    Sven2: Elliptical screens would be much more natural and allow for some fancy user interface designs.

    What? Unless you wanted to use then for - reading documents, or watching tv/movies, or ... essentially anything else people usually do with screens, beside analogue clocks and radar.

  11. Julien L says:

    @Count Zero: I agree, there are too many applications that try to restore their position manually without taking monitors into account. To do this correctly, one only has to use GetWindowPlacement/SetWindowPlacement:

    "If the information specified in WINDOWPLACEMENT would result in a window that is completely off the screen, the system will automatically adjust the coordinates so that the window is visible, taking into account changes in screen resolution and multiple monitor configuration."

  12. Count Zero says:

    @Julien L - I could live with that (though lots of users without the knowledge/possibility of writing their own tools don't).  The thing that disturbs me is the aggressivity those programs show when I try to move their forms (back to the screen).

  13. not an anon says:

    @Gabe: I take it that a reverse-L of 3 monitors with the topmost monitor primary would yield negative coordinates then?  Or is the primary monitor always one of the leftmost monitors in the configuration?

    @Count Zero: that behavior really is TRWTF.

  14. Gabe says:

    not an anon: Whichever monitor you specify as "primary" is the one that gets assigned (0,0) as its upper-left corner. Any monitor to the left or top gets negative coordinates.

    In your example with the top-most monitor being primary, the left-most monitor would have negative x-coordinates.

  15. Deanna says:

    You can also create arrangements with holes in with 4+ monitors.

  16. James Johnston says:

    You could also use EnumDisplayMonitors and then call GetMonitorInfo for each monitor.  The primary monitor will have MONITORINFOF_PRIMARY set in dwFlags.

    That is a more explicit method; it's pretty clear to Windows you are searching for a primary monitor by using a documented "MONITORINFOF_PRIMARY" flag.

    I didn't know that origin (0,0) was contractually guaranteed to always be on the primary monitor in future versions of Windows.  (Of course, I suppose for compatibility reasons this will probably always be so...)

  17. Count Zero says:

    @Deanna - You can create holes, but you can't create an arrangement where (0, 0) is not on the (primary) screen.

  18. Joshua says:

    @Douglas: I'm pretty sure Windows doesn't boot on a machine with no monitor attachment points (Windows assumes the last monitor is still present when it's disconnected for the obvious reason).

  19. Douglas says:

    Going by what @James Johnston is saying, and checking the docs (of course), this should be acceptable, right? Although, now that I look at it, this won't work on a system with no monitors, but that's easy enough to detect.

    Oh, and for all the people wanting official documentation on (0,0) and the primary monitor, it's here: msdn.microsoft.com/.../dd145136(v=vs.85).aspx

    Oddly, I couldn't find anything to say that there is at most one primary monitor. I think that we can take that for granted, though.

    BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData){

    MONITORINFO mi;

    mi.cbSize = sizeof(MONITORINFO);

    GetMonitorInfo(hMonitor, &mi);

    if(mi.dwFlags & MONITORINFOF_PRIMARY){

    *((HMONITOR*)dwData) = hMonitor;

    return false;

    }

    return true;

    }

    HMONITOR getPrimaryMonitor(void){

    HMONITOR hm;

    EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&hm);

    return hm;

    }

  20. Gabe says:

    Joshua: All programs run on a Desktop (msdn.microsoft.com/.../ms682573.aspx), and a Desktop may not have a monitor associated with it. For example, services run in Session 0, which doesn't have a monitor. A process on an RDP session loses its monitor with the session is disconnected. A UAC prompt probably does the same thing temporarily.

  21. Joshua says:

    @Gabe: If you ask for monitor params on the service desktop, you get 1 at 640x480 1bpp. I heard rumor that somebody managed to open some windows on it and get a screen snapshot (by auto-snapshot program). I wonder how.

Comments are closed.

Skip to main content