Page 1 of 2 12 LastLast
Results 1 to 40 of 44

Thread: [RESOLVED] Per-Monitor DPI Awareness & VB

  1. #1

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Resolved [RESOLVED] Per-Monitor DPI Awareness & VB

    I don't have Win8.1 to try it else I would & post the results to this forum.

    Background: Per-Monitor DPI Awareness (PMDA) is new with Win8.1. It kinda works this way: User moves your app from say a 96 DPI monitor to a 144 DPI monitor. Without declaring PMDA, Windows will scale your app as needed for the new DPI. However, if you did declare your app as PMDA with a manifest, then no DPI virtualization occurs, but you are responsible for scaling your project to the new DPI. You'll know when a different DPI applies by subclassing a main-level window & looking for a WM_DPIChanged message.

    Now. I doubt many have played with this new option. It does require a lot of work, manual scaling, multiple monitors, and Win8.1 to play with. Probably too much to hope for, this early in Win8.1's lifetime.

    If, however, you have, here's what I'm curious about...

    1) Internally, how does VB receive mouse X,Y coordinates thru its events? Does VB scale them, not knowing it is in a different DPI environment? May depend on the object's ScaleMode property? In other words, using a picbox, and if the cursor was on the right edge of the picbox, would the X,Y coordinates received in a MouseMove event, be equal the physical right edge of the picbox or scaled somehow, giving 'false' values?

    2) Are VB-related measurements hosed, can they be trusted? For example, I'd think Screen.Width/Height would be broken. Maybe picBox.ScaleWidth would return good values for anything other than a Twips scalemode?

    3) Externally, do coordinate-related APIs work. Example: using picbox again with mouse over right or left edges, would WindowFromPoint API return the picbox.hWnd in both cases? Would the reverse work, i.e.,
    WindowFromPoint ScaleX(picBox.Left+1,Me.ScaleMode,vbPixels), ScaleY(picBox.Top+1,Me.ScaleMode,vbPixels)?

    4) From what I've read, in multi-monitor environments,the X,Y coordinates can be negative. This isn't Win8.1 restricted. Wonder how that effects VB, internally/externally?

    Again, just curious.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  2. #2

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Per-Monitor DPI Awareness & VB

    As long as we are on the topic of DPI-Awareness. Here's a manifest I use for my vb6.exe file so I can design a project in the current DPI my screen is in. To remove the theme option, delete the 'dependency' section regarding Windows.Common-Controls. That has a habit of hiding the palette in property sheet items that display it. But on the other hand, your controls are themed while in IDE.
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
      <assemblyIdentity
        version="6.00.9782.0"
        processorArchitecture="X86"
        name="Visual Basic"
        type="win32"
        />
      <description>Microsoft Corporation VB6</description>
        <dependency>
            <dependentAssembly>
                <assemblyIdentity
                    type="win32"
                    name="Microsoft.Windows.Common-Controls"
                    version="6.0.0.0"
                    processorArchitecture="X86"
                    publicKeyToken="6595b64144ccf1df"
                    language="*"
                 />
            </dependentAssembly>
        </dependency>
        <dependency>
            <dependentAssembly>
                <assemblyIdentity
                    type="win32"
                    name="Microsoft.Windows.GdiPlus"
                    version="1.1.0.0"
                    processorArchitecture="X86"
                    publicKeyToken="6595b64144ccf1df"
                    language="*"
                 />
            </dependentAssembly>
        </dependency>
    <!-- Identify the application as DPI-aware: Vista and above -->
      <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
          <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
            <dpiAware>true</dpiAware>
          </asmv3:windowsSettings>
      </asmv3:application>
    </assembly>
    Also, if using this manifest on XP, remove the GDI+ v1.1 section else VB6 won't start.

    Copy contents and save to a new NotePad file in same folder as vb6.exe. Rename the file vb6.exe.manifest and restart VB. To stop the manifest from working, rename the manifest file with a .bak extension. Sometimes, adding/removing the .bak extension fails to take effect. On Vista, at least, a simple solution is to close VB first, then right click on vb6.exe, select Properties, and under the 'compatibility' tab:
    1) Check or uncheck 'run this program...' option
    2) Click 'Apply' button
    3) repeat steps 1 & 2 again
    4) Open VB6
    For Win7 and above, manifest caching is done by the system & if the above tactic won't work, from what I've read, you may need to touch vb6.exe date/time stamp. Add/subtract a minute from it. Maybe another tactic works?

    Note: for per-monitor awareness, a different DPI-Awareness entry is required. Here's that entry
    replace
    Code:
    <dpiAware>true</dpiAware>
    with
    Code:
    <dpiAware>True/PM</dpiAware>
    For those that use my Manifest Creator (linked in signature below), just updated that project to include option of per-monitor DPI awareness.
    Last edited by LaVolpe; Dec 20th, 2014 at 10:14 PM. Reason: added per-monitor awareness entry
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  3. #3

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Per-Monitor DPI Awareness & VB

    Just a follow up. If you were to use 192 DPI, that is exactly twice the DPI from 96. And 192 DPI equates to 7.5 TwipsPerPixel, using the formula: 1440 / 192 = 7.5, and complimentary, to determine DPI from TwipsPerPixel: 1440 / 7.5 = 192.

    Hmmm. I compiled an exe and manifested it so that it is DPI-Aware (not per-monitor at this point). I ran it and clicked a button that behind that button, it reported a couple of things: TwipsPerPixelX, calculated DPI based on 1440/TwipsPerPixel, and reported DPI from APIs.

    Does VB suffer from rounding when it comes to DPI and TwipsPerPixelX,Y, even though those values are held in Single vartypes? VB's TwipsPerPixel was 7, not 7.5. Using that calculation, this equates to a DPI of 205.7143 instead of 192. The API reported the DPI as 192.
    Code:
        Dim tDC As Long, tDPI As Long
        tDC = GetDC(GetDesktopWindow)
        tDPI = GetDeviceCaps(tDC, LOGPIXELSX)
        ReleaseDC GetDesktopWindow, tDC
    Also, I threw a 61x61 image on the form & had its stretch property set to true. With double the DPI, you'd expect the image to be double the size at 122x122, but it wasn't. It was scaled even larger, by VB, to 130.7143 which is equivalent to a DPI of 205.7143, or 61*(15/7) vs 61*(15/7.5).

    FYI for anyone following this thread. It appears with VB, you cannot blindly use the DPI reported by APIs. Instead, a safer formula is to use 1440 / Screen.TwipsPerPixelX which would return a value of 205.7143 in this case. It appears VB is scaling by that adjusted DPI and not actual DPI. When it comes to making a project per-monitor DPI aware, I think this will have to be addressed by the coder?

    Whether this is true in all cases, I do not know. It is entirely possible that monitor software is in play here? But regardless, APIs & VB agree to disagree with the DPI

    I've included some images to show how DPI aware manifest affects scaling in VB. In the images below, the left column of images are a picturebox with .AutoSize=True on top and image control with Stretch=False on bottom. The next column has the properties reversed. All fonts are true-type fonts except the 1st command button. You can see that @ 192 DPI, the form size is different & that's because VB is using a larger DPI than 192 for scaling. What you can't really see is how crisp the DPI-aware versions are where the other versions are somewhat blurry. So, I've zipped them up should you want to better inspect them.

    Name:  DPI96.jpg
Views: 2911
Size:  24.7 KB
    Name:  DPI144.jpg
Views: 2789
Size:  22.9 KB
    Name:  DPI192.jpg
Views: 2789
Size:  21.7 KB
    Attached Files Attached Files
    Last edited by LaVolpe; Dec 21st, 2014 at 02:00 PM. Reason: added screenshots
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  4. #4
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,487

    Re: Per-Monitor DPI Awareness & VB

    I haven't explored PMDA yet, and was planning on waiting for a stable late beta of Windows 10 before even bothering.

    One thing I wonder about is a form that spans monitors, i.e. when will your program become aware it needs to rescale a form when it moves between monitors?

    I usually try to deal with all metrics in Twips (or Points for fonts), and then at runtime scale to dots/pixels on an as-required basis when using GDI or GDI+ operations. So far this seems to be working quite successfully.

    For bitmap image formats I have to convert the other way as well (instead of using simple LoadPicture() calls or the design-time equivalent). I.e. load the image, examine its stored DPI setting (or jam in 96 as a default), and rescale it based on the screen DPI before using the result as a control image.

    This seems far more practical than shrinking the controls to fit their bitmaps as screen DPI goes up.

  5. #5

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Per-Monitor DPI Awareness & VB

    @ dilettante, I handle my graphics nearly the same as you. For those that want to fake graphics DPI-awareness, the simple solution is to use image controls with their Stretch property set to true. A picturebox can fake DPI-awareness by not using .AutoSize but placing an image control inside the picturebox vs assigning image to the .Picture property. This way when the DPI goes up, the picbox scales up & the image inside the image control, inside the picbox goes up as long as its Stretch property is true. This all being said, there are negatives, mainly blurring and does not resolve issues for any other objects with pictures, like buttons. Best solution obviously is to have multiple resolution images in one's resource file & choosing best for the active DPI.

    I think the situation where VB uses an adjusted DPI vs what's reported by API is one like this: Your app is launched on a 192 DPI monitor. If VB doesn't use 192, but 205 for example, then when your app gets the WM_DPIChanged message, you have to manually scale all of your controls, graphics, fonts, etc. But what are you scaling them from, 192 or 205 DPI? Without doing these simple tests, I wouldn't have thought twice. Without being able to prove it at this time, I am assuming that whatever DPI VB is launched to is the DPI VB will use forever until the app is unloaded. This makes VB 'System' DPI-aware naturally, assuming it is manifested, & it will never be per-monitor aware on its own. Without manifesting the app, the app gets DPI Virtualization from the O/S, i.e., stretching.

    To answer your question:
    Quote Originally Posted by msdn
    The WM_DPICHANGED window notification is sent to per-monitor DPI-aware applications when a window’s position changes such that most of its area intersects a monitor with a DPI that is different from the DPI before the position change or when the user moves the display slider. To create an application that resizes and re-renders itself when a user moves it to a different display, use this notification.
    Edited: Thinking out loud while laughing inside. Wonder how MS defines "most of its area"? What if, when you receive that message, you adjust the form's dimensions & offset it's left/top edge by 1/2 the difference in scaled size. Would then, the "most of its area" still be on the same monitor, or would you create an infinite loop?
    Last edited by LaVolpe; Dec 21st, 2014 at 03:50 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  6. #6
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,454

    Re: Per-Monitor DPI Awareness & VB

    Quote Originally Posted by LaVolpe View Post
    Your app is launched on a 192 DPI monitor. If VB doesn't use 192, but 205 for example, then when your app gets the WM_DPIChanged message, you have to manually scale all of your controls, graphics, fonts, etc. But what are you scaling them from, 192 or 205 DPI? Without doing these simple tests, I wouldn't have thought twice.
    All these considerations become moot, when one would be working with Pixels in his VB-App -
    and take all the scaling from there.

    Even the new WM_DPICHANGED message addresses this approach to things with what's delivered in the lParam:
    lParam:
    ... A pointer to a RECT structure that provides the size and position of the suggested window, scaled for the new DPI
    So, there you have your new suggested Window-position and -Size (in Pixels!).
    - Resize that TopLevel-Window accordingly (in Pixels)
    - in the internal Resize-Event of that Window, react to the new ScaleWidth/ScaleHeight of its new Client-Area
    . (re-arranging your Controls accordingly - most reliable Scalewidth/Scaleheight which is reported here is, again: Pixels)

    I see the also provided DPI-carrying wParam only as a rough suggestion, on what to do with
    the internal Scaling of your Controls (Font-Sizes being the most obvious thing which needs to
    be taken care of, when it's not handled automatically - and here it doesn't really matter much,
    if the DPI-based Scalefactor is a few percent-points off).

    Olaf

  7. #7

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Per-Monitor DPI Awareness & VB

    Quote Originally Posted by Schmidt View Post
    All these considerations become moot, when one would be working with Pixels in his VB-App -
    and take all the scaling from there.
    Have to disagree. Doesn't matter what your scalemode is. The bottom line, is that you have to determine what DPI you are in and what DPI you are moving to; or more precisely what scaling factor. Once you know that you calculate a scaling factor which is simply the difference/ratio between the 2 DPIs. Walk through all your controls and multiply their positions/sizes by that factor. Whether your scalemode is pixels or twips doesn't matter, you are still multiplying Object.Left * scaling factor.

    What does matter is knowing the scale VB is using when it launched. What I was pointing out is that you cannot assume VB is using the DPI returned by APIs. I don't know if simply taking the current window size and getting its ratio to the suggested size would be ideal. Would the non-client area differences/ratio always be the same as the client area ratio? If that is always true, then I'd agree that one doesn't need to know the current scale. And I don't think we'll know that until we can test it, which brings me back to my 1st post.

    Edited. And to be clear. This only applies when using per-monitor DPI-awareness. If that doesn't apply, then your app is DPI virtualized when moving between DPIs. If using DPI awareness, but not per-monitor awareness, then about the only thing that must be addressed is graphics. If one is scaling their app due to resolution, that's another topic
    Last edited by LaVolpe; Dec 21st, 2014 at 06:10 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  8. #8
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,454

    Re: Per-Monitor DPI Awareness & VB

    Quote Originally Posted by LaVolpe View Post
    Have to disagree.
    Doesn't matter what your scalemode is.
    But with "doesn't matter what your scalemode is" - you already agreed.

    Because, since it *doesn't* matter, you can "forget about VB-Scalemodes" - and what's left then is,
    how the system prefers to handle things, and the system apparently prefers to work with the true
    physical dimensions on a given pixel-oriented (Screen)device, it even handles its graphical system-
    containers (its hWnds, no matter if TopLevel or ChildLevel) - in Pixel-Dimensions too.

    What I was trying to point out is, that the fact that you're wondering about some discrepancies
    in Values, reported by VBs "virtual Scale-Handling" - is only happening because you used these
    Scalemodes in the first place, instead of using, what the System supports at the root-level of things.

    Quote Originally Posted by LaVolpe View Post
    The bottom line, is that you have to determine what DPI you are in and what DPI you are moving to.
    Once you know that you calculate a scaling factor which is simply the difference/ratio between the 2 DPIs.
    We don't disagree about that part - one has to determine a new ScaleFactor - but these new X/Y-Facs could
    be more reliably determined by using the (incoming per lParam) Pixel-Dimensions of the new,
    recommended Window-Rectangle - in comparison to the current Pixel-Dimensions of your Form.

    Aside from that, I'd doubt that this "resizing of existing VB-Containers" will work without any
    surprises, once you moved a Form over from a 96dpi Screen to a 192dpi one.

    I'd guess that there's a lot of "static-Var-stuff" with regards to VBs Scale-handling in VBs OleControl-
    Implementation - intermixed with stuff that is dynamically calling the system-APIs again to determine
    DPIs or other resolution-related things (since as VB-code was written, the assumption that there's
    a constant DPI-resolution for Screens - until the next Session-reboot, was a correct one).

    I currently have not the time (nor the monitors), to build-up such a setting around my Win8.1-install here.

    Maybe others can report, how VB-Controls will react when shifted into "higher dpi spheres" - and what's
    happening at the next Resize of them - will FontSizes auto-adjust themselves in that case to the new Monitor-DPI -
    or will they remain true to the setting of the Monitor-DPI, which the VB-App-Main-Window was startet in?

    Quite some questions which are not answered so far...

    Olaf
    Last edited by Schmidt; Dec 21st, 2014 at 06:47 PM.

  9. #9

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Per-Monitor DPI Awareness & VB

    Quote Originally Posted by olaf
    What I was trying to point out is, that the fact that you're wondering about some discrepancies
    in Values, reported by VBs "virtual Scale-Handling" - is only happening because you used these
    Scalemodes in the first place, instead of using, what the System supports at the root-level of things.
    Not quite. I was more concerned with getting the existing objects scaled correctly to the new DPI scale. If we were to move from 192 to 96 DPI, the ratio of change is 50%. We can scale our entire project (be it twips or pixels) by 50% and all should be well. Though, we won't really be in 96 DPI at that point, since we started with an adjusted scale of 205 DPI vs 192 DPI. In the screen shots I posted in previous posts, imagine that 192 DPI window (the one that is larger) scaled 50%, it will still be a bit larger, after scaling, than the 96 DPI samples. To scale to "correct" 96 DPI sizes (as would be if the app launched on a 96 DPI monitor), we'd have to scale from 205 > 96 DPI, not 192 > 96 DPI. So instead of .Left * 0.5, it would be .Left * 0.4666

    Using the suggested window size I feel is a recipe for disaster. One must assume that the current window dimensions compared to the suggested dimensions equate to a reliable scaling factor/ratio. Does the O/S treat non-client borders any differently between DPIs, does it take into consideration the possibility of a scaled menubar moving to/from a wrapped row due to font scaling? Possibility of toolbars changing height a bit more/less than the expected ratio, due to icon/font scaling? Wouldn't want client area adjustments moving into the client area. Though, I think that could be a possibility whenever the app is scaled. But unless Microsoft can tell us exactly how the suggested rectangle is calculated. I'd rather use the difference in O/S reported DPI or another method. Heck maybe that's all MS is doing, scaling the current window size by the difference in source/destination DPI, or worse: scaling AdjustWindowRect API

    Until I'm proven wrong by experimentation, I will continue to use this formula:
    Ratio.X = newDPI.X / VB_DPI.X where VB DPI is: 1440 / Screen.TwipsPerPixel
    Last edited by LaVolpe; Dec 21st, 2014 at 09:31 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  10. #10
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,487

    Re: Per-Monitor DPI Awareness & VB

    Quote Originally Posted by LaVolpe View Post
    Edited: Thinking out loud while laughing inside. Wonder how MS defines "most of its area"? What if, when you receive that message, you adjust the form's dimensions & offset it's left/top edge by 1/2 the difference in scaled size. Would then, the "most of its area" still be on the same monitor, or would you create an infinite loop?
    This is one of the things that makes me wonder if the whole notion of DPI per monitor was ill-conceived.

    I'm sure they used their own secret recipes in WinRT XAML and may have changed WPF under the covers too (possibly even the same way, but just as likely using another scheme). For everyone else the chips fall where they may.

    I'm hoping they realize that themselves and pull the "feature" from Windows 10 before it ships. Then we can let the entire Win8.x debacle fade away into well deserved obscurity.

  11. #11
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,454

    Re: Per-Monitor DPI Awareness & VB

    Quote Originally Posted by LaVolpe View Post
    Not quite. I was more concerned with getting the existing objects scaled correctly to the new DPI scale.
    Same here, but to do that reliably and without surprises, I'd seriously start with applying the suggested
    new Window-Size in the exact Pixel-dimensions the "inventor apparently considered useful on the new Screen".

    And before I apply that new size per SetWindowPos or MoveWindow, I'd store the old ClientAreas
    PixelDimensions in OldClientRect As Rect (retrieved by the GetClientRect-API, if not already available otherwise).

    Now we will receive a Form_Resize-Event in which we will call GetClientRect again, to retrieve the new
    Pixel-Dimensions, we have to work with now. And these new dx/dy dimensions are what we have to
    scale our Client-Controls to appropriately - it really is that simple - ScaleXFac can be derived by:
    ScaleXFac = NewClientRect.Right / OldClientRect.Right

    And ScaleYFac using the Bottom of the ClientRects appropriately - I don't see how any DPI-Values
    were needed so far - the Controls are properly resized - no ambiguity about ScaleFactors possible.

    Thinking out loud while laughing inside. Wonder how MS defines "most of its area"? What if, when you receive that message, you adjust the form's dimensions & offset it's left/top edge by 1/2 the difference in scaled size. Would then, the "most of its area" still be on the same monitor, or would you create an infinite loop?
    <g>
    And that's exactly why I would use the recommended new Window-size and take everything from there...

    Nevertheless, I think I'll also wait with any further exploration of that feature, until Win10 comes out...
    <shrug>

    Olaf

  12. #12

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Per-Monitor DPI Awareness & VB

    Quote Originally Posted by Schmidt
    I'd seriously start with applying the suggested
    new Window-Size in the exact Pixel-dimensions the "inventor apparently considered useful on the new Screen".
    When MS says "suggested", I shrug, because I translate that as "best guess"

    Quote Originally Posted by Schmidt View Post
    Nevertheless, I think I'll also wait with any further exploration of that feature, until Win10 comes out...
    <shrug>
    Olaf
    May be a good bet.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  13. #13
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,487

    Re: Per-Monitor DPI Awareness & VB

    Quote Originally Posted by LaVolpe View Post
    Just a follow up. If you were to use 192 DPI, that is exactly twice the DPI from 96. And 192 DPI equates to 7.5 TwipsPerPixel, using the formula: 1440 / 192 = 7.5, and complimentary, to determine DPI from TwipsPerPixel: 1440 / 7.5 = 192.

    Hmmm. I compiled an exe and manifested it so that it is DPI-Aware (not per-monitor at this point). I ran it and clicked a button that behind that button, it reported a couple of things: TwipsPerPixelX, calculated DPI based on 1440/TwipsPerPixel, and reported DPI from APIs.

    Does VB suffer from rounding when it comes to DPI and TwipsPerPixelX,Y, even though those values are held in Single vartypes? VB's TwipsPerPixel was 7, not 7.5. Using that calculation, this equates to a DPI of 205.7143 instead of 192. The API reported the DPI as 192.
    Maybe not so much rounding as truncation? Perhaps there is some integer arithmetic used when TwipsPerPixelX & Y are calculated when the runtime initializes?

    Have you tried to force a custom setting like 188% (i.e. 180 DPI)? That seems like it ought to bypass any rounding or truncation.

  14. #14

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Per-Monitor DPI Awareness & VB

    Quote Originally Posted by dilettante View Post
    Maybe not so much rounding as truncation? Perhaps there is some integer arithmetic used when TwipsPerPixelX & Y are calculated when the runtime initializes?

    Have you tried to force a custom setting like 188% (i.e. 180 DPI)? That seems like it ought to bypass any rounding or truncation.
    Didn't get around to trying non-standard DPIs. I was on Vista when I was playing and am not even sure it is an option. I did try to drop down to 72 DPI, but Vista just smiled and said "nice try" (in my mind anyway).

    Oh, what's really nice about applying that DPI-Aware manifest back in post #2.... Not only does the IDE show themed controls, but you get a WYSIWYG view of your app in whatever DPI you loaded IDE in.

    On a side note: With VB pics, you know we gotta kinda use ScaleX() to get himetric to pixel/twips as desired. At 192 DPI, ScaleX return value was incorrect (larger) and most likely due to the adjusted DPI. However, the himetric value itself was correct. Just FYI
    1) ScaleX(somePic.Picture.Width, vbHimetric, vbPixels) = slightly wrong result
    2) somePic.Picture.Width is correct and properly scaled by actual DPI, in this case was exactly 1/2 of 96 DPI value when project was in 192 DPI.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  15. #15
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,454

    Re: Per-Monitor DPI Awareness & VB

    Quote Originally Posted by LaVolpe View Post
    When MS says "suggested", I shrug, because I translate that as "best guess"
    If I'd be in the shoes of the responsible MS-devs who worked on the code, which is finally sending the
    rectangle in that Windows-Message, I'd have taken really good care about, that the new *ClientAreas*
    AspectRatio remained the same as before (no matter how large the new TopLevel-Window-Caption or
    the new Borders might then be rendered on the new screen).

    I'd think that stuff like that would come out in any "healthy discussion" - and I just can't
    imagine, that the MS-Devs didn't have one about that specific topic.

    But then there's murphy again or things like 'reality', standing in the way or trying to wreak havoc
    especially on 'oh so clever plans' ... (or just plain stupidity)

    Olaf

  16. #16

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Per-Monitor DPI Awareness & VB

    Sounds like you haven't had the opportunity to play and I don't have the resources to play, so we are making a lot of assumptions.

    I'm convinced (stupidly without any proof) that the rectangle you get from that message would be exactly 1/2 the size of the current rectangle when moving from 192 DPI to 96 DPI. If that's true, 50% scaling would not get us to actual 96 DPI when VB thinks it is at 192 DPI. Just gotta look at my screenshots I posted. That last sample screenshot when scaled 50% will be larger than if the app initially launched on a 96 DPI monitor
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  17. #17
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,487

    Re: Per-Monitor DPI Awareness & VB

    Quote Originally Posted by LaVolpe View Post
    Didn't get around to trying non-standard DPIs. I was on Vista when I was playing and am not even sure it is an option.
    I was looking at a Vista machine and "custom" accepts values in percents, and at least the 188% showed as 180 DPI in the dialog. I didn't go ahead with it because rebooting gets old really fast, so I'm not certain it would actually work.

    In any case it might not tell us anything useful. 200% still has to be dealt with.

  18. #18
    Fanatic Member
    Join Date
    Aug 2013
    Posts
    806

    Re: Per-Monitor DPI Awareness & VB

    Wow, tons of questions in this thread. I've got a high-DPI laptop with Windows 8.1 on it if anyone wants me to test specifics. Here are some answers I can provide without further testing:

    1) Why is per-monitor DPI important? My common use-case is high-DPI laptop attached to a projector or TV screen, typically for a PowerPoint presentation. Laptop is used to control the presentation, while the projector displays the actual presentation. 200% DPI is required to use the laptop comfortably (13" 2560x1600). But 200% DPI makes text enormous on a two-meter projector screen. So it's crucial to run the laptop at 200% and the attached projector at 100%.

    2) VB's internal Screen.Whatever measurements are always in reference to the primary monitor ONLY. Multiple monitors are never taken into account. I would consider the Screen object measurements always broken, unless you can guarantee single-monitor environments only.

    3) VB's internal Twips measurements are not reliable at 200% DPI, as LaVolpe discusses above. The expected 7.5 conversion is truncated to 7 (I think dilettante is correct and it's truncation, not rounding), and all of VB's "automatic DPI scaling" behavior is similarly off - not by a lot, but enough to generally be noticeable. For correct scaling, you will need to use the API to handle DPI calculations, window positioning, and measurements. (But you'll be doing this anyway if you want to cover per-monitor DPI awareness.)

    3.5) As an addendum to the comment above, the IDE will cause you grief on a 200% DPI monitor. If you attach a manifest to VB6.exe, be warned that VB's IDE is oddly not high-DPI aware, so toolbar buttons in particular are absolutely miniscule at 200% DPI, making it near impossible to work. You will want to do any high-DPI testing in your compiled .exe. I eventually gave up on a high-DPI manifest for vb6.exe as it was too unpleasant to work with mm-sized interface elements.

    4) VB handles negative screen coordinates just fine. You can test this on a single-monitor display by moving your windows off the top-left edge of the screen, and checking reported Top/Left measurements.

    5) When moving an application window from one monitor to another, the window maintains the DPI of the current monitor as long as 50+% of the window remains on the current screen. For two monitors with varying DPI, this will cause the window to be comically large or small on the "new" monitor. When 50+% of the window resides on the new monitor, the window is suddenly snapped to the new DPI, causing a sudden and dramatic resize if moving between say 100% and 200%. Windows automatically handles window positioning to ensure that 50% of the resized window remains on the new monitor, to prevent an infinite loop of resize -> change monitors -> resize -> change monitors etc.

    6) Applications that are NOT per-monitor DPI aware receive "false" DPI measurements when moved to a new monitor with different DPI. Basically, the behavior is identical to a non-DPI-aware application on a single monitor. Windows continues reporting the old screen measurements to the application, and the system applies its own rescaling using a StretchBlt-like function.

    7) Probably obvious, but per-monitor DPI awareness is useless in VB without manual handling, because even though VB is capable of doing some of its own DPI scaling, it (obviously) doesn't respond to the new WM_DPICHANGED message.

    8) If handling WM_DPICHANGED manually, I recommend respecting the suggested window RECT provided by lParam. Attempting to move the window to a rect of your own calculation might cause it to migrate to the neighboring monitor, triggering a new WM_DPICHANGED message, and entering a nasty loop. Also, using the supplied rect will allow your window to behave like other system windows that are per-monitor DPI aware. Note that for interface purposes, you can easily determine the client area of the new window rect using AdjustWindowRect with a negative sign (http://blogs.msdn.com/b/oldnewthing/.../10457292.aspx).

    9) Prior to Windows 8, DPI changes required login/logoff. So VB's internal scaling was a (mostly) acceptable solution, as you knew your program would be restarted between DPI changes, giving VB's internal DPI code a chance to do its thing. Windows 8 no longer makes this tenable, as your application can have its DPI changed while still running.

    10) If you provide standard "remember last window location" functionality, DPI is a big headache. You should probably store DPI settings to your INI or properties file between sessions, so you can detect if DPI has changed since the previous session. Otherwise, you will be restoring a faulty size and/or position, which may lead to your application lying off the screen or being too large/small to comfortably work with.

    I've done just enough work with the new DPI features to realize they're a massive headache in VB6. If anyone has specific things they want tested, throw together some code and I'll be happy to run it for you, though it may take me a few days to get around to it on account of the holidays.
    Check out PhotoDemon, a pro-grade photo editor written completely in VB6. (Full source available at GitHub.)

  19. #19

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Per-Monitor DPI Awareness & VB

    Tanner, great info. Thank you. Regarding your observations....

    2) VB's internal Screen.Whatever measurements are always in reference to the primary monitor ONLY. Multiple monitors are never taken into account. I would consider the Screen object measurements always broken, unless you can guarantee single-monitor environments only.
    Answers one of my questions. VB launches to primary monitor always. So primary DPI will be what VB uses (maybe adjusted a bit)

    3) VB's internal Twips measurements are not reliable at 200% DPI, as LaVolpe discusses above. ... For correct scaling, you will need to use the API to handle DPI calculations, window positioning, and measurements. (But you'll be doing this anyway if you want to cover per-monitor DPI awareness.)
    Maybe not if launching to the 200% DPI. VB will scale itself (mostly) if that is the primary monitor. Obviously, moving to any other scale requires manual scaling or choosing not to be per-monitor aware

    4) VB handles negative screen coordinates just fine. You can test this on a single-monitor display by moving your windows off the top-left edge of the screen, and checking reported Top/Left measurements.
    Negative coords are important for ppl to know for API usage where they need to retrieve/set packed coordinates from/to API parameters.

    I'm also curious how VB handles coordinates sent to the window if it's internally in a different DPI than the monitor. Did you test that too? If it's not per-monitor aware, then the system scaling the app would adjust as needed. But if the system is not scaling, then... ?

    7) Probably obvious, but per-monitor DPI awareness is useless in VB without manual handling, because even though VB is capable of doing some of its own DPI scaling, it (obviously) doesn't respond to the new WM_DPICHANGED message.
    Think it is even more of a headache. Wonder how menus are handled. We can't easily change the menu font's VB uses & honestly don't know if what VB uses scales well. With other add-ons that you add to your project from the toolbox or custom controls, they will probably not be per-monitor aware. Per-monitor awareness without manual scaling is not an option
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  20. #20
    Fanatic Member
    Join Date
    Aug 2013
    Posts
    806

    Re: Per-Monitor DPI Awareness & VB

    Happy to help!

    As an addendum, for coders interested in replacing Screen object measurements, this MSDN project provides a nice, gentle introduction to proper multimonitor handling:

    http://support.microsoft.com/kb/194578

    These days, multiple monitors are common enough that VB apps should really be using virtual desktop measurements instead of Screen object ones.

    I'm also curious how VB handles coordinates sent to the window if it's internally in a different DPI than the monitor. Did you test that too? If it's not per-monitor aware, then the system scaling the app would adjust as needed. But if the system is not scaling, then... ?
    I can check this in the coming days. (Holiday schedule may push it to next week, sorry!) Just to confirm that I'm testing it right:

    1) Create new project, add manifest with per-monitor DPI awareness specified.
    2) Compile app, run it, and move it to a new monitor with different DPI setting
    3) See how VB's internal coordinates are reported now that it's on a monitor that differs from the original DPI.

    I'll also double-check things like menu bar appearance on the new monitor, but it seems likely that all elements will remain at an identical pixel size on the new monitor, so a potentially nasty problem if moving between monitors with large DPI differences (as the menu may be very large/small relative to the window's new size).

    My personal feeling is that it's borderline insurmountable for a VB6 developer to handle per-monitor DPI well, unless the project is very small and simple with minimal UI elements.
    Check out PhotoDemon, a pro-grade photo editor written completely in VB6. (Full source available at GitHub.)

  21. #21
    Fanatic Member
    Join Date
    Aug 2013
    Posts
    806

    Re: Per-Monitor DPI Awareness & VB

    One more link for the interested. This MSDN page breaks down the new DPI stuff in Windows 8.1. There are actually quite a few new APIs and other features to examine:

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

    Two things I found particularly interesting from that link:

    Note that the non-client area of a per monitor–DPI aware application is not scaled by Windows, and will appear proportionately smaller on a high DPI display.
    In practice, other things can affect the desktop scaling factor, such as viewing distance or minimum required lines of vertical resolution. For example... the Surface Pro is 212 DPI but has a 150% default scaling factor. This is because its native resolution of 1920x1080 would shrink to a logical resolution of 960x640 if a 200% scaling factor were used. That resolution is below the minimum resolution of 1024x720, so the scaling factor steps down to the next lower plateau of 150%.
    The second quote applies to the OS's "automatic" DPI scaling feature, where it tries to guess the best DPI of a given screen when it's attached for the first time. If you're attempting to scale UI elements to certain real-world sizes based on the physical size of the display, it's helpful to know what Windows is doing to DPI measurements before it passes them to your app.

    Microsoft has never handled DPI settings well, and it has really come back to bite them in the modern era, where high-DPI support is crucial on modern hardware, but Windows has long used DPI as a "fake magnification tool" feature instead. Even their use of the term "DPI" is ridiculous considering that it bears little relation to the physical DPI of the hardware, but I guess we're stuck with it now.
    Check out PhotoDemon, a pro-grade photo editor written completely in VB6. (Full source available at GitHub.)

  22. #22
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,454

    Re: Per-Monitor DPI Awareness & VB

    Quote Originally Posted by Tanner_H View Post
    If anyone has specific things they want tested, throw together some code and I'll be happy to run it for you, though it may take me a few days to get around to it on account of the holidays.
    The only thing I'd be interested in currently is, wheter my assumption is correct,
    that the AspectRatio of the .Right and .Bottom members of the results of:
    - GetClientRect (before applying the suggested lParam-Rect to your moving Window)
    - GetClientRect (after applying the suggested lParam-Rect to your moving Window per SetWindowPos)
    ...remains the same - or if it's the AspectRatio of the "outer TopLevel-WindowDimensions".

    If you don't have any Subclassing-Code for WM_DPICHANGED already in place from your own testing,
    I could write and post a small example which attempts those measurements?

    Olaf

  23. #23

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Per-Monitor DPI Awareness & VB

    Quote Originally Posted by Tanner_H View Post
    I can check this in the coming days. (Holiday schedule may push it to next week, sorry!) Just to confirm that I'm testing it right:

    1) Create new project, add manifest with per-monitor DPI awareness specified.
    2) Compile app, run it, and move it to a new monitor with different DPI setting
    3) See how VB's internal coordinates are reported now that it's on a monitor that differs from the original DPI.
    Yepper. Curious that if mouse hovers over right/bottom edge of a picbox, for example, whether the reported X,Y coordinates in the MouseMove event are accurate if picbox scalemode is pixels or twips. Maybe a dual test? Add a button to test project and toggle picbox scalemode. While mouse moves, log to textbox/listbox what is received and what is expected?
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  24. #24
    Fanatic Member
    Join Date
    Aug 2013
    Posts
    806

    Re: Per-Monitor DPI Awareness & VB

    If you don't have any Subclassing-Code for WM_DPICHANGED already in place from your own testing,
    I could write and post a small example which attempts those measurements?
    No problem, I can take care of it. However, given Microsoft's explicit admission that the non-client area is *not* automatically scaled by the system when switching between displays with different DPI, I think we have a good indication of how the client rect will also be treated.
    Check out PhotoDemon, a pro-grade photo editor written completely in VB6. (Full source available at GitHub.)

  25. #25
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,454

    Re: Per-Monitor DPI Awareness & VB

    Quote Originally Posted by Tanner_H View Post
    No problem, I can take care of it. However, given Microsoft's explicit admission that the non-client area is *not* automatically scaled by the system when switching between displays with different DPI, I think we have a good indication of how the client rect will also be treated.
    Ah, you mean that the outer rectangle of the TopLevel-Window in question is not touched in its Pixel-
    Dimensions at all (in the "suggested lParam-Rect" I mean)? That would be good to know (or confirm).

    Thanks in advance...

    Olaf

  26. #26
    Fanatic Member
    Join Date
    Aug 2013
    Posts
    806

    Re: Per-Monitor DPI Awareness & VB

    Quote Originally Posted by LaVolpe View Post
    Yepper. Curious that if mouse hovers over right/bottom edge of a picbox, for example, whether the reported X,Y coordinates in the MouseMove event are accurate if picbox scalemode is pixels or twips. Maybe a dual test? Add a button to test project and toggle picbox scalemode. While mouse moves, log to textbox/listbox what is received and what is expected?
    Great idea, will do. I guess there are three possible outcomes:

    1) Pixel and Twips measurements are both wrong.
    2) Pixels are right, but Twips are wrong. IMO, this is most likely. My (arbitrary) guess is that VB manages internal measurements as pixels, like all other WAPI functions, and then translates into other ScaleModes as necessary, prior to reporting via properties or events.
    3) Pixel and Twips are both correct. A true holiday miracle! Hard to see how VB could pull this off, unless it calls GetDeviceCaps() every time it needs to convert between pixels and other measurements, and is thus capable of dynamically changing its conversion factor while the program is running. Seems unlikely due to the performance overhead involved. But I could be totally off on how VB handles coordinate calculations.
    Check out PhotoDemon, a pro-grade photo editor written completely in VB6. (Full source available at GitHub.)

  27. #27
    Fanatic Member
    Join Date
    Aug 2013
    Posts
    806

    Re: Per-Monitor DPI Awareness & VB

    Quote Originally Posted by Schmidt View Post
    Ah, you mean that the outer rectangle of the TopLevel-Window in question is not touched in its Pixel-
    Dimensions at all (in the "suggested lParam-Rect" I mean)? That would be good to know (or confirm).
    Well, the MSDN page is not entirely clear, but this is the exact quote (emphasis mine):

    Per monitor–DPI aware applications are a new class of applications in Windows 8.1. These applications dynamically scale up or down when a user changes the DPI or moves the application between monitors that have different DPIs. These applications always render crisply and at the correct size for a given display. DWM does not scale and virtualize this class of applications.

    Note that the non-client area of a per monitor–DPI aware application is not scaled by Windows, and will appear proportionately smaller on a high DPI display.
    Later on, when discussing WM_DPICHANGED, they say:

    Dynamically DPI–aware applications must first draw based on monitor DPI. Then they must respond to DPI changes. By listening for the WM_DPICHANGED notification, the application receives notification when a DPI change occurs. The application can query again for the monitor DPI. This notification fires when the user moves the application between monitors of different DPI and when the user changes the DPI in Control Panel. When this notification fires, a pointer to the suggested new window size and location is sent. The application should use these to avoid constantly rescaling between the two monitors while the user moves the application. If you do not want your application to use the suggested size, you can ignore the suggested size and location information.
    Testing will say for certain, but I take that to mean that Windows deliberately aims to keep the window rect consistent, to "avoid constantly rescaling between the two monitors while the user moves the application".
    Check out PhotoDemon, a pro-grade photo editor written completely in VB6. (Full source available at GitHub.)

  28. #28
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,487

    Re: Per-Monitor DPI Awareness & VB

    I got the impression that under the covers OLE tries to use integer HiMetric units for eveything except fonts where size is in Points represented in Currency format.

    The VB6 runtime probably uses IOleControlSite::TransformCoords and similar methods to gin up ScaleMode units for positions and dimensions. The IOleControlSite interface being implemented by Forms, UserControls, PictureBoxes, etc.

    No idea how this might play into the errors seen at 200 DPI settings, and of course it has no bearing on DPI-per-monitor issues.


    But if VB6 is such a mess at 200 DPI then I have to wonder how printing works at all. 200 DPI is common enough as are far higher settings from 600 to 1200 and up.

  29. #29

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Per-Monitor DPI Awareness & VB

    Quote Originally Posted by dilettante View Post
    ...But if VB6 is such a mess at 200 DPI then I have to wonder how printing works at all. 200 DPI is common enough as are far higher settings from 600 to 1200 and up.
    Fyi: Printer.TwipsPerPixelX is 2.4 on a 600 DPI printer
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  30. #30
    Fanatic Member
    Join Date
    Aug 2013
    Posts
    806

    Re: Per-Monitor DPI Awareness & VB

    Sorry for the long delay in testing this. I really didn't want to install Win 8 on my laptop (sigh), and between that and the holidays, time got away from me. Hopefully the wait didn't affect any critical projects.

    First, some notes on the testing setup, to help make sense of the weird screenshots. A 2560x1600 laptop (primary display) is on the right, at 200% DPI. It is connected to a 1920x1080 TV (secondary display) on the left, at 100% DPI.

    To give an example of how a per-monitor DPI aware application should work, here are two screenshots. (Sorry, the inline versions are useless, but below are links to the originals.) First image shows a normal Windows Explorer window, as seen on the 200% DPI monitor. Second image is after moving it to the 100% DPI monitor:

    Name:  Sample_System_Window_1.jpg
Views: 2673
Size:  11.5 KB

    Name:  Sample_System_Window_2.jpg
Views: 2616
Size:  9.5 KB

    Originals: first image, second image

    As you can see, everything in both the client and non-client region has been resized to account for the new DPI.

    Here is the same thing, but using a DPI-aware VB6 project. Upon receiving a WM_DPICHANGED message, the project resizes itself according to the WM_DPICHANGED lParam (which contains the suggested window size and position). No other special handling is applied:

    Name:  VB_Window_1.jpg
Views: 2721
Size:  10.2 KB

    Name:  VB_Window_2.jpg
Views: 2659
Size:  9.8 KB

    Originals: first image, second image

    Aside from the manual window resize, nothing - client or non-client - is automatically updated to match the new DPI. So everything appears 2x larger than it should.

    So no surprise here, but per-monitor DPI awareness will require you to manually redraw everything, including non-client regions. Unpleasant task.

    Next, to answer the question of "how do VB's internal pixels and twips measurements work, after moving the application to a monitor with different DPI?"

    Here is a screenshot of the test program, with some diagnostic info displayed. Everything should be self-explanatory, except maybe the "manually converted to pixels" numbers. To arrive at those measurements, I just used (VB's measurement in Twips) / (Screen.TwipsPerPixel). The underlying ScaleMode remained in Twips.

    Name:  Final_DPI_report.jpg
Views: 3782
Size:  41.6 KB

    Original: report image

    A few observations:

    1) As expected, the Screen object is not refreshed. It always reports TwipsPerPixel and Screen measurements of the primary display, only.

    2) Based on (1), it's not surprising to see that VB's Twips measurements still use the "7 twips per pixel" conversion from the primary display, despite being moved to a "15 twips per pixel" monitor.

    3) This one was a bit surprising to me, but VB's pixel measurements remain accurate, even after the monitor switch! VB must internally manage everything in pixels (no surprise there, since all APIs and window messages are passing pixels). When a Twips measurement is requested, VB just multiplies the internal pixel measurement by the cached Twips multiplier.

    From this, it seems that manual Twips to Pixel conversions will still work on a per-monitor DPI situation. Just note that Twips are definitely not reliable as a "DPI-agnostic" measurement under these conditions. (But no one but dilettante advocates using Twips in the modern era, anyway - right?? )

    Finally, I'm not sure why the (7.5 != 7) TwipsPerPixel issue is not problematic here. Despite the Screen object incorrectly reporting 7 TwipsPerPixel instead of 7.5, all pixel measurements come out correct. Any insight on this?

    I've apparently exceed my attachment quota for a single post, so here's an off-site link to the test project. It contains source code only (no exe), and obviously Win 8 is required for any of the per-monitor stuff to work: DPI_testing.zip
    Check out PhotoDemon, a pro-grade photo editor written completely in VB6. (Full source available at GitHub.)

  31. #31

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Per-Monitor DPI Awareness & VB

    Tanner, thank you for the follow up. I'll take some time this weekend to digest what you've added along with the previous posts in this thread.

    But the gist of the problem sounds like: if you can't dictate how VB controls draw themselves (or any 3rd party controls), then avoid marking your app as per-monitor aware. What good is it if you can have your custom stuff be aware while the rest of the objects are not? Maybe the solution is to just cave in & make your custom code per-monitor unaware and deal with up/down virtualized scaling.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  32. #32
    Fanatic Member
    Join Date
    Aug 2013
    Posts
    806

    Re: Per-Monitor DPI Awareness & VB

    You're welcome. Thanks for kicking off this topic. It's nice to finally have some clarity.

    Quote Originally Posted by LaVolpe View Post
    But the gist of the problem sounds like: if you can't dictate how VB controls draw themselves (or any 3rd party controls), then avoid marking your app as per-monitor aware. What good is it if you can have your custom stuff be aware while the rest of the objects are not? Maybe the solution is to just cave in & make your custom code per-monitor unaware and deal with up/down virtualized scaling.
    Yep, that's the take-home message, I think. If you have control over every visual aspect of your program (including non-client rendering), then per-monitor DPI is feasible. A lot of work, but feasible. Doubt that applies to many coders.

    This has mostly been about per-monitor DPI, but it's worth mentioning that the whole notion of "run-time DPI changes without logging out" is not workable in the average VB project, since it's the same problem - you can subclass and detect the DPI change, but there's no way to tell VB to resize everything per the new DPI.
    Check out PhotoDemon, a pro-grade photo editor written completely in VB6. (Full source available at GitHub.)

  33. #33
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,487

    Re: Per-Monitor DPI Awareness & VB

    A few more small bits of info at Implementing per-monitor DPI awareness (3rd party blog post). The meat is in the information beginning at the subheading The global DPI setting and through the end of the post.

  34. #34

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Per-Monitor DPI Awareness & VB

    Thank you guys for providing valuable info, ideas, & links. Think this thread may be helpful for VBers when this thread comes up in related searches. I'll consider this closed.

    FYI: I originally started this thread because I wanted to make a graphical control per-monitor DPI aware via a user-defined DPI setting (i.e., WM_DPIChanged). Though it is 100% doable for my control, not really worth implementing. I may decide to leave the logic in should the user actually draw their entire form.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  35. #35
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    6,192

    Re: [RESOLVED] Per-Monitor DPI Awareness & VB

    Has anyone noticed that in 200% DPI one cannot actually position user controls (esp. VB6 created UCs) because of the wrong `TwipsPerPixelX`/`TwipsPerPixelY` calculation? When one `.Move`s a child control its size in the container becomes smaller in pixels.

    A workaround I found out is that after resize one can `.Move` a control without specifying `Width`/`Height` params, in which case the run-time retrieves actual sizes from the user control and its size in the container becomes correct in pixels.

    Just FYI as a workaround.

    cheers,
    </wqw>

  36. #36

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [RESOLVED] Per-Monitor DPI Awareness & VB

    Just a follow-up. High DPI can really mess up any values you store as twips.

    Some quick formulas to recap... TPP = TwipsPerPixel
    1. realTPP = 1440 / DPI
    2. vbTPP = Int(1440 / DPI) = Screen.TwipsPerPixel
    3. Pixels = Twips / TPP
    4. Twips = Pixels * TPP
    5. vbDPI = 1440 / Screen.TwipsPerPixel
    6. realDPI = retrieved via APIs

    Ok, let's say you are storing a 320 pixel value as twips when your app is in a 96 DPI environment:
    realTPP = vbTPP = 1440 / 96 = 15. So 320 pixels = 4800 twips (320 * 15)

    Now, let's say your app is being run in a 192 DPI environment. You stored your measurement in twips thinking you can easily convert to pixels with: 4800 / Screen.TwipsPerPixel. And theoretically that should work if VB did not truncate Screen.TwipsPerPixel. The realTPP would be 7.5 = 1440 / 192. But Screen.TwipsPerPixel reports 7 not 7.5. Now your 4800 twips equates to 685.714 vs. the expected 640: 320 * 2 since DPI has doubled now.

    Recommendations: For both solutions, you will need to retrieve the real DPI

    a) Store values in pixels and also store the realTPP value. Then scale the cached pixel value when you read it. Using 4800 twips example if stored as 320 pixels & 15 TPP. When in a 192 DPI environment: newPixel value = 320 * storedTPP / realTPP = (320 * 15 / 7.5) = 640

    b) Avoid storing measurements in twips if you are going to use VB's Screen.TwipsPerPixel for scaling or if using VB's ScaleX/ScaleY functions. If you wish to continue to use those for scaling, this can negate the incorrect TPP VB reports when realTPP is fractional:

    1. Adjust your stored twips when you read them, using this formula. twipValue = [cached value] / realTPP * vbTPP
    In the case of 4800 twips, that value would change to 4480: 4800 / 7.5 * 7 = 4480. Then ScaleX/ScaleY would return the correct pixel value for the adjusted twip value: 4480 / 7 = 640 = doubled value for doubled DPI

    2. When writing twips, suggest using this formula vs. blindly writing whatever ScaleX/ScaleY gives you: [cached value] = [twip value] * realTPP / vbTPP

    Edited: Above only applies if your app is DPI aware. Why not if not DPI Aware? Because your app is likely to run only in 96 or 120 DPI. In both those DPIs, realTpp = vbTPP & no hacks needed. In any other DPI, your app will enter DPI virtualization and internally, it will be running at 96 DPI.
    Last edited by LaVolpe; Aug 16th, 2015 at 08:50 AM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  37. #37
    Addicted Member
    Join Date
    Jul 2006
    Posts
    159

    Re: [RESOLVED] Per-Monitor DPI Awareness & VB

    Just thought I'd add my tuppence worth as I'm well through converting to per monitor...

    Instead of subclassing & looking for a WM_DPIChanged you can do a nicer job using a timer that checks to see if the top left corner of the form has changed monitors. It also checks whether the left mouse button is down. If it is on a monitor with a different scale, it re-sizes, but not until the user releases the mouse. This is much nicer than having it resize half way between monitors!

  38. #38

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [RESOLVED] Per-Monitor DPI Awareness & VB

    John, what if the top/left didn't change monitors, but a vast majority of the form is now on a different DPI/monitor once the button was released? Trying to visualize the scenario you described, sounds like it would be a nicer overall solution if WM_DPIChanged occurred while dragging while the mouse was down (don't know if that's the case).

    On a side note. I'm struggling trying to make a usercontrol (UC) DPI aware (not necessarily per-monitor aware at this point). An off & on project. Discovered more inconsistencies with VB and usercontrols. For example, a 3000 twip, 200 pixel control at 96 DPI has the following measurements when loaded @ 192 DPI, 200%:

    - From outside the control via the form's property sheet: 3000 twips & 428.571 pixels.
    Twips are correct, but pixels are being reported as twips / 7 vs. 7.5. No serious issue there, other than it doesn't sync with the UC

    - From inside the UC. ScaleWidth property is in pixels and the Width property is always twips. These are reported: 428 pixels and 2996 twips. Ugh. It appears VB is taking the original Twips / 7 and truncating it, which returns as 428 for the ScaleWidth (pixel size). Then the Twips value is result of 428 * 7.

    - And here's the kicker @ 192 DPI, but just 90% confident VB is doing it vs. some of my code & will have verify sometime soon. You'd think UserControl.Width - Screen.TwipsPerPixelX would result in a 7 twip reduction, but no, that'd be too consistent.

    Edited: Follow-up. Just wanted to verify that last statement & it is pretty sad.
    In 192 DPI, 7 TPP, and 2996 twips for width & height, I called UserControl.Size Width + Screen.TwipsPerPixelX*2, Height + TwipsPerPixelY*2 expecting 3010 twips (size + 14). When the UserControl.Resize event triggered. Got something out of the twilight zone instead: The UC resized to 2807 and that's not an increase, but a decrease of 203 pixels from 3010. And since we appear to be in bizzaro world, from outside the UC, the form shows the UC as 3010!
    Last edited by LaVolpe; Aug 16th, 2015 at 10:57 AM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  39. #39
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,487

    Re: [RESOLVED] Per-Monitor DPI Awareness & VB

    Each time VB high DPI scaling errors in ScaleX, ScaleY, and friends comes up I walk away and then smack my head again. Surely this isn't new and has been encountered and somehow dealt with long ago with printers, where high DPI values have been common for a very long time?

    Aside from the multi-monitor thing none of this should be new... should it? Or did we all just ignore it for printed output?

  40. #40

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [RESOLVED] Per-Monitor DPI Awareness & VB

    FYI, printers appear to be handled differently. In post #29, a 600 DPI printer returned a non-truncated TwipsPerPixel
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

Page 1 of 2 12 LastLast

Posting Permissions

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



Click Here to Expand Forum to Full Width