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
mov eax, Point.y
Sure?
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
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 "Get
YRelativeToParent", 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...
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 ::)
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...
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
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.
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
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)
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.
You normally subtract the top X or Y from the bottom X or Y to get the size.
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
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
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:
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.
@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:
It's not processing WM_SIZING :eusa_naughty: , but WM_SIZE :t
Regards. HSE
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.
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
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.
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
I wonder if lparam of WM_SIZE really solves the problem, which is the wrong rc.top value...
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
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.
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
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?
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
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