Win 10 Excel 2016 Unexplained PixelsToPoints coefficient to position UserForm

浪子不回头ぞ 提交于 2019-12-11 05:07:34

问题


Preambule

When trying to position a UserForm at a particular Pixel position (stored in a POINTAPI Type structure), one must convert the Pixel coordinates to Point coordinates to be able to set the UserForm.Left and UserForm.Top VBA properties. Let's call this coefficient K.

From my tests, I came to understand that in my case, GetWindowRect and the VBA positioning properties of a UserForm (Left, Top, Width, Height) includes the shadows around the window (of class "ThunderDFrame") containing the MSForm UserForm control. To really get the rectangle of the window delimited by the borders, DwnGetWindowAttribute(hWnd, DWMWA_EXTENDED_FRAME_BOUNDS, rcOutRECT, LenB(rcOutRECT) Win API must be used.

The origin of the coordinate system to position a UserForm is pixel (0; 0), so no need to worry about ActiveWindow.PointsToScreenPixelsX / ActiveWindow.PointsToScreenPixelsY and the offset between the top left corner of the Excel window and the top left corner of the worksheet grid (at least not until Range.Left, Range.Top, etc. properties come into play). However, it is interesting to note that ActiveWindow.PointsToScreenPixelsX does not behave like ActiveWindow.ActivePane.PointsToScreenPixelsX. The first one works with pixels has input, not points, as the second does. The real name of the method should rather be ActiveWindow.WorksheetPixelsXToScreenPixelsX. You can verify it easily:

ActiveWindow.PointsToScreenPixelsX(1) - ActiveWindow.PointsToScreenPixelsX(0)

returns 1, while if it was really doing a convertion it should return something greater than 1 since 1 Point occupy several Pixels on screen. (not really 1/K either because of integer rounding of pixels)

Problem

Considering the zoom factor is 1 to simplify my MCV Example, the coefficients to determine the .Left and .Top properties in Points of the UserForm from the (x; y) position in Screen Pixels at which we want it displayed should be :

72 / GetDeviceCaps(GetDC(0), LOGPIXELSX)
72 / GetDeviceCaps(GetDC(0), LOGPIXELSY)

which is

  • 0.75 for a 96 DPI legacy display (I have tried it with a PC using Win 7 + Excel 2007
  • 0.375 with my Surface Pro 4 tablet running on Win 10 64-bit with Excel 2016 32-bit

Now the problem is that on my tablet, while the above calculation returns 0.375, the correct coefficient to position a UserForm at a given Pixel position (obtained from GetCursorPos Win API for example) by converting it to the corresponding Point position is 0.35. I have no idea where that value comes from...???

Current progress

On the tablet:

reg key HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics\AppliedDPI indicates 192 and 72 / 192 = 0.375

I have also tried some function from the High DPI Reference in MSDN's Windows Destop App UI Reference:

  • GetDPIForWindow (I tried with Application.Hwnd and UserForm's window handle)
  • GetDPIForMonitor

but everything rightfully returns 192.

The Minimal, Complete and Verifiable Example

The following allows me to retrieve the mysterious K = 0.35 coefficient on my tablet, but returns 0.75 on the other computer, as expected.

Module1.bas

Private Declare Function GetWindowRect Lib "user32" (ByVal hWnd As Long, rcWindowRect As RECT) As Long
Private Declare Function GetCursorPos Lib "user32" (ptCursorPoint As POINTAPI) As Long

Private Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

Private Type POINTAPI
    X As Long
    Y As Long
End Type

Sub test()
    Dim rcUsfWindowRect As RECT
    UserForm1.Show vbModeless
    lRet& = GetWindowRect(UserForm1.hWnd, rcUsfWindowRect)
    dblUsfRectWidth# = rcUsfWindowRect.Right - rcUsfWindowRect.Left
    dblUsfRectHeight# = rcUsfWindowRect.Bottom - rcUsfWindowRect.Top
    Debug.Print UserForm1.Width / dblUsfRectWidth
End Sub

UserForm1

Private Declare Function FindWindowA Lib "user32" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Public hWnd As Long

Private Sub UserForm_Initialize()
    hWnd = FindWindowA("ThunderDFrame", UserForm1.Caption)
End Sub

来源:https://stackoverflow.com/questions/50742182/win-10-excel-2016-unexplained-pixelstopoints-coefficient-to-position-userform

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!