The MASM Forum

General => The Campus => Topic started by: Ar0n on August 10, 2015, 04:55:57 PM

Title: Problems with MapWindowPoints
Post by: Ar0n on August 10, 2015, 04:55:57 PM
Hello guys, I'm trying to center a child window horizontrally using SetWindowPos, however, SetWindowPos takes as input X and Y so I need to get the Y value (vertical), I use MapWindowPoints for that, but it looks like this is not working... also, my textbox simply disappears! help please!

include \masm32\include\masm32rt.inc
.686

WinMain proto :HWND,:UINT,:WPARAM,:LPARAM

.const
   ClassName db "MainWinClass",0
   AppName  db "Main Window",0
   
   cedit db "edit",0
   
.data?
   hInstance HINSTANCE ?
   CommandLine LPSTR ?
   hedit HWND ?
.code
start:
   invoke GetModuleHandle, NULL
   mov    hInstance,eax
   invoke GetCommandLine
   mov    CommandLine,eax
   invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
   invoke ExitProcess,eax

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
   LOCAL wc:WNDCLASSEX
   LOCAL msg:MSG
   
   mov   wc.cbSize,SIZEOF WNDCLASSEX
   mov   wc.style, CS_HREDRAW or CS_VREDRAW
   mov   wc.lpfnWndProc, OFFSET WndProc
   mov   wc.cbClsExtra,NULL
   mov   wc.cbWndExtra,NULL
   mrm   wc.hInstance,hInstance
   mov   wc.hbrBackground,COLOR_BTNFACE+1
   mov   wc.lpszMenuName,NULL
   mov   wc.lpszClassName,OFFSET ClassName
   
   invoke LoadIcon,NULL,IDI_APPLICATION
   mov   wc.hIcon,eax
   mov   wc.hIconSm,eax
   
   invoke LoadCursor,NULL,IDC_ARROW
   mov   wc.hCursor,eax
   

   invoke RegisterClassEx, addr wc
   INVOKE CreateWindowEx,0,ADDR ClassName,ADDR AppName,\
           DS_3DLOOK or DS_CENTER or DS_MODALFRAME or DS_SHELLFONT or WS_CAPTION or \
           WS_VISIBLE or WS_GROUP or WS_SYSMENU or WS_THICKFRAME, \
           0 , 0 ,400,400,NULL,NULL,\
           hInst,NULL

   .WHILE TRUE
      invoke GetMessage, ADDR msg,NULL,0,0
      .BREAK .IF !eax
      invoke TranslateMessage, ADDR msg
      invoke DispatchMessage, ADDR msg
   .ENDW
   mov     eax,msg.wParam
   ret
WinMain endp


GetYRelativeToParent proc Child:HWND
    LOCAL Parent:HWND
    LOCAL Point:POINT
   
    invoke GetParent,Child
    mov Parent, eax
    xor eax, eax
    mov Point.x, eax
    mov Point.y, eax
    invoke MapWindowPoints, Child, Parent, addr Point, 1
    mov eax, Point.y
   
    ret

GetYRelativeToParent endp


CenterHorizontal proc Child:HWND
    LOCAL Parent:HWND
    LOCAL Rect1:RECT
    LOCAL Rect2:RECT
   
    invoke GetParent, Child
    mov Parent, eax
    invoke GetClientRect, Parent, addr Rect1
    invoke GetWindowRect, Child, addr Rect2
    invoke GetYRelativeToParent, Child   
    mov edx, eax
    mov ecx, Rect1.right
    add ecx, Rect2.left
    sub ecx, Rect2.right
    sar ecx,1
    invoke SetWindowPos, Child, 0, ecx, edx, 0, 0, SWP_NOZORDER or SWP_NOSIZE
    ret

CenterHorizontal endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
   
   .IF uMsg==WM_CREATE
        invoke CreateWindowEx, WS_EX_CLIENTEDGE ,addr cedit, NULL, WS_CHILD or WS_VISIBLE, \
        0, 40, 200, 200, hWnd, NULL, hInstance, NULL
       
        mov hedit, eax       
   .ELSEIF uMsg==WM_DESTROY
      invoke PostQuitMessage,NULL
      xor eax,eax
    .ELSEIF uMsg==WM_SIZING
      invoke CenterHorizontal,  hedit       
   .ELSEIF uMsg==WM_CREATE
      xor eax,eax
   .ELSE
      invoke DefWindowProc,hWnd,uMsg,wParam,lParam     
   .ENDIF
   ret

WndProc endp
end start


Title: Re: Problems with MapWindowPoints
Post by: jj2007 on August 10, 2015, 05:28:37 PM
mov eax, Point.y

Sure?
Title: Re: Problems with MapWindowPoints
Post by: rrr314159 on August 10, 2015, 05:29:56 PM
Hello ArOn,

MapWindowPoints is not relevant here, you can center it by changing CenterHorizontal as follows:

;   invoke GetXRelativeToParent, Child    ; comment these two lines out
;   mov edx, eax
    mov edx, Rect1.bottom                      ; add these 4 lines
    add edx, Rect2.top
    sub edx, Rect2.bottom
    sar edx,1


The textbox starts out not centered, but it centers when you resize; I suppose you know what to do about that since it's not part of your question

[edit] jj, just read your post, I was wondering about that myself but changing it to Point.x is wrong. Apparently, MapWindowPoints not needed anyway
Title: Re: Problems with MapWindowPoints
Post by: Ar0n on August 10, 2015, 05:57:44 PM
Quote from: jj2007 on August 10, 2015, 05:28:37 PM
mov eax, Point.y

Sure?
Yeah, this function returns the Y value of the child window ( I noticed that I wrote "GetXRelativeToParent", sorry for the confusion, it should be "GetYRelativeToParent", I fixed it).

Quote from: rrr314159 on August 10, 2015, 05:29:56 PM
Hello ArOn,

MapWindowPoints is not relevant here, you can center it by changing CenterHorizontal as follows:

;   invoke GetXRelativeToParent, Child    ; comment these two lines out
;   mov edx, eax
    mov edx, Rect1.bottom                      ; add these 4 lines
    add edx, Rect2.top
    sub edx, Rect2.bottom
    sar edx,1


The textbox starts out not centered, but it centers when you resize; I suppose you know what to do about that since it's not part of your question

[edit] jj, just read your post, I was wondering about that myself but changing it to Point.x is wrong. Apparently, MapWindowPoints not needed anyway

well, clearing my question, I want to center a child window to its parent, but only horizontally, without moving the vertical position, so I need to get the Y coordinate that corresponds to the vertical posision then pass that value to SetWindowPos, that is why I use MapWindowPoints...

Title: Re: Problems with MapWindowPoints
Post by: jj2007 on August 10, 2015, 07:35:52 PM
Quote from: Ar0n on August 10, 2015, 05:57:44 PMwell, clearing my question, I want to center a child window to its parent, but only horizontally, without moving the vertical position, so I need to get the Y coordinate that corresponds to the vertical posision then pass that value to SetWindowPos, that is why I use MapWindowPoints...

It should look like this:

    invoke GetWindowRect, Child, addr Rect2
    deb 4, "y", eax, $Err$(), Rect2.top
    mov ecx, Rect1.right      ; full width parent
    add ecx, Rect2.left
    sub ecx, Rect2.right            ; minus width child
    sar ecx,1
    invoke SetWindowPos, Child, 0, ecx, Rect2.top, 0, 0, SWP_NOZORDER or SWP_NOSIZE


... but I've run into trouble: Rect2.top is way too high, 2000 and more ::)
Title: Re: Problems with MapWindowPoints
Post by: Ar0n on August 10, 2015, 08:09:45 PM
Quote from: jj2007 on August 10, 2015, 07:35:52 PM

It should look like this:

    invoke GetWindowRect, Child, addr Rect2
    deb 4, "y", eax, $Err$(), Rect2.top
    mov ecx, Rect1.right      ; full width parent
    add ecx, Rect2.left
    sub ecx, Rect2.right            ; minus width child
    sar ecx,1
    invoke SetWindowPos, Child, 0, ecx, Rect2.top, 0, 0, SWP_NOZORDER or SWP_NOSIZE


... but I've run into trouble: Rect2.top is way too high, 2000 and more ::)

: error A2008: syntax error : integer:

deb 4, "y", eax, $Err$(), Rect2.top

is it me or? unable to build that code...
Title: Re: Problems with MapWindowPoints
Post by: jj2007 on August 10, 2015, 08:16:02 PM
Sorry, comment out the deb, it's MasmBasic.

I get rubbish values from invoke GetWindowRect, hedit, addr somerect, wherever I put it. Is it just me?
Win7-64
Title: Re: Problems with MapWindowPoints
Post by: Ar0n on August 10, 2015, 08:29:20 PM
Quote from: jj2007 on August 10, 2015, 08:16:02 PM
Sorry, comment out the deb, it's MasmBasic.

I get rubbish values from invoke GetWindowRect, hedit, addr somerect, wherever I put it. Is it just me?
Win7-64
jj2007, GetWindowRect seems to work well to me :P same Win7-64

Edited:
Guys, I realized that if I remove WS_EX_CLIENTEDGE (CreateWindowEx), my code works perfectly!
any idea?  :icon_eek:  :icon_eek: :icon_eek: .MapWindowPoints returns the correct coordinates.
Title: Re: Problems with MapWindowPoints
Post by: TouEnMasm on August 10, 2015, 09:57:33 PM
The WS_EX_CLIENTEDGE add a border to the window.
A border had a size not given by the windows API.
To know it play with GetWindowRect and GetclientRect on the same window handle.
The substract of the two will give the size of the border.

You have need also of the ScreenToClient
Title: Re: Problems with MapWindowPoints
Post by: dedndave on August 10, 2015, 11:00:44 PM
i thought we already did this, Aron - lol

http://masm32.com/board/index.php?topic=3994.msg42085#msg42085 (http://masm32.com/board/index.php?topic=3994.msg42085#msg42085)
Title: Re: Problems with MapWindowPoints
Post by: jj2007 on August 10, 2015, 11:51:02 PM
Quote from: Ar0n on August 10, 2015, 08:29:20 PMjj2007, GetWindowRect seems to work well to me :P same Win7-64
...
my code works perfectly!

Can you do me a favour and post source and exe? My GetWindowRect continues to return rubbish.
Title: Re: Problems with MapWindowPoints
Post by: hutch-- on August 11, 2015, 12:25:45 AM
You normally subtract the top X or Y from the bottom X or Y to get the size.
Title: Re: Problems with MapWindowPoints
Post by: Ar0n on August 11, 2015, 04:07:07 AM


Quote from: jj2007 on August 10, 2015, 11:51:02 PM
Quote from: Ar0n on August 10, 2015, 08:29:20 PMjj2007, GetWindowRect seems to work well to me :P same Win7-64
...
my code works perfectly!

Can you do me a favour and post source and exe? My GetWindowRect continues to return rubbish.
I added it.

Quote from: ToutEnMasm on August 10, 2015, 09:57:33 PM
The WS_EX_CLIENTEDGE add a border to the window.
A border had a size not given by the windows API.
To know it play with GetWindowRect and GetclientRect on the same window handle.
The substract of the two will give the size of the border.

You have need also of the ScreenToClient

Yeah, that seems to be the solution :-P but it looks somewhat rustic... sorry if it would be the right way.

Quote from: dedndave on August 10, 2015, 11:00:44 PM
i thought we already did this, Aron - lol

http://masm32.com/board/index.php?topic=3994.msg42085#msg42085 (http://masm32.com/board/index.php?topic=3994.msg42085#msg42085)
dedndave, I need to center the child window horizontally. Yes, it seems that I just delete the part to center the window vertically but can not leave this value to zero, that's why I need the original coordinates.

Quote from: hutch-- on August 11, 2015, 12:25:45 AM
You normally subtract the top X or Y from the bottom X or Y to get the size.
hutch, I don't need the size of the child window, I need the coordinates relative to its parent...

Guys, at this point, I'm not sure if I'm implying my problem ... :-P


Title: Re: Problems with MapWindowPoints
Post by: dedndave on August 11, 2015, 05:21:28 AM
not tested, but give it a try

we perform horizontal center, just as before (EBX)

then, we use ScreenToClient to convert the screen coordinates into client coordinates (left and top only)
we use the previous child top coordinate
and, we use the SWP_NOSIZE flag so that we do not have to calculate width or height

CenterChildHrz PROTO :HWND,:HWND
;
;
;
CenterChildHrz PROC USES EBX hWnd:HWND,hChild:HWND

    LOCAL   _rcClient   :RECT
    LOCAL   _rcChild    :RECT

    INVOKE  GetClientRect,hWnd,addr _rcClient
    INVOKE  GetWindowRect,hChild,addr _rcChild

    mov     ebx,_rcClient.right
    add     ebx,_rcChild.left
    sub     ebx,_rcChild.right
    sar     ebx,1

    INVOKE  ScreenToClient,hWnd,addr _rcChild.left

    xor     eax,eax
    INVOKE  SetWindowPos,hChild,eax,ebx,_rcChild.top,eax,eax,SWP_NOZORDER or SWP_NOSIZE
    ret

CenterChildHrz ENDP
Title: Re: Problems with MapWindowPoints
Post by: rrr314159 on August 11, 2015, 05:46:32 AM
Quote from: ArOnGuys, at this point, I'm not sure if I'm implying my problem ... :-P

- I'm glad u fixed your problem, assuming you're happy without the "clientedge" (works on my system also). I'm with jj2007, thought simply Rect2.top might do it, but the value is way off. Curious why, will look into it when I get to it ... or just wait for him to figure it out :biggrin:
Title: Re: Problems with MapWindowPoints
Post by: jj2007 on August 11, 2015, 02:19:50 PM
Quote from: rrr314159 on August 11, 2015, 05:46:32 AMI'm with jj2007, thought simply Rect2.top might do it, but the value is way off. Curious why, will look into it when I get to it ... or just wait for him to figure it out :biggrin:

Same for Win XP and Win7-64: Works without client edge. I thought of adding a manifest but it didn't help.
Title: Re: Problems with MapWindowPoints
Post by: Ar0n on August 11, 2015, 02:34:56 PM
@dedndave, you did it so simple  :biggrin: I was starting to play with GetWindowRect and GetClientRect to get the size of the border. Thank you!

Quote from: rrr314159 on August 11, 2015, 05:46:32 AM
Quote from: ArOnGuys, at this point, I'm not sure if I'm implying my problem ... :-P

- I'm glad u fixed your problem, assuming you're happy without the "clientedge" (works on my system also). I'm with jj2007, thought simply Rect2.top might do it, but the value is way off. Curious why, will look into it when I get to it ... or just wait for him to figure it out :biggrin:
yeah, it's weird for me too.

thanks guys for your time. :icon_exclaim:
Title: Re: Problems with MapWindowPoints
Post by: HSE on August 12, 2015, 02:18:40 AM
It's not processing WM_SIZING :eusa_naughty: , but WM_SIZE  :t

Regards. HSE
Title: Re: Problems with MapWindowPoints
Post by: jj2007 on August 12, 2015, 03:18:26 AM
Quote from: HSE on August 12, 2015, 02:18:40 AM
It's not processing WM_SIZING :eusa_naughty: , but WM_SIZE  :t

Same problem with client edge. The only difference is that the move downwards is slower, of course.
Title: Re: Problems with MapWindowPoints
Post by: dedndave on August 12, 2015, 04:05:22 AM
WM_SIZE has some very important values in wParam and lParam
i see a lot of code that totally ignores them, too - lol

WM_SIZE, wParam values

SIZE_RESTORED  EQU 0
The window has been resized, but neither the SIZE_MINIMIZED nor SIZE_MAXIMIZED value applies.

SIZE_MINIMIZED EQU 1
The window has been minimized.

SIZE_MAXIMIZED EQU 2
The window has been maximized.

SIZE_MAXSHOW   EQU 3
Message is sent to all pop-up windows when some other window has been restored to its former size.

SIZE_MAXHIDE   EQU 4
Message is sent to all pop-up windows when some other window is maximized.


you typically want to perform some adjustments for SIZE_RESTORED and SIZE_MAXIMIZED, and do nothing for the other values
lParam holds the new client dimensions
what i sometimes do, is to store the new values in a global _SIZE structure
that way, i don't have to call GetClientRect during WM_PAINT (or other places)

    mov     eax,uMsg
    .if eax==WM_SIZE
        .if !(wParam&(NOT SIZE_MAXIMIZED))                            ;perform if SIZE_RESTORED or if SIZE_MAXIMIZED
            mov     edx,lParam
            movzx   ecx,dx
            shr     edx,16
            mov     sizeClient.x,ecx
            mov     sizeClient.y,edx
        .endif
        xor     eax,eax                                               ;return 0


in this particular case, Aron could do a similar thing with the position of the child window
i.e., store the Y postition in a global variable, and only calculate the X position when SIZE_RESTORED or SIZE_MAXIMIZED
Title: Re: Problems with MapWindowPoints
Post by: HSE on August 12, 2015, 04:20:12 AM
Hi JJ. I'am in the original "center" problem (in Win 7-32).

Good trick Dave!! I think something close to that, but I don't resolve the problem with maximized windows.



Title: Re: Problems with MapWindowPoints
Post by: dedndave on August 12, 2015, 04:37:18 AM
it's not an issue of "resolving a problem with maximized windows"

when the window is maximized, you still want to update the client _SIZE structure   :t
Title: Re: Problems with MapWindowPoints
Post by: jj2007 on August 12, 2015, 05:35:38 AM
I wonder if lparam of WM_SIZE really solves the problem, which is the wrong rc.top value...
Title: Re: Problems with MapWindowPoints
Post by: dedndave on August 12, 2015, 06:33:08 AM
well - he wants to center the child window (or control) horizontally
so - having the client width handy means you don't have to call GetClientRect to get it
not that it's a slow function, really
but you also don't have to create a local RECT to get it   :P
Title: Re: Problems with MapWindowPoints
Post by: rrr314159 on August 12, 2015, 06:56:18 AM
Here's another way to do it, which works with WS_EX_CLIENTEDGE - on my machine. Unfortunately it uses a "magic number" which may not work on your machine.

Rect2.top has the textbox in screen coords, so we need the window's top in screen coords also, and subtract them. So, after computing ecx in CenterHorizontal call GetWindowRect for the parent (instead of GetClientRect) and subtract its top from the textbox. Then adjust by the "magic number" 26h which is the thickness of the window's title bar. So CenterHorizontal becomes:

CenterHorizontal proc Child:HWND
    LOCAL Parent:HWND
    LOCAL Rect1:RECT
    LOCAL Rect2:RECT
   
    invoke GetParent, Child
    mov Parent, eax
    invoke GetClientRect, Parent, addr Rect1
    invoke GetWindowRect, Child, addr Rect2
;    invoke GetYRelativeToParent, Child   ; this technique is alternative to MapWindowPoints
    mov ecx, Rect1.right
    add ecx, Rect2.left
    sub ecx, Rect2.right
    sar ecx,1

push ecx ; could rearrange to make it cleaner and avoid this push
    invoke GetWindowRect, Parent, addr Rect1
pop ecx

    mov edx, Rect2.top
    sub edx, Rect1.top
    sub edx, 26h

    invoke SetWindowPos, Child, 0, ecx, edx, 0, 0, SWP_NOZORDER or SWP_NOSIZE
    ret

CenterHorizontal endp


The code could be cleaner, of course. I think u can skip the GetClientRect call to Parent and subtract its GetWindowRect coords (right-left) to get the value which is in Rect1.right, for instance.

This works with or without WS_EX_CLIENTEDGE. The problem is, I doubt you can count on that "26h" for the title bar. On different systems and with different styles it may change. In fact that's exactly the problem MapWindowPoints is supposed to handle. But (for some reason) it doesn't work with clientedge ... Anyway this resolves (IMHO) the issue with Rect2.top, FWIW.
Title: Re: Problems with MapWindowPoints
Post by: jj2007 on August 12, 2015, 07:27:43 AM
Quote from: rrr314159 on August 12, 2015, 06:56:18 AMthe "magic number" 26h which is the thickness of the window's title bar.

include \masm32\include\masm32rt.inc
.code
start: MsgBox 0, str$(rv(GetSystemMetrics, SM_CYCAPTION)), "Height of your window title bars:", MB_OK
exit
end start
Title: Re: Problems with MapWindowPoints
Post by: rrr314159 on August 12, 2015, 08:43:03 AM
The call to GetSystemMetrics probably can make this approach portable and more or less equivalent to using MapWindowPoints - except for clientedge. The question is, why does MapWindowPoints have problem with clientedge?
Title: Re: Problems with MapWindowPoints
Post by: dedndave on August 12, 2015, 09:34:52 AM
you can use system metrics to get the border width, as well
i think it's SM_BORDER
double it, of course
you have to do that for the caption bar height, anyways
the caption bar includes a border
Title: Re: Problems with MapWindowPoints
Post by: TouEnMasm on August 12, 2015, 04:11:49 PM
The GetSystemMetrics function have not the SM_BORDER
https://msdn.microsoft.com/en-us/library/aa929225.aspx
Must be an old name

Answer is SM_CXBORDER, SM_CYBORDER
But SM_CXEDGE, SM_CYEDGE make things a little more difficult to use.
The better way stay a substract between the getwindowrect,getclientrect