This is something I do a lot in my programs, so I came up with the following routine to do this:
;============================================
; CenterWindow (winHandle, winWidth, winHeight)
;
; Centers window (by w. & h.) on another window.
;
; Returns:
; ECX = x-position for window
; EDX = y-position
;============================================
CenterWindow PROC winHandle:HWND, winWidth:DWORD, winHeight:DWORD
LOCAL gpRect:RECT
INVOKE GetWindowRect, winHandle, ADDR gpRect
; Calculate X-position of window:
MOV EAX, gpRect.right
SUB EAX, gpRect.left
SUB EAX, winWidth
MOV ECX, EAX
AND ECX, 1 SHL 31 ;Mask for sign bit.
SHR EAX, 1 ;Quick-n-dirty IDIV / 2.
OR EAX, ECX ;Replace sign bit.
ADD EAX, gpRect.left
MOV ECX, EAX ;Stash x-pos.
; Calculate Y-position of window:
MOV EAX, gpRect.bottom
SUB EAX, gpRect.top
SUB EAX, winHeight
MOV EDX, EAX
AND EDX, 1 SHL 31
SHR EAX, 1
OR EAX, EDX
ADD EAX, gpRect.top
MOV EDX, EAX
RET
CenterWindow ENDP
The handle passed in to the subroutine is that of the window you want to center the other window on; the height and width parameters are for the window you want centered. This works whether the window to be centered is larger or smaller than the other window. (To do this, I think my method of doing a "poor-man's IDIV" here is fairly clever: I use SHR 1 to divide by half, but preserve the sign bit beforehand and OR it back into the result afterwards to preserve the sign of the value.)
After calling this, you can pass the values in ECX and EDX directly to SetWindowPos() to center the window.
to restore the sign, you want 2 bits :P
SAR (shift arithmetic right) takes care of that for you
(http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/Chapter_6/images/ch06a2.gif)
Yeah, SAR is certainly easier, isn't it! Dunno how I missed that.
But why do you say "2 bits"? It's just the one bit, the sign bit, no? I don't care about the carry bit here.
Anyhow, here's the simplified code:
; Calculate X-position of window:
MOV EAX, gpRect.right
SUB EAX, gpRect.left
SUB EAX, winWidth
SAR EAX, 1 ;Quick-n-dirty IDIV / 2.
ADD EAX, gpRect.left
MOV ECX, EAX ;Stash x-pos.
; Calculate Y-position of window:
MOV EAX, gpRect.bottom
SUB EAX, gpRect.top
SUB EAX, winHeight
SAR EAX, 1
ADD EAX, gpRect.top
MOV EDX, EAX
RET
2 bits - one is the sign, one is the extension
for bytes...
1abcdefg
becomes
11abcdef
and
0abcdefg
becomes
00abcdef
Hmm, don't know what you mean by the "extension". Isn't that just the most significant bit of the (signed) quantity?
In any case, my original code worked fine; it was just needlessly complex.
well - under the right (wrong) conditions, it would have returned incorrect results
let's play....
-10, in hex...
FFFF FFF6
your calculation would have yielded...
DFFF FFFB
but, -10, diviided by 2 should be somewhere near -5 :P
FFFF FFFB
you can plug those values into the str$ macro to see
mov eax,0FFFFFFF6h
print str$(eax),32
mov eax,0DFFFFFFBh
print str$(eax),32
mov eax,0FFFFFFFBh
print str$(eax),13,10
on a different note, here's something you might consider...
;create a structure for your stuff
MyWinStruct STRUCT
dwWidth dd ?
dwHeight dd ?
rcRect RECT <>
; left dd ?
; top dd ?
; right dd ?
; bottom dd ?
MyWinStruct ENDS
;define it in the data area
.DATA?
mws MyWinStruct <>
now, you can use a register to point to the base of the structure
your horizontal values are at offsets 0, 8, 16
your vertical values are at offsets 4, 12, 20
Calc PROC
mov eax,offset mws
call Calc00
mov ecx,edx
add eax,4
Calc00: push ecx
mov edx,[eax].MyWinStruct.rcRect.right
mov ecx,[eax].MyWinStruct.rcRect.left
sub edx,[eax].MyWinStruct.dwWidth
sub edx,ecx
sar edx,1
add edx,ecx
pop ecx
ret
Calc ENDP
you could also put the result for each in the structure, if you like
not only that, but if you pass the address of the structure in EAX, you can use it for multiple windows :P
addressing data with a register and an index is smaller and faster than addressing it directly
"smaller and faster" may not appeal to you - how about "more efficient"
here is what the code looks like
i always like to look at the disassembly to see where i can do better :P
00000018 Calc PROC
00000018 B8 00000000 R mov eax,offset mws
0000001D E8 00000005 call Calc00
00000022 8B CA mov ecx,edx
00000024 83 C0 04 add eax,4
00000027 51 Calc00: push ecx
00000028 8B 50 10 mov edx,[eax].MyWinStruct.rcRect.right
0000002B 8B 48 08 mov ecx,[eax].MyWinStruct.rcRect.left
0000002E 2B 10 sub edx,[eax].MyWinStruct.dwWidth
00000030 2B D1 sub edx,ecx
00000032 D1 FA sar edx,1
00000034 03 D1 add edx,ecx
00000036 59 pop ecx
00000037 C3 ret
00000038 Calc ENDP
; Calculate X-position of window:
00000038 A1 00000010 R MOV EAX, mws.rcRect.right
0000003D 2B 05 00000008 R SUB EAX, mws.rcRect.left
00000043 2B 05 00000000 R SUB EAX, mws.dwWidth
00000049 D1 F8 SAR EAX, 1 ;Quick-n-dirty IDIV / 2.
0000004B 03 05 00000008 R ADD EAX, mws.rcRect.left
00000051 8B C8 MOV ECX, EAX ;Stash x-pos.
; Calculate Y-position of window:
00000053 A1 00000014 R MOV EAX, mws.rcRect.bottom
00000058 2B 05 0000000C R SUB EAX, mws.rcRect.top
0000005E 2B 05 00000004 R SUB EAX, mws.dwHeight
00000064 D1 F8 SAR EAX, 1
00000066 03 05 0000000C R ADD EAX, mws.rcRect.top
0000006C 8B D0 MOV EDX, EAX
0000006E C3 RET
55 bytes of code vs 32
Quote from: dedndave on April 09, 2012, 03:03:17 AM
well - under the right (wrong) conditions, it would have returned incorrect results
let's play....
-10, in hex...
FFFF FFF6
your calculation would have yielded...
DFFF FFFB
I don't see how you get that. Using my code:
MOV EAX, gpRect.right
SUB EAX, gpRect.left
SUB EAX, winWidth
MOV ECX, EAX
AND ECX, 1 SHL 31 ;Mask for sign bit.
SHR EAX, 1 ;Quick-n-dirty IDIV / 2.
OR EAX, ECX ;Replace sign bit.
let's look at the result, using your example of -10:
1. -10 = FFF6 (let's pretend it's a WORD instead of a DWORD to make things easier).
2. Mask (CX, copy of original AND 8000) = 8000
3. FFF6 SHR 1 = 7FFB (AX)
3. Result = AX OR 8000 = FFFB = -5
Q.E.D.: my method works.
But your method (SAR vs SHR) is clearly superior, and I changed my original code. I just mistakenly found a more expensive way to implement SAR is all.
oops !
my mistake
cudda saved us a lot of typing - lol
Hey, no harm, no foul.
Of course, I would never make a mistake like that ...
brain fart on my part
when i was younger, i had a full set of registers upstairs - lol
FYI guys,
when I see code that looks like this, I can only wonder how confusing that must look to noob programmers.
INVOKE GetWindowRect, winHandle, ADDR gpRect
MOV EAX, gpRect.right
SUB EAX, gpRect.left
SUB EAX, winWidth
MOV ECX, EAX
AND ECX, 1 SHL 31 ;Mask for sign bit.
SHR EAX, 1 ;Quick-n-dirty IDIV / 2.
OR EAX, ECX ;Replace sign bit.
ADD EAX, gpRect.left
MOV ECX, EAX ;Stash x-pos.
The problem appears to be the usage of TABS in your code examples.
Instead, perhaps you could use SPACES:
INVOKE GetWindowRect, winHandle, ADDR gpRect
MOV EAX, gpRect.right
SUB EAX, gpRect.left
SUB EAX, winWidth
MOV ECX, EAX
AND ECX, 1 SHL 31 ;Mask for sign bit.
SHR EAX, 1 ;Quick-n-dirty IDIV / 2.
OR EAX, ECX ;Replace sign bit.
ADD EAX, gpRect.left
MOV ECX, EAX ;Stash x-pos.
Whether or not you use TABS in your code, that is up to you.
However, when you post it for all to view, that is another thing.
It makes it very hard to read and (for some, especially new programmers) Assembly Language can be very hard to read to begin with. :U
Steve,
Have a look at your own post with Firefox. It looks perfectly "tabbed".
Quote from: jj2007 on April 09, 2012, 03:55:55 PM
Have a look at your own post with Firefox. It looks perfectly "tabbed".
I had figured it was an issue with the forum and it still may be.
I'm not surprised.
I've seen other cases where a forum looked one way on one browser and different on another.
SourceForge is an example of that too.
I guess they all use Firefox there.
They were not aware that their forums looked bad on IE, until I informed them of a similar issue.
At any rate, this forum does not display correctly on IE.
I believe it is fixable.
You can't assume everyone uses Firefox or non-IE browsers.
Steve,
for IE, there is a feature called "Compatibility View"
you may have it disabled :P
i am using XP MCE2005, SP3 with IE8 - Compatibilty View enabled
your post looks the same in Firefox and IE
Just checked with IE7 (<rant>I'll never understand why the bloody beast points me every single time I start it to runonce, although I always tell it what my homepage is</rant>), and I can confirm that IE does not show the tabs correctly. Looks awful indeed.
Quote from: dedndave on April 09, 2012, 05:24:29 PM
for IE, there is a feature called "Compatibility View"
you may have it disabled :P
i am using XP MCE2005, SP3 with IE8 - Compatibilty View enabled
your post looks the same in Firefox and IE
Dave,
I'm aware of "Compatibility View".
I'm running XP, SP3, IE8 w/Compatibility View
enabled.
And this is what I see for many posts with code:
INVOKEGetWindowRect, winHandle, ADDR gpRect
MOVEAX, gpRect.right
SUBEAX, gpRect.left
SUBEAX, winWidth
MOVECX, EAX
ANDECX, 1 SHL 31
SHREAX, 1
OREAX, ECX
ADDEAX, gpRect.left
MOVECX, EAX
where TABS are used in the code.
Dunno why y'all are having problems with IE. I just tried my version (old: v5) and it displayed correctly.
Did Micro$oft break tab rendering in later versions of IE?
ok - i was playing around - lol
you have to disable compatibility view for this site
IE - Tools menu - Compatibility View
i had it disabled for alll websites except those in my list
IE - Tools menu - Compatibility View Settings
Quote from: dedndave on April 09, 2012, 06:59:11 PM
ok - i was playing around - lol
you have to disable compatibility view for this site
IE - Tools menu - Compatibility View
i had it disabled for alll websites except those in my list
IE - Tools menu - Compatibility View Settings
Okay, once I removed masm32 from my Compatibility View list, it displayed correctly.
Now, I can't remember why I had it on my list. :eek
Quote from: SteveAsm on April 09, 2012, 10:59:25 PM
Okay, once I removed masm32 from my Compatibility View list, it displayed correctly.
Now, I can't remember why I had it on my list. :eek
Ohoh!
now I remember.
It has to due with SMF Forums.
SMF Forums, (and masm32 is one of them), has a glitch that pertains to IE-8.
Unless you use Compatibility View, when entering text in the textbox for submitting a post, the textbox becomes unstable.
I remember discussing this in emails with SMF support. It is a well known bug.
Their only solution is to turn Compatibility View
ON.
Try it.
Using IE8, Compatibility View turned OFF, enter (or copy) a dozen or so lines of text and at the end of the page, start typing.
It will become unstable.
This raises another issue, tho'.
Now, as I have illustrated, with Compatibility View turned ON, TABS become a problem as text is run together without proper spacing.
Hi there this seems to be a good Idea what am I doing wrong invoking the SetWindowPos ?
... I commented out because It crashes on me :(
SWP_NOMOVE + SWP_NOSIZE
you should OR constants together, not ADD
SWP_NOMOVE or SWP_NOSIZE
but - that's not the problem
also, the x and y position parameters will be ignored if the SWP_NOMOVE flag is set :P
but - that's not the problem
Quote from: dedndave on April 11, 2012, 10:09:33 PM
SWP_NOMOVE + SWP_NOSIZE
you should OR constants together, not ADD
SWP_NOMOVE or SWP_NOSIZE
but - that's not the problem
also, the x and y position parameters will be ignored if the SWP_NOMOVE flag is set :P
but - that's not the problem
so what is the problem?
Call CenterWindow
CenterWindow PROC winHandle:HWND, winWidth:DWORD, winHeight:DWORD
when CenterWindow returns, it POP's 3 dwords off the stack
lemme see - that'd be the stored EBP value, the return address for DlgProc, and the hWnd parm :bg
no wonder it crashes
then - when you exit the DlgProc routine, it tries to jam the uMsg value into ESP and POP wParam into EBP :lol
it then proceeds to execute code at the address of whatever lParam is pointing to - probably crashes right there
Quote from: dedndave on April 11, 2012, 10:14:20 PM
Call CenterWindow
CenterWindow PROC winHandle:HWND, winWidth:DWORD, winHeight:DWORD
LOL ...
I don't get it
If you use call, you need to push the parameters then call, or use invoke and you would see what the error is!
well, first, you have to get the window width and height
i am guessing you want to center it on the desktop, so you can use GetSystemMetrics for those
INVOKE CenterWindow,hWnd,width,height
woops
Quote from: dedndave on April 11, 2012, 10:20:14 PM
well, first, you have to get the window width and height
i am guessing you want to center it on the desktop, so you can use GetSystemMetrics for those
INVOKE CenterWindow,hWnd,width,height
I thought this centers the window within another window .....not in the center of the desktop ...I just use poponcenter in the rsrc.rc with MASMeD
oh - well it will center any window in any other window, i think
the desktop is a window :P
HWND_DESKTOP = 0
Quote from: dedndave on April 11, 2012, 10:20:14 PM
well, first, you have to get the window width and height
i am guessing you want to center it on the desktop, so you can use GetSystemMetrics for those
INVOKE CenterWindow,hWnd,width,height
I tried all this Last night on the example that I posted above and no go ...the window is not centered on my main window ...and it goes to the upper left corner of the desktop .... also no window just a title bar?????
I have another way that I do this but it does not keep the window proportion with regards to the window size ...you have to set left right top bottom and window height and width....
maybe I think this will do something that It does not..... what I thought this does is.... for the child window to pop up on center in relation to the parent window even if I move the parent window anywhere on the desktop before I execute the child window
well - show us your example
what you may be dealing with is a coordinate reference issue
i.e., screen coordinates vs client coordinates
Quote from: dedndave on April 12, 2012, 04:49:44 PM
well - show us your example
what you may be dealing with is a coordinate reference issue
i.e., screen coordinates vs client coordinates
the example that does not work is the one above that I want to work using this authors way ..... I have no problem with the other one it works great ... I am not at home at my personal PC ...but If you want to see that one let me know and I will grab it with me on a flash drive and upload it ...I have no questions about that one ....
I am trying to make this one work
http://www.masm32.com/board/index.php?PHPSESSID=fc2c702b1f62df3f61be07c96a25b83f&action=dlattach;topic=18662.0;id=10550
I did not re-upload it with the modifications suggested last night
ok
that example doesn't tell us which window you want centered on which other window :P
remember - the parms for CenterWindow are missing - so we cannot see what you want to do
on another note...
looking again at the code,
it seems logical that the function could be passed 2 window handles, rather than a handle, width, and height
i dunno - a matter of application, i suppose
Heather...
this is a simple thing :P
if you can handle bitmaps, you should be able to handle this
Quote from: dedndave on April 12, 2012, 05:02:38 PM
ok
that example doesn't tell us which window you want centered on which other window :P
remember - the parms for CenterWindow are missing - so we cannot see what you want to do
on another note...
looking again at the code,
it seems logical that the function could be passed 2 window handles, rather than a handle, width, and height
i dunno - a matter of application, i suppose
Heather...
this is a simple thing :P
if you can handle bitmaps, you should be able to handle this
LOL the child window ... so say I execute my main window .... than I move it to the button corner of the screen ...I thought this proc makes sure that the child window opens in the center of the parent window
I know that I should be able to handle this but I want to use his proc the way he intended it ...and I do not know how ....
for example my way the "INVOKE GetWindowRect, winHandle, ADDR gpRect" is not in the proc it gets invoked Like so:
.IF wParam == IDC_WINDOWBUTTON
INVOKE GetWindowRect,hWnd, addr rect
invoke DialogBoxParam,hInstance,IDC_WINDOW,hWnd,addr WindowProc,0
and the rect is not defined LOCAL ....
SO I do not know were to place his "invoke CenterWindow", and were do I place "invoke SetWindowPos"
I just thought I would try his proc that's all :(
we'll make it fly :U
gimme a while - i am playing with the enumeration thingy
yah - little snafu with coordinates
GetWindowRect returns screen coordinates
MoveWindow uses client coordinates for child windows, screen coordinates for top-level windows
SetWindowPos uses client coordinates
so - the routine works ok for centering the main window of a program
we can use ScreenToClient to straighten things out, i think
Quote from: dedndave on April 12, 2012, 07:59:36 PM
yah - little snafu with coordinates
GetWindowRect returns screen coordinates
MoveWindow and SetWindowPos use client coordinates for child windows, screen coordinates for top-level windows
so - the routine works ok for centering the main window of a program
we can use ScreenToClient to straighten things out, i think
The authors original post said that it does what I thought it would ..????
I have an example that does that .... I just thought he had a better way..... oh well ......
not that important ...... I am sure the author might respond and explain or give a demo of how he uses this proc
look at the first proc quote "Centers window (by w. & h.) on another window"
maybe i am missing something
at the end of each section in the code, he adds the left or top screen position back onto the result
who knows I am sure he will post an example of how he meant this to be used
Thank you for all your help with every thing so far :bg
ok - i must have misunderstood something or other - lol
give this a try...
Quote from: dedndave on April 12, 2012, 08:44:00 PM
ok - i must have misunderstood something or other - lol
give this a try...
Yes that is what I wanted to do :U
but that is not the way that the author described using the proc .....the original post made it seem like all you have to do is call CenterWindow and than SetWindowPos
I was on this for the most part of the day and still would not get it to work .......
you had to add a bunch of stuff that makes the CenterWindow proc almost irrelevant your way can be modified so you do not need to use that proc
It is very similar to an example that I had
As I promised yesterday that I will bring my example on a flash drive and upload it ..... this gives you the ability to Control the final Child window size and the position
Thank you for all your hard work ... :bg I hope one day that I will be good enough to start helping people too
well - normally, you know what size the inside window will be ahead of time - the height and width would be constants
no need to call GetWindowRect before the CenterWindow call to get the size
that was just some example code i tossed together
for example - you want to center a "standard sized" button in hWin...
INVOKE CenterWindow,hWin,86,26
INVOKE MoveWindow,hButton,ecx,edx,86,26,TRUE
a trick that Edgar (donkey) taught me a couple years ago...
main window - WM_CREATE handler - create all your controls
the initial sizes and positions can be all 0's
then let the WM_SIZE handler set their sizes and positions :P
(works especially well for scroll bars and status bars - whose sizes and positions depend on the window size)
Quote from: dedndave on April 09, 2012, 03:35:22 AM
here is what the code looks like
i always like to look at the disassembly to see where i can do better :P
00000018 Calc PROC
00000018 B8 00000000 R mov eax,offset mws
0000001D E8 00000005 call Calc00
00000022 8B CA mov ecx,edx
00000024 83 C0 04 add eax,4
00000027 51 Calc00: push ecx
00000028 8B 50 10 mov edx,[eax].MyWinStruct.rcRect.right
0000002B 8B 48 08 mov ecx,[eax].MyWinStruct.rcRect.left
0000002E 2B 10 sub edx,[eax].MyWinStruct.dwWidth
00000030 2B D1 sub edx,ecx
00000032 D1 FA sar edx,1
00000034 03 D1 add edx,ecx
00000036 59 pop ecx
00000037 C3 ret
00000038 Calc ENDP
; Calculate X-position of window:
00000038 A1 00000010 R MOV EAX, mws.rcRect.right
0000003D 2B 05 00000008 R SUB EAX, mws.rcRect.left
00000043 2B 05 00000000 R SUB EAX, mws.dwWidth
00000049 D1 F8 SAR EAX, 1 ;Quick-n-dirty IDIV / 2.
0000004B 03 05 00000008 R ADD EAX, mws.rcRect.left
00000051 8B C8 MOV ECX, EAX ;Stash x-pos.
; Calculate Y-position of window:
00000053 A1 00000014 R MOV EAX, mws.rcRect.bottom
00000058 2B 05 0000000C R SUB EAX, mws.rcRect.top
0000005E 2B 05 00000004 R SUB EAX, mws.dwHeight
00000064 D1 F8 SAR EAX, 1
00000066 03 05 0000000C R ADD EAX, mws.rcRect.top
0000006C 8B D0 MOV EDX, EAX
0000006E C3 RET
55 bytes of code vs 32
How'd did you do that? What disassembler did you used?
masm generated that listing with the Fl switch
i sometimes use Sang Cho's simple disassembler if i want another view (he's a prof at CheongJu University)
http://hcilab.cju.ac.kr/
there are numerous more powerful disassemblers out there
Quote from: hfheatherfox07 on April 12, 2012, 08:04:43 PM
Quote from: dedndave on April 12, 2012, 07:59:36 PM
yah - little snafu with coordinates
GetWindowRect returns screen coordinates
MoveWindow and SetWindowPos use client coordinates for child windows, screen coordinates for top-level windows
so - the routine works ok for centering the main window of a program
we can use ScreenToClient to straighten things out, i think
The authors original post said that it does what I thought it would ..????
I have an example that does that .... I just thought he had a better way..... oh well ......
not that important ...... I am sure the author might respond and explain or give a demo of how he uses this proc
look at the first proc quote "Centers window (by w. & h.) on another window"
Yes, I'm the OP (original poster), and yes, it does what you thought I said it did (and what I did say it did, and what in fact does).
It centers one window, whose X- and Y-coordinates are passed in, on another window, whose handle is passed in. For example, the window to be centered could be a pop-up window, and the window you want it centered on could be your main window. Remember (and this may be where some confusion came in) that the X- and Y-coordinates for centering the window are
screen coordinates, not client coordinates (i.e., relative to (0,0) of the parent window). This can't be used to center a child window on a parent window, though it could easily be modified to do so.
It works exactly as described. The way to use it is thus:
INVOKE CenterWindow, winHandle, (window width), (window height)
; X- and Y-coords. come back in ECX & EDX
INVOKE CreateWindowEx, WS_EX_OVERLAPPEDWINDOW, (class), (title),
(styles), ECX, EDX, (window width), (window height),
NULL, NULL, InstanceHandle, NULL
Of course, this shows it being used to create another window centered on the main one. You could just as easily use it with an existing window by calling SetWindowPos() to move the window.
And it works whether the window to be centered is larger or smaller than the other window.
Try it sometime!