From: Peter Olcott on

"Joseph M. Newcomer" <newcomer(a)flounder.com> wrote in
message news:vuetp51t69g884pi2lb6k5ibdbnqve3upp(a)4ax.com...
> It is very, very simple: you, and you alone, are
> responsible for knowing what objects are
> selected into a DC. If an object is selected into a DC,
> you must deselect it. You should
> not use the DC as a "repository" of any object; the
> simplest approach is to start with a
> DC which has nothing active, select into it what you need
> to do drawing, do the drawing,
> deselect all the objects (RestoreDC()), and repeat as
> required. It is considered poor
> practicce to leave an object selected into a DC across,
> say, an message pump invovation,
> because temporary objects exhibit odd behavior under such
> conditions. This is just good
> programming practice.
> joe
>

I want to minimize the complexity of the code, I want to
minimize human user actions. To minimize the complexity of
the code I have a minimum number of objects and I perform
the minimum number of operations upon these objects to
achieve the required functional result.

I have exactly one CBitmap, CFont, and MemoryDC. Once a user
has performed an operation upon these objects I want this
operation to stick until the user performs another operation
upon them. (These operations can occur in any order or
sequence) I implemented this requirement by make these GDI
objects the members of the CDialog instance.

The user may load a graphics file into the MemoryDC's
CBitmap, capture the screen to the bitmap, save whatever is
in the bitmap to a graphics file, or write to whatever is in
the bitmap using TextOut(). The user may do these operations
in any order or sequence. A default 100 * 100 bitmap is
created when ScreenCapture object that does all of these
operations is created.

The trick of always deselecting the currently selected GDI
object is too difficult to implement and not required for
the following reasons:
(1) The only way to unselect a CBitmap is to select another
CBitmap.
(2) The other CBitmap does not exist until I create it, and
to minimize program complexity there is only one of these.
(3) So (according to your requirements) I can't create a
CBitmap without deleting the original CBitmap, and I can't
delete the original CBitmap without creating a new CBitmap.
(4) Apparently I can delete the original CBitmap while it is
selected into a MemoryDC, because DeleteObject() returns a 1
indicating successful deletion.



> On Sun, 14 Mar 2010 12:22:49 -0500, "Peter Olcott"
> <NoSpam(a)OCR4Screen.com> wrote:
>
>>The point is that the function listed below can be called
>>repeatedly, and it does not work if the
>> this->font.DeleteObject();
>>is removed which as far as I can tell must mean that a GDI
>>object is definitely being deleted while selected in a
>>device context. Proof that a GDI object is being deleted
>>while selected into a device context contradicts Joe's
>>statement that it can't be done.
>>
>>What I suspect is there is something that I am missing
>>here,
>>and Joe is not wrong, yet the explicit contradiction still
>>remains unresolved.
>>
>>"Goran" <goran.pusic(a)gmail.com> wrote in message
>>news:bc8e5ce9-773d-42df-b509-097b70e021d1(a)33g2000yqj.googlegroups.com...
>>On Mar 12, 4:07 pm, "Peter Olcott" <NoS...(a)OCR4Screen.com>
>>wrote:
>>> I will study your concrete example an attempt to
>>> implement
>>> it. My great difficulty is with the tedious little
>>> syntactical details, thus Joe's abstract examples don't
>>> work
>>> for me. I can't simply let my GDI object get destroyed
>>> because the objects must retain their state in case
>>> subsequent operations must be performed on them.
>>
>>I see in your code below that you use a memory DC. Without
>>having any
>>further info, only thing I have to say is that normally a
>>memory DC is
>>used to draw something, then e.g. stored in a bitmap or
>>BitBlt-ed on
>>screen. From that standpoint, normal drawing we all know
>>is
>>to select
>>your GDI objects into the DC, call drawing code, then
>>un-select them.
>>If that is what you are doing, then you have no
>>correlation
>>between
>>your GDI objects (e.g. bitmaps, pens, fonts, brushes)
>>except
>>that they
>>have to outlive time when they are selected into the DC
>>for
>>drawing.
>>So I honestly do not see your difficulty. Just make sure
>>that, during
>>the drawing code, you do stuff by the book (hence e.g. my
>>CTempGdiObjectSelection), and as for lifetime of your GDI
>>object,
>>well, just handle their lifetime (hence my
>>shared_ptr-based
>>map
>>there).
>>
>>> I open a bitmap and it may be written to, or saved or
>>> another bitmap may be opened. If another bitmap is
>>> opened,
>>> I
>>> must create another CBitmap object of this new size.
>>> Currently I only have the single CBitmap object as an
>>> object
>>> member variable.
>>
>>So make that two of them. Note also that there's nothing
>>wrong in
>>creating whatever GDI object you might need on the heap.
>>
>>> I am guessing that I could implement your design by
>>> making
>>> pairs of GDI object member and toggling between them
>>> upon
>>> every re-use. For example CBitmap cbitmap[2]; and then
>>> toggle its subscript between one and zero.
>>
>>Here, either I am not very smart, either there's a lot of
>>things you
>>have in your head that weren't put into writing here,
>>because I don't
>>understand what you are talking about :-).
>>
>>> I looked at your design again and there were too many
>>> things
>>> that I did not understand.
>>
>>I'd say, points to take from it:
>>
>>1. use something like CTempGdiObjectSelection to ensure
>>correct GDI
>>object selection idiom, which is "select it/draw/un-select
>>it".
>>
>>2. use some C++ object lifetime handling technique to
>>handle
>>your GDI
>>object (font, bitmap, pen...) lifetime. Hence I proposed
>>shared_ptr -
>>it gets you far. If you indeed use a std::map, attention
>>to
>>map::operator[], that might not do what you think (hence
>>my
>>insistence
>>on that "const").
>>
>>3. divorce lifetime of a DC and GDI objects used to draw
>>on
>>it (you
>>seem to be having trouble with this). In other words, when
>>you select
>>an object into a DC, do not try to destroy it. But I don't
>>understand
>>why you even started down that route.
>>
>>> Here is my currently working code. It does not work if I
>>> remove the:
>>> this->cfont.DeleteObject();
>>> It does work with repeated invocations, thus must be
>>> deleting the selected CFont object.
>>>
>>> // Displays a Font Selection DialogBox with
>>> // default "Times New Roman", Bold, Italic, 8 Point
>>> //
>>> inline void ScreenCaptureType::SelectFont() {
>>> this->cfont.DeleteObject();
>>>
>>> int PointSize = 8;
>>> int FontHeight = -MulDiv(PointSize,
>>> GetDeviceCaps(MemoryDC.m_hDC, LOGPIXELSY), 72);
>>> LOGFONT LogFont = {FontHeight, 0, 0, 0, FW_BOLD, 1, 0,
>>> 0,
>>> ANSI_CHARSET, OUT_DEFAULT_PRECIS,
>>> CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
>>> FF_DONTCARE, L"Times New Roman"};
>>> CFontDialog dlg(&LogFont);
>>> if (dlg.DoModal() == IDOK)
>>> cfont.CreateFontIndirect(&LogFont);
>>> this->MemoryDC.SelectObject(&cfont);
>>>
>>> }
>>
>>Without knowing anything about the rest of your code, the
>>purpose of
>>this function is to select some font into a memory DC
>>(providing that
>>MemoryDC indeed is a CMemoryDC). Normally, one selects a
>>font into a
>>DC to do some drawing, so I personally find it hugely
>>surprising that
>>a modal dialog is displayed just before selecting it into
>>a
>>DC. I see
>>that working well in some bigger design only if said font
>>is
>>the only
>>font that will be used while drawing. But, as I said
>>before,
>>I don't
>>actually understand your difficulty at all, so I might be
>>completely
>>off the mark.
>>
>>By the way, please, PLEASE do something about that
>>CreateFontIndirect
>>call. It stands out like a sore thumb. It's a friggin
>>resource
>>allocation and that can fail (if so, it returns FALSE).
>>Imagine that
>>this indeed happens. Would you want to do
>>MemoryDC.SelectObject(&cfont) then?
>>
>>Goran.
>>
> Joseph M. Newcomer [MVP]
> email: newcomer(a)flounder.com
> Web: http://www.flounder.com
> MVP Tips: http://www.flounder.com/mvp_tips.htm


From: Goran on
On Mar 16, 1:54 pm, "Peter Olcott" <NoS...(a)OCR4Screen.com> wrote:
> It looks like all of this may be moot
> because DeleteObject() is confirming that the object is
> being deleted while it is selected by its return value of 1,
> so my code is already good the way that it is. I only tested
> this with VS 2008, but, it works on Windows 7 and XP.

Man, Joe is telling you repeatedly that you are mistaken. I told you
to try some GDI resource monitor program and see whether your GDI
objects indeed do get destroyed. I now believe that you didn't try
that and that you don't actually know more about that except
DeleteObject returned true. That is NOT ENOUGH.

But fine, don't trust us. Try this: start your task manager and add
"GDI objects" column. Make a test program where you create (or get) a
DC, then create a font, select it into a DC, and then call
DeleteObject on it. Watch GDI object count for your process. Did you
see that count dropped by 1 when you called DeleteObject? No you
haven't, despite the fact that DeleteObject returned TRUE.

BTW, if you do this, you WILL see that GDI object count drops, but
only when your DC (not font, DC) is destroyed. So that might mean that
some sort of reference counting is employed for fonts, or it might
mean absolutely NOTHING, because, AFAIK, none of that is actually
documented.

Now, do the same for e.g. a pen. There, you will see that GDI object
count indeed does drop. This is in line with doc for DeleteObject who
says "Do not delete a drawing object (pen or brush) while it is still
selected into a device context.". That, IMO, hints at the following:
if you delete e.g. a pen, and then do LineTo, what pen is a DC
supposed to use to draw? There is no pen anymore! Perhaps situation is
different for a font, but wouldn't you say now that it's a mess
playing with DeleteObject like that? Just unselect it before
destruction and that's all.

So what you choose to do, is to distrust the documentation and
disregard honest advice of people you often see here, and to rely on
undocumented behavior that you observe in your particular use case. Do
you actually think that is a good way to write code? If so, then
perhaps you don't deserve to be helped.

Goran.
From: Tom Serface on
Funny, I thought starting to use .NET would help with some of this stupid
Windows behavior. Not so. My first real .NET application sucked up GDI
resources because I was creating Image objects and not specifically
Dispose()'ing them. Turns out they don't give back handles even when
garbage collected if you don't do that manually.

The worse thing is if you have another thread and it tries to get resource
that has been garbage collected, that you haven't destroyed, it will just
throw an "out of memory" exception which causes you to go down a whole
complete red herring path while debugging.

I've found managing these sorts of resource "trickies" to be some of the
most annoying parts of coding multimedia software. I can't blame Peter for
being a little confused about it. The whole font creation and usage thing
in MFC is just too cumbersome. That is something that .NET got right. You
just use the font (properties or otherwise) and you don't have to worry
about destroying it or whether it's still available or ...

Tom

"Goran" <goran.pusic(a)gmail.com> wrote in message
news:a3fc4a6b-0a96-4674-88d4-d8e3caf79120(a)m37g2000yqf.googlegroups.com...
> On Mar 16, 1:54 pm, "Peter Olcott" <NoS...(a)OCR4Screen.com> wrote:
>> It looks like all of this may be moot
>> because DeleteObject() is confirming that the object is
>> being deleted while it is selected by its return value of 1,
>> so my code is already good the way that it is. I only tested
>> this with VS 2008, but, it works on Windows 7 and XP.
>
> Man, Joe is telling you repeatedly that you are mistaken. I told you
> to try some GDI resource monitor program and see whether your GDI
> objects indeed do get destroyed. I now believe that you didn't try
> that and that you don't actually know more about that except
> DeleteObject returned true. That is NOT ENOUGH.
>
> But fine, don't trust us. Try this: start your task manager and add
> "GDI objects" column. Make a test program where you create (or get) a
> DC, then create a font, select it into a DC, and then call
> DeleteObject on it. Watch GDI object count for your process. Did you
> see that count dropped by 1 when you called DeleteObject? No you
> haven't, despite the fact that DeleteObject returned TRUE.
>
> BTW, if you do this, you WILL see that GDI object count drops, but
> only when your DC (not font, DC) is destroyed. So that might mean that
> some sort of reference counting is employed for fonts, or it might
> mean absolutely NOTHING, because, AFAIK, none of that is actually
> documented.
>
> Now, do the same for e.g. a pen. There, you will see that GDI object
> count indeed does drop. This is in line with doc for DeleteObject who
> says "Do not delete a drawing object (pen or brush) while it is still
> selected into a device context.". That, IMO, hints at the following:
> if you delete e.g. a pen, and then do LineTo, what pen is a DC
> supposed to use to draw? There is no pen anymore! Perhaps situation is
> different for a font, but wouldn't you say now that it's a mess
> playing with DeleteObject like that? Just unselect it before
> destruction and that's all.
>
> So what you choose to do, is to distrust the documentation and
> disregard honest advice of people you often see here, and to rely on
> undocumented behavior that you observe in your particular use case. Do
> you actually think that is a good way to write code? If so, then
> perhaps you don't deserve to be helped.
>
> Goran.

From: Goran on
On Mar 18, 7:43 pm, "Peter Olcott" <NoS...(a)OCR4Screen.com> wrote:
> Since I have no idea what an HFONT is (other than a handle
> to a font) or how it works, knowing this does not help.
> Learning MFC programming in terms of Win32 programming only
> works if you know Win32 programming.

That's a silly thing to say, and thinking that way won't get you far
with MFC.

MFC really is a rather thin layer over Win32. That influences very
much how it's made and what it does. And indeed, if you look at docs
for MFC, there is often corresponding Win32 function link at the end,
and doc for it is pretty much the same then.

For example, you work with LOGFONT. That has nothing to do with MFC
and all to do with Win32. So you in fact do Win32, not MFC,
programming, when you handle it. Your trouble here with selecting
stuff into DC stems from poorly understanding both Win32 and MFC in
that area. What's worse, your "functional requirements" you throw
around are wrong because of that.

You just shouldn't be doing this. There's no abstraction that doesn't
leak (see http://en.wikipedia.org/wiki/Leaky_abstraction), and MFC is
indeed an abstraction that leaks a lot, probably more than it has to.
If you want stronger abstractions, use a better framework.

Goran.
From: Joseph M. Newcomer on
I agree. I have many slide disbributed through my Systems Programming course, which cover
what happens when the Win32 API meets MFC, and it is not not always obvious what happens
unless you understand both the API and MFC. And not at a superficial level.

You can't really understand MFC unless you understand the concept of handle maps and
temporary objects. Yes, I successfully worked in it for two years before I got the deep
insights, but I found that they were critical to my future success. Now I teach how to
use both STL and MFC collections at the interfaces.
joe

On Fri, 19 Mar 2010 03:39:55 -0700 (PDT), Goran <goran.pusic(a)gmail.com> wrote:

>On Mar 18, 7:43�pm, "Peter Olcott" <NoS...(a)OCR4Screen.com> wrote:
>> Since I have no idea what an HFONT is (other than a handle
>> to a font) or how it works, knowing this does not help.
>> Learning MFC programming in terms of Win32 programming only
>> works if you know Win32 programming.
>
>That's a silly thing to say, and thinking that way won't get you far
>with MFC.
>
>MFC really is a rather thin layer over Win32. That influences very
>much how it's made and what it does. And indeed, if you look at docs
>for MFC, there is often corresponding Win32 function link at the end,
>and doc for it is pretty much the same then.
>
>For example, you work with LOGFONT. That has nothing to do with MFC
>and all to do with Win32. So you in fact do Win32, not MFC,
>programming, when you handle it. Your trouble here with selecting
>stuff into DC stems from poorly understanding both Win32 and MFC in
>that area. What's worse, your "functional requirements" you throw
>around are wrong because of that.
>
>You just shouldn't be doing this. There's no abstraction that doesn't
>leak (see http://en.wikipedia.org/wiki/Leaky_abstraction), and MFC is
>indeed an abstraction that leaks a lot, probably more than it has to.
>If you want stronger abstractions, use a better framework.
>
>Goran.
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm