News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Dialog units vs. screen units

Started by NoCforMe, April 19, 2025, 09:08:02 AM

Previous topic - Next topic

NoCforMe

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.

You cannot view this attachment.

Just to be clear:
  • The first set of #s is the dialog units for the control, hard-coded
  • The second set of #s is the return from MapDialogRect()
  • The 3rd set of #s is the return from GetWindowRect() for the control
    (adjusted so I'm getting the actual W/H, by subtracting .left from .right and .top from .bottom)

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.

??????????
Assembly language programming should be fun. That's why I do it.

zedd151

 :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.

sinsi


NoCforMe

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.
Assembly language programming should be fun. That's why I do it.

NoCforMe

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
Assembly language programming should be fun. That's why I do it.

zedd151

What sez Microsoft about MapDialogRect???
Are you supposed to 'invoke GetDialogBaseUnits...'?

NoCforMe

MapDialogRect()
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.
Assembly language programming should be fun. That's why I do it.

NoCforMe

One thing: I might oughta try displaying those sizes somewhere else besides the WM_INITDIALOG handler. Maybe those sizes are somehow pre-adjustment???
Assembly language programming should be fun. That's why I do it.

NoCforMe

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.
Assembly language programming should be fun. That's why I do it.

sinsi

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.

zedd151

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!

NoCforMe

So Zedd, how did you get those numbers?
Assembly language programming should be fun. That's why I do it.

zedd151

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.

479x442!!

Results from conversion + GetWindowRect



Client area is 477, 410!!!

NoCforMe

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:

You cannot view this attachment.

So MapDialogRect() is the right thing to use. (And it should work on child controls as well as the dialog itself.)
Assembly language programming should be fun. That's why I do it.

zedd151

#14
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: