Date: | August 9, 2007 / year-entry #292 |
Tags: | code |
Orig Link: | https://blogs.msdn.microsoft.com/oldnewthing/20070809-00/?p=25643 |
Comments: | 30 |
Summary: | The primary monitor by definition has its upper left corner at (0, 0). Therefore, you can use this function: HMONITOR GetPrimaryMonitorHandle() { const POINT ptZero = { 0, 0 }; return MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY); } To make double extra sure (belt and suspenders), we also tell it, "If you're not sure what monitor to return, give... |
The primary monitor by definition has its upper left corner at
HMONITOR GetPrimaryMonitorHandle() { const POINT ptZero = { 0, 0 }; return MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY); } To make double extra sure (belt and suspenders), we also tell it, "If you're not sure what monitor to return, give us the primary."
Sure, this sounds obviously simple, but I actually found somebody
who
fumbled around in the dark passing intentionally invalid
parameters
to |
Comments (30)
Comments are closed. |
As opposed to <a href="http://research.microsoft.com/research/pubs/view.aspx?msr_tr_id=MSR-TR-95-52">Intentional Programming</a>, I assume.
@lauren smith –
Yeah, Simonyi — guy’s a space cadet.
If you use display properties to put the secondary on the left and thus presumably containing (0, 0), what happens then? Or am I misunderstanding the point?
If you really wanted to use EnumDisplayMonitors to solve this, you could call GetMonitorInfo from inside the iteration function to see if it had the MONITORINFOF_PRIMARY flag. Raymond’s way seems easier, though.
Kemp: If the secondary monitor is to the left of the primary monitor, the rightmost column of pixels of the secondary monitor has an x-coordinate of -1, and the leftmost column of pixels on the primary monitor has an x-coordinate of 0. We know that (0,0) is on the primary monitor since that’s the used as the definition of the coordinate system.
If you put the secondary on the left, it will have negative coördinates. It says so right <a href="http://msdn2.microsoft.com/en-us/library/ms534613.aspx">here</a>
pcooper: Apparently MonitorFromPoint can never fail but EnumDisplayMonitors can.
Oops, thanks for correcting me.
Sometimes it’s called “programming to make a deadline when you can’t find the documentation you need.” MSDN’s Win32 API documentation has been pretty good, but when was the last time you heard of someone bootstrapping themselves on OLE using only MSDN? And all the best books on OLE are out of print.
(“What do you want me to do about it?” Bug your manager.)
If the deadline doesn’t account for time required in order to find out how to write an actual working program then it’s still programming by accident – it’s just that some code monkey’s idiot manager demanded an accident, and guaranteed that their company’s product would be of lower quality.
If a manager doesn’t know how to get information from one side of the company to the other, then that’s a tragedy.
And no I am not saying that this applies to every nagging documentation comment you get on your blog. Just documentation that ends up creating compatibility problems you have to fix.
Isn’t that what Amazon Marketplace is for? I’ll bet you can pick up a whole whack of out-of-print OLE books for not much more than shipping.
> Isn’t that what Amazon Marketplace is for?
Yay, plug for amazon!
> Do you expect a DMV supervisor to be able to forward a suggestion to the Bureau of Land Management.
DMV maamngers are a bit different from a dev manager, don’t you think? Dev managers are supposed to be able to communicate these sorts of things. A closer analogy would be the DMV manager communicating with another branch in the same city.
Well, you could blog about these things.
Which is what you did, and that’s great, and I’ll shut up now.
A few years ago I was looking for a solution to identify whether Windows had two or more monitors attached. I came across some code dated 1998 on MSDN which essentially iterated through a series of 640×480 virtual screens, testing which handle was returned for each one within the overall desktop coordinate space. This method seems to me to suffer exactly the same problem Raymond outlines! I guess it was intended for Windows 98 and earlier but surely there is a better way?
Okay, honest question here: In what scenario would you ever need this?
Most applications have no business caring which monitor is "primary". Desktop apps should be monitor-agnostic and run wherever the user puts the window. Full-screen games should give the user the option of monitor on which to run. Likewise with media players.
I’ll probably never be able to go back to the days of running on a single-monitor, but one of the biggest headaches I have with multi-mon is the number of apps that blithely assume that I want everything on whichever monitor happens to have been marked "primary", and don’t allow the user to specify where they go.
The idea of a "primary" monitor is an excellent backward-compatibility concept for those apps that were written before computers could have more than one monitor (Win95?), but modern programs should be written for multi-monitors just as surely as they should be written for keyboard input or for high-DPI support.
Mack: "Yeah, Simonyi — guy’s a space cadet"
I think, generally, one ceases being a space cadet when one actually goes into space…
How about this:
BOOL CALLBACK enumMonitorProc(HMONITOR hMonitor, HDC, LPRECT rect, LPARAM lParam)
{
HMONITOR *hm = (HMONITOR*) lParam;
*hm = hMonitor;
return false;
}
HMONITOR getPrimaryMonitor()
{
HMONITOR hm;
EnumDisplayMonitors(NULL, NULL, enumMonitorProc, (LONG) &hm);
return hm;
}
Which will enumerate monitors starting with the primary, and stop after the first. Which is what we wanted.
Ryan: If I run a application for the first time then there has been no opportunity for me to tell it which monitor to run on (unless you want people to manually edit config files before running apps for the first time), so using the primary monitor seems like a very sensible step.
The only alternative I can think of right now is to open on the monitor where the mouse is (or where the main/active window of the launching process is, if applicable). There are pros and cons in each case but I don’t think I’d ever object to a new program opening on the primary monitor.
If a program doesn’t let me move it to another monitor after the first use then that might be annoying.
I wonder what CW_USEDEFAULT does in relation to monitors – does it always open a window on the primary monitor? If so, you could use that the first time your application runs, and then the stored position afterwards.
Odd… I can’t seem to find it in the Win32 docs that EnumDisplayMonitors() uses any particular order. They do say that it includes both physical and invisible pseudo-monitors, unlike GetSystemMetrics()*. I’ve done my share of Programming by Accident, but not recently, and not when there was a clean, documented way to do what I needed. Like they say, a week or two in the lab can save you an hour in the library.
*At first glance, I was somewhat surprised by this, but it makes sense after I think about it for a while.
@Ryan – Games actually can’t choose – DirectX chooses for them. The only things games can choose is whether or not they want to use extra monitors or not.
I’ve seen one app do wierd things on multiple monitors – it doesn’t use MDI, but opens separate windows. End result was some windows opened on the primary (notably, dialog boxes and the work item), but the app’s main toolkit opened on the secondary!
And, I suppose, a reasonable use for this code would be to have apps use multiple monitors – by default, open the main workarea on the primary, and secondary work areas on the other monitor(s) (which could be stuff like documentation, alternate views, etc). E.g. a graphic artist would do their stuff using an expensive color-matched monitor (pricey), but can have stuff like info boxes (histograms, properties, etc) on a cheaper LCD display, maximizing their work area, but also not having useful items hidden.
It’s perfectly reasonable to want to know about monitors. Any app which has multiple windows and wants to put them back where the user left them the last time the app ran needs to know this kind of thing. If you think you can get away with just remembering the absolute position of each window, you’re not taking into account the fact that monitors can move and/or disappear and you may well be stranding your user’s windows off-screen. As well, you’re not taking into account the fact that users think in terms of monitors rather than absolute coordinates. Finally, you’re obviously not writing apps which care whether the windows they create will fit on an available monitor or have enough colors to do the job.
That said, Raymond’s idea seems like a good short-cut for people who need to know about the main monitor, but this information is often of limited utility. Most apps will need SPI_GETWORKAREA instead of or in addition to this technique.
I just wish it was simpler to get the rectangle for a maximize window on any given monitor, taking stay on top edges like the toolbar and side bar into account.
@Jon: AFAIK, CW_USEDEFAULT causes the window to open on the monitor that currently contains the mouse pointer.
Which can actually be irritating in some cases (usually when you have something that opens windows asynchronously), but that’s rare. In the majority of cases it behaves as you’d reasonably expect.
Define primary.
The system designates one of the monitors primary. I don’t know the rules it follows to do this, but one doesn’t need to know them. One only needs to know that after the system designates one of the monitors primary, two things happen: the upper left corner of the primary monitor becomes the the origin of desktop coordinates, in other words location 0,0 in quadrant IV of a Cartesian coordinate system, and apps such as Explorer ask for the primary monitor and do such things as place the task bar there. If your app is multiple-monitor-savvy, it probably doesn’t think much about 0,0, implicitly or explicitly, but instead thinks of each window as having an affinity to a monitor without regard to that monitor’s location relative to the origin. All you really need to know is [1] that coordinates increase as they move right and down and [2] there are multiple monitors, each of which has coordinates.
Primary monitor is the one that shows a BIOS boot screen, no?
Then I got 2 of them. :)
Be careful; video cards often display their own ego gratification when powered up — even before BIOS gets control.
That wouldn’t have been an answer, anyway; it just would have pushed the question down to how the BIOS decides. Windows could easily make a different decision.
Of course, the user can have her own say. On XP, open the Settings tab of the Display control panel and note the check-box "Use this device as the primary monitor". (This doesn’t explain how Windows decides what the primary monitor should be the first time it boots.)