The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: xroot on June 19, 2011, 03:38:39 PM

Title: CreateSolidBrush
Post by: xroot on June 19, 2011, 03:38:39 PM
I have a loop with these two lines and it works.
I was told that I would run out of brushes doing it this way.
Is this wrong to do it this way?? :tdown :thumbu
Thanks

   invoke nrandom,0ffffffh
   invoke SelectObject,hDC,rv(CreateSolidBrush,eax)  :naughty:

Title: Re: CreateSolidBrush
Post by: dedndave on June 19, 2011, 03:44:51 PM
if you look at the docs for SelectObject, you will find that it returns the handle for the object that is being replaced
you can use that handle to delete it with DeleteObject

http://msdn.microsoft.com/en-us/library/dd162957%28v=vs.85%29.aspx

http://msdn.microsoft.com/en-us/library/dd183539%28v=vs.85%29.aspx
Title: Re: CreateSolidBrush
Post by: jj2007 on June 19, 2011, 03:59:43 PM
Not tested, but this should do the job:

   invoke nrandom, 0ffffffh
   invoke CreateSolidBrush, eax
   push eax ; will be arg for DeleteObject
   invoke SelectObject, hDC, eax
   push eax   ; save previous object
   ... draw ...
   pop eax
   invoke SelectObject, hDC, eax   ; select previous object
   call DeleteObject   ; the arg is already on the stack
Title: Re: CreateSolidBrush
Post by: xroot on June 19, 2011, 04:21:07 PM
My program works fine, I don't care about saving the old brush, just want to know if my way will run out of brushes.(someone said this without any reason why or how)
I have read SelectObject API and have always used it like jj2007 says.
When I execute SelectObject over and over without saving the old brush does creating a new brush each time
use up different brushes each time somewhere in memory??
Title: Re: CreateSolidBrush
Post by: qWord on June 19, 2011, 04:36:34 PM
xroot,
you are producing a so called 'handle leak' - that is simply a bug and it is a question of time, that your program stop working.
Title: Re: CreateSolidBrush
Post by: jj2007 on June 19, 2011, 04:40:05 PM
Just test it. Create an endless loop, with an invoke Sleep, 1 to prevent problems with your Office suite, and let it run some days. Then report to us what happened.
Title: Re: CreateSolidBrush
Post by: dedndave on June 19, 2011, 05:03:22 PM
just add one more line...
   invoke nrandom,0ffffffh
   invoke SelectObject,hDC,rv(CreateSolidBrush,eax)
   invoke DeleteObject,eax


deleting unused objects reduces your use of system resources   :U
Title: Re: CreateSolidBrush
Post by: jj2007 on June 19, 2011, 06:00:47 PM
Dave,

that's almost as evil as jmp DefWindowProc :green2
Title: Re: CreateSolidBrush
Post by: xroot on June 19, 2011, 06:18:17 PM
Thanks, qWord
That is what I wanted to know I will change my code
and again thanks.

http://en.wikipedia.org/wiki/Handle_leak
Title: Re: CreateSolidBrush
Post by: hutch-- on June 19, 2011, 11:31:02 PM
xroot,

> I don't care about saving the old brush

You need to care if you don't want the memory leak. The high level logic is you select an object AND save the old one. Do what you need with the selected object then delete it and restore the old one.

In pseudo code,


    SelectObject newobj
    mov hOldObj, eax
  ; perform what you want with the object.
    DeleteObject newobj
    SelectObject hOldObj


The problem with doing the following,


invoke SelectObject,hDC,rv(CreateSolidBrush,eax)


is you don't save the old brush so every time you call the function you waste more memory.

Title: Re: CreateSolidBrush
Post by: dedndave on June 20, 2011, 02:37:17 PM
i am playing with something similar - but i am selecting a font, rather than a brush

just a guess, here - it probably takes longer to delete an object than it does to restore the original handle
my thinking is that selecting a font or brush for a DC simply involves placing the object handle in a table that describes the DC
whereas, deleting an object requires more time to free the resources

in my case, i create the font in a routine that allows the user to select fonts
that handle is then stored in a global variable, where it remains unaltered until the user selects a different font
no need to repeatedly create and delete that object

in the paint routine, i select the font object, saving the original (replaced) font handle on the stack
once the paint routine is done, i restore the orignal font with another SelectObject call
i.e., the only time an object is deleted is if the user selects a new font - i delete the old one

your case is a little different, in that you are randomly creating a different object with each pass
it seems you should delete an object, whether it is the original one, or the one you created
however, it seems to be a little more efficient to delete the original object than the one you created
because it requires an additional system call to delete the one you created

Hutch's pseudo-code
    SelectObject newobj
    mov hOldObj, eax
  ; perform what you want with the object.
    DeleteObject newobj
    SelectObject hOldObj


Dave's pseudo-code
    SelectObject newobj
    DeleteObject oldobj
  ; perform what you want with the new object.


the only problem i see is that you might be trying to delete a system-created object
i read something about that on MSDN, but i don't remember what it was - lol - old age
(as i recall, it was either "don't do it" or "the attempt is ignored")
you might want to thoroughly review the SelectObject and DeleteObject documentation to see what the details are

EDIT:
ok - i found a note in the documentation for SelectObject...
QuoteThis function returns the previously selected object of the specified type. An application should always
replace a new object with the original, default object after it has finished drawing with the new object.

unfortunately, they do not explain why or what happens if you don't   :(
your hair may fall out, i guess   :P

what you probably want is something like this
   invoke nrandom,0ffffffh
   invoke SelectObject,hDC,rv(CreateSolidBrush,eax)   ;create the first brush outside the loop
   push   eax                                         ;save the original handle

top_of_loop:
;paint something
;delete the created handle
;nrandom
;create solid brush
;select object
;count and branch to top_of_loop

;delete the last object
;reselect the original one

Title: Re: CreateSolidBrush
Post by: hutch-- on June 20, 2011, 03:28:39 PM
Dave,

There is an easy way to see what happens, put the call in the WM_PAINT for a Window with a looped function and load Task Manager. Start the window and watch it leak like a sieve.

Effectively the OS maintains a "current object" for as many types of objects as are available, for your process it is available until you alter that state by selecting your own object, if you don't restore it in the documented way you don't recover the memory used for your new object.
Title: Re: CreateSolidBrush
Post by: qWord on June 20, 2011, 03:53:50 PM
switching to GDI+ avoids these annoying SelctObject()-hell :lol
Title: Re: CreateSolidBrush
Post by: jj2007 on June 20, 2011, 04:42:46 PM
Quote from: dedndave on June 20, 2011, 02:37:17 PM
the only problem i see is that you might be trying to delete a system-created object
i read something about that on MSDN, but i don't remember what it was - lol - old age
(as i recall, it was either "don't do it" or "the attempt is ignored")

You can try but it will be gracefully ignored. This is for lazy programmers like you and me who do not want an extra check if the object is sys or private :bg

Quote
EDIT:
ok - i found a note in the documentation for SelectObject...
QuoteThis function returns the previously selected object of the specified type. An application should always
replace a new object with the original, default object after it has finished drawing with the new object.

unfortunately, they do not explain why or what happens if you don't   :(
your hair may fall out, i guess   :P

Actually, it is a non-trivial question. I tried DeleteObject on a font that was still selected, and it returns sometimes 1, sometimes 0 but in any case "The operation was completed successfully". Hmm... dig further and you find this:

"Do not delete a drawing object (pen or brush) while it is still selected into a DC."

You see? Fonts are not mentioned, hehe! :green2
Title: Re: CreateSolidBrush
Post by: MichaelW on June 20, 2011, 04:58:26 PM
I seem to recall a post here recently that explained why you should always replace a new object with the original but I can't recall who posted it or find the post.
Title: Re: CreateSolidBrush
Post by: jj2007 on June 20, 2011, 05:22:29 PM
It depends probably on the type of handle. If what you get is a pointer to a resource that Windows has to create and maintain, then deleting the object the handle points to is an invitation for an access violation. If instead you get an entry to some global structure that Windows maintains anyway - like fonts -, you might get away with "deleting" the pointer to the font table because the fonts are still around after you marked the reference as bad via DeleteObject.

Having said that: After a while my deleted fonts stop working...
Title: Re: CreateSolidBrush
Post by: MichaelW on June 20, 2011, 05:47:54 PM
I think the point was for your last SelectObject call to always restore the default.

Title: Re: CreateSolidBrush
Post by: hutch-- on June 21, 2011, 01:31:03 AM
 :bg

many of you guys missed out on the sheer fun of writing Win16 code. Software multitasking meant that all of Windows was one running program and if your app made a mess of memory, it took out the entire operating system. On the bright side, Win16 used to boot a lot faster than the 32 bit versions. Win32 at least restricts the messups to the running process so if you make a mess of memory you trash your own app, not everything else as well.

The test for a memory leak with GDI objects is reasonably simple, put the output in a loop and run task manager, if you have got it wrong you will see memory usage continually going up.

Magic rule is "Observe the SelectObject/DeleteObject rules" or watch it go BANG !
Title: Re: CreateSolidBrush
Post by: dedndave on June 21, 2011, 05:02:40 AM
"Bang" - i think that'll be the name for my next project   :P
Title: Re: CreateSolidBrush
Post by: Twister on June 21, 2011, 06:55:37 AM
I don't understand why you need to delete your drawing objects and brushes after drawing. I always thought of it as borrowing art supplies from the system, then giving them back after the program is done, or when you want to get some supplies off hand due to memory concerns.