GetDC() producing errors after delay

Posted on 2005-04-08
Last Modified: 2013-11-20
in my custom paint method, I grab a DC within a method of a CDialog derived class:

               CDC* pDC = GetDC();

I then proceed to create offscreen memory DC's, paint and blit and such.

For every:
            CDC memDC;
I do:

and the method ends with:

                pDC = NULL;

I have another thread which is polling a camera feed and doing something similar with it's own device context which is also CStatic derived.

The app will run smoothly for several minutes, at which point it crashes,  pDC not being null, but it looks like this when I hold my mouse over it in the debugger:
memDC = 0x08acfe04 { hdC = 0x00000000 attrib=0x00000000}

GetLastError() returns 0.

As far as I can tell, everywhere in my app that I call GetDC() I am following it with a ReleaseDC() and I'm calling DeleteObject() for every CreateCompatibleDC() I create.

Any thoughts as to what I might start looking for?

Question by:PMH4514
    LVL 48

    Expert Comment

    All drawing code must be executed from main application thread which creates the window. Worker thread should not do any windows-related code. When window must be redrawn, worker thread must post message to the window, and window redraws itself in the main thread.

    Author Comment

    generally I'd agree with that. in this case however, there are two camera displays, each running at its own frame rate, and thus I have threads dedicated to drawing them.

    anyway, I've turned all camera threads off, and am still seeing the failure.

    Author Comment

    maybe I'm missing something..  I have a worker thread which is constantly polling a system status and calls back to CUserInterface::CustomPaintUI()
    (CUserInterface  created the window)

    void CUserInterface::CustomPaintUI()
          PAINTSTRUCT ps;

          CDC* pDC = GetDC();

          //get and store info about the clientRect
          CRect clientRect;

          // Create a memory DC to do the drawing to...
          CDC memDC;

          // double buffer bitmap
          CBitmap m_BMP;
          m_BMP.CreateCompatibleBitmap(pDC, clientRect.right, clientRect.bottom);

          // select the double buffer bitmap into the memory DC  

          // save pointer to the front buffer
          CDC* pRealDC = pDC;

          // draw into the back buffer    
          pDC = &memDC;    
          // clear the buffer
          pDC->BitBlt(0, 0, clientRect.right, clientRect.bottom, NULL, 0, 0, BLACKNESS);    

          // blit the background skin

          CDC memDCSkin;
          hOldBmp = (HBITMAP)SelectObject(memDCSkin, hSkinBmp);
          pDC->BitBlt(0,0,clientRect.right, clientRect.bottom, &memDCSkin, 0,0, SRCCOPY);
          SelectObject(memDCSkin, hOldBmp);

          // clean up
          pDC = NULL;


    So that method is being executed repeatedly as long as my thread that calls it isn't stopped. It'll run for several minutes, and then crash on this line:

    as described in my first post.  

    I had the thread post WM_PAINT and put this code in OnPaint() not caling BeginPaint/EndPaint (ie. the same thing) and saw the same problems.

    LVL 48

    Accepted Solution

    BeginPaint should be used only inside of WM_PAINT message handler. To draw window from other handler use GetDC/ReleaseDC.
    Again, don't draw from the worker thread, results are unpredictable.
    Using Task Manager test whether number of GDI objects used by the program is constantly growing.

    Author Comment

    >> BeginPaint should be used only inside of WM_PAINT message handler.
    that could be the problem, I was using that and GetDC/ReleaeDC

    I have been looking at the task manager, at the Mem Usage for my app, it doesn't really fluctuate. .What process name would I be looking for to actually see the number of GDI objects in use by the program?

    >>Again, don't draw from the worker thread,
    I'm not really sure that I am (since I've commented this all out, this isn't directly related to this problem, but just to clarify) -  I have a CStatic derived class I call "CCameraDisplay" and I have a class called CCamera that has a member instance of CCameraDisplay.  CCamera  has a worker thread which is collecting frame data from a physical camera, packaging it up along with various other system paramaters at the time of capture, and pushing it to CCameraDisplay::DrawFrame(..) That method subsequently blits the image into a memory DC and when CCameraDisplay::OnPaint() is called, the offscreen surface is copied to the display.

    That is not a case of a worker thread drawing is it? It's merely pushing data along to a CStatic derived instance which draws it OnPaint. My main application CDialog contains a graphical UI, which is what the CustomPaintUI() method (the topic of this discussion) is responsible for painting, that is, painting everything outside of the CCameraDisplay "screen real estate".  The areas of the screen that display camera feeds are not painted by the main dialog, rather, by OnPaint() in the CCameraDisplay class. Since those OnPaint() methods are getting their data from a worker thread that is not associated with the main UI, I think is why I said that I had another thread displaying the camera data.

     This is the correct approach right?


    LVL 48

    Expert Comment

    In the Processes tab of Task Manager select View - Select Columns. Check GDI objects.

    >> This is the correct approach right?

    No, this is not correct. Any window (including static window) must be redrawn in the same thread where it was created. To do this we neet to post user-defined message from worker thread to the window. Messages are handled in the window message queue which runs in the thread which created this window.

    Author Comment

    >> In the Processes tab of Task Manager select View - Select Columns. Check GDI objects.
    cool! I never realized there were other available columns..

    That definitely helped..  With most of my paint block commented out, the GDI count remained the same +/- a few. I then commented back in sections at a time while the app was running until suddenly the GDI object count started shooting way up.  That pointed to an error.

    >>No, this is not correct. Any window (including static window) must be redrawn in the same thread where it was created. To do this we neet to post user-defined >>message from worker thread to the window. Messages are handled in the window message queue which runs in the thread which created this window.

    I guess I'm confused then.  Is posting a user defined message "different" than calling back to a static member function in so far as what will actually get executed?

    Author Comment

    ok so answer me this if you would.

    I have my custom paint method in my CStatic derived class:


    I have a thread that CUserInterface launched, the purpose of which (at least my intention was) to poll the system status (other hardware controllers and such) so that the UI will repaint itself based on system state changes.  

    I did it as such:

    UINT CUserInterface::ThreadProc(LPVOID a_pParam)
      CUserInterface* pUI      = CUserInterface::Instance();
      while( FALSE == m_bKillThread )

    where m_bKillThread and ThreadProc are static   (the thread launches and runs just fine)

    Are you saying that it is incorrect for me to call CustomPaintUI from the thread, and rather, I need to push a WM_PAINT message to CUserInterface instead?
    If so, could you show me the code to use and explain what the difference is between doing that and calling it directly?


    Author Comment

    Anyway, Alex, don't feel obligated to get into the whole windows messaging thing here in this thread (no pun intended :) - that really is a different discussion. Lets just leave that be, as my app is very much "not a normal windows app" - it looks more like a video game and doesn't rely upon standard messaging. I do believe I need to do more research into messaging and getting threads to inform creation windows about updates etc..

    That being said - it turns out watching the number of GDI objects in the task manager was the perfect solution.. As I stepped through all my drawing code, I discovered many places where I'd so something like:

          HRGN tempRegion = CreateRectRgn(a_Rect.left,, a_Rect.right, a_Rect.bottom);
          HBRUSH br1 = CreateSolidBrush( a_Color );


    and never call DeleteObject()!  I don't know what I was thinking, but these added up over several minutes to the point where I got my crash, which is what this EE question was all about, so thanks! I'm going to accept that response as the answer.


    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    Looking for New Ways to Advertise?

    Engage with tech pros in our community with native advertising, as a Vendor Expert, and more.

    Introduction: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
    Introduction: The undo support, implementing a stack. Continuing from the eigth article about sudoku.   We need a mechanism to keep track of the digits entered so as to implement an undo mechanism.  This should be a ‘Last In First Out’ collec…
    This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
    This video is in connection to the article "The case of a missing mobile phone (". It will help one to understand clearly the steps to track a lost android phone.

    779 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    16 Experts available now in Live!

    Get 1:1 Help Now