The MASM Forum

General => The Workshop => Windows API => Topic started by: NoCforMe on April 19, 2025, 09:08:02 AM

Title: Dialog units vs. screen units
Post by: NoCforMe on April 19, 2025, 09:08:02 AM
I made a li'l testbed to test how MapDialogRect() works when converting dialog units to screen units.

(For those who are just tuning in, when you create a Windows dialog, the units used--both locations and sizes (width/height) of things are given in dialog units, which are different from screen units, which are pixel dimensions on the actual display.)

I created 3 edit controls of different widths. I used MapDialogRect() to convert each control's dimensions in dialog units to screen units and displayed it.

Then I got each edit control's actual size, using GetWindowRect() and displayed it.

I do not understand the results at all.

DlgSizingTest.jpg

Just to be clear:

Of course, it is possible I made a mistake somewhere, but I don't think so.
Why is the displayed actual size (the last set of #s) almost the same as the dimensions in dialog units (-1 on both W & H)?
This makes no sense to me.

I double-checked using WinSpy to get the actual dimensions of all the edit controls, and they match my results exactly.

??????????
Title: Re: Dialog units vs. screen units
Post by: zedd151 on April 19, 2025, 09:16:03 AM
 :biggrin:
I'll take a look in a few, when I'm back inside. Wait no attachment??
Glad you started the "heavy lifting", I was going to do something similar tomorrow.  :joking:

Just to be clear, is that created with your dialog proggy?

Have you tested a dialog box created with ResEd?

MapDialogRect appears to return dialog units -1, not pixel based coordinates.
Title: Re: Dialog units vs. screen units
Post by: sinsi on April 19, 2025, 09:19:04 AM
How about some code?
Title: Re: Dialog units vs. screen units
Post by: NoCforMe on April 19, 2025, 09:19:18 AM
Quote from: zedd151 on April 19, 2025, 09:16:03 AMJust to be clear, is that created with your dialog proggy?
Yepper.
QuoteHave you tested a dialog box created with ResEd?
No, and it wouldn't make any difference. A dialog is a dialog.
You can go ahead and try it if you like.
Title: Re: Dialog units vs. screen units
Post by: NoCforMe on April 19, 2025, 09:21:39 AM
Quote from: sinsi on April 19, 2025, 09:19:04 AMHow about some code?

Sure. This is all in the dialog's WM_INITDIALOG handler:
SizeFmt LABEL BYTE
DB "Edit #%u: Dialog units: %u X %u   screen units: %u X %u", $CRLF
DB $tab, "actual RECT: %u X %u", $CRLF, $CRLF, 0

LOCAL bufferOffset:DWORD, gpRect1:RECT, gpRect2:RECT, buffer[512]:BYTE

;=====================================
; Dialog initialization
;=====================================
do_init:

; Center dialog on desktop:
CALL GetDesktopWindow
INVOKE CenterDialog, EAX, hWin
INVOKE SetWindowPos, hWin, HWND_TOP, EAX, EDX, 0, 0, SWP_NOSIZE

INVOKE GetDlgItem, hWin, $edit1
MOV EDX, EAX
INVOKE GetWindowRect, EDX, ADDR gpRect2
MOV gpRect1.left, 0
MOV gpRect1.right, 50
MOV gpRect1.top, 0
MOV gpRect1.bottom, 20
INVOKE MapDialogRect, hWin, ADDR gpRect1

; Make sure RECTs give W & H in .right & .bottom elements:
MOV EAX, gpRect1.left
SUB gpRect1.right, EAX
MOV EAX, gpRect1.top
SUB gpRect1.bottom, EAX
MOV EAX, gpRect2.left
SUB gpRect2.right, EAX
MOV EAX, gpRect2.top
SUB gpRect2.bottom, EAX

INVOKE wsprintf, ADDR buffer, OFFSET SizeFmt,
1, 50, 20, gpRect1.right, gpRect1.bottom, gpRect2.right, gpRect2.bottom
MOV bufferOffset, EAX

INVOKE GetDlgItem, hWin, $edit2
MOV EDX, EAX
INVOKE GetWindowRect, EDX, ADDR gpRect2
MOV gpRect1.left, 0
MOV gpRect1.right, 75
MOV gpRect1.top, 0
MOV gpRect1.bottom, 20
INVOKE MapDialogRect, hWin, ADDR gpRect1

MOV EAX, gpRect1.left
SUB gpRect1.right, EAX
MOV EAX, gpRect1.top
SUB gpRect1.bottom, EAX
MOV EAX, gpRect2.left
SUB gpRect2.right, EAX
MOV EAX, gpRect2.top
SUB gpRect2.bottom, EAX

LEA EAX, buffer
ADD EAX, bufferOffset
INVOKE wsprintf, EAX, OFFSET SizeFmt,
2, 75, 20, gpRect1.right, gpRect1.bottom, gpRect2.right, gpRect2.bottom
ADD bufferOffset, EAX

INVOKE GetDlgItem, hWin, $edit3
MOV EDX, EAX
INVOKE GetWindowRect, EDX, ADDR gpRect2
MOV gpRect1.left, 0
MOV gpRect1.right, 125
MOV gpRect1.top, 0
MOV gpRect1.bottom, 20
INVOKE MapDialogRect, hWin, ADDR gpRect1

MOV EAX, gpRect1.left
SUB gpRect1.right, EAX
MOV EAX, gpRect1.top
SUB gpRect1.bottom, EAX
MOV EAX, gpRect2.left
SUB gpRect2.right, EAX
MOV EAX, gpRect2.top
SUB gpRect2.bottom, EAX

LEA EAX, buffer
ADD EAX, bufferOffset
INVOKE wsprintf, EAX, OFFSET SizeFmt,
3, 125, 20, gpRect1.right, gpRect1.bottom, gpRect2.right, gpRect2.bottom
ADD bufferOffset, EAX
INVOKE SetDlgItemText, hWin, $resultsSt, ADDR buffer

JMP zero_exit
Title: Re: Dialog units vs. screen units
Post by: zedd151 on April 19, 2025, 09:23:06 AM
What sez Microsoft about MapDialogRect???
Are you supposed to 'invoke GetDialogBaseUnits...'?
Title: Re: Dialog units vs. screen units
Post by: NoCforMe on April 19, 2025, 09:26:32 AM
MapDialogRect() (https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mapdialogrect?redirectedfrom=MSDN)
QuoteConverts the specified dialog box units to screen units (pixels). The function replaces the coordinates in the specified RECT structure with the converted coordinates, which allows the structure to be used to create a dialog box or position a control within a dialog box.

QuoteThe MapDialogRect function assumes that the initial coordinates in the RECT structure represent dialog box units. To convert these coordinates from dialog box units to pixels, the function retrieves the current horizontal and vertical base units for the dialog box, then applies the following formulas:

left   = MulDiv(left,   baseunitX, 4);
right  = MulDiv(right,  baseunitX, 4);
top    = MulDiv(top,    baseunitY, 8);
bottom = MulDiv(bottom, baseunitY, 8);
If the dialog box template has the DS_SETFONT or DS_SHELLFONT style, the base units are the average width and height, in pixels, of the characters in the font specified by the template.
Title: Re: Dialog units vs. screen units
Post by: NoCforMe on April 19, 2025, 09:29:46 AM
One thing: I might oughta try displaying those sizes somewhere else besides the WM_INITDIALOG handler. Maybe those sizes are somehow pre-adjustment???
Title: Re: Dialog units vs. screen units
Post by: NoCforMe on April 19, 2025, 09:32:39 AM
Quote from: zedd151 on April 19, 2025, 09:23:06 AMAre you supposed to 'invoke GetDialogBaseUnits...'?
No. In fact, in the documentation for that function they say
QuoteFor either type of dialog box, it is easier to use the MapDialogRect function to perform the conversion. MapDialogRect takes the font into account and correctly converts a rectangle from dialog template units into pixels.
Title: Re: Dialog units vs. screen units
Post by: sinsi on April 19, 2025, 09:44:58 AM
I think that MapDialogRect only works on the dialog, not child controls, so Windows is using the RECT as the dialog size.
What happens if you pass the dialog rect? Then WinSpy should give the dialog size in pixels that match the rect.
Title: Re: Dialog units vs. screen units
Post by: zedd151 on April 19, 2025, 09:57:13 AM
dialog box only
x 0
y 0
width  318 dialog units
height 252 dialog units

after conversion
x 0
y 0
width  477 pixels
height 410 pixels

actual size
x 0
y 0
width  479 pixels
height 442 pixels

So much for an easy, accurate conversion. Thanks, Microsoft!  :thumbsup:  You've done it again. My Hero!
Title: Re: Dialog units vs. screen units
Post by: NoCforMe on April 19, 2025, 10:07:33 AM
So Zedd, how did you get those numbers?
Title: Re: Dialog units vs. screen units
Post by: zedd151 on April 19, 2025, 10:12:56 AM
Quote from: NoCforMe on April 19, 2025, 10:07:33 AMSo Zedd, how did you get those numbers?
from rsrc.rc
100 DIALOGEX 0,0,318,252

Actual size from taking a screen capture and physically measuring the height and width.
(https://i.postimg.cc/pXcdM0dx/dialog.png)
479x442!!

Results from conversion + GetWindowRect
(https://i.postimg.cc/CK3BTcmd/untitled.png)


Client area is 477, 410!!!
Title: Re: Dialog units vs. screen units
Post by: NoCforMe on April 19, 2025, 10:14:49 AM
OK, totally my bad.
I was using the wrong numbers for the dialog size.
I forgot that my program, DialogGen, converts the actual dialog size to dialog units (in the include file).
Once I plugged the right numbers in, everything looks fine:

DlgSizingTest.jpg

So MapDialogRect() is the right thing to use. (And it should work on child controls as well as the dialog itself.)
Title: Re: Dialog units vs. screen units
Post by: zedd151 on April 19, 2025, 10:24:38 AM
Quote from: NoCforMe on April 19, 2025, 10:14:49 AMOK, totally my bad.
I was using the wrong numbers for the dialog size.
After conversion, the RECT structure is apparently filled with the client area dimensions not the dimensions of the entire dialog box. (Which is why left and top were always zero). See my post above.
Mystery solved, at least for me.  :smiley:

As a test, along with calling MapDialogRect, I'll try GetClientRect with the handle of the dialog box. If my assumptions are correct, the results should be identical... I'll test that when I'm back at my computer...  :biggrin:
Title: Re: Dialog units vs. screen units
Post by: zedd151 on April 19, 2025, 03:23:09 PM
Quote from: zedd151 on April 19, 2025, 10:24:38 AMAs a test, along with calling MapDialogRect, I'll try GetClientRect with the handle of the dialog box. If my assumptions are correct, the results should be identical... I'll test that when I'm back at my computer...  :biggrin:
Sorry for the delay.

The top entries are after calling MapDialogRect to do the conversion.
left
top
right
bottom
(https://i.postimg.cc/1X9Gny2L/untitled.png)

:biggrin:  :biggrin:  :biggrin:

Well it does actually do a conversion, but calling GetClientRect gives the same exact results.
Make of it what you will.  :cool:

Actually I was expecting MapDialogRect to return the screen coordinates of the entire dialog box, its position on the screen and by extension, its size in the left,top,right,bottom members of the structure.  :biggrin:
Title: Re: Dialog units vs. screen units
Post by: NoCforMe on April 20, 2025, 03:56:12 AM
Quote from: zedd151 on April 19, 2025, 03:23:09 PMWell it does actually do a conversion, but calling GetClientRect gives the same exact results.
Make of it what you will.  :cool:
Well, Larry, that's the whole point.
The conversion takes dialog units and gives you screen units.
GetClientRect( just confirms this by giving you those same screen units, which shows that the whole thing worked correctly.
Title: Re: Dialog units vs. screen units
Post by: zedd151 on April 20, 2025, 05:45:17 AM
Quote from: NoCforMe on April 20, 2025, 03:56:12 AMWell, Larry, that's the whole point.
The conversion takes dialog units and gives you screen units.
GetClientRect( just confirms this by giving you those same screen units, which shows that the whole thing worked correctly.

Quote from: zedd151 on April 19, 2025, 03:23:09 PMActually I was expecting MapDialogRect to return the screen coordinates of the entire dialog box, its position on the screen and by extension, its size in the left,top,right,bottom members of the structure.  :biggrin:
I was not expecting the client RECT.  :biggrin:  but the Window RECT
Title: Re: Dialog units vs. screen units
Post by: NoCforMe on April 20, 2025, 05:54:07 AM
Well, keep in mind that GetClientRect() returns the approximately the same dimensions (width & height) as GetWindowRect(), but with the .top and .left elements set to zero. (Obviously GetWindowRect() includes the window's non-client areas as well, like the border, menu bar, etc.)

GetWindowRect() gives you the location of the window in relation to the "real world" (i.e., the desktop), while GetClientRect() just gives you the size of the client area with no location information.
Title: Re: Dialog units vs. screen units
Post by: zedd151 on April 20, 2025, 05:58:48 AM
Quote from: NoCforMe on April 20, 2025, 05:54:07 AMGetWindowRect() gives you the location of the window in relation to the "real world" (i.e., the desktop)...

For some reason that is what I originally thought that MapDialogRect was supposed to do. I don't remember reading anywhere that it fills in the RECT structure with the client area... if it is the MS docs, I had missed it.
Title: Re: Dialog units vs. screen units
Post by: NoCforMe on April 20, 2025, 06:08:07 AM
Quote from: zedd151 on April 20, 2025, 05:58:48 AM
Quote from: NoCforMe on April 20, 2025, 05:54:07 AMGetWindowRect() gives you the location of the window in relation to the "real world" (i.e., the desktop)...

For some reason that is what I originally thought that MapDialogRect was supposed to do. I don't remember reading anywhere that it fills in the RECT structure with the client area... if it is the MS docs, I had missed it.
It doesn't do that.
All it does is convert the dialog's coordinates in dialog units to screen units. These can give you the size[1] of the dialog by subtracting .top from .bottom and .left from .right.

QuoteConverts the specified dialog box units to screen units (pixels). The function replaces the coordinates in the specified RECT structure with the converted coordinates, which allows the structure to be used to create a dialog box or position a control within a dialog box.

[1] Which I assume is the window size, not the client size.
Title: Re: Dialog units vs. screen units
Post by: zedd151 on April 20, 2025, 06:11:19 AM
Quote from: NoCforMe on April 20, 2025, 06:08:07 AM[1] Which I assume is the window size, not the client size.
Exactly - Sounds ambiguous.
Title: Re: Dialog units vs. screen units
Post by: NoCforMe on April 20, 2025, 06:15:31 AM
Quote from: zedd151 on April 20, 2025, 06:11:19 AM
Quote from: NoCforMe on April 20, 2025, 06:08:07 AM[1] Which I assume is the window size, not the client size.
Exactly - Sounds ambiguous.
Easy enough to find out which it is--just use WinSpy.
Title: Re: Dialog units vs. screen units
Post by: zedd151 on April 20, 2025, 06:22:22 AM
Quote from: NoCforMe on April 20, 2025, 06:15:31 AM
Quote from: zedd151 on April 20, 2025, 06:11:19 AM
Quote from: NoCforMe on April 20, 2025, 06:08:07 AM[1] Which I assume is the window size, not the client size.
Exactly - Sounds ambiguous.
Easy enough to find out which it is--just use WinSpy.

No need. I have run my tests.

Why RECT structures anyway? (Rhetorical question) Some functions need x,y,width,height. Which to me is more immediately useful information. Why not a structure for x, y, width, height instead? (Another Rhetorical question btw, no reply needed)

Using a RECT, you'd have to fiddle  :eusa_boohoo:  around to get the width and height. I guess it's pronounced "wrecked" for a reason.  :joking:
Title: Re: Dialog units vs. screen units
Post by: NoCforMe on April 20, 2025, 06:56:58 AM
I think the RECT structure fit the purposes of most of those early Windows functions the best.
(In other words, Micro$oft's programmers weren't stupid.)