Hi all,
I've witnessed this big red cross appearing in place of an UltraGrid when calls wern't marshalled correctly to the main/UI thread when making use of the control.
I have an application that I've ensured only accesses controls from the main/UI thread.
Recently, we've been stress-testing our application and have witnessed this red cross again. This time it appears in place of a ribbon/toolbar control. It's only ever appeared when we're using excessive amounts of memory - causing some components of the application to become sluggish. One example is when the user creates a scatter UltraChart component that has about 40,000 points of data.
So I have a couple of questions concerning this issue:
I'd appreciate any more information regarding this red cross. From what I've read so far:
Any information what so ever (even simply to clarify my current understanding is correct) would be greatly appreciated.
Cheers,
Richard
Can anyone help with this? I've now noticed it can occur when using a low amount of memory, so that doesn't seem to affect it. The stack trace I'm getting from the unhandled exception is:
************** Exception Text **************
System.ArgumentException: Parameter is not valid.
at System.Drawing.Graphics.GetHdc()
at Infragistics.Win.FormattedLinkLabel.PositionElementsCache.MeasureTextGDIOrThemed(String text, Font font, TextFormatFlags textFormatFlags)
at Infragistics.Win.FormattedLinkLabel.PositionElementsCache.MeasureCharacterRangesGDI(String text, Font font, TextFormatFlags textFormatFlags, CharacterRange[] ranges)
at Infragistics.Win.FormattedLinkLabel.PositionElementsCache.ReMeasureParts(String text, Int32[] parts, Single[] widths, Int32 partStartIndex, Int32 partEndIndex, Font font, Single& lineHeight)
at Infragistics.Win.FormattedLinkLabel.PositionElementsCache.MeasureParts(String text, Int32[] parts, Font font, Single& lineHeight)
at Infragistics.Win.FormattedLinkLabel.NodeText.TextLayoutInfo.Measure(PositionElementsInfo& info)
at Infragistics.Win.FormattedLinkLabel.NodeText.PositionSelf(PositionElementsInfo& info)
at Infragistics.Win.FormattedLinkLabel.NodeBase.PositionHelper(PositionElementsInfo& info)
at Infragistics.Win.FormattedLinkLabel.NodeBase.Position(PositionElementsInfo& info)
at Infragistics.Win.FormattedLinkLabel.NodeBase.PositionChildNodes(PositionElementsInfo& info)
at Infragistics.Win.FormattedLinkLabel.NodeBlock.PositionChildNodes(PositionElementsInfo& info)
at Infragistics.Win.FormattedLinkLabel.NodeBase.PositionElements(IFormattedLinkLabelOwner owner, UIElement containerElem, Rectangle containerRect, Boolean calcIdealLayoutSize, Size& layoutSize)
at Infragistics.Win.FormattedLinkLabel.FormattedTextUIElement.PositionElementsHelper(Rectangle layoutRect, Boolean setElemRectToIdealSize)
at Infragistics.Win.FormattedLinkLabel.FormattedTextUIElement.PositionChildElements()
at Infragistics.Win.UltraWinToolbars.RibbonCaptionUIElement.PositionChildElements()
at Infragistics.Win.UIElement.VerifyChildElements(ControlUIElementBase controlElement, Boolean recursive)
at Infragistics.Win.UIElement.DrawHelper(Graphics graphics, Rectangle invalidRectangle, Boolean doubleBuffer, AlphaBlendMode alphaBlendMode, Boolean clipText, Boolean forceDrawAsFocused, Boolean preventAlphaBlendGraphics)
at Infragistics.Win.UIElement.Draw(Graphics graphics, Rectangle invalidRectangle, Boolean doubleBuffer, AlphaBlendMode alphaBlendMode, Boolean forceDrawAsFocused, Boolean preventAlphaBlendGraphics)
at Infragistics.Win.ControlUIElementBase.Draw(Graphics graphics, Rectangle invalidRectangle, Boolean doubleBuffer, AlphaBlendMode alphaBlendMode, Size elementSize, Boolean preventAlphaBlendGraphics)
at Infragistics.Win.ControlUIElementBase.Draw(Graphics graphics, Rectangle invalidRectangle, Boolean doubleBuffer, AlphaBlendMode alphaBlendMode, Size elementSize)
at Infragistics.Win.ControlUIElementBase.Draw(Graphics graphics, Rectangle invalidRectangle, Boolean doubleBuffer, AlphaBlendMode alphaBlendMode)
at Infragistics.Win.UltraControlBase.OnPaint(PaintEventArgs pe)
at Infragistics.Win.UltraWinToolbars.UltraToolbarsDockArea.OnPaint(PaintEventArgs pe)
at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer)
at System.Windows.Forms.Control.WmPaint(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
The big red "X" occurs any time an exception occurs inside the OnPaint method of a control. Since the controls have been around so long and are so well-used and therefore well-tested, we rarely find bugs in the painting code any more. But it can happen.Does the exception always occur with the same call stack which includes a reference to the FormattedLinkLabel?Is the exception always on a call to GetHdc?Or does the exception vary each time it occurs?If the exception always happens on the same call to GetHdc being called from MeasureTextGDIOrThemed, then this is likely a bug in the FormattedLinkLabel.If the exception varies each time it occurs, then it's probably a memory or threading issue.
Mike,
My colleague has done some research on this and found that the problem is likely related to a GDI Memory Leak (http://megakemp.com/2009/02/25/gdi-memory-leak-in-windows-forms/).
Infragistics.Win.FormattedLinkLabel.PositionElementsCache contains a function with this signature:
private SizeF MeasureTextGDIOrThemed(string text, Font font, TextFormatFlags textFormatFlags), which does exactly what the link I provided says.
If I understand the article correctly, this signature is not disposing of 1 and possible 2 pointers:
IntPtr hObject2 = NativeWindowMethods.SelectObject(hdc, hObject);and if this needs cleaned up, then I would assume the following line would need to be cleaned up as well:NativeWindow.Methods.SelectObject(hdc, hObject2);
Mike: Please pass this onto your developers, as this signature appears to be the same in Infragistics4.Win.v13.2.dll
Thanks,Johnie Karr
Hello Johnie,
I'm attempting to reproduce the issue you described, but I'm not able to. Which version of Windows are you using?
Dave,We can verify the problem with Windows XP, 7, and 8.
Here is what you will need to do for an easy test.
By default, Windows allows 10,000 user objects and 10,000 GDI objects per application instance. What you are testing for is a slow leak, and obviously 10,000 objects is a lot to work your way up to.
Luckily for us, this "quota" is a setting in the Registry, so we can first modify the registry to a more manageable number, say 1,000 user objects and 500 GDI objects.
GDI Object Limit:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\GDIProcessHandleQuotaUser Object Limit:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\USERProcessHandleQuota
I only changed one of these at a time, and I used a computer that didn't have any other programs running. To monitor, open Task Manager and add columns User Objects and GDI Objects.
Now that you have your settings to a easily manageable number, open a project that has lots of Infragistics controls and many child windows that also have Infragistics controls. As you continue to open and close windows, you will see that the GDI Objects and User Objects will slowly creep up, and once they hit their limit, you will get the red box.
The decompiled code I provided in my earlier post is only one place where we found this slow leak in the library, we only looked in this one place though, so it's likely in more places.
Thank you for your response. I should have been more clear with my previous response. When I run my sample, I don't see the number of GDI objects or USER objects going up and up without stop.
I've attached my sample so you can see if it reproduces the issue on your end. If it doesn't, let me know how I can modify it so it does reproduce the issue.
Hi Dave,
The reason we can't duplicate the issue with your sample, is because you are dynamically creating and then disposing that created object. This doesn't represent a real-world application however. I've modified the sample for you, and in the process, I have come to a better understanding of the leak behavior.
The sample contains an MDI parent with a button. When the button is clicked, a child window is opened up. When the child window is closed, the counts do not drop to the original value. It should be noted that the object counts will not go up past this new number on subsequent window open/closes. I don't know how to make that statement clear, so I'm sorry it doesn't make any sense. I've used our real application and took step-by-step screenshots (the word document), which will demonstrate what I mean. Using the new sample project, here is what happens.
Obviously, this issue wouldn't occur for a small application (like our sample). However; our application contains many, many windows, so as windows are opened and closed over time, this number grows higher and higher.
Thanks,Johnie
Thank you for your response.
What you're seeing there is not actually a leak. What you're seeing is some objects being retained after they are created for optimization purposes. I've modified your sample to remove all of the Infragistics controls and added a second MDI child form that is opened by "button1". If you run it, you'll see the same kind of behavior in regards to the GDI and USER objects.
It is still very possible that your application has a GDI/USER object leak, but the sample you provided doesn't reproduce that.