can not draw on GDI+ bitmap object - c++

I am writing program in c++ gdi gdi+.
Drawing large image on gdi+ bitmap is slow is using gdi+ api.
So I used the following way to draw:
Bitmap img(xxx);
Graphics gr(&img);
HDC dc = gr.GetHDC();
::StretchDIBits(
dc,
rec.left, rec.top,
(rec.right - rec.left), (rec.bottom - rec.top),
m_recRegin.left , m_recRegin.top,
m_recRegin.right - m_recRegin.left, m_recRegin.bottom - m_recRegin.top,
XXX, XXX, DIB_RGB_COLORS, SRCCOPY);
gr.ReleaseHDC(dc);
this code run perfectly some time.
But when the system-wide pool is full by creating lots of compatibleDCs with large size of CBitmap. It seems can not draw any thing on the Bitmap.
What happened? when this part of code failed, I can still draw on the graphics using GDI+ APIs
GetLastError() return 8.
Many thanks!

GetLastError() return 8
8 is "Not enough storage is available to process this command."
So you ran out of storage for GDI to use to execute ::StretchDIBits.
In the future, you can lookup Windows errors from the command line with: net helpmsg <error in decimal>.

In addition to what others have said, Graphics objects implement IDisposable. This means they likely (and actually do) hold onto a limited resource. Ensure you are calling "gr.Dispose()" or placing things in a "using" block. Failing to do this will leave it up to the garbage collector to determine when the objects are finalized, and their resources released. That is a bad practice for resource intensive objects-- such as Graphics.
Depending on the size Bitmaps may also be resource hungry as they can eat a lot of RAM. If the bitmaps used in your code sample are never referenced after it, also ensure they're getting disposed of...

Related

Taking a screenshot, analyzing it, then deleting it

I've been trying to code an auto clicker for a simple game online (a php coded one), but I've had trouble analyzing the colors on-screen. (English isn't my first language, sorry!) I've already done a bit of C++ in university, but only for science-oriented simple console programs. (Edit: I'm working on windows!! forgot to mention)
I've already tried the getpixel function, but since my chrome window is zoomed out at 80% to get the full game in frame, it seems I'm having some DPI related issues, but looking into this made my head dizzy.
After watching a Codebullet video, I thought a better approach to this would be to take a screenshot of the problematic area, analyze it to see if the condition is filled, then delete the screenshot. The problem is, I have no idea how I could achieve this and Google didn't help much this time :\
My code is extremely messy so I can't show it right now, but it's basically just a:
-click there
-click there after 5 seconds
-click there if this pixel is this color
-repeat
Is there an easy answer to this? I'd be really thankful if there is. Have a nice day! :)
You don't need to save the screen shot if you don't want to:
Pass the target window handle to GetDC(), t will return the the device context of the window.
Pass the device context to CreateCompatibleDC() to create a compatible DC.
Use CreateCompatibleBitmap(), passing in the DC and the size of the window. This returns a handle to a bitmap
Use SelectObject() to select the bitmap
Use BitBlt() to do a bitblock transfer of the selected pixels from the regular DC into the compatible DC using the SRCCOPY raster operation code to do a normal copy.
Create a BITMAP object. Use GetObject() and pass the handle to the bitmap you created.
Create a BITMAPINFOHEADER and define the member vars. Create an array of unsigned chars big enough to fit all the pixels from your bitmap.
Use GetDIBits() passing in the handle to the compatible bitmap, the bitmap header and a pointer to the pixel array. This loads the pixels from the bitmap into the pixel array.
Now parse all that juicy pixel data, search for the colors you're looking for and test the results against your conditionals to decide what to do next.
Don't forget to delete objects and release memory & device contexts.
I believe this is the tutorial I followed where I learned this, courtesy of MSDN: https://learn.microsoft.com/en-us/windows/desktop/gdi/capturing-an-image

How to clean my GDI objects efficiently and quikcly in pure C++ - winapi (not .net, c#)?

I am writing a program in pure C++ - winapi (not .net, c#). The program has a lot HWND objects such as pushbutton, checkautobox, icon (LoadImage()), edit and tab control etc. Total number of them around 300, most of them are globally defined, and also has a lot of string objects too.
I check GDI object number from Task manager, it showing 1865 at the start, and it reaches 10,000 quickly after switching my different tab control several times in program, so leads to GDI leaks. Program sucks with gray color.
Now, how can I fix this problem? Should I use DestroyIcon(icon) for every icon, also DeleteObject(hwnditem) function to delete every object after it's creation or usage (all created in WM_CREATE block)? Will this actions reduce my GDI object number and will not lead GDI leak? is there any quick method to deal with this problem? here GDI object number screened image given with GDIView program.
I have solved my problem by adding DeleteObject(x) and DestroyIcon(y) methods on appropriate places of my drawing and add-icon code blocks. Now, numbers of GDI objects are almost steady, not increasing.

CreateCompatibleBitmap Vs SelectObject

I'm wondering , if I want to create different bitmaps,
I use the CreateCompatibleBitmap function again and again, to associate it to the same memory CDC.
is it the same meaning that I CreateBitmap and SelectObject again and again??
I ask this question because I want to do something to the newly created bitmap by another CDC.
Without seeing the specific code it's hard to know the exact problem but CreateCompatibleBitmap is commonly used in double-buffering situations to avoid flickering. Rather than drawing directly to the Device Context (DC) you first draw to an off-screen, or memory, DC which is basically drawing to a bitmap. The bitmap is then copied directly to the screen DC using BitBlt, so it appears like all the drawing happens at the same time.
The usual steps are this (and will probably happen on every WM_PAINT):
Use the screen DC to create a bitmap, which is 'compatible' with it, using CreateCompatibleBitmap.
Create a memory DC
Select the bitmap into the memory DC (this is what you'll draw to)
When drawing is finished BitBlt the memory DC's bitmap onto the screen DC.
More information available here: Guide to Win32 Memory DC (Code Project)
Yes, CreateCompatibleBitmap() creates a new bitmap, a new memory allocation, a new handler each time you call it in a loop;

Odd MFC/GDI behaviour (blank image) that doesn't appear when screen is recorded

There is this weird bug in my program that I'm trying to fix, but I'm really at a loss for what it could be. This part of my program has a dialog which shows previews of various items using MFC/GDI. When I scroll through different items, sometimes the preview image just disappears and goes blank. However, it:
Only happens on some machines
Apparently happens on both Windows 7 and XP
Doesn't happen on the same item every time
Item IS STILL THERE when one takes a screenshot, but it is blank when viewing it normally.
Seems to happen at random places throughout the code when I'm attempting to trace through it with breakpoints. It's not always in the same location that the screen goes from image to blank, which leads me to believe that it's not happening in the same thread as my main thread, even though that's really the only thread that's not blocked at that point. That means that it's happening in a windows thread or something, doesn't it?
I'm assuming it's a race condition of some sort, but the behaviour of the preview in screenshots, in particular, rather confuses me. Why would it be fine when taking a screenshot but be blank when viewing it on screen? Is there some mechanic of the "printscreen" that bypasses what's displyed or updated on the screen?
I realize that I haven't given much information and that people obviously can't help much, but if anyone could think of ANYTHING, it would be much appreciated :)
Thanks!
Another theory: GDI resource leak
If you forget to free your GDI objects, weird things start to happen - including unpainted areas.
Run taskmgr.exe and add the "GDI Objects" column.
Run your software and monitor the GDI object count. Does it stabilize?
If your GDI Object count does not stabilize, look in your relevant WM_PAINT handlers.
Here's an example of a GDI leak:
void CMyWnd::OnPaint()
{
CPaintDC dc(this);
dc.SelectObject(&font);
}
Selected GDI objects must always be deselected:
void CMyWnd::OnPaint()
{
CPaintDC dc(this);
CFont *pOldFont = dc.SelectObject(&font);
// Use font
dc.SelectObject(pOldFont);
}
When you record your screen, are you reading the desktop using GDI apis? In that case, any hardware-accelerated surface may become black (or possibly white). To test this, you can disable hardware acceleration for your graphics card. If your recorder starts working then you've found the culprit!
To record these non-GDI surfaces you probably need to read the surface using DirectX/OpenGL. I would start with this article: http://www.codeproject.com/KB/dialog/screencap.aspx

Drawing without flickering

I have a win32 application which was developed in c++. The application draws some stuff on the window using basic shapes (rectangles). The windows is repainted every 20ms (50hz) using InvalidateRect. All works well but the drawing is flickering. How can i prevent the flickering? In c# i normally use a double buffered component (such as pictureBox), how could i get rid of this in c++ using win32?
You can create an in-memory device context, draw those shapes to it (just like you would to the window's device context) and then blit from it to window's device context when the window is invalidated.
You also need to disable background clearing (handle WM_ERASEBKGND window message appropriately) before the draw happens.
Edit: I stumbled upon a pretty exhaustive tutorial on flicker-free drawing in GDI, which explains all aspects of drawing in Windows and comes with examples.
You can easily implement double buffering in Win32 as well. Assuming you are doing your painting directly on the Window using its device context, do this instead:
Create a "memory" device context and do all your drawing on that device context, then copy the invalidated portions of the window to the actual device context when appropriate, using the BitBlt() function
There's a pretty good (albeit high level) overview here.
You can double buffer in C++, too.
When you get the DC to paint to, you create an offscreen bitmap (CreateCompatibleBitmap) and a memory DC (CreateCompatibleDC). Do all your painting to that DC. At the end, do a BitBlt from the memory DC to the actual DC.
For performance, you might want to cache the offscreen bitmap and DC, but remember to recreate them when the window size changes.
Here's the greatest tutorial i've found yet:
https://msdn.microsoft.com/en-us/library/ms969905.aspx
In short - yes, you have to implement the double-buffering. It's done through creating the in-memory DC and then drawing everything you want to an in-memory bitmap using that DC, only afterwards commiting this bitmap to an actual DC.