GetDeviceCaps issue in Windows 7, wrong size
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 11 of 11

Thread: GetDeviceCaps issue in Windows 7, wrong size

  1. #1
    Join Date
    Jan 2011
    Posts
    15

    GetDeviceCaps issue in Windows 7, wrong size

    I am having an issue with my application now that I am starting to use newer Windows 7 computers. I know that this is a windows 7 issue because I have duplicated this on multiple computers, multiple monitors and even downgrading from Windows 7 to Windows XP on the same computers.

    My output is is MM_HIMETRIC and I am plotting everything in specific sizes. Please don't give me all the reasons that I should use pixels instead of millimeters, I need to maintain the proper scale in metric on the screen and the printed values so it is much better for me to get the monitor display to work correctly than to re-write millions of lines of code that currently use the MM_HIMETRIC map mode.

    Anyway, here is my exact problem...

    WinXP Result ____ Win7 Result ____ Function Call
    ____ 320 __________ 564 ________ pDC->GetDeviceCaps(HORZSIZE)
    ____ 240 __________ 318 ________ pDC->GetDeviceCaps(VERTSIZE)

    Since GetDeviceCaps is returning the wrong values in Windows 7 (XP values are correct when compared to measuring with a ruler), my output is being displayed at about 50 - 60% reduction in scale.

    Does anyone know how I can get the correct values of the display's physical size in Windows 7?

    I would rather not require the operator to enter the physical dimensions for the screen every time I install my program on a new computer - then scaling my CScrollView in metric, then switching to MM_ANISOTROPIC and using SetWindowExt() based on the operator entered values.

    I have to believe that others have run into this problem as well and there must be a better solution out there.

    Any help getting the correct values in Windows 7 would be a huge help.

    Thanks.

  2. #2
    Join Date
    Apr 1999
    Posts
    27,424

    Re: GetDeviceCaps issue in Windows 7, wrong size

    Quote Originally Posted by vandy_mike View Post
    I am having an issue with my application now that I am starting to use newer Windows 7 computers. I know that this is a windows 7 issue because I have duplicated this on multiple computers, multiple monitors and even downgrading from Windows 7 to Windows XP on the same computers.
    Does this help any?

    http://msdn.microsoft.com/en-us/libr...%29.aspx#step1

    Regards,

    Paul McKenzie

  3. #3
    Join Date
    Jan 2011
    Posts
    15

    Re: GetDeviceCaps issue in Windows 7, wrong size

    No... this isn't a DPI issue. As you can see from my post, GetDeviceCaps thinks that the physical size is 50 - 60% larger. I have tried making my projects DPI aware in the past but it only really affected things like menus and dialogs... not my core output. I have graphic heavy output, plotting trendlines and whatnot, so the MoveTo() and LineTo() type of functions aren't corrected by the DPI issues.

  4. #4
    Join Date
    Apr 1999
    Posts
    27,424

    Re: GetDeviceCaps issue in Windows 7, wrong size

    Quote Originally Posted by vandy_mike View Post
    No... this isn't a DPI issue. As you can see from my post, GetDeviceCaps thinks that the physical size is 50 - 60% larger. I have tried making my projects DPI aware in the past but it only really affected things like menus and dialogs... not my core output. I have graphic heavy output, plotting trendlines and whatnot, so the MoveTo() and LineTo() type of functions aren't corrected by the DPI issues.
    Why not put together a simple Win32 program that demonstrates the error? Then everyone can try this and see if they are getting the same results.

    This Win32 console program gives me correct numbers (or close to correct) when run with Windows 7 (32-bit), using the Intel G33/G31 Express Chipset Family, version 8.15.10.1930.
    Code:
    #include <windows.h>
    #include <iostream>
    
    void ScreenSizeInInches()
    {
        HDC hdc = GetDC(GetDesktopWindow());
        DWORD ret = GetDeviceCaps(hdc, HORZSIZE);
        DWORD ret2 = GetDeviceCaps(hdc, VERTSIZE);
        std::cout << "Your screen size in inches is " << ret/25.4 << "\" x " << ret2/25.4 << "\" \n";
        ReleaseDC(GetDesktopWindow(), hdc);
    }
    
    void ScreenSizeInPixels()
    {
        HDC hdc = GetDC(GetDesktopWindow());
        DWORD ret = GetDeviceCaps(hdc, HORZRES);
        DWORD ret2 = GetDeviceCaps(hdc, VERTRES);
        std::cout << "Your screen size in pixels is " << ret << " x " << ret2 << "\n";
        ReleaseDC(GetDesktopWindow(), hdc);
    }
    
    void ScreenSizeInLogicalPixels()
    {
        HDC hdc = GetDC(GetDesktopWindow());
        DWORD ret = GetDeviceCaps(hdc, LOGPIXELSX);
        DWORD ret2 = GetDeviceCaps(hdc, LOGPIXELSY);
        std::cout << "Your screen size in logical pixels is " << ret << " x " << ret2 << "\n";
        ReleaseDC(GetDesktopWindow(), hdc);
    }
    
    void ScreenSizeInInchesUsingMapMode()
    {
        HDC hdc = GetDC(GetDesktopWindow());
        if ( SetMapMode(hdc, MM_HIMETRIC))
        {
            DWORD ret = GetDeviceCaps(hdc, HORZSIZE);
            DWORD ret2 = GetDeviceCaps(hdc, VERTSIZE);
            std::cout << "Your screen size in inches using MM_HIMETRIC is " << ret/25.4 << "\" x " << ret2/25.4 << "\" \n";
        }
        else
            std::cout << "Error in setting mapping mode MM_HIMETRIC\n";
        ReleaseDC(GetDesktopWindow(), hdc);
    }
    
    void ScreenSizeInPixelsUsingMapMode()
    {
        HDC hdc = GetDC(GetDesktopWindow());
        if ( SetMapMode(hdc, MM_HIMETRIC))
        {
            DWORD ret = GetDeviceCaps(hdc, HORZRES);
            DWORD ret2 = GetDeviceCaps(hdc, VERTRES);
            std::cout << "Your screen size in pixels using MM_HIMETRIC is " << ret << " x " << ret2 << "\n";
        }
        else
            std::cout << "Error in setting mapping mode MM_HIMETRIC\n";
        ReleaseDC(GetDesktopWindow(), hdc);
    }
    
    void ScreenSizeInLogicalPixelsUsingMapMode()
    {
        HDC hdc = GetDC(GetDesktopWindow());
        if ( SetMapMode(hdc, MM_HIMETRIC))
        {
            DWORD ret = GetDeviceCaps(hdc, LOGPIXELSX);
            DWORD ret2 = GetDeviceCaps(hdc, LOGPIXELSY);
            std::cout << "Your screen size in logical pixels using MM_HIMETRIC is " << ret << " x " << ret2 << "\n";
        }
        else
            std::cout << "Error in setting mapping mode MM_HIMETRIC\n";
        ReleaseDC(GetDesktopWindow(), hdc);
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        ScreenSizeInInches();
        ScreenSizeInPixels();
        ScreenSizeInLogicalPixels();
        ScreenSizeInInchesUsingMapMode();
        ScreenSizeInPixelsUsingMapMode();
        ScreenSizeInLogicalPixelsUsingMapMode();
        return 0;
    }
    
    Output:
    
    Your screen size in inches is 23.3465" x 14.5669"
    Your screen size in pixels is 1680 x 1050
    Your screen size in logical pixels is 96 x 96
    Your screen size in inches using MM_HIMETRIC is 23.3465" x 14.5669"
    Your screen size in pixels using MM_HIMETRIC is 1680 x 1050
    Your screen size in logical pixels using MM_HIMETRIC is 96 x 96
    So given the program above, what exactly did you expect to see as the results of setting the mapping mode?

    When I read the documentation of GetDeviceCaps() for HORZSIZE, and VERTSIZE there is only mention of millimeters, and nothing I see that states this value must be changed by setting the mapping mode.

    http://msdn.microsoft.com/en-us/libr...=vs.85%29.aspx

    Regards,

    Paul McKenzie

  5. #5
    Join Date
    Jan 2011
    Posts
    15

    Re: GetDeviceCaps issue in Windows 7, wrong size

    Quote Originally Posted by Paul McKenzie View Post
    Code:
        DWORD ret = GetDeviceCaps(hdc, HORZSIZE);
        DWORD ret2 = GetDeviceCaps(hdc, VERTSIZE);
    
        SetMapMode(hdc, MM_HIMETRIC))
        DWORD ret = GetDeviceCaps(hdc, HORZSIZE);
        DWORD ret2 = GetDeviceCaps(hdc, VERTSIZE);
    I appreciate your code but you have missed the crux of my problem...

    When I run my program using Windows 7, pDC->GetDeviceCaps(HORZSIZE) and pDC->GetDeviceCaps(VERTSIZE) return 564mm and 318mm respectively. [bold]HOWEVER[/bold] when I use a ruler I get values more like 320mm and 240mm. These lower values (320mm x 240mm) match the results that I get when I run in Windows XP. I don't have any expectation that these numbers should change between map modes.

    My issue is that I am getting bogus information (564mm X 318mm) that is clearly too large for my monitor. Since Windows thinks the monitor is so much bigger, everything that I plot on my screen ends up shrinking by this amount (320 / 564 = 56.74% of original height, 240 / 318 = 75.47% of original height). My original output (which looks fine in XP) is now too small to read legibly and there is excess white space around to the right and bottom of my output.

    The Win7 values of 564mm and 318mm do not seem to be coming from my mapping mode changes, and they do not seem to be affected by making my software DPI aware... so what can I do to get back to the correct 320mm and 240mm values that I get from WinXP?

  6. #6
    Join Date
    Apr 1999
    Posts
    27,424

    Re: GetDeviceCaps issue in Windows 7, wrong size

    Quote Originally Posted by vandy_mike View Post
    My issue is that I am getting bogus information (564mm X 318mm) that is clearly too large for my monitor.
    Those numbers aren't bogus for my monitor and driver.

    Note I highlighted driver. Maybe your driver for Windows 7 is what is buggy. That's why I mentioned it in my post.

    Also, what is your monitor's native (highest) resolution? Are you running in that resolution for XP? If you're not running in your monitor's native resolution, then those numbers will be different (at least with Windows 7):

    Edit:
    Code:
    Your screen size in inches is 17.7953" x 13.3465"
    Your screen size in pixels is 1280 x 960
    Your screen size in logical pixels is 96 x 96
    Your screen size in inches using MM_HIMETRIC is 17.7953" x 13.3465"
    Your screen size in pixels using MM_HIMETRIC is 1280 x 960
    Your screen size in logical pixels using MM_HIMETRIC is 96 x 96
    This is my output when running in 1280 x 960 instead of the "natural" 1680 x 1050. So Windows 7 scales down the screen size information as well as the pixel info.

    Also, there are functions that get the monitor information:

    http://msdn.microsoft.com/en-us/libr...=vs.85%29.aspx

    Regards,

    Paul McKenzie
    Last edited by Paul McKenzie; February 17th, 2012 at 02:18 PM.

  7. #7
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,553

    Re: GetDeviceCaps issue in Windows 7, wrong size

    Quote Originally Posted by Paul McKenzie View Post
    [When running in "native" 1680 x 1050 mode]
    Code:
    Your screen size in inches is 23.3465" x 14.5669"
    [When running in 1280 x 960 mode]
    Code:
    Your screen size in inches is 17.7953" x 13.3465"
    ...
    I think the OP's point is demonstrated by the differing outputs, despite the same physical screen. Why would Win 7 report that the same screen has different sizes, simply because it's being run in different modes? And, what is the "real" physical size of the screen, as measured by a ruler? Is the screen really as large as 23.3465" x 14.5669" (which seems pretty big to me)?

    Note that the documentation for GetDeviceCaps() would lead me to expect that the returned value for HORZSIZE and VERTSIZE is the actual width (or height), in millimeters, of the physical screen. With such a definition, there is no apparent reason for different return values for different modes on the same physical screen.

    Also note that there are inconsistencies within either one of the returned values. LOGPIXELSX / Y returns the number of pixels per logical inch along the screen width / height. So one would expect simple divisions to yield consistent results, but they don't. For example, with respect to this output:
    Code:
    Your screen size in inches is 17.7953" x 13.3465"
    Your screen size in pixels is 1280 x 960
    Your screen size in logical pixels is 96 x 96
    1280 pixels / 96 pixels per inch = 13.3333 inches, not 17.7953
    960 pixels / 96 pixels per inch = 10.0000 inches, not 13.3465

    Or, alternatively,
    1280 / 17.7953 = 71.9291 pixels per inch, not 96
    960 / 13.3465 = 71.9290 pixels per inch, not 96

    I don't know the answer, but I think I understand the reason for the question.

  8. #8
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,553

    Re: GetDeviceCaps issue in Windows 7, wrong size

    See "Reading Monitor Physical Dimensions, or: Getting the EDID, the Right Way" at http://thetweaker.wordpress.com/2011...the-right-way/

    "EDID" is "Extended Display Identification Data". A copy of the EDID block is kept in the registry, and bytes 21/22 of it contain the width/height of the monitor, in cm

    Mike

  9. #9
    Join Date
    Jan 2011
    Posts
    15

    Re: GetDeviceCaps issue in Windows 7, wrong size

    Quote Originally Posted by MikeAThon View Post
    See "Reading Monitor Physical Dimensions, or: Getting the EDID, the Right Way" at http://thetweaker.wordpress.com/2011...the-right-way/
    I implemented Ofek's solution, this goes further to proving my problem... but not so much helping to find a solution.

    For the computer that I am working on now... the numbers that I am getting back from the EDID are centimeters instead of millimeters (34 cm and 19 cm). This is pretty close to the 344mm and 193mm that I get using a ruler, but it is still far from the GetDeviceCaps values of (564mm and 318mm).

    Since the EDID only holds centimeters, it is a little bit coarse for my needs. I can use this as a "close enough" solution, but it would be great if I could get finer values (or better yet, if GetDeviceCaps could give me the correct value - but that sounds like it just isn't going to happen).

    My work around is that I am using SetScrollSizes in MM_HIMETRIC and using the rectangle_size * GetDeviceCaps_size / EDID_size. Then I am changing to MM_ANISOTROPIC and using SetWindowExt based on the EDID_size. This does not give me exactly what I had hoped for (I can't draw a perfect 1 inch square without doing a lot of modification), but it is close enough.

    Does anyone have information that might help me further?

  10. #10
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,553

    Re: GetDeviceCaps issue in Windows 7, wrong size

    Quote Originally Posted by vandy_mike View Post
    Since the EDID only holds centimeters, it is a little bit coarse for my needs. I can use this as a "close enough" solution, but it would be great if I could get finer values ....
    Under WinXP, your results were 320 x 240 (per your first post), so it seems like the EDID results of 340 x 190 are far closer to the true size of 344 x 193.

    How much more accuracy do you need, considering that you were satisfied with the results under WinXP? The EDID error is less than about 1.5% (both horizontal and vertical) whereas the GetDeviceCaps results under WinXP had errors of 7.0% horizontal, 24.4% vertical.

    Mike

  11. #11
    Join Date
    Jan 2011
    Posts
    15

    Re: GetDeviceCaps issue in Windows 7, wrong size

    Quote Originally Posted by MikeAThon View Post
    The EDID error is less than about 1.5% (both horizontal and vertical) whereas the GetDeviceCaps results under WinXP had errors of 7.0% horizontal, 24.4% vertical.
    I understand that the percentage difference is so small... that is why I called it a "close enough" solution. However, I am wondering if anyone has a way for me to get from "close enough" to "correct" values.

    Also... (I haven't debugged this fully, so pardon the possible error on my part)... Windows XP reports BAD_EDID for the default monitor so this does not seem to be working for XP computers. Since my original output was good for Windows XP, I can work around this but it would be really helpful to get correct numbers from the EDID in either operating system.

    Any ideas?

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Azure Activities Information Page

Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center