From: "Bill" don't want more on
I'm doing a program that needs to capture bitmaps off a window of another
program. I'm doing okay except I have an intermittent failure. I admit I'm
not testing for all the possible MFC error returns at this early stage, but
even I did I'm not sure how I'd deal with this error.

My piece of code looks like this.

CDC m_memoryDc;
CBitmap m_bitmap;

void CMyDlg::GrabRect(CWnd *pWnd, CRect rc)
{
CDC * pSourceDc = pWnd->GetDC();
Sleep(50); // !!!!! need this or the crash happens almost right away
m_bitmap.Detach();
m_bitmap.CreateCompatibleBitmap(pSourceDc, rc.Width(), rc.Height()); <--
error here
m_memoryDc.Detach();
BOOL ret = m_memoryDc.CreateCompatibleDC(pSourceDc);
m_memoryDc.SelectObject(&m_bitmap); <-- error here
m_memoryDc.BitBlt(0, 0, rc.Width(), rc.Height(), pSourceDc, rc.left,
rc.top, SRCCOPY);
}

I'm trying to capture a bit of window into m_bitmap. I'll later use the
m_memoryDC to access the pixels of the bitmap.

I need the Sleep function call. If I set to 50 ms, then I will get an error
after a few hundred calls to this function. If I set it to 1 msec, I will
get an error after a few calls only. If I set it longer, like 200 msec, I
can run a longer time, but since it's slower, I don't know if it will run
forever without a crash or just takes longer to crash.

Sometimes the error occurs at CreateCompatibleBitmap. pSourceDC is NULL so
the GetDC call failed I guess. But I don't know if I can check the reason
because there is no error code returned.

Sometimes the error occurs at SelectObject. In this case pSourceDC looks
valid (0x00c0fe70) and the m_hDC and m_hAttribDC both have the same value
(0x70015a85) but ret is NULL and two handles of m_memoryDC are both NULL.

I'm not sure what to try next. Am I not releasing some resource and running
out of memory or soemthing? Is there a need for a delay after the calls for
the object to be valid? Doesn't seem right, but if so, is there a way to
check if they are valid myself so I'm not wasting time when they are already
valid?

Actually, is there any way to manipulate bitmaps without going through the
seemingly extra step of using a CDC?

Thanks...


From: Joseph M. Newcomer on
See below...
On Mon, 12 Apr 2010 18:11:36 +0800, "Bill" <<don't want more spam>> wrote:

>I'm doing a program that needs to capture bitmaps off a window of another
>program. I'm doing okay except I have an intermittent failure. I admit I'm
>not testing for all the possible MFC error returns at this early stage, but
>even I did I'm not sure how I'd deal with this error.
>
>My piece of code looks like this.
>
>CDC m_memoryDc;
>CBitmap m_bitmap;
>
>void CMyDlg::GrabRect(CWnd *pWnd, CRect rc)
>{
> CDC * pSourceDc = pWnd->GetDC();
> Sleep(50); // !!!!! need this or the crash happens almost right away
****
Any program that requires a Sleep to work correctly is inherently wrong to start with!
****
> m_bitmap.Detach();
***
Note that this leaks bitmaps; you must first DeleteObject to kill the bitmap, or you start
accumulating bitmaps and will run out of GDI resources. Detach() does not destroy a
bitmap, it just breaks the association between a CBitmap object and the bitmap!
****
> m_bitmap.CreateCompatibleBitmap(pSourceDc, rc.Width(), rc.Height()); <--
>error here
****
I'm sure there an "error", whatever that means! But you have not said what the error is,
so we are left to use psychic vibrations to determine the cause.
*****
> m_memoryDc.Detach();
> BOOL ret = m_memoryDc.CreateCompatibleDC(pSourceDc);
> m_memoryDc.SelectObject(&m_bitmap); <-- error here
> m_memoryDc.BitBlt(0, 0, rc.Width(), rc.Height(), pSourceDc, rc.left,
>rc.top, SRCCOPY);
>}
>
>I'm trying to capture a bit of window into m_bitmap. I'll later use the
>m_memoryDC to access the pixels of the bitmap.
>
>I need the Sleep function call. If I set to 50 ms, then I will get an error
>after a few hundred calls to this function. If I set it to 1 msec, I will
>get an error after a few calls only. If I set it longer, like 200 msec, I
>can run a longer time, but since it's slower, I don't know if it will run
>forever without a crash or just takes longer to crash.
****
The word "crash" is a nonsense term that conveys no meaning. Do you mean "I had an
assertion failure" (which is not a crash, by the way), or "I had an access fault", or
what?
****
>
>Sometimes the error occurs at CreateCompatibleBitmap. pSourceDC is NULL so
>the GetDC call failed I guess. But I don't know if I can check the reason
>because there is no error code returned.
****
Well, then it would help if you checked the return values and did not continue execution
if there is a problem.
****
>
>Sometimes the error occurs at SelectObject. In this case pSourceDC looks
>valid (0x00c0fe70) and the m_hDC and m_hAttribDC both have the same value
>(0x70015a85) but ret is NULL and two handles of m_memoryDC are both NULL.
****
You need to check at each stage that things are working right!
*****
>
>I'm not sure what to try next. Am I not releasing some resource and running
>out of memory or soemthing? Is there a need for a delay after the calls for
>the object to be valid? Doesn't seem right, but if so, is there a way to
>check if they are valid myself so I'm not wasting time when they are already
>valid?
***
Well, the Detach() is a Really Bad Idea, since you don't actually delete the bitmap.
*****
>
>Actually, is there any way to manipulate bitmaps without going through the
>seemingly extra step of using a CDC?
****
No. Not to do what you want.

Note also that "capturing the bitmap" means you will capture the rectangular area of the
screen that defines where the window is; if there is something laying on top of it at the
moment, you will get the pixels that are on the screen, not necessarily the pixels of the
window.
joe

****
>
>Thanks...
>
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: "Bill Brehm" don't want on
"Any program that requires a Sleep to work correctly is inherently wrong to
start with!"

Yes, I agree. I put it in as a test and to make some progress until I could
figure out what is going wrong. I dislike timer delays because unless you
guess perfectly, you are either wasting time or still facing the problem
that the delay is supposed to be hiding. That's why I asked if the pointer
that is return cannot be used immediately, how can I tell when it is safe to
use it?

"I'm sure there an "error", whatever that means! But you have not said what
the error is, so we are left to use psychic vibrations to determine the
cause."

I also don't know what the error is. That's why I'm here looking for the
help of experts with lots of experience. What I know is what I mentioned
about certain pointers or handles being NULL. Running out of GDI resources
might be the cause and I will test for that. But it's seems unlikely to me
that GDI resources would be depleted after fewer calls (not after a shorter
time) with a 1 msec delay than with a 50 msec delay. The help says typically
that a function returns 0 if error and non zero if success. So 0 only tells
me there was an error but not what the error was. It also doesn't tell me to
call GetLastError so I assume it's not updated in this case.

"you must first DeleteObject to kill the bitmap"

Okay, thanks. I'll try this. I'd rather not Detach and recreate all the time
if it's not necessary. But many MFC functions that return a pointer say that
the pointer is temporary and should not be saved for future use. So I try
getting a fresh one before I need to use it because I don't know such when a
pointer will become "stale". Could you please shed some light on that? When
do these temporary pointers become invalid? Is it a matter of memory being
swapped out and into a new address? Or control switching out of my thread
then coming back? Is the underlying bitmap or DC (in this example) stable
but only the MFC object might not have a stable connection to it (meaning I
should use the SDK level instead of MFC)?

"The word "crash" is a nonsense term"

Yes, it was ASSERTs in the MFC code or sometimes also access violations. I
traced backwards to find the cause and found the NULL pointers / handles.

"Well, then it would help if you checked the return values and did not
continue execution if there is a problem."

I agree but then my goal will be to recover from the error. How to recover
when the error is not understood. I'm pretty sure you will disagree with my
way of working, but I tend to go for the functionality first then come back
and fill in the error checking and recovery to a level that depends on who
the user will be. If for myself only, I do less of it and if for others I do
more.

"Note also that "capturing the bitmap" means you will capture the
rectangular area of the screen that defines where the window is"

Yes, I'm aware of that. It caught me by surprise in an earlier project but
thinking about it, it's quite logical. At first I thought there was some
image of each window in memory somewhere and Windows displays it and the
program maintains it. But then I learned that the program paints or draws to
the screen directly when Windows asks it to. On this project I discovered
that when the workstation times out and locks itself, there is also nothing
there to capture.

Thanks.

"Joseph M. Newcomer" <newcomer(a)flounder.com> wrote in message
news:u4q6s5hvlckon72ngk3sc2ul709e2jbcdq(a)4ax.com...
> See below...
> On Mon, 12 Apr 2010 18:11:36 +0800, "Bill" <<don't want more spam>> wrote:
>
>>I'm doing a program that needs to capture bitmaps off a window of another
>>program. I'm doing okay except I have an intermittent failure. I admit I'm
>>not testing for all the possible MFC error returns at this early stage,
>>but
>>even I did I'm not sure how I'd deal with this error.
>>
>>My piece of code looks like this.
>>
>>CDC m_memoryDc;
>>CBitmap m_bitmap;
>>
>>void CMyDlg::GrabRect(CWnd *pWnd, CRect rc)
>>{
>> CDC * pSourceDc = pWnd->GetDC();
>> Sleep(50); // !!!!! need this or the crash happens almost right away
> ****
> Any program that requires a Sleep to work correctly is inherently wrong to
> start with!
> ****
>> m_bitmap.Detach();
> ***
> Note that this leaks bitmaps; you must first DeleteObject to kill the
> bitmap, or you start
> accumulating bitmaps and will run out of GDI resources. Detach() does not
> destroy a
> bitmap, it just breaks the association between a CBitmap object and the
> bitmap!
> ****
>> m_bitmap.CreateCompatibleBitmap(pSourceDc, rc.Width(), rc.Height()); <--
>>error here
> ****
> I'm sure there an "error", whatever that means! But you have not said
> what the error is,
> so we are left to use psychic vibrations to determine the cause.
> *****
>> m_memoryDc.Detach();
>> BOOL ret = m_memoryDc.CreateCompatibleDC(pSourceDc);
>> m_memoryDc.SelectObject(&m_bitmap); <-- error here
>> m_memoryDc.BitBlt(0, 0, rc.Width(), rc.Height(), pSourceDc, rc.left,
>>rc.top, SRCCOPY);
>>}
>>
>>I'm trying to capture a bit of window into m_bitmap. I'll later use the
>>m_memoryDC to access the pixels of the bitmap.
>>
>>I need the Sleep function call. If I set to 50 ms, then I will get an
>>error
>>after a few hundred calls to this function. If I set it to 1 msec, I will
>>get an error after a few calls only. If I set it longer, like 200 msec, I
>>can run a longer time, but since it's slower, I don't know if it will run
>>forever without a crash or just takes longer to crash.
> ****
> The word "crash" is a nonsense term that conveys no meaning. Do you mean
> "I had an
> assertion failure" (which is not a crash, by the way), or "I had an access
> fault", or
> what?
> ****
>>
>>Sometimes the error occurs at CreateCompatibleBitmap. pSourceDC is NULL so
>>the GetDC call failed I guess. But I don't know if I can check the reason
>>because there is no error code returned.
> ****
> Well, then it would help if you checked the return values and did not
> continue execution
> if there is a problem.
> ****
>>
>>Sometimes the error occurs at SelectObject. In this case pSourceDC looks
>>valid (0x00c0fe70) and the m_hDC and m_hAttribDC both have the same value
>>(0x70015a85) but ret is NULL and two handles of m_memoryDC are both NULL.
> ****
> You need to check at each stage that things are working right!
> *****
>>
>>I'm not sure what to try next. Am I not releasing some resource and
>>running
>>out of memory or soemthing? Is there a need for a delay after the calls
>>for
>>the object to be valid? Doesn't seem right, but if so, is there a way to
>>check if they are valid myself so I'm not wasting time when they are
>>already
>>valid?
> ***
> Well, the Detach() is a Really Bad Idea, since you don't actually delete
> the bitmap.
> *****
>>
>>Actually, is there any way to manipulate bitmaps without going through the
>>seemingly extra step of using a CDC?
> ****
> No. Not to do what you want.
>
> Note also that "capturing the bitmap" means you will capture the
> rectangular area of the
> screen that defines where the window is; if there is something laying on
> top of it at the
> moment, you will get the pixels that are on the screen, not necessarily
> the pixels of the
> window.
> joe
>
> ****
>>
>>Thanks...
>>
> Joseph M. Newcomer [MVP]
> email: newcomer(a)flounder.com
> Web: http://www.flounder.com
> MVP Tips: http://www.flounder.com/mvp_tips.htm


From: Oliver Regenfelder on
Hello,

Bill Brehm wrote:
> disagree with my
> way of working, but I tend to go for the functionality first then come back
> and fill in the error checking and recovery to a level that depends on who
> the user will be.

In my experience this is the style of work where error checking never
happens. First it is postponed and once things work everybody goes on.
The first time error checking is included then is when the customer
complains.

> At first I thought there was some
> image of each window in memory somewhere and Windows displays it and the
> program maintains it. But then I learned that the program paints or draws to
> the screen directly when Windows asks it to.

I think now you have to be more specific what 'Windows' you mean: XP,
Vista, Seven?

Best regards,

Oliver
From: John H. on
On Apr 12, 8:33 pm, "Bill Brehm" <don't want spam> wrote:
> "Well, then it would help if you checked the return values and did not
> continue execution if there is a problem."
>
> I agree but then my goal will be to recover from the error. How to recover
> when the error is not understood. I'm pretty sure you will disagree with my
> way of working, but I tend to go for the functionality first then come back
> and fill in the error checking and recovery to a level that depends on who
> the user will be. If for myself only, I do less of it and if for others I do
> more.

Error recovery isn't the only consideration here. From a "go for the
functionality" point of view, checking the error codes can still be
useful, because it can offer insight into what is going wrong with
your code, i.e. can help you determine what you are doing wrong.