Hi Willy,
I'm glad that I can reproduce this error in a single form. I will post it
again just so other people will notice. Here goes:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace Test_EEE_bug
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private DataTable dtSource = new DataTable( "Entries" );
private ArrayList logQueue = null;
private System.Timers.Timer logTimer = null;
private readonly object logLock = new object( );
private System.Threading.Thread workerThread = null;
private int counter = 0;
private System.Windows.Forms.DataGrid dataGrid1;
private System.Windows.Forms.DataGridTableStyle dataGridTableStyle1;
private System.Windows.Forms.DataGridTextBoxColumn dataGridTextBoxColumn1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
private delegate void SimpleHandler( );
private delegate void AddRowsToTableHandler( DataRow[] drs );
public Form1()
{
InitializeComponent();
DataColumn dtColumn = new DataColumn( "Text", typeof(string) );
dtColumn.ReadOnly = true;
dtSource.Columns.Add( dtColumn );
dataGrid1.SetDataBinding( dtSource, null );
logQueue = new ArrayList( );
logTimer = new System.Timers.Timer( );
logTimer.AutoReset = false;
logTimer.Interval = 250;
logTimer.SynchronizingObject = null;
logTimer.Elapsed += new
System.Timers.ElapsedEventHandler(logTimer_Elapsed);
logTimer.Enabled = true;
}
private void OnLoad(object sender, System.EventArgs e)
{
SpawnThread( );
}
private void SpawnThread()
{
workerThread = new System.Threading.Thread( new
System.Threading.ThreadStart( WorkingThread ) );
workerThread.Start( );
}
private void WorkingThread( )
{
try
{
for( int i = 0; i != 8; ++i )
Write( "Log line " + ++counter );
}
finally
{
this.BeginInvoke( new SimpleHandler( SpawnThread ) );
}
}
public void Write( string text )
{
lock( logLock )
logQueue.Add( text );
}
private void logTimer_Elapsed(object sender,
System.Timers.ElapsedEventArgs e)
{
ArrayList writeOutQueue = null;
lock( logLock )
if( logQueue.Count != 0 )
{
writeOutQueue = logQueue;
logQueue = new ArrayList( );
}
if( writeOutQueue == null )
logTimer.Enabled = true;
else
{
ArrayList dataRows = new ArrayList( );
for( int i = 0; i != writeOutQueue.Count; ++i )
{
DataRow dr1 = dtSource.NewRow( );
dr1[ "Text" ] = writeOutQueue[ i ];
dataRows.Add( dr1 );
}
BeginInvoke( new AddRowsToTableHandler( AddRowsToTable ), new object[]{
(DataRow[]) dataRows.ToArray( typeof(DataRow) ) } );
}
}
private void AddRowsToTable( DataRow[] drs )
{
dataGrid1.SuspendLayout( );
dtSource.BeginLoadData( );
foreach( DataRow dr in drs )
dtSource.Rows.Add( dr );
dtSource.EndLoadData( );
dataGrid1.ResumeLayout( );
logTimer.Enabled = true;
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.dataGrid1 = new System.Windows.Forms.DataGrid();
this.dataGridTableStyle1 = new System.Windows.Forms.DataGridTableStyle();
this.dataGridTextBoxColumn1 = new
System.Windows.Forms.DataGridTextBoxColumn();
((System.ComponentModel.ISupportInitialize)(this.dataGrid1)).BeginInit();
this.SuspendLayout();
//
// dataGrid1
//
this.dataGrid1.DataMember = "";
this.dataGrid1.HeaderForeColor = System.Drawing.SystemColors.ControlText;
this.dataGrid1.Location = new System.Drawing.Point(8, 8);
this.dataGrid1.Name = "dataGrid1";
this.dataGrid1.ReadOnly = true;
this.dataGrid1.Size = new System.Drawing.Size(592, 440);
this.dataGrid1.TabIndex = 0;
this.dataGrid1.TableStyles.AddRange(new
System.Windows.Forms.DataGridTableStyle[] {
this.dataGridTableStyle1});
//
// dataGridTableStyle1
//
this.dataGridTableStyle1.DataGrid = this.dataGrid1;
this.dataGridTableStyle1.GridColumnStyles.AddRange(new
System.Windows.Forms.DataGridColumnStyle[] {
this.dataGridTextBoxColumn1});
this.dataGridTableStyle1.HeaderForeColor =
System.Drawing.SystemColors.ControlText;
this.dataGridTableStyle1.MappingName = "";
this.dataGridTableStyle1.ReadOnly = true;
//
// dataGridTextBoxColumn1
//
this.dataGridTextBoxColumn1.Format = "";
this.dataGridTextBoxColumn1.FormatInfo = null;
this.dataGridTextBoxColumn1.HeaderText = "Text";
this.dataGridTextBoxColumn1.MappingName = "Text";
this.dataGridTextBoxColumn1.ReadOnly = true;
this.dataGridTextBoxColumn1.Width = 75;
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(608, 453);
this.Controls.Add(this.dataGrid1);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.OnLoad);
((System.ComponentModel.ISupportInitialize)(this.dataGrid1)).EndInit();
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
}
}
Kind regards,
--
Tom Tempelaere.
Willy Denoyette said:
Ok, this excludes possible reentrancy problems.
I'm affraid you will have to provide a small repro case.
Willy.
TT (Tom Tempelaere) said:
Hi Willy,
I changed BeginInvoke by Invoke, but I end up in the same situation:
ExecutionEngineException at the same place ("bm.Position=bm.Count-1").
Kind regards,
--
Tom Tempelaere.
Willy Denoyette said:
What happens when you use Invoke instead of BeginInvoke?
Willy.
"TT (Tom Tempelaere)" <_|\|_0$P@|/\|titi____AThotmailD.Tcom|/\|@P$0_|\|_>
wrote in message
Hi Paul,
Thank you for your response. I am using Microsoft compiler, on a
Microsoft
platform. The versions:
Microsoft Visual C# .NET 69462-335-0000007-18823
Microsoft Development Environment: 7.1.3088
.NET framework 1.1.4322
The program is very complex, and I suspect that there are several
issues
leading to the problem. I will first illustrate the problem, the code
fragments follow.
The ExecutionEngineException exception is always triggered at the same
spot,
a delegate that is invoked (using BeginInvoke) from a timer on a
DataGrid
which adds DataRow objects to the DataSource to which the grid is
bound.
Basically the situation is like this. We have a timer that checks
whether
there are any rows that are to be added to the grid (these rows are
added
to
a queue that is then checked). If there are rows to be added, the timer
invokes a delegate on the DataGrid that adds the rows. At the end of
that
delegate, the timer is reset. If there are no rows to be added, the
timer
resets itself.
The row-checker (RC) delegate is registered to the Elapsed event from a
timer (System.Timers.Timer) that has AutoReset set to false, with an
Interval of 250ms and SynchronizingObject is null. The RC delegate
checks
if
rows are present to be added. If so it invokes a row-adding (RA)
delegate on the DataGrid (using BeginInvoke) that does the following:
- SuspendLayout on the DataGrid
- BeginLoadData on the DataTable to which the DataGrid is bound
- Add the DataRow objects to the DataTable (passed as DataRow[]
parameter
to
the delegate)
- EndLoadData on the DataTable to which the DataGrid is bound
- Get the BindingContext of the DataGrid, and set the position to the
last
row
- ResumeLayout on the DataGrid
- Reset the timer (by setting its Enabled property to true)
The code for this delegate is (I assume that variables speak for
themselves):
private void AddRowsToTable( DataRow[] drs )
{
logTable.SuspendLayout( );
dtSource.BeginLoadData( );
if( maxEntries > 0 )
{
int diff = dtSource.Rows.Count + drs.Length - maxEntries;
if( diff > 0 )
for( int i = 0; i != diff; ++i )
dtSource.Rows.RemoveAt( 0 );
}
foreach( DataRow dr in drs )
dtSource.Rows.Add( dr );
dtSource.EndLoadData( );
if( TraceLastLine )
{
BindingManagerBase bm = logTable.BindingContext[
logTable.DataSource,
logTable.DataMember ];
bm.Position = bm.Count - 1;// <--exception here
}
logTable.ResumeLayout( );
if( LoggingEnabled )
logTimer.Enabled = true;
}
The ExecutionEngineException always triggers at the
"bm.Position=bm.Count-1"
statement. bm.Count is always greater than zero (the delegate isn't
invoked
unless there are rows present). The exception occurs when each
time-cycle
(250ms) there are rows present, and if the DataGrid has filled the
visible
region for the first time. I hope that last sentence makes sence. I
debugged
the invoked delegate; the first times the delegate is invoked the
exception
doesn't occur. It is when the grid's visible region is filled, that the
ExecutionEngineException is thrown.
I don't know if this is helpful. I think that if I don't find a
problem, I
will have to produce a small program that gives the exception. That is
a
pitty, because there are a lot of factors in the program. Anyway, any
help
or
hints are useful.
Thanks,
--
Tom Tempelaere.
PS 1: Timer construction code
logTimer = new System.Timers.Timer( );
logTimer.AutoReset = false;
logTimer.Interval = updateInterval_ms; // 250ms
logTimer.SynchronizingObject = null;
logTimer.Elapsed += new System.Timers.ElapsedEventHandler(
logTimer_Elapsed );
logTimer.Enabled = true;
PS 2: Timer delegate
private void logTimer_Elapsed( object sender,
System.Timers.ElapsedEventArgs
e )
{
ArrayList writeOutQueue = null;
lock( logLock )
{
if( logQueue.Count != 0 )
{
writeOutQueue = logQueue;
logQueue = new ArrayList( );
}
}
if( writeOutQueue == null )
{
if( LoggingEnabled )
logTimer.Enabled = true;
}
else
{
ArrayList dataRows = new ArrayList( );
int lowerLimit = ( maxEntries > 0 ) ? Math.Max( 0,
writeOutQueue.Count -
maxEntries ) : 0;
for( int i = lowerLimit; i != writeOutQueue.Count; ++i )
{
object[] logLine = (object[]) writeOutQueue[ i ];
DataRow dr1 = dtSource.NewRow( );
dr1[ "ID" ] = ++nrEntries;
dr1[ "Time" ] = ((DateTime) logLine[ 5 ]).TimeOfDay;
dr1[ "Message" ] = logLine[ 1 ];
MessageSeverity severity = (MessageSeverity) logLine[ 0 ];
dr1[ "Severity" ] = (severity==MessageSeverity.error) ? "Error" :
(severity==MessageSeverity.warning) ? "Warning" : "Info";
dr1[ "Category" ] = (short) logLine[ 2 ];
dr1[ "Event" ] = (int) logLine[ 3 ];
dr1[ "Data" ] = (object) DBNull.Value;
dataRows.Add( dr1 );
}
BeginInvoke( new AddRowsToTableHandler( AddRowsToTable ), new
object[]{
(DataRow[]) dataRows.ToArray( typeof(DataRow) ) } );
}
}
:
"TT (Tom Tempelaere)"
In my code I get an ExecutionEngineException. I don't
know what to do with it, and I can't seem to get rid of it.
How can I figure out what is causing it? It always appears
on the exact same line of code.
ExecutionEngineException indicates an unexpected internal error in the
runtime, so you might have found a bug. Are you using the Microsoft
compiler and framework, or an alternative version like Mono?
Posting the code would definitely be helpful!
P.