OK, rookie conceptual questions here. I hope you'll be kind to this n00b.
So say a guy wants to create a simple window, with a very small window inside it, just for proof-of-concept purposes. The parent window will create the "client area", within which the small window is free to move. The idea is to be able to drag the small window around inside the parent, like placing an object with a drawing program, say.
OK, so far so good. I've created the parent and the child(*) windows. I started playing around with intercepting mouse-move and button messages. But I'm very confused about a basic point that I need to get cleared up before I go further.
I tried making the child window the message-interceptor, using RegisterClassEx() to set up a message-handling procedure (let's call it "ChildProc"). On left-button-down messages, I checked for signs of dragging, using DragDetect(), at which point I captured the mouse with SetCapture(). After this, I watched for WM_MOUSEMOVE messages, thinking I could use them to actually move my window around.
Let me back this up to a more conceptual level. I'm confused about who should handle what in this situation.
Because I'm looking at mouse coordinates from the child's point of view, (0, 0) is at the upper-left of the child window, correct? But I want to move this window within the client area (=parent window). So should I be looking for mouse moves within the parent instead of the child?
Using pseudocode:
[ParentProc]
case WM_MOUSEMOVE:
if (DragFlag)
- move child window to (mouseX, mouseY)
case WM_LBUTTONUP:
- DragFlag = FALSE
- ReleaseCapture()
...
[ChildProc]
case WM_LBUTTONDOWN:
- if (DragDetect())
- DragFlag = TRUE
- SetCapture()
case WM_LBUTTONUP:
- DragFlag = FALSE
- ReleaseCapture()
...
The basic idea is that the signal to capture the mouse comes from the user clicking and dragging within the child, but of tracking mouse movements from the parent's point of view, so that the child can be moved within the parent (that is, relative to (0,0) of the parent). Both parent and child must monitor for WM_LBUTTONUP to know when the user releases the left button (DragFlag is a global variable).
Will this work? Is this the way to do this? Remember, all I want to do is be able to drag this little child around in the client area.
But I'm confused about who gets (and handles) what messages when. Is there some clear explanation of this out there in web-land? There's some good stuff at MSDN, but it's not basic enough to clear this up for me.
Other questions: should I use SetWindowPos() or MoveWindow() to move the window?
What about repainting, invalidating rectangles, etc.? What are the minimal requirements for being able to drag this child around and have it visible and with underlying stuff repainted as needed?
* Do I need to create the child as an actual child (that is, with the Windows child property)?
Probably more questions later.
Your idea looks suspiciously like \masm32\examples\exampl02\mdidemo :bg
if the mouse is moved outside the main window, i believe you no longer get WM_MOUSEMOVE messages
you may want to use "mouse capture"
http://msdn.microsoft.com/en-us/library/windows/desktop/ms645601%28v=VS.85%29.aspx#_win32_Mouse_Capture
if you create an MDI child, you may not have this problem, but it has it's own quirks, too - lol
Quote from: jj2007 on October 04, 2011, 07:47:44 PM
Your idea looks suspiciously like \masm32\examples\exampl02\mdidemo :bg
Yes, something like what happens if you click the first button, except that I don't want the scroll bars to appear when the child is dragged to the extremes. So close, but no cigar.
Quote from: dedndave on October 04, 2011, 07:52:03 PM
if the mouse is moved outside the main window, i believe you no longer get WM_MOUSEMOVE messages
you may want to use "mouse capture"
http://msdn.microsoft.com/en-us/library/windows/desktop/ms645601%28v=VS.85%29.aspx#_win32_Mouse_Capture
Look at my pseudocode; I'm already capturing the mouse. The question is,
who captures it, the parent or the child?
Quoteif you create an MDI child, you may not have this problem, but it has it's own quirks, too - lol
Yes, looks like maybe too many quirks for me. I'd like a robust, elegant solution I can use from now on.
i don't think you are using the SetCapture function :P
if you were, you probably wouldn't ask that question
QuoteThe system typically posts a mouse message to the window that contains the cursor hot spot when a mouse event
occurs. An application can change this behavior by using the SetCapture function to route mouse messages to a
specific window. The window receives all mouse messages until the application calls the ReleaseCapture function
or specifies another capture window, or until the user clicks a window created by another thread.
I am using SetCapture(). Here's my code:
MOV EAX, uMsg
CMP EAX, WM_LBUTTONDOWN
JE lbuttondown
...
lbuttondown:
; Left button down: see if user dragged:
MOV EAX, lParam
MOV EDX, EAX ;Make a copy
AND EAX, 0FFFFH ;Mask off high word
MOV pt.x, EAX
SHR EDX, 16 ;High word--> low word
MOV pt.y, EDX
INVOKE DragDetect, hWin, pt.x, pt.y
OR EAX, EAX ;Did we detect dragging?
JZ cp999
MOV Dragging, TRUE ;Yes, set flag.
INVOKE SetCapture, hWin
JMP cp999 ;Exit
I went ahead and tried what I described above in pseudocode. My hunch seems to have been right: it works pretty well. I can pick up and drag my child window all over the inside of the parent window.
Few weird things, though:
- When I drag it past the edge of the parent window, the window keeps on going, but it gets clipped by the parent. I'm guessing I need to do that ClipCursor() thing to keep it inside the client area.
- No matter where I grab the child, the mouse cursor always jumps to the upper left-hand corner of the window. How do you handle this? (I'd like the cursor to stay wherever it was when I grabbed it.)
- Another weird thing: If I grab the window in its interior, I can move the mouse left and right inside the window without it being moved, even though I can see from my indicators that the mouse button is down and mouse capture is in progress. It's as if I can't actually move the window until the cursor hits one edge or the other.
Clearly I've got a lot to learn here. But I'm making progress.
I would still very much appreciate a general explanation of how this all works, without too many of the actual implementation details. (There's always time for them later!)
the child window should clip inside the client of the main window - that's a good thing :bg
(in fact, i strongly recommend using the WS_CLIPCHILDREN flag when creating the main window)
but, you shouldn't be able to drag the cursor outside the main window client
attached is a small MDI window that i use
i don't use IF/ELSEIF/ELSE/ENDIF structures in my code, so it doesn't make a wonderful example for newbies :P
but, it does demonstrate proper dragging behaviour of a child window
Quote from: dedndave on October 04, 2011, 11:41:15 PM
the child window should clip inside the client of the main window - that's a good thing :bg
(in fact, i strongly recommend using the WS_CLIPCHILDREN flag when creating the main window)
but, you shouldn't be able to drag the cursor outside the main window client
attached is a small MDI window that i use
That still exhibits the problem I described with my test, except that your mouse cursor is constrained within the parent window. It's still possible to drag part of the child over the edge of the parent so it clips. I'd like my window to stop when it "bumps into" the parent window. (Not a huge problem, but still ...)
Quotei don't use IF/ELSEIF/ELSE/ENDIF structures in my code, so it doesn't make a wonderful example for newbies :P
Well, I'm a n00b to Win32 only. Been writing 16-bit code for decades now. I also don't care much for those "streamlined" directives. Hell, why not just write C, if that's what you want your code to look like?
yes - the child window will be clipped inside the main window
that is always true for child windows and is generally considered desirable
however, if you do not want that, then you do not want a
child windowyou want an independant window, or more likely, a dialog box
no more SetCapture, either :U
QuoteWell, I'm a n00b to Win32 only. Been writing 16-bit code for decades now. I also don't care much for
those "streamlined" directives. Hell, why not just write C, if that's what you want your code to look like?
a man after my own heart - lol
my thoughts exactly - if i wanted my program to look like a C program, i'd probably write it in C :bg
btw - i also wrote 16-bit asm for years
More progress to report. Got clipping working correctly, using a page from MSDN (http://msdn.microsoft.com/en-us/library/windows/desktop/ms648380%28v=vs.85%29.aspx#_win32_Confining_a_Cursor):
PrevRect RECT <>
ChildProc PROC hWin:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
LOCAL pt:POINT
MOV EAX, uMsg
CMP EAX, WM_LBUTTONUP
JE lbuttonup
...
lbuttonup:
CMP MouseCaptured, TRUE ;Are we watching the mouse?
JNE cddodef ;Nope.
INVOKE ReleaseCapture
INVOKE ClipCursor, ADDR PrevRect ;Un-clip to our window.
INVOKE SetWindowText, mousebtnhandle, ADDR upmsg
MOV MouseCaptured, FALSE ;Clear flag.
JMP cddodef
...
WindowProc PROC hWin:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
LOCAL pt:POINT, clipRect:RECT
MOV EAX, uMsg
CMP EAX, WM_MOUSEMOVE
JE domousemove
CMP EAX, WM_LBUTTONUP
JE buttonup
...
domousemove:
CMP MouseCaptured, TRUE ;Are we watching the mouse?
JE dm10 ;Yes, move child window.
CMP DragFlag, TRUE ;No; did child report dragging?
JNE dodefault ;Nope, do nothing.
MOV DragFlag, FALSE ;Clear flag
MOV MouseCaptured, TRUE
INVOKE SetCapture, hWin
INVOKE GetClipCursor, ADDR PrevRect ;Get current clip rectangle
INVOKE GetWindowRect, hWin, ADDR clipRect
INVOKE ClipCursor, ADDR clipRect
dm10: INVOKE MoveWindow, ChildHandle, pt.x, pt.y, $childWidth, $childHeight, TRUE
buttonup:
CMP MouseCaptured, TRUE ;Are we watching the mouse?
JNE dodefault ;Nope.
INVOKE ReleaseCapture ;Yep, stop capture.
INVOKE ClipCursor, ADDR PrevRect ;Un-clip to our window.
INVOKE SetWindowText, mousebtnhandle, ADDR upmsg
MOV MouseCaptured, FALSE ;Clear flag.
JMP dodefault
Notice that PrevRect is a global so it is preserved across calls.
here's a thread you might like :P
http://www.masm32.com/board/index.php?topic=12092.0
Next question: I've got this window-dragging stuff working reasonably well. For one window. But what if one has dozens of windows that one wants to be able to drag around? I can see this turning into a real nightmare, unless one comes up with a clever organization scheme.
Hmm, I wonder if I could create an array of structures to keep track of all of these windows wandering all over the place?
Any thoughts?
Wait, wait! I think I just figured it out.
You might have dozens of windows, even active windows within a parent. But since the user can only drag one window at a time, it should actually be easy. (I'm leaving aside the ability to move more than one window at a time aside, like with marquee-selecting.) There will always be at most one window being dragged to keep track of.
In fact, it'll work fine the way I have things set up now. The window proc for the child window simply detects whether the user clicked and dragged in that window (using DragDetect()), then sets a flag. The parent window proc checks this flag, and if set, starts mouse capture. To move the child window (following the mouse), it needs the handle to the child window. So all the child window has to do is to copy its handle into a global variable, which the parent proc can use. Easy!
I'll have to try this to see if it's as easy as it looks ...
Problem: Each child window still requires its own window proc. That could still make the code pretty bloat-y. Any way to funnel all this through a single window proc? I don't see how you'd know which child window the user tried to drag. Any way to retrieve the ID of the window?
it's probably given to you in wParam or lParam :P
Nope. WM_LBUTTONDOWN (http://msdn.microsoft.com/en-us/library/ms645607%28v=VS.85%29.aspx) has a bunch of flags in wParam, and of course the mouse X and Y in lParam. Same for WM_LBUTTONUP and WM_MOUSEMOVE.
By the way, enjoyed that thread on C++ very much. I don't hate it (never really learned it myself, just C), but I can see why people do.
It works!
Figured out how to have multiple windows share a common window proc.
Was wondering up above, hmm, how could I tell which window I'm handling this time around? lParam? No. wParam? No.
Well, duh! Just look at the window handle, dummy! (Talking to myself here.) After all, it's guaranteed to be unique.
It works. On creating a child window, store its handle in a global variable. Inside the childProc(), compare the handle passed to the routine to the stored one. If it matches, bingo! that's the child.
So I can just build me an array of structures, storing the handles there, plus all the interesting stuff I need for each child (text to paint, colors, sizes, etc., etc.). Search the list, matching the Windows handle to the stored ones, use the index to access the other stuff.
I think that's pretty slick ... of course, I'm sure some of you figured this out long ago.
the trick is to design the code so that each window is treated the same
that way, you don't care which one it is :bg
of course, that can't always be a good solution
Quote from: dedndave on October 06, 2011, 02:10:40 PM
the trick is to design the code so that each window is treated the same
that way, you don't care which one it is :bg
of course, that can't always be a good solution
Yes, I've learned that. My childProc() doesn't discriminate at all against any of its children. I guess you could say it's "orthogonal".
It works fine now; I'm wondering how well it'll work with lots and lots of children. Theoretically, it should be fine. Have to try it.
Hey, I'm still having some basic problems with my child windows, like cursor position whle dragging, repainting, etc. Would you be willing to take a look at my program if I posted it here (in a .zip)? or should I post code snippets?
Also, if you're interested, I could post the essentials of my multiple-children-on-one-proc method, including a really easy way to generate lots and lots of windows using only one subroutine and some data structures.
attach the complete program
i'll have a look
OK, done.
Couple warnings: I use different INCLUDE paths (didn't like the default position of MASM32 in my folder structure).
A good deal of commented-out code.
If anything doesn't make sense to you, ask me. Hopefully you'll find it pretty straightforward.
Things I'm not happy with:
- Drag the child boxes around and look what happens to their borders when you drag them over the text at the bottom. (However, dragging the box beyond the client edge restores them.)
- See how the cursor always jumps to the upper-left corner of the window.
- The background color of the drawn text is different from the window background. (Guess I need to set some more "brushes".)
at first glance, things look pretty good, for the most part
there are a couple things i notice right away, however
1) i see that you do not have the masm32 folder in the drive root
this is likely to cause you problems in the future - it can be on any drive, but should be in the root
also, it is helpful to put the "[drive]:\masm32\bin" folder in the PATH system environment variable
let me know if you need guidance, there
2) i notice the mouse position at the bottom of the window
it is pretty easy to create a status bar and use SendMessage to set the text
i will find or make a simple example after i get out of the shower :P
then, time permitting, i will look at the program again in more detail
Quote from: dedndave on October 06, 2011, 06:54:05 PM
1) i see that you do not have the masm32 folder in the drive root
this is likely to cause you problems in the future - it can be on any drive, but should be in the root
also, it is helpful to put the "[drive]:\masm32\bin" folder in the PATH system environment variable
let me know if you need guidance, there
Thanks, but I think I've got that covered. I'm using 4DOS, my old-time favorite Windows shell (so much better than the default "command window"!).
Why on earth would I want to put that stuff in my root? I can easily set paths with 4DOS (or modify them on the fly if needed). My path to MASM is f:\techstuff\masm32\bin. 4DOS has no problems finding my executables. Seems like different strokes for different folks, no? (Unless there's some potential problem with programs finding DLLs?)
Of course, there are problems with
other people's code, but I can always edit (or, my preference, lift out the "good parts" and copy them into my code).
Anyway, thanks for your help.
lol
well - have a look at masm32\include\masm32rt.inc
you will see what issues may arise
at any rate - it is a simple thing
you can just move the folder and change the path setting
no need to completely re-install masm32
Quote from: dedndave on October 06, 2011, 07:19:18 PM
lol
well - have a look at masm32\include\masm32rt.inc
you will see what issues may arise
I see what you mean. The solution is simple: don't use masm32rt.inc. I think I can figure out which include files I need in my projects. (Or I could edit the include files to tailor them to my liking.)
just make a copy of it, name it "MyMasm32rt.inc", and edit the paths :U
that way, when you want to assemble an example, you just add 2 letters "My" :P
Quote from: dedndave on October 06, 2011, 07:26:36 PM
just make a copy of it, name it "MyMasm32rt.inc", and edit the paths :U
that way, when you want to assemble an example, you just add 2 letters "My" :P
ça peut crèer pas mal de problèmes si tout le monde parle une autre langue... il y'à de bonnes raisons pq on a une certaine standardisation: ça marche!
all may be well if he runs under 4dos, and "techstuff" becomes the root
not sure how that program works
Well, yes, all is fine and dandy under 4DOS (a product of JP Software (http://jpsoft.com/) if you're interested; it's now morphed into something called "Take Command"). It's just a command shell, just like the default Windows "Command prompt". But so much nicer; has memory-based batch files (.BTMs), customizeable everything, editable PATHs, lots of other goodies. I've used it since the 1990s.
And no, I didn't make \techstuff the root; why would I want to do that? I simply set my path to point to the MASM "bin" folder (Path=F:\TECHSTUFF\MASM32\BIN). Easy peasy. All the "makeit.bat" files in the MASM32 examples work fine.
I hope I haven't opened a can of worms here; after reading jj's Masm32 page, I can see why he suggests people use the standard locations for things (so that other people can test their code). So I pledge that if I post code here that might actually be used by others, I'll take care that the path names for include files, etc., are the standard ones. For my own projects, however, I really like to be able to put things where I want them.
it's ok - you're bound to bump into problems at some point
when you do, it's an easy fix :P
here is a status bar that displays mouse position
the stuff i added to make the status bar is surrounded by "$$$$$$"
Quote from: NoCforMe on October 06, 2011, 08:16:27 PMFor my own projects, however, I really like to be able to put things where I want them.
It is a can of worms indeed. Reflect what you gain by
not having masm32 in one of your roots (you have several drives, don't you?). We use English not because everybody likes English but because it makes life so much easier...
Hey, what can I say? I don't like to be like everyone else. (I'm a 'Merkin, after all.)
i can see another problem with not using the standard location
your programs are going to require modification if other members want to assemble them
that means, when you ask for help, you may not get the response you would like :P
Quote from: NoCforMe on October 06, 2011, 08:57:26 PM
Hey, what can I say? I don't like to be like everyone else. (I'm a 'Merkin, after all.)
Merkin (http://www.urbandictionary.com/define.php?term=merkin), that sounds good ::)
Jokes apart: We are all very different from everyone else here. Honestly :thumbu
But over time we have learnt that include \masm32\include\masm32rt.inc is a fantastic start into the World of Assembly :bg
Hey, Dave, I tried adding a window to my test bed by calling CreateStatusWindow(), just like in your example, but the linker complained "undefined symbol : CreateStatusWindowA". (I copied all the INCLUDELIBs from masm32rt into my program.) Where is this object?
it can also be done using CreateWindowEx, using a class name of 'msctls_statusbar32'
but, CreateStatusWindowA is in comctl32.inc / lib
that means you should probably use InitCommonControlsEx
my little window program had that already (first thing executed)
it may not be necessary for a status bar
Assembles and links perfectly. You seem to have a problem with your includes and/or paths.
include \masm32\include\masm32rt.inc
.code
AppName db "Masm32:", 0
start: MsgBox 0, "Hello World", addr AppName, MB_OK
exit
invoke CreateStatusWindow, 0, 0, 0, 0
end start
:lol
i see Jochen is in a good mood, today :P
Well, I got it working (needed the comctl32 stuff).
So Dave, basically that whole example you linked boiled down to this, so far as setting up the status window goes:
StatusMessage DB "Mouse: X: "
StatusXpos DB "#### Y: "
StatusYpos DB "####"
NullString DB 0
...
; Create the status bar:
INVOKE CreateStatusWindow, WS_CHILD or WS_VISIBLE, OFFSET NullString, WindowHandle, $statusbarID
MOV StatusHandle, EAX
...
(in parent WndProc:)
domousemove:
; First, show current mouse position:
IF 1
PUSH EDI
MOVZX EAX, WORD PTR lParam ;EAX = X position (lParam low word)
MOV EDI, OFFSET StatusXpos + 3
CALL B2Asc
MOVZX EAX, WORD PTR lParam + 2 ;EAX = Y position (lParam high word)
MOV EDI, OFFSET StatusYpos + 3
CALL B2Asc
INVOKE SendMessage, StatusHandle, SB_SETTEXT, 0, offset StatusMessage
POP EDI
(I left out the stuff for resizing the window, which just goes in the handler for WM_SIZE.) That's pretty much it.
I will say it's a heck of a lot nicer display than what I had. I'll keep it.
By the way, I got "gotcha!"-d by the weird way you do your binary-to-ASCII conversion. Couldn't figure out why it looked so funky until I saw that you start at the right side of the number and work leftwards. (Hence the + 3s in the code.)
Regarding the resizing stuff, it's kind of funny to watch what happens when you resize the window without that code. The status bar just hangs there, orphaned.
So I added zero-suppression to your binary-to-ASCII routine (I don't like leading zeroes):
;====================================================================
; B2A4
;
; Converts binary value to ASCII numeric digits (4 digits, limited to
; maximum value of 9999). Result is leading-zero suppressed.
;
; On entry,
; EAX = value to convert
; EDI--> place to store digits (4)
;
; Return value: (none)
;
;====================================================================
B2A4 PROC
MOV ECX, 4 ;4 digits
b2a10: PUSH ECX
MOV ECX, 10
XOR EDX, EDX
DIV ECX
OR DL, '0' ;Binary--> ASCII
POP ECX
MOV [EDI], DL
DEC EDI
LOOP b2a10
; Now do leading-zero suppression:
MOV ECX, 3 ;Look @ 1st 3 digits
b2a20: INC EDI
CMP BYTE PTR [EDI], '0'
JNE b2a499 ;Stop on 1st non-zero digit.
MOV BYTE PTR [EDI], ' '
LOOP b2a20
b2a499: RET
B2A4 ENDP
(Edit: fixed bad code. Hate bad code!)
[interjection] use a text editor which allows convertion of tabs to spaces -> before posting code, make a convertion ... just for reasons of readability :8)[/[interjection]
Uh oh; bigger problem.
Adding your status bar (which works) makes all my child windows go "Poof!" when I click on them.
WTF?????
I'm starting to think that there's something fundamentally wrong with the way I'm creating these little windows. Probably something having to do with the window styles, or the extended window style.
Thinking about it, in a "normal" window--that is, one with a title bar--you can only grab the window with the cursor by the title bar. But my windows can be moved by dragging inside them (I guess because that's the way I detect that the user wants to move them, by using DragDetect() and then capturing the mouse). But as I indicated earlier, the cursor always jumps to the upper-left corner when they're being dragged. So the "hot spot" must be that corner. Which makes me unsure just what kinds of windows these really are.
Quote from: qWord on October 06, 2011, 10:43:15 PM
[interjection] use a text editor which allows convertion of tabs to spaces -> before posting code, make a convertion ... just for reasons of readability :8)[/[interjection]
Is that the convention around here? I personally hate spaces (they're just "empty calories" in text files), but I notice that all the code examples here seem to use them. I'm guessing the reason is that there's no agreed-upon convention for tab spacing (I use 8, others use 4).
Is this really a problem?
Like I wrote earlier, I'm willing to follow conventions if I ever post any code worthy of other people using it.
well - i don't see anything that hits me in the face as far as the problems you describe
i do have a few helpful tips, though
first, the use of the $defStatTxt macro is a bit confusing, and probably unnecessary
you define the structure:
$ST STRUCT ;Static text structure
$st_X DD ?
$st_Y DD ?
$st_w DD ?
$st_h DD ?
$st_text DD ?
$st_ID DD ?
$ST ENDS
all is good, there, although i would probably reduce the names a little
$ST STRUCT ;Static text structure
X DD ?
Y DD ?
w DD ?
h DD ?
text DD ?
ID DD ?
$ST ENDS
in the macro...
$defStatTxt MACRO tname, txt, x, y, w, h, ID
LOCAL sname
sname DB &txt, 0 ;Declare the string
tname $ST <x, y, w, h, OFFSET sname, ID> ;Declare the structure
ENDM
not sure i would use a macro for this
anyways - the structure is all dwords - nice if they were dword aligned
by placing a variable-length string at the beginning, it doesn't happen
you already have a structure member that is a pointer to the string
if the array were all $ST structures, and the string data was seperate, everyone would be aligned
another way might be to align the structure definition and place the string at the end
$ST STRUCT 4 ;Static text structure
X DD ?
Y DD ?
w DD ?
h DD ?
text DD ?
ID DD ?
$ST ENDS
notice the "$ST STRUCT 4"
that means everyone is dword aligned
then, in the macro, place the string after the structure
personally, i would probably seperate the string data from the dword structure array
it makes it easy to index mathematically (even easier if each struct had 8 dword members :P )
@ST_Font $ST <10, 14, 40, 20, szFont, 401>
@ST_mouse $ST <10, 250, 300, 20, szMouse, 402>
@ST_mousebtn $ST <109, 250, 30, 20, szMouseBtn, 403>
@ST_mouseX $ST <205, 250, 40, 20, szMouseX, 404>
@ST_mouseY $ST <265, 250, 40, 20, szMouseY, 405>
szFont db 'Font:',0
szMouse db 'Mouse: lbutton down pos: x: y: ',0
szMouseBtn db 'up',0
szMouseX db '#####',0
szMouseY db '#####',0
at any rate, addressing structure members can be simplified
CreateStaticText PROC stPtr:DWORD
; Returns window handle in EAX.
MOV EBX, stPtr
INVOKE CreateWindowEx, WS_EX_LEFT, ADDR STclassName, [EBX + OFFSET $ST.$st_text], $STattrs,
[EBX + OFFSET $ST.$st_X], [EBX + OFFSET $ST.$st_Y],
[EBX + OFFSET $ST.$st_w], [EBX + OFFSET $ST.$st_h], WindowHandle,
[EBX + OFFSET $ST.$st_ID], InstanceHandle, 0
RET
CreateStaticText ENDP
for example,
[EBX + OFFSET $ST.$st_text]
can be
[EBX].$ST.$st_text
or, you can use ASSUME
CreateStaticText PROC stPtr:DWORD
; Returns window handle in EAX.
ASSUME EBX:Ptr $ST
MOV EBX, stPtr
INVOKE CreateWindowEx, WS_EX_LEFT, ADDR STclassName, [EBX].$st_text, $STattrs,
[EBX].$st_X, [EBX].$st_Y,
[EBX].$st_w, [EBX].$st_h, WindowHandle,
[EBX].$st_ID, InstanceHandle, 0
RET
ASSUME EBX:Nothing
CreateStaticText ENDP
i also notice that the main window has the WS_EX_OVERLAPPEDWINDOW style
not really needed if you use WS_OVERLAPPEDWINDOW
for the main window, i would also use WS_CLIPCHILDREN - that helps paint - keeps the thing from flickering, too
not sure why you enumerate fonts
it is easy to use SystemParametersInfo with SPI_NONCLIENTMETRICS to get the user-selected fonts
then, set the size you want and CreateFont using the LOGFONT in the NONCLIENTMETRICS structure
i will look at the program some more tomorrow
you said you had trouble when you added a status bar
perhaps you could post the updated program for me to work with
Hey, thanks for looking at my code.
1. Re: structure member names: I guess I got so used to naming the members the same as the structure (like $ST_text) that I didn't realize this was totally unnecessary, as you never use just the member name alone. So thanks for the tip. (You can see I like descriptive names, but why not save some typing?)
2. Re: my scheme for declaring structures containing text with a macro: Yes, having variable-length text embedded in what would otherwise be a nice DWORD-aligned structure is not good. I thought about that too. The reason I did things this way was to try to do the whole declaration thing in one fell swoop. The macro allocates the text, declares the structure, plugs in the elements, and uses the first macro argument as the name of the finished structure. Makes declaring lots of static-text items really easy.
Couple things come to mind: one is to declare the strings separately from the structures, put them in a heap, and let the structures line up nicely.
Another way would be to insert alignment statements after the string, to bring the next element to a WORD or DWORD boundary. Of course, that wastes a little space, not much.
3. Turns out there are at least 3 ways to reference structure members with a pointer register:
MOV EAX, [EBX + OFFSET $ST.text]
MOV EAX, [EBX + $ST.text]
MOV EAX, [EBX.$ST.text]
I've settled on the 2nd one. Don't like the last one 'cause the dot between reg and struct name just looks plain weird to me. But not having to include OFFSET in every dang one is an improvement. (This, of course, is a matter of style, not of programming accuracy.) I like the "+" operator. By the way, you'll notice that I combine bitwise flag values with "+" instead of "OR", just because it's more intuitive for me (OR looks to me like "hmm, I either get this value or that value or that value"). Of course, the result is exactly the same, and it's my program, so I'll keep on doing it that way, thank you very much.
4. I'm listing fonts as part of another project, where I want to be able to select from any installed font. Actually, that was the first Windoze thing I got working (ever!), and was pretty happy when it all came together. Are you saying there's an easier way to do font enumeration than EnumFontFamiliesEx()?
5. That business of the status bar killing my child windows was, of course, just a stupid error on my part (I wasn't computing the mouse X and Y before trying to move the window, so of course it just went into the bit bucket). Fixed now.
I want to wait until I get the resize code working before I give you another copy. Speaking of which, could you please explain the following from that program (SmallWin) you attached?
SizeWin:
mov ecx,[esp+8] ;ECX = hWnd
sub esp,sizeof RECT
INVOKE GetClientRect,ecx,esp
pop eax
pop edx
pop ecx
sub eax,ecx ;EAX = client height
pop ecx
sub edx,ecx ;EDX = client width
mov ecx,StbHeight
sub eax,ecx
INVOKE MoveWindow,hStatus,0,eax,edx,ecx,TRUE
I have no idea what's going on with all that stuff pulled off the stack. How can you keep track of that stuff? It's totally non-intuitive. (I can see that you're getting the client RECT structure, then doing some arithmetic with the window size, then passing it to MoveWindow()). If you could explain what's what in there, I'd appreciate it. I really do not have the patience to try to unravel the stack to see which register corresponds to which parameter.
Anyhow, thanks again for all the help.
3. yah - this is really a matter of personal taste :P
i have gotten used to [reg].structtype.member
a habit i picked up from qWord, i think
4. well - there are a number of caveats to enumerating fonts - good you got it working, actually :U
you may also want to look into ChooseFont - there are 1 or 2 examples in masm32\examples
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646914%28v=vs.85%29.aspx
5. well - i create a temporary RECT structure on the stack (without using LOCAL)
sub esp,sizeof RECT
after the call, i pop the RECT members into registers - it makes for small code
what i am really after, there, is the position and size for the status bar
so - i get the RECT for the client
the X position for the status bar is always 0
the Y position is the client height minus the status bar height (client height = bottom minus top)
the width is the same as the client width (client width = right minus left)
the height is the height of a status bar (measured and stored in StbHeight during WM_CREATE)
now that i think about it, that code could be simpler
because the left and top are always 0 :P
so - the first 2 SUB instructions could be removed, i guess
as for the stack stuff, you'll get used to it
the win32 API always passes parameters on the stack
so - it is something you'll see a lot of
also, the stack is a great place for small temporary allocations
fast - small code to access it
New .zip of source & exe is attached.
You'll notice there's still the problem of the child window borders getting messed up. Since you can drag them over the status bar, try that and see what happens to them.
Speaking of the status bar, it's working fine (including resizing--piece of cake). However, one thing I don't like: I tried to adjust the clipping rectangle I used to clip the cursor by subtracting the height of the status bar, but it doesn't seem to work correctly:
INVOKE GetWindowRect, hWin, ADDR gpRect
; Adjust clipping rectangle to exclude status bar:
MOV EAX, SBheight
SUB gpRect.bottom, EAX
INVOKE ClipCursor, ADDR gpRect
I can't be sure, but it looks as if the clip area may be correct, but the child windows can extend below it by their height (in other words, since the window is being dragged by the upper-left corner (0,0), the rest of the window goes out of the clip area. Or something like that. Yet more evidence that I'm doing something wrong with the children.
it appears that you attached the old version :P
whoops, sorry 'bout that.
Regarding the problems I'm having with constraining the mouse (ClipRect() and all that), seems to me that it's probably working correctly, but the problem lies elsewhere. The cursor is being correctly constrained; it cannot go beyond the client area. But since the child window is being dragged by its ear (0,0), it extends beyond the bottom and right of the client area.
What I want is an object that will be constrained within the client area. In other words, when any edge of the object bumps into the edge of the client area, I want the object to stop moving.
; Now do leading-zero suppression:
MOV ECX, 3 ;Look @ 1st 3 digits
b2a20: INC DI
CMP BYTE PTR [EDI], '0'
JNE b2a499 ;Stop on 1st non-zero digit.
MOV BYTE PTR [EDI], ' '
LOOP b2a20
i am a little surprised this assembles :bg
b2a20: INC DI
i guess it just puts a size override byte in there - hope we don't wrap a 64 kb boundry :P
one solution that comes to mind would be to create a large child window that does not include the drop-down and status bar
then, create the little windows under that one
i have done this in the past to prevent scroll bar flicker
B2A4 PROC
MOV ECX, 4 ;4 digits
b2a10: CMP CL,4
JZ b2a11
OR EAX,EAX
JZ b2a12
b2a11: PUSH ECX
MOV CL, 10
XOR EDX, EDX
DIV ECX
OR DL, '0' ;Binary--> ASCII
POP ECX
MOV [EDI], DL
DEC EDI
LOOP b2a10
RET
b2a12: MOV BYTE PTR [EDI],20h
DEC EDI
LOOP b2a12
RET
B2A4 ENDP
i should mention - the LOOP instruction is slow in 32-bit world
we generally use DEC ECX/JNZ
however - speed isn't super critical here
Quote from: dedndave on October 07, 2011, 06:52:25 PM
one solution that comes to mind would be to create a large child window that does not include the drop-down and status bar
then, create the little windows under that one
i have done this in the past to prevent scroll bar flicker
So like this?
Main window--> big child window--> little kid windows?
The big child window would have no title bar, no resizeable borders, just a big (borderless?) "playground" for the small children.
Would respond to resize messages just like the status bar (handled in parent).
Seems to make sense.
By the way, I think your latest B2A routine needs a little work ...
it seems to work ok - i just tried it for the first go - lol
i may have missed something
the point was, though, why convert them after the fact ?
if the dividend is 0, fill the rest in with spaces
of course, you want the first 0, in case the value is 0
there are far more efficient ways to do this - it was a down-and-dirty approach :P
yes - a child window with no border or title - the style would be "WS_VISIBLE or WS_CHILD or WS_CLIPCHILDREN"
which, btw - i see you using "+" to add flags together
this will byte you in the ass - lol
use "OR" :U
you write a seperate WndProc for it - of course, one more class to register, too
in a way, it makes it nice because you put all the child stuff in one WndProc and the main window in another
should make it a little easier to read
you can combine them into one, but it's not worth the effort
when the main window is resized, you set the size for the "master" child
that code can be combined with the status bar size code
the problem with the little windows seems to be that they are not being redrawn entirely
we must be missing a style bit someplace :bg
Quote from: dedndave on October 07, 2011, 07:13:35 PM
yes - a child window with no border or title - the style would be "WS_VISIBLE or WS_CHILD or WS_CLIPCHILDREN"
which, btw - i see you using "+" to add flags together
this will byte you in the ass - lol
Side issue, but I disagree: how do you suppose that there's any difference between 'X or Y or Z" and "X + Y + Z" when they're all unsigned quantities?
I already explained eariler why I do this.
I do realize that there are places where this would byte one in the ass. This isn't one of them. No problems with overflow here.
Quote from: dedndave on October 07, 2011, 07:25:42 PM
the problem with the little windows seems to be that they are not being redrawn entirely
we must be missing a style bit someplace :bg
\
Yes! I'm sure that's at least part of the problem.
Gotta leave now, but when I come back I'll go through the code and extract all the style settings and put them in a message. There's some kind of conflict somewhere, I'm sure.
ok - rock on :P
let me think of an example....
try this...
mov eax,WS_OVERLAPPEDWINDOW+WS_SYSMENU
print str$(eax),13,10
mov eax,WS_OVERLAPPEDWINDOW or WS_SYSMENU
print str$(eax),13,10
Quote from: NoCforMe on October 07, 2011, 07:27:20 PM
Side issue, but I disagree: how do you suppose that there's any difference between 'X or Y or Z" and "X + Y + Z" when they're all unsigned quantities?
Good example, Dave. In many cases - see first three below - Windows shows benign behaviour because only 1 bit is set for each constant. It is the exceptions that will let your code go bang. Chasing such bugs is a nightmare...
WS_VISIBLE = 00010000000000000000000000000000
WS_CHILD = 01000000000000000000000000000000
WS_CLIPCHILDREN= 00000010000000000000000000000000
WS_OVERLAPPEDWINDOW= 00000000110011110000000000000000
WS_SYSMENU= 00000000000010000000000000000000
Sys or OverLap= 00000000110011110000000000000000
Sys + OverLap= 00000000110101110000000000000000
well - there are better examples, but that one was easy to come up with - lol
the thing is....
like Jochen says, trying to find this bug will make you pull your hair out
OK, jj, you convinced me. I guess I'm just used to working with single-bit flags in my own code. OR it is.
I'm still having to break myself of my 16-bit habits, like that INC DI in the b2a routine. Still seems strange to type things like EAX, EDX, etc. And realize that PUSH and POP expect 32-bit entities, not 16-bit.
=====================================================
Regarding my child-window problem, before I code another layer of window like you suggested, let's think about this a moment. The problem is that the child windows' borders aren't being redrawn (or not redrawn properly): why is this? Is it something I'm doing or not doing in my program? or do I have the wrong styles somewhere?
I'd like to understand what's actually wrong here, rather than just start throwing darts at the dartboard, if you know what I mean.
I'll wait until you (Dave) have had a chance to look at my newest program.
I made a small improvement to your routine:
B2A4 PROC
MOV ECX, 4 ;4 digits
JMP SHORT b2a11
b2a10: OR EAX, EAX
JZ b2a12
b2a11: PUSH ECX
MOV CL, 10
XOR EDX, EDX
DIV ECX
OR DL, '0' ;Binary--> ASCII
POP ECX
MOV [EDI], DL
DEC EDI
LOOP b2a10
RET
b2a12: MOV BYTE PTR [EDI], ' '
DEC EDI
LOOP b2a12
RET
B2A4 ENDP
Do you see what it is? (Hint: it gives a tiny speed improvement as well as code size reduction.)
there ya go :P
let me find another one...........
some code by drizz...
http://www.masm32.com/board/index.php?topic=12234.msg93949#msg93949
i squeezed 2 clock cycles out of it - lol
B2Asc PROC
push ebx
mov edx,4294968 ;2^32/1000
mov ebx,10 ;per digit
mul edx ;extend first digit
mov ecx,edx ;digit 1 in CL
mul ebx ;second digit
mov ch,dl ;digit 2 in CH
mul ebx ;third digit
bswap ecx ;digits 1 & 2 up high
mov ch,dl ;digit 3 in CH
mul ebx ;digit 4 in DL
lea ecx,[edx+ecx+'0000'] ;combine and make ASCII
bswap ecx ;re-order bytes
pop ebx
ret
B2Asc ENDP
you'll want to take out the EDI stuff from the calling code
you still call it with the value in EAX, but you have to place the results from ECX when done
mov eax,9999
call B2Asc
mov SomeLabel,ecx
it takes about 30 clock cycles :bg
MOV EAX, lParam ;Yep, get new X & Y pos.
MOV EDX, EAX ;Make a copy for later
AND EAX, 0FFFFH ;Mask off high word
CWDE ;Sign-extend to DWORD
MOV pt.x, EAX
MOV EAX, EDX ;Get back copy
SHR EAX, 16 ;High word--> low word
CWDE
MOV pt.y, EAX
i just noticed your code here :P
ouch !
replace all of this...
domousemove:
; First, get current mouse position (from lParam):
MOV EAX, lParam ;Yep, get new X & Y pos.
MOV EDX, EAX ;Make a copy for later
AND EAX, 0FFFFH ;Mask off high word
CWDE ;Sign-extend to DWORD
MOV pt.x, EAX
MOV EAX, EDX ;Get back copy
SHR EAX, 16 ;High word--> low word
CWDE
MOV pt.y, EAX
; Display current pos:
PUSH EDI
MOV EAX, pt.x
MOV EDI, OFFSET StatusXpos + 3
CALL B2A4
MOV EAX, pt.y
MOV EDI, OFFSET StatusYpos + 3
CALL B2A4
INVOKE SendMessage, StatusHandle, SB_SETTEXT, 0, offset StatusMessage
POP EDI
and this
B2A4 PROC
MOV ECX, 4 ;4 digits
b2a10: CMP CL,4
JZ b2a11
OR EAX,EAX
JZ b2a12
b2a11: PUSH ECX
MOV ECX, 10
XOR EDX, EDX
DIV ECX
OR DL, '0' ;Binary--> ASCII
POP ECX
MOV [EDI], DL
DEC EDI
LOOP b2a10
RET
b2a12: MOV BYTE PTR [EDI],20h
DEC EDI
LOOP b2a12
RET
B2A4 ENDP
with this
domousemove:
movzx eax,word ptr lParam
push ebx
mov pt.x,eax
call B2As4
movzx eax,word ptr lParam+2
mov dword ptr StatusXpos,ecx
mov pt.y,eax
call B2As4
mov dword ptr StatusYpos,ecx
pop ebx
INVOKE SendMessage,StatusHandle,SB_SETTEXT,0,offset StatusMessage
and this
B2As4 PROC
mov edx,4294968 ;2^32/1000
mov ebx,10 ;per digit
mul edx ;extend first digit
mov ecx,edx ;digit 1 in CL
mul ebx ;second digit
mov ch,dl ;digit 2 in CH
mul ebx ;third digit
bswap ecx ;digits 1 & 2 up high
mov ch,dl ;digit 3 in CH
mul ebx ;digit 4 in DL
lea ecx,[edx+ecx+'0000'] ;combine and make ASCII
bswap ecx ;re-order bytes
ret
B2As4 ENDP
it probably does both strings in about the same time as a single DIV instruction - lol
(not including the SendMessage)
you'll have to use .586 (or .486) instead of .386
Well, OK. But remember that at this point the plan is to get this working, not super-optimizing it. It'll be a while before this goes to market ...
yah - sorry about that - can't help it - lol
i notice the status message stops updating when the cursor is over one of the child windows
that's because the child proc gets the messages
we can fix that, easy enough
at this point, i may take a different tack
As promised, style definitions:
- Main window: WS_OVERLAPPEDWINDOW OR WS_CLIPCHILDREN
- Main window extended: WS_EX_OVERLAPPEDWINDOW
- Child windows: WS_BORDER OR WS_CHILD OR WS_VISIBLE
- Child windows extended: WS_EX_WINDOWEDGE
- Status bar: WS_CHILD OR WS_VISIBLE
That's it. Pretty vanilla.
my problem up til now has been trying to understand everything you are doing
it is consuming too much time :P
so - i am going to take one of my little "standard" window programs...
first, i'll confine the mouse movement when it's being dragged
then, i'll put 2 static text boxes on it and make it so you can drag one over the top of the other
after that, i'll make it so the boxes, themselves, are confined to the client area
these are all things that i have not had to do yet - lol
it's sort of a "start at the beginning and make each step work" approach
by using one of my own window programs, i do not have to spend time familiarizing myself with someone elses code
before i start working on that, i added leading zero suppression to the B2As4 routine above...
B2As4 PROC
mov edx,4294968 ;2^32/1000
mov ebx,10 ;per digit
mul edx ;extend first digit
mov ecx,edx ;digit 1 in CL
mul ebx ;second digit
mov ch,dl ;digit 2 in CH
mul ebx ;third digit
bswap ecx ;digits 1 & 2 up high
mov ch,dl ;digit 3 in CH
mul ebx ;digit 4 in DL
lea ecx,[edx+ecx+'0000'] ;combine and make ASCII
bswap ecx ;re-order bytes
cmp cl,30h
jnz B2As42
cmp ch,30h
jnz B2As41
test ecx,0F0000h
jnz B2As40
and ecx,03F202020h
ret
B2As40: mov cx,2020h
ret
B2As41: mov cl,20h
B2As42: ret
B2As4 ENDP
here's a function we can use :U
http://msdn.microsoft.com/en-us/library/windows/desktop/ms648383%28v=vs.85%29.aspx
btw, i don't think i caught your name ?
and, that's step 1
i even made it stay above the status bar :P
(only when left button is down, of course)
Quote from: dedndave on October 08, 2011, 05:34:15 AM
here's a function we can use :U
http://msdn.microsoft.com/en-us/library/windows/desktop/ms648383%28v=vs.85%29.aspx
Already in there. Look in WindowProc, under "domousemove".
Quote from: NoCforMe on October 08, 2011, 06:34:05 AM
Already in there. Look in WindowProc, under "domousemove".
Yep, ClipCursor is there. Can't test it, though - Error A2087: Cannot open include file '\techstuff\masm32\include\kernel32.inc'
Well, sorry about that. I guess at this point I had planned on playing this game (learning assembly language forWindows) my way, by my rules, on my computer. I hadn't envisioned joining a "community" just yet.
You could just change the include statement. The program does assemble and link OK.
OK, here's a copy with the standard includes ("\masm32\include ...") just for you. It should be build-able. Then you can see the problem with moving the child windows.
Interesting.
If anyone out there is actually playing with my little testbed program, notice the difference between using
INVOKE InvalidateRect, ChildHandle, NULL, TRUE
and
INVOKE RedrawWindow, ChildHandle, NULL, NULL, RDW_FRAME OR RDW_INVALIDATE
immediately after using MoveWindow() on the child window.
You can use conditional assembly to make testing easier:
Quotedm10: INVOKE MoveWindow, ChildHandle, pt.x, pt.y, $childWidth, $childHeight, TRUE
UseInvRect = 1
if UseInvRect
INVOKE InvalidateRect, ChildHandle, NULL, TRUE
else
INVOKE RedrawWindow, ChildHandle, NULL, NULL, RDW_FRAME OR RDW_INVALIDATE
endif
Case 1 redraws the background after moving the child over the status bar, case 0 doesn't.
Thanks; that makes sense, and jibes with what actually happens.
Can someone tell me exactly what kind of windows I've created here? They don't seem to fit the categories of windows that I see described in the references (MSDN). The strangest part of their behavior is how the mouse cursor always attaches itself to the upper-left corner. (Although this may be a side effect of doing something wrong in my window-moving code.) It behaves like there's a one-pixel "handle" at (0,0).
Here's what I actually want: small windows that I can drag by clicking anywhere in the interior of the window, and resizeable. (Resizing is easy: just add the WS_SIZEBOX style. Of course, for some WEIRD reason, this also forces the box to acquire the WS_THICKFRAME style.)
Let me tell you what I'm after here: I thought, perhaps a little grandiosely, that I might create a tool to create resource templates. Like the resource editors in Visual {xxx}, but much simplified. So the child windows could represent fixed-text items, for instance. I want to be able to position them, resize them (by grabbing their frames), and to put stuff in them (like text, maybe even bitmaps). So what kind of child windows do I want? I'm starting to suspect that this will require owner-draw controls to do it properly. Haven't learned that yet ...
Quote from: NoCforMe on October 08, 2011, 09:48:15 AM
Can someone tell me exactly what kind of windows I've created here? They don't seem to fit the categories of windows that I see described in the references (MSDN). The strangest part of their behavior is how the mouse cursor always attaches itself to the upper-left corner. (Although this may be a side effect of doing something wrong in my window-moving code.) It behaves like there's a one-pixel "handle" at (0,0).
You need the initial position of the mouse, and then use an offset for MoveWindow.
Quote
for some WEIRD reason, this also forces the box to acquire the WS_THICKFRAME style.)
You can get rid of the thick frame by subclassing and capturing the nc paint message.
BTW, check RDW_FRAME OR RDW_INVALIDATE or RDW_ERASE
the windows are Static Controls
they are a special window because the OS has predefined the class for them
the OS also provides the WndProc for these special control classes
typically, they are used in dialog boxes
you can create them by using CreateWindowEx, just as any other window
but, you do not have to register the class, just use the string 'Static' as the class name
http://msdn.microsoft.com/en-us/library/windows/desktop/bb773173%28v=VS.85%29.aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/bb773169%28v=VS.85%29.aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/bb760769%28v=VS.85%29.aspx
likewise, you can register your own class and make them any way you like
you then have to provide the WndProc code
once i get my static controls in there, i will be able to constrain the box inside the client
this will be done by using the mouse position when WM_LBUTTONDOWN is received
and by subtracting the complimentary window dimensions from the clip rectange
reading through some of the previous posts, here...
QuoteI guess at this point I had planned on playing this game (learning assembly language forWindows)
my way, by my rules, on my computer. I hadn't envisioned joining a "community" just yet.
:bg
i look at it this way...
i am in the "learn mode"
once i have learned everything there is to know about windows, i can do it however i like
unfortunately, i probably won't live that long :P
QuoteI want to be able to position them, resize them (by grabbing their frames), and to put stuff in them
(like text, maybe even bitmaps). So what kind of child windows do I want? I'm starting to suspect
that this will require owner-draw controls to do it properly.
well - we don't want static controls, then
they are meant to be, well, static :bg
you could almost use an MDI arrangement - a bit clumsy for some of the controls you will want to add
i think if i were doing what you want to do,
i would use a sizable window for each type of control that the user may want to add
that means they will have borders while many of the controls do not
anyways, you put the type of control they ask for inside the sizing window and size the control when they size the window
you could create a class for each control type, each with a special WndProc
they ask for a slider, your "slider-class" WndProc handles all the stuff that is appropriate for a slider
they ask for a button, your "button-class" WndProc handles all the stuff that is appropriate for a button
Just to make things clear (because this thread is starting to get confused, and I'm not sure you really understand what I'm after here, or what my knowledge of assembly language is): are you suggesting that I create these controls as small child windows, like what I have now, but with other controls (text, bitmaps, etc.) inside them? I did want one type to be a static-text control
creator (
not a static control in and of itself--get it?) that would allow the user to type text into it.
Currently, the child windows are
not static-text windows. (I removed all the static-text stuff when I pulled that font-selection combo box out.)
Again, I need a type of window that:
- Allows the user to grab it and move it at any point, inside or on the edge;
- Is resizeable (I know how to do that)
- Can accept text or bitmap images
- Is properly repainted when it goes behind other objects or under the status bar.
For now I think I can live with the child window being able to be dragged beneath the status bar; not a huge deal.
I'd really like to get this right from the get-go, both for the sake of my learning, and to get the bugs worked out before I get a big, complicated application going and have to debug it. So it's important that I understand what's going on conceptually, as well as how it's implemented.
I'm almost convinced that this needs to be an owner-draw type of window. Any suggestions in this area appreciated.
I looked through Iczelion's tutorials, but there doesn't seem to be much on this subject specifically. (Bits and pieces here and there.)
yes - i think what you are after is a button that looks like a button
if they ask for an edit box, it looks like an edit box
then, they can size and place them as desired
i have something in works - it only supports buttons and trackbars (sliders)
but, that should be enough to build on by adding the other control types
when they add a slider, it opens a sliderWin
they can size that window however they like
when they do, the slider that is inside it will size with the window (always filling the window)
same for buttons, except it opens a buttonWin
now, let's take buttons as an example
besides the size and location, there are other attributes like text, color, control ID number
you can handle it however you like - i was thinking if they right-click on it, a dialog comes up and lets them set those
i was going to point you at Ketil Olsen's ResEd program, but i am having a hard time finding a link
you might get some ideas from his program
here you go
http://www.oby.ro/rad_asm/resed/index.html
Ketil is a very powerful windows programmer :U
I'm still not clear what you're suggesting. You're saying make the control a button: is that the containing window? Isn't a button a type of control?
I thought what you were saying was to create a child window, then put a control (slider, edit control, whatever) inside it. Is that it?
(Regarding your link) Yes, that looks like what I'm after (although I'm thinking of a much more modest program!). It looks like you can download the app for free (which is nice), but not the source. But yes, that's the idea.
QuoteI thought what you were saying was to create a child window, then
put a control (slider, edit control, whatever) inside it. Is that it?
yes - that's the idea
you could have a right-click context menu, too - they are easy to implement :P
if they right-click on a button window, it gives them a list of things they can edit for that type of control
just a few thoughts
The other cool and free Asm IDE is WinASM. It is now open source, you could DL that and see how they do it. http://www.winasm.net/forum/index.php?showtopic=3713
Dave, I should first say thank you--that was exactly what I was looking for!
OK, I don't have to write this app now; forget everything I said.
Just kidding. I still want to know how to do this. Yes, source is included, but wow: this is one hell of a complicated program.
The controls are EXACTLY what I was looking for. When you create a new control, you get box with the name of the control type (e.g., IDC_CHK) in it, plus a graphic of the control (checkbox, radio button, etc.). When you select the control, you see 9 resize handles, and you can grab it and put it anywhere you want to.
Anyone want to download this and tell me just where this happens in the code? (Hint: I think it's somewhere in the file DlgEdt.asm.)
Anyhow, I'll have fun playing with this and looking through the code.
oops - wrong thread :P
Dave, did you send him the source? Is he to be trusted to be in our "secret" society :bdg
I would think it is in CreateCtl but that is as far as I will go. AFAIK, ResEdit NOR RadASM is open source, so I won't discuss modifying the source here.
Believe me, I have no desire to modify that source! Angels fear to tread and all that.
I'd like to learn how it works, and I might borrow stuff from it for my own code.
So what or where is CreateCtl? Can't find that in any of the .asm files.
yah - and Ketil's source files are nice to read, too :P
let me see if i can find his old text editor as an example....
dang - can't find it
That is why I posted the link to WinASM, it is a similar IDE and became open source recently.
well, so far, i can make sizable boxes :P
(http://img525.imageshack.us/img525/3434/re1m.png)
i had to use WS_CLIPSIBLINGS - that may be the problem on your other program
Quote from: dedndave on October 09, 2011, 06:07:07 PM
i had to use WS_CLIPSIBLINGS - that may be the problem on your other program
Well, I tried that, and it didn't fix the problem I'm having.
However: the plot thickens.
Currently my little child windows are resizeable. If I drag one
without resizing it, it gets repainted correctly after being drug under the status bar. But if I resize it, then it gets messed up when you do this.
Does this give anyone a clue as to what's going on here?
i was having problems when creating a new child
the new one was underneath any previously created child (if they overlapped)
instead of using MoveWindow to change the window position, try using SetWindowPos
this function has some flags that allow you to control the Z-order, as well as certain aspects of the redraw process
most notably, a flag for SWP_DRAWFRAME
using SetWindowPos after window creation solved my Z-order problem
i had already tried SetForegroundWindow, SetFocus, SetActiveWindow, EnableWindow :P
these are the style flags i am using for child windows
WS_CHILD or WS_THICKFRAME or WS_VISIBLE or WS_CLIPSIBLINGS
maybe i am missing one - i would have thought the newly created window would be on top
I tried that (SetWindowPos() instead of MoveWindow()). Interesting: it fixed the border-drawing problem.
But it created a new problem: the text inside the child window isn't redrawn until you release the mouse button. ??????
Further investigation required.
(The flags I used are SWP_DRAWFRAME OR SWP_NOSIZE OR SWP_NOZORDER OR SWP_SHOWWINDOW, since I wasn't changing either the window size or its Z-order.)
hmmmm - interesting
you might try using HWND_TOP for the hWndInsertAfter parameter
then, play with the uFlags parameter, starting with just the SWP_SHOWWINDOW flag
it sounds as though you have the SWP_NOCOPYBITS flag set, which you do not
maybe the SWP_DRAWFRAME causes it to draw just the frame :P
i haven't got to the text part yet - lol
i do have boxes that size properly
when you left click on a box (including its sizing border), it comes to the top
i was just working out a strategy for moving the boxes
as far as i can see, there should be no need for DragDetect
when you get a WM_MOUSEMOVE message, bit 0 of wParam tells you if the left button is up or down
if it is up, you simply update the cursor position in the status bar and exit
if it is down, you do that, then move the box, as well
sounds simple enough :bg
oh - you might check your display settings - just to make sure...
Display Properties
Appearance tab
Effects button
be sure you have the "Show window contents while dragging" box checked
Quote from: dedndave on October 10, 2011, 04:18:09 AM
you might try using HWND_TOP for the hWndInsertAfter parameter
Tried it, no improvement.
Quotethen, play with the uFlags parameter, starting with just the SWP_SHOWWINDOW flag
it sounds as though you have the SWP_NOCOPYBITS flag set, which you do not
maybe the SWP_DRAWFRAME causes it to draw just the frame :P
Yep, that flag fixed the no-text problem, but now the messed-up borders are back!
Quoteas far as i can see, there should be no need for DragDetect
when you get a WM_MOUSEMOVE message, bit 0 of wParam tells you if the left button is up or down
if it is up, you simply update the cursor position in the status bar and exit
if it is down, you do that, then move the box, as well
sounds simple enough :bg
But what if you just click in the window without moving the mouse? I guess no harm, no foul, eh? Although I don't think DragDetect() is my problem.
Quoteoh - you might check your display settings - just to make sure...
Display Properties
Appearance tab
Effects button
be sure you have the "Show window contents while dragging" box checked
In Win2K, it's in the Effects tab, but it's checked in any case.
well - it was worth a shot :P
notice that the hWndInsertAfter parameter is only valid without the SWP_NOZORDER flag set
SetWindowPos is like MoveWindow on steroids - lol
tomorrow, i should have a sizable, movable button
i will be able to see how it behaves with text, then
Hey, Dave, wondering if you could do me a flavor: Could you go through the source for ResEd and find out where the code is that creates controls (like, say, when you add a text control to a dialog)? Whatever is done in there works 100%, so it might be useful to find out just how it's being done.
I've looked through the code, and MEGO. How could you say that that's good code? There's hardly a single comment in it (the only ones I could find were labels when data types were being defined). Since we can't read the author's mind, it's very difficult to figure out what's being done.
there are a number of programs named "ResEd" and "ResEdit"
are you refering to Ketil's program ?
where did you get the source ?
btw, here are a couple others...
http://www.resedit.net/
http://www.wilsonc.demon.co.uk/d10resourceeditor.htm
the later has source, but it's in Delphi :P
still, you can see what functions are called
Quote from: dedndave on October 10, 2011, 06:20:44 PM
there are a number of programs named "ResEd" and "ResEdit"
are you refering to Ketil's program ?
where did you get the source ?
It's the one you pointed me to in post #82 (http://www.masm32.com/board/index.php?topic=17487.msg147123#msg147123l). The package includes all the source. (Or I guess I downloaded the source separately, but it's all there.)
ok - that is Ketil's program
his own site is down, but someone set up a mirror for him (Bogdan, i think)
let me have a look....
well - a quick glance
what i did was search for files that contain the text "CreateWindowEx"
here is that list...
DlgEdit.asm
FileIO.asm
Project.asm
Property.asm
RAResEd.Asm
RCDataEdit.asm
ResEd.Asm
ToolbarEdit.asm
ToolBox.asm
XPManifestEdit.asm
of course, not all controls are created that way
you may also search for anything with the word "dialog", for example
some of the stuff you want to see may be in his DLL or LIB's, too
some of the other functions that can create dialogs or controls...
CreateDialog
CreateDialogIndirect
CreateDialogIndirectParam
CreateDialogParam
DialogBox
DialogBoxIndirect
DialogBoxIndirectParam
DialogBoxParam
MessageBox
MessageBoxEx
MessageBoxIndirect
I really do not have the patience to go through 4,400 lines of almost totally uncommented assembly language (DlgEdit.asm) to find out where these controls are created.
oh - and i do ? :lol
that particular file isn't so bad
i opened it with Notepad and used Find to locate "CreateWindow"
a coupled popped right up...
.if hCur
invoke CreateWindowEx,0,
addr szStaticClass,0,
WS_CHILD or WS_VISIBLE or SS_WHITERECT or WS_BORDER or SS_NOTIFY,
xP,yP,6,6,
hPar,0,hInstance,0
.else
invoke CreateWindowEx,0,
addr szStaticClass,0,
WS_CHILD or WS_VISIBLE or SS_GRAYRECT or WS_BORDER or SS_NOTIFY or WS_CLIPSIBLINGS or WS_CLIPCHILDREN,
xP,yP,6,6,
hPar,0,hInstance,0
.endif
i would have used a register to hold the style bits, then a single CreateWindowEx in that case :P
.if hCur
mov eax,WS_CHILD or WS_VISIBLE or SS_WHITERECT or WS_BORDER or SS_NOTIFY
.else
mov eax,WS_CHILD or WS_VISIBLE or SS_GRAYRECT or WS_BORDER or SS_NOTIFY or WS_CLIPSIBLINGS or WS_CLIPCHILDREN
.endif
invoke CreateWindowEx,0,
addr szStaticClass,0,eax,
xP,yP,6,6,
hPar,0,hInstance,0
there are many more lines that use "CreateWindow"
i see he also uses CreateDialogIndirectParam several times in that file
NoCforMe,
what are you exactly trying to do? - what is so hard on creating child controls?
i didn't get much time to play, today - back to it tomorrow :P
my move window code seems to have a bug - well, at least one :bg
my head hurts - lol
i am going to set it aside for the moment and put together a "display messages" window
that should go better
ok - i got one bug fixed - the main one
for window move, however, you must move slowly - lol
i know what is happening and how to fix it
the mouse gets outside the child window before the window move happens
then, that proc no longer gets WM_MOUSEMOVE messages
but, i thought you might like to play with what i have so far....