I am trying to create a menuitem class that displays
icons. I have found several sources on the internet and
have cobbled together the following class. The problem I
have is that when I use it on a form it works for a while
but then starts giving the following exception:
An unhandled exception of
type 'System.OutOfMemoryException' occurred in
system.drawing.dll
Additional information: Out of memory.
Can anyone see a problem with the class. or the way I am
calling it
MENU ITEM CLASS
Imports System.Drawing.Text
Imports System.ComponentModel
Namespace NSIconMenuItem
Public Class IconMenuItem
Inherits System.Windows.Forms.MenuItem
#Region " Windows Form Designer generated code "
Private _DisplayIcon As Icon
#Region " Constructors "
Public Sub New()
MyBase.New()
'This call is required by the Windows Form
Designer.
InitializeComponent()
'Add any initialization after the
InitializeComponent() call
Me.OwnerDraw = True
End Sub
Public Sub New(ByVal text As String)
MyBase.New(text)
'This call is required by the Windows Form
Designer.
InitializeComponent()
'Add any initialization after the
InitializeComponent() call
Me.OwnerDraw = True
End Sub
Public Sub New(ByVal text As String, ByVal OnClick
As EventHandler)
MyBase.New(text, OnClick)
'This call is required by the Windows Form
Designer.
InitializeComponent()
'Add any initialization after the
InitializeComponent() call
Me.OwnerDraw = True
End Sub
Public Sub New(ByVal text As String, ByVal Items()
As MenuItem)
MyBase.New(text, Items)
'This call is required by the Windows Form
Designer.
InitializeComponent()
'Add any initialization after the
InitializeComponent() call
Me.OwnerDraw = True
End Sub
Public Sub New(ByVal text As String, ByVal OnClick
As EventHandler, ByVal Shortcut As Shortcut)
MyBase.New(text, OnClick, Shortcut)
'This call is required by the Windows Form
Designer.
InitializeComponent()
'Add any initialization after the
InitializeComponent() call
Me.OwnerDraw = True
End Sub
Public Sub New(ByVal MergeType As MenuMerge, ByVal
MergeOrder As Integer, ByVal Shortcut As Shortcut, _
ByVal text As String, ByVal OnClick As
EventHandler, ByVal OnPopup As EventHandler, _
ByVal OnSelect As EventHandler, ByVal Items()
As MenuItem)
MyBase.New(MergeType, MergeOrder, Shortcut,
text, OnClick, OnPopup, OnSelect, Items)
'This call is required by the Windows Form
Designer.
InitializeComponent()
'Add any initialization after the
InitializeComponent() call
Me.OwnerDraw = True
End Sub
#End Region
Protected Overloads Overrides Sub Dispose(ByVal
disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
_DisplayIcon.Dispose()
_DisplayIcon = Nothing
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As
System.ComponentModel.IContainer
'NOTE: The following procedure is required by the
Windows Form Designer
'It can be modified using the Windows Form
Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> Private
Sub InitializeComponent()
'
'
'
components = New
System.ComponentModel.Container()
End Sub
#End Region
Public Property DisplayIcon() As Icon
Get
DisplayIcon = _DisplayIcon
End Get
Set(ByVal Value As Icon)
_DisplayIcon = Value
End Set
End Property
Protected Overrides Sub OnMeasureItem(ByVal e As
System.Windows.Forms.MeasureItemEventArgs)
MyBase.OnMeasureItem(e)
Dim sf As StringFormat = New StringFormat()
Dim fnt As Font = SystemInformation.MenuFont
sf.HotkeyPrefix = HotkeyPrefix.Show
sf.SetTabStops(50, New Single() {0})
If Me.DisplayIcon.Height > fnt.Height Then
e.ItemHeight = Me.DisplayIcon.Height + 6
Else
e.ItemHeight = fnt.Height + 6
End If
e.ItemWidth = CInt(e.Graphics.MeasureString
(AppendShortcut(), _
fnt, 1000, sf).Width) +
Me.DisplayIcon.Width + 5
sf.Dispose()
sf = Nothing
End Sub
Protected Overrides Sub OnDrawItem(ByVal e As
System.Windows.Forms.DrawItemEventArgs)
MyBase.OnDrawItem(e)
Dim sf As StringFormat
sf = New StringFormat()
Try
sf.HotkeyPrefix = HotkeyPrefix.Show
sf.SetTabStops(50, New Single() {0})
If ((e.State And
System.Windows.Forms.DrawItemState.Selected) <> 0) Then
e.Graphics.FillRectangle(New SolidBrush
(SystemColors.Highlight), e.Bounds)
e.Graphics.DrawString(AppendShortcut
(), SystemInformation.MenuFont, New SolidBrush
(SystemColors.HighlightText), New PointF(e.Bounds.Height +
2, CType((e.Bounds.Height - e.Graphics.MeasureString
(Me.Text, SystemInformation.MenuFont).Height), Integer) /
2), sf)
Else
e.Graphics.FillRectangle(New SolidBrush
(SystemColors.Menu), e.Bounds)
e.Graphics.DrawString(AppendShortcut
(), SystemInformation.MenuFont, New SolidBrush
(SystemColors.MenuText), New PointF(e.Bounds.Height + 2,
CType((e.Bounds.Height - e.Graphics.MeasureString(Me.Text,
SystemInformation.MenuFont).Height), Integer) / 2), sf)
End If
If Not (Me.DisplayIcon Is Nothing) Then
e.Graphics.DrawIcon(Me.DisplayIcon,
New Rectangle(0, 0, e.Bounds.Height, e.Bounds.Height))
End If
Catch x As Exception
MessageBox.Show(x.StackTrace)
End Try
sf.Dispose()
sf = Nothing
End Sub
Private Function AppendShortcut() As String
Dim s As String
s = Me.Text
' Check to see if you have a shortcut
' If so, append it to your existing text
If Me.ShowShortcut And Me.Shortcut <>
Shortcut.None Then
Dim k As Keys = CType(Shortcut, Keys)
s = s & Convert.ToChar(9) & _
TypeDescriptor.GetConverter(GetType
(Keys)).ConvertToString(k)
End If
Return s
End Function
End Class
End Namespace
FORM CLASS
Imports nsIconMenuItem
Public Class Form1
Inherits System.Windows.Forms.Form
#Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
'This call is required by the Windows Form
Designer.
InitializeComponent()
'Add any initialization after the
InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal
disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the
Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
Friend WithEvents MainMenu1 As
System.Windows.Forms.MainMenu
Friend WithEvents MenuItem1 As
System.Windows.Forms.MenuItem
Friend WithEvents MenuItem2 As IconMenuItem
Friend WithEvents MenuItem3 As
System.Windows.Forms.MenuItem
Friend WithEvents MenuItem4 As
System.Windows.Forms.MenuItem
<System.Diagnostics.DebuggerStepThrough()> Private Sub
InitializeComponent()
Me.MainMenu1 = New System.Windows.Forms.MainMenu()
Me.MenuItem1 = New System.Windows.Forms.MenuItem()
Me.MenuItem2 = New IconMenuItem()
Me.MenuItem3 = New System.Windows.Forms.MenuItem()
Me.MenuItem4 = New System.Windows.Forms.MenuItem()
'
'MainMenu1
'
Me.MainMenu1.MenuItems.AddRange(New
System.Windows.Forms.MenuItem() {Me.MenuItem1})
'
'MenuItem1
'
Me.MenuItem1.Index = 0
Me.MenuItem1.MenuItems.AddRange(New
System.Windows.Forms.MenuItem() {Me.MenuItem2,
Me.MenuItem3, Me.MenuItem4})
Me.MenuItem1.Text = "&File"
'
'MenuItem2
'
Me.MenuItem2.Index = 0
Me.MenuItem2.Text = "&Open"
Me.MenuItem2.DisplayIcon = New Icon("C:\Documents
and Settings\steveip.CORPOFLONDON\My Documents\Visual
Studio Projects\MenuTest\new.ico")
Me.MenuItem2.Shortcut = Shortcut.CtrlO
'
'MenuItem3
'
Me.MenuItem3.Index = 1
Me.MenuItem3.Text = "-"
'
'MenuItem4
'
Me.MenuItem4.Index = 2
Me.MenuItem4.Text = "E&xit"
'
'Form1
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5,
13)
Me.ClientSize = New System.Drawing.Size(292, 273)
Me.Menu = Me.MainMenu1
Me.Name = "Form1"
Me.Text = "Form1"
End Sub
#End Region
Private Sub Form1_Load(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles MyBase.Load
End Sub
Private Sub MenuItem2_Click(ByVal sender As Object,
ByVal e As System.EventArgs) Handles MenuItem2.Click
MessageBox.Show("icon clicked", "menu icon",
MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
End Class
--
This posting is provided "AS IS" with no warranties, and confers no rights.
You assume all risk for your use. © 2001 Microsoft Corporation. All rights
reserved.
"steve percival" <steve.p...@corpoflondon.gov.uk> wrote in message
news:a19e01c1c135$129b7550$9ae62ecf@tkmsftngxa02...
I also did a bit of playing around with the code and found
that the following scenario caused the problem.
in the IconMenuItem classes method ondrawitem put the
following lines of code.
dim a as integer =0
a = 32/a
this will cause an exception. now remove the lines of
code. and re run the program the out of memory exception
in System.Drawing.dll will appear. the only thing that
will cure it is a reboot. Also the above will also screw
up context menus on the desktop. (This was tested using a
win2000 pro)
Could this be a bug is the Framework?
Steve.
>> IconMenuItem
>> InitialiÍ{ wð!h ,_¶ zeComponent() call
Good debugging...that helped a lot. You are correct with your diagnosis;
the exception being thrown (in this case DivideByZeroException, but it
doesn't matter) is the core problem here. Doing so does break context menus
in the Windows Shell (ouch! I'll follow up on that one to see if we can't
stop that from happening...).
The OutOfMemoryException you're seeing seems to only occur after those
steps. When I fire up your code from the previous posting, it works great.
If I then throw the exceptoin from the MenuItem.DrawItem event, Windows is
now in a pretty unhappy state and GDI+ fails to get a hold of a drawing
surface and you get the results you're seeing.
Shawn
--
This posting is provided "AS IS" with no warranties, and confers no rights.
You assume all risk for your use. © 2001 Microsoft Corporation. All rights
reserved.
"steve percival" <steve.p...@corpoflondon.gov.uk> wrote in message
news:ac4b01c1c35f$c1898850$9ae62ecf@tkmsftngxa02...