What is going on in _gdi.py?

As some of you may know, I have spent the last four years on a massive project that I can't reveal the details of due to the fact that it was going to be a commercial product. However, the company this product was for is close to shutting it's doors and I'm trying to convince the owners to allow me to open source this project. This project has become more to me than a "product". It's become a work of love, as imperfect as it is in places.

This project is a "kiosk-mode" program intended to be used with a touchscreen. It's also supposed to run indefinitely with no crashes. However, every three to seven days the program crashes. I have included in this email the exception logs with some parts redacted because they reveal the nature of this product. I have struggled with this problem for the past couple of years, and tried MANY things to fix it. However, I simply cannot seem to solve it.

Can I get some insight or wisdom into why this is happening?

Chris.

2012/02/25 07:05 --
Traceback (most recent call last):
   File "ButtonLine.py", line 526, in SetToggledName
   File "ButtonLine.py", line 516, in RefreshButtons
   File "ButtonLine.py", line 231, in _RefreshButtons
   File "ButtonLine.py", line 494, in _RenderLabels
   File "GraphicLabel.py", line 251, in GetSelectedBitmap
   File "GraphicLabel.py", line 109, in AlignText
   File "SubmersionServices.py", line 901, in RescaleKeepAspect
   File "C:\Python27\lib\site-packages\wx-2.8-msw-unicode\wx\_gdi.py", line 4857, in __init__
     """
PyAssertionError: C++ assertion "wxAssertFailure" failed at ..\..\src\msw\dcmemory.cpp(118) in wxMemoryDC::DoSelect(): Couldn't select a bitmap into wxMemoryDC

2012/03/02 12:06 --
Traceback (most recent call last):
   File "ButtonLine.py", line 376, in SetIterator
   File "ButtonLine.py", line 371, in SetSearchTerm
   File "ButtonLine.py", line 355, in RefreshButtons
   File "ButtonLine.py", line 231, in _RefreshButtons
   File "ButtonLine.py", line 157, in _RenderLabels
   File "GraphicLabel.py", line 250, in GetSelectedBitmap
   File "GraphicLabel.py", line 173, in OverlayText
   File "SubmersionServices.py", line 901, in RescaleKeepAspect
   File "C:\Python27\lib\site-packages\wx-2.8-msw-unicode\wx\_gdi.py", line 4857, in __init__
     """
PyAssertionError: C++ assertion "wxAssertFailure" failed at ..\..\src\msw\dcmemory.cpp(118) in wxMemoryDC::DoSelect(): Couldn't select a bitmap into wxMemoryDC

2012/03/10 11:09 --
Traceback (most recent call last):
   File "ButtonLine.py", line 442, in SetIterator
   File "ButtonLine.py", line 535, in Reset
   File "ButtonLine.py", line 516, in RefreshButtons
   File "ButtonLine.py", line 231, in _RefreshButtons
   File "ButtonLine.py", line 496, in _RenderLabels
   File "GraphicLabel.py", line 246, in GetBitmap
   File "GraphicLabel.py", line 109, in AlignText
   File "SubmersionServices.py", line 901, in RescaleKeepAspect
   File "C:\Python27\lib\site-packages\wx-2.8-msw-unicode\wx\_gdi.py", line 4857, in __init__
     """
PyAssertionError: C++ assertion "wxAssertFailure" failed at ..\..\src\msw\dcmemory.cpp(118) in wxMemoryDC::DoSelect(): Couldn't select a bitmap into wxMemoryDC

2012/03/15 12:26 --
Traceback (most recent call last):
   File "ButtonLine.py", line 526, in SetToggledName
   File "ButtonLine.py", line 516, in RefreshButtons
   File "ButtonLine.py", line 231, in _RefreshButtons
   File "ButtonLine.py", line 494, in _RenderLabels
   File "GraphicLabel.py", line 251, in GetSelectedBitmap
   File "GraphicLabel.py", line 109, in AlignText
   File "SubmersionServices.py", line 901, in RescaleKeepAspect
   File "C:\Python27\lib\site-packages\wx-2.8-msw-unicode\wx\_gdi.py", line 4857, in __init__
     """
PyAssertionError: C++ assertion "wxAssertFailure" failed at ..\..\src\msw\dcmemory.cpp(118) in wxMemoryDC::DoSelect(): Couldn't select a bitmap into wxMemoryDC

2012/03/26 10:46 --
Traceback (most recent call last):
   File "ButtonLine.py", line 379, in SetIterator
   File "ButtonLine.py", line 706, in Reset
   File "ButtonLine.py", line 670, in RefreshButtons
   File "ButtonLine.py", line 231, in _RefreshButtons
   File "ButtonLine.py", line 643, in _RenderLabels
   File "GraphicLabel.py", line 245, in GetBitmap
   File "GraphicLabel.py", line 173, in OverlayText
   File "SubmersionServices.py", line 901, in RescaleKeepAspect
   File "C:\Python27\lib\site-packages\wx-2.8-msw-unicode\wx\_gdi.py", line 4857, in __init__
     """
PyAssertionError: C++ assertion "wxAssertFailure" failed at ..\..\src\msw\dcmemory.cpp(118) in wxMemoryDC::DoSelect(): Couldn't select a bitmap into wxMemoryDC

2012/03/31 12:03 --
Traceback (most recent call last):
   File "ButtonLine.py", line 442, in SetIterator
   File "ButtonLine.py", line 535, in Reset
   File "ButtonLine.py", line 516, in RefreshButtons
   File "ButtonLine.py", line 231, in _RefreshButtons
   File "ButtonLine.py", line 496, in _RenderLabels
   File "GraphicLabel.py", line 246, in GetBitmap
   File "GraphicLabel.py", line 109, in AlignText
   File "SubmersionServices.py", line 901, in RescaleKeepAspect
   File "C:\Python27\lib\site-packages\wx-2.8-msw-unicode\wx\_gdi.py", line 4857, in __init__
     """
PyAssertionError: C++ assertion "wxAssertFailure" failed at ..\..\src\msw\dcmemory.cpp(118) in wxMemoryDC::DoSelect(): Couldn't select a bitmap into wxMemoryDC

2012/04/10 06:18 --
Traceback (most recent call last):
   File "ButtonLine.py", line 379, in SetIterator
   File "ButtonLine.py", line 706, in Reset
   File "ButtonLine.py", line 670, in RefreshButtons
   File "ButtonLine.py", line 231, in _RefreshButtons
   File "ButtonLine.py", line 643, in _RenderLabels
   File "GraphicLabel.py", line 245, in GetBitmap
   File "GraphicLabel.py", line 173, in OverlayText
   File "SubmersionServices.py", line 901, in RescaleKeepAspect
   File "C:\Python27\lib\site-packages\wx-2.8-msw-unicode\wx\_gdi.py", line 4857, in __init__
     """
PyAssertionError: C++ assertion "wxAssertFailure" failed at ..\..\src\msw\dcmemory.cpp(118) in wxMemoryDC::DoSelect(): Couldn't select a bitmap into wxMemoryDC

It looks like maybe you have a leak of GDI objects, and eventually you use up all of the fixed number (64K ?) that Windows allows.

···


Best Regards,
Michael Moriarity

Hi,

As some of you may know, I have spent the last four years on a massive
project that I can't reveal the details of due to the fact that it was going
to be a commercial product. However, the company this product was for is
close to shutting it's doors and I'm trying to convince the owners to allow
me to open source this project. This project has become more to me than a
"product". It's become a work of love, as imperfect as it is in places.

This project is a "kiosk-mode" program intended to be used with a
touchscreen. It's also supposed to run indefinitely with no crashes.
However, every three to seven days the program crashes. I have included in
this email the exception logs with some parts redacted because they reveal
the nature of this product. I have struggled with this problem for the past
couple of years, and tried MANY things to fix it. However, I simply cannot
seem to solve it.

Can I get some insight or wisdom into why this is happening?

Hard to say from just the error but generally these sort of problems
can be traced to system resource leaks. Typically leaking gdi handles.
On Windows processes are usually limited to 10K GDI handles and once
that count has been reached many api calls begin failing or acting
erratically.

This is fairly easy to diagnose as you can use process monitor or
event the task manager to watch the GDI count on the application. If
this happens every 3-7 days as you say then you could probably add
some logging to the application to periodically record the resource
usage to see if there is gradual leak up until the crash.

Cody

···

On Wed, Apr 11, 2012 at 1:17 PM, Christopher L. Spencer <cspencer@cinci.rr.com> wrote:

Yes, I see that immediately now. Thank you for pointing out that I can track this using the task manager. My next question is, what is the recommended way of destroying the GDI objects once I am done with the images?

Here is the function that is representative of how I create and destroy DC objects...

     def RescaleKeepAspect(self,o_Bitmap,o_Size):
         self.log.debug("RescaleKeepAspect("+repr(o_Bitmap)+","+repr(o_Size)+")")
         bmpw=o_Size[0]
         bmph=o_Size[1]

         newwidth,newheight=self.GetResizeKeepAspect(wx.Size(o_Bitmap.GetWidth(),o_Bitmap.GetHeight()),o_Size)

         tempbmp=wx.EmptyBitmap(bmpw,bmph)
         tdc=wx.MemoryDC(tempbmp)

         img=wx.ImageFromBitmap(o_Bitmap)
         img.Rescale(newwidth,newheight)
         newbitmap=wx.BitmapFromImage(img)
         newdc=wx.MemoryDC(newbitmap)

         ix=(bmpw-newwidth)/2
         iy=(bmph-newheight)/2

         tdc.Blit(ix,iy,newwidth,newheight,newdc,0,0)

         newdc.SelectObject(wx.NullBitmap)
         tdc.SelectObject(wx.NullBitmap)

         del newdc
         del tdc

         return tempbmp

···

On 4/11/2012 2:27 PM, Cody wrote:

Hi,

On Wed, Apr 11, 2012 at 1:17 PM, Christopher L. Spencer > <cspencer@cinci.rr.com> wrote:

As some of you may know, I have spent the last four years on a massive
project that I can't reveal the details of due to the fact that it was going
to be a commercial product. However, the company this product was for is
close to shutting it's doors and I'm trying to convince the owners to allow
me to open source this project. This project has become more to me than a
"product". It's become a work of love, as imperfect as it is in places.

This project is a "kiosk-mode" program intended to be used with a
touchscreen. It's also supposed to run indefinitely with no crashes.
  However, every three to seven days the program crashes. I have included in
this email the exception logs with some parts redacted because they reveal
the nature of this product. I have struggled with this problem for the past
couple of years, and tried MANY things to fix it. However, I simply cannot
seem to solve it.

Can I get some insight or wisdom into why this is happening?

Hard to say from just the error but generally these sort of problems
can be traced to system resource leaks. Typically leaking gdi handles.
On Windows processes are usually limited to 10K GDI handles and once
that count has been reached many api calls begin failing or acting
erratically.

This is fairly easy to diagnose as you can use process monitor or
event the task manager to watch the GDI count on the application. If
this happens every 3-7 days as you say then you could probably add
some logging to the application to periodically record the resource
usage to see if there is gradual leak up until the crash.

Cody

Hi,

···

On 11 April 2012 20:37, Christopher L. Spencer wrote:

Yes, I see that immediately now. Thank you for pointing out that I can
track this using the task manager. My next question is, what is the
recommended way of destroying the GDI objects once I am done with the
images?

Here is the function that is representative of how I create and destroy DC
objects...

def RescaleKeepAspect(self,o_Bitmap,o_Size):

self.log.debug("RescaleKeepAspect("+repr(o_Bitmap)+","+repr(o_Size)+")")
bmpw=o_Size[0]
bmph=o_Size[1]

newwidth,newheight=self.GetResizeKeepAspect(wx.Size(o_Bitmap.GetWidth(),o_Bitmap.GetHeight()),o_Size)

   tempbmp=wx\.EmptyBitmap\(bmpw,bmph\)
   tdc=wx\.MemoryDC\(tempbmp\)

   img=wx\.ImageFromBitmap\(o\_Bitmap\)
   img\.Rescale\(newwidth,newheight\)
   newbitmap=wx\.BitmapFromImage\(img\)
   newdc=wx\.MemoryDC\(newbitmap\)

   ix=\(bmpw\-newwidth\)/2
   iy=\(bmph\-newheight\)/2

   tdc\.Blit\(ix,iy,newwidth,newheight,newdc,0,0\)

   newdc\.SelectObject\(wx\.NullBitmap\)
   tdc\.SelectObject\(wx\.NullBitmap\)

Why do you need to create a wx.MemoryDC in the first place? Can't you
just Rescale() the image and return img.ConvertToBitmap()?

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/

Don't really see anything wrong with what your doing there.

Should look at places where you either create transient windows
objects like dialogs and make sure that after they are getting closed
and no longer needed that the instance is explicitly destroyed. Beyond
that would need to start looking at usage of things like Pens, Fonts,
ect... though those tend to be harder to leak in wxPython than they
are in native c++ applications. If nothing fruitful if found from the
obvious things above then the leak could very well be inside of
wxWidgets somewhere as well.

Cody

Cody

···

On Wed, Apr 11, 2012 at 1:37 PM, Christopher L. Spencer <cspencer@cinci.rr.com> wrote:

Yes, I see that immediately now. Thank you for pointing out that I can
track this using the task manager. My next question is, what is the
recommended way of destroying the GDI objects once I am done with the
images?

Here is the function that is representative of how I create and destroy DC
objects...