Updating DataRow throws Exception 0xC0000005

  • Thread starter Pedro \Shade\ Miller
  • Start date
P

Pedro \Shade\ Miller

Hi guys,

I'm facing a very puzzling problem and thought maybe someone here
could help. It's been driving me nuts, really.

I'm developing a Windows CE application (to be deployed in Windows CE
4.2 core) and my emulator is running Windows CE .NET v4.10 (build
908). I don't have a device with me now where I could test the
software, unfortunately (that's still being arranged).

One of the code bits is a button to consolidate data, merging rows in
a DataTable:

Code:
private void btnConsolidar_Click(object sender, System.EventArgs e)
{
for( int j=0; j < dataTable.Rows.Count; j++ )
{
DataRow row1 = dataTable.Rows[j];
String ean = (String)row1["ean"];
String cod = (String)( ( row1["codigo"] == null ) ? "" :
row1["codigo"] );

int idx;
for( idx=j+1; idx < dataTable.Rows.Count; idx++ )
{
DataRow row2 = dataTable.Rows[idx];
if( ((String)row2["ean"]) == ean || (cod != "" &&
((String)row2["codigo"]) == cod ))
{
long q1 = long.Parse((string)row1["quant"]);
long q2 = long.Parse((string)row2["quant"]);


if( bConferencia )
{
if( (string)row1["quant1"] == "0" )
{
string q =
(string)row2["quant1"];
//row1["quant1"] = q;
dataTable.Rows[j]["quant1"] = q; // CRASH!
}
if( (string)row1["quant2"] == "0" )
//row1["quant2"] = (string)row2["quant2"];
dataTable.Rows[j]["quant2"] =
(string)row2["quant2"];
}

row1["quant"] = q1+q2;

// remove a fileira copiada
dataTable.Rows.RemoveAt( idx );
//dataTable.AcceptChanges();
// row1 = dataTable.Rows[j];

// compensa a fileira removida
idx--;
}
}
}

dgItens.DataSource = dataTable;
dgItens.Refresh();
}

Please forgive the commented extra code, I've been adding and removing
scaffolding looking for the problem.

What this does is something like this: suppose you have three rows,
thus:

A 0 0 7
B 4 3 0
A 0 0 3
C 1 5 0
A 2 2 0

It consolidates the same products to:

A 2 2 10
B 4 3 0

It works when you only have one product repeated (i.e., only one row1
is updated). However, if there are several repeated products,

A 0 0 7
B 0 0 5
A 2 2 0
B 4 3 0

the system crashes with a native exception (code 0xC0000005, which
research shows is an illegal memory access exception) when I try to
update the second row in the table (line marked "CRASH!", above). Note
that the first update goes well! Also, if I set it up with only one
product repeated, press the button, set it up with another product
repeated, and press the button again, it works.

I'm guessing it has to do with the way DataTable updates its rows, but
so far, I've had no luck figuring the problem out. I'll greatly
appreciate any help I can get!

Thanks in advance,

Shade.
 
Joined
Feb 25, 2008
Messages
3
Reaction score
0
Oops, sorry, I didn't realize that posting it to Google Groups would make the thread appear here.

Cheers

Shade
 
B

Bjorn Brox

Pedro "Shade" Miller skrev:
Hi guys,

I'm facing a very puzzling problem and thought maybe someone here
could help. It's been driving me nuts, really.
....

Code:
private void btnConsolidar_Click(object sender, System.EventArgs e)
{
for( int j=0; j < dataTable.Rows.Count; j++ ) ....
dataTable.Rows.RemoveAt( idx );[/QUOTE]

Classical error: You are modifying the table you are doing the "for"
loop on. BTDT

You cannot continue in the loop after such an operation and have to
restart the loop with new loop conditions if you want to perform others
operations.
 
Joined
Feb 25, 2008
Messages
3
Reaction score
0
Bjorn Brox said:

Classical error: You are modifying the table you are doing the "for"
loop on. BTDT
Thanks for the input, Bjorn. And yes, BTDT with modifying loop conditions as well. But how can I restart the loop in this case? I've used numerical indices with exactly that concern in mind.

I've done some alterations just to try it out, but still no luck:

Code:
  private void btnConsolidar_Click(object sender, System.EventArgs e)
  {
  	bool modified = true;
  	while( modified ) 
  	{
  		modified = false;
  		for( int j=0; j < dataTable.Rows.Count-1; j++ ) 
  		{
  			DataRow row1 = dataTable.Rows[j];
  			String ean = (String)row1["ean"];
  			String cod = (String)( ( row1["codigo"] == null ) ? "" : row1["codigo"] );
  
  			int idx;
  			for( idx=j+1; idx < dataTable.Rows.Count; idx++ ) 
  			{
  				DataRow row2 = dataTable.Rows[idx];
  				if( ((String)row2["ean"]) == ean || (cod != "" && ((String)row2["codigo"]) == cod )) 
  				{						
  					long q1 = long.Parse((string)row1["quant"]);
  					long q2 = long.Parse((string)row2["quant"]);
  
  					row1["quant"] = q1+q2;
  									    
  					// remove a fileira copiada
  					dataTable.Rows.RemoveAt( idx );
  					modified = true;
  
  					break;
  				}
  			}
  			if( modified ) 
  			{
  				break;
  			}
  		}
  	    dataTable.AcceptChanges();
  				
  		 dgItens.DataSource = dataTable;
  	    dgItens.Refresh();
  	}
 }

I mean, this is as much a <s>dumb</s> thorough loop as I can think is possible -- I'm even looping unnecessarily for *each* repeated line! And I'm even refreshing the DataTable and its associated DataGrid.

I think this reeks of DataTable trouble. But what gets me is that as long as we stay inside the inner loop any alterations are fine.

How can I upgrade my emulator, i.e., install a service pack? Perhaps something will click.

Cheers and thanks again!
 
P

Pedro \Shade\ Miller

Classical error: You are modifying the table you are doing the "for"
loop on. BTDT

Thanks for the input, Bjorn. And yes, BTDT with modifying loop
conditions as well. But how can I restart the loop in this case? I've
used numerical indices with exactly that concern in mind.

I've done some alterations just to try it out, but still no luck:

Code:
private void btnConsolidar_Click(object sender, System.EventArgs e)
{
bool modified = true;
while( modified )
{
modified = false;
for( int j=0; j < dataTable.Rows.Count-1; j++ )
{
DataRow row1 = dataTable.Rows[j];
String ean = (String)row1["ean"];
String cod = (String)( ( row1["codigo"] == null ) ? "" :
row1["codigo"] );

int idx;
for( idx=j+1; idx < dataTable.Rows.Count; idx++ )
{
DataRow row2 = dataTable.Rows[idx];
if( ((String)row2["ean"]) == ean || (cod != "" &&
((String)row2["codigo"]) == cod ))
{
long q1 = long.Parse((string)row1["quant"]);
long q2 = long.Parse((string)row2["quant"]);

row1["quant"] = q1+q2;

// remove a fileira copiada
dataTable.Rows.RemoveAt( idx );
modified = true;

break;
}
}
if( modified )
{
break;
}
}
dataTable.AcceptChanges();

dgItens.DataSource = dataTable;
dgItens.Refresh();
}
}

I mean, this is as much a <s>dumb</s> thorough loop as I can think is
possible -- I'm even looping unnecessarily for *each* repeated line!
And I'm even refreshing the DataTable and its associated DataGrid.

I think this reeks of DataTable trouble. But what gets me is that as
long as we stay inside the inner loop any alterations are fine.

How can I upgrade my emulator, i.e., install a service pack? Perhaps
something will click.

Cheers and thanks again!
 
G

Guest

You should start at the last row and move up. When you remove at the top,
all lower rows get moved up, causing your indexing to no longer work.

e.g.
for( int j=dataTable.Rows.Count - 1; j >= 0 ; j-- )
{
...
}


--

Chris Tacke, eMVP
Join the Embedded Developer Community
http://community.opennetcf.com


Pedro "Shade" Miller said:
Classical error: You are modifying the table you are doing the "for"
loop on. BTDT

Thanks for the input, Bjorn. And yes, BTDT with modifying loop
conditions as well. But how can I restart the loop in this case? I've
used numerical indices with exactly that concern in mind.

I've done some alterations just to try it out, but still no luck:

Code:
private void btnConsolidar_Click(object sender, System.EventArgs e)
{
bool modified = true;
while( modified )
{
modified = false;
for( int j=0; j < dataTable.Rows.Count-1; j++ )
{
DataRow row1 = dataTable.Rows[j];
String ean = (String)row1["ean"];
String cod = (String)( ( row1["codigo"] == null ) ? "" :
row1["codigo"] );

int idx;
for( idx=j+1; idx < dataTable.Rows.Count; idx++ )
{
DataRow row2 = dataTable.Rows[idx];
if( ((String)row2["ean"]) == ean || (cod != "" &&
((String)row2["codigo"]) == cod ))
{
long q1 = long.Parse((string)row1["quant"]);
long q2 = long.Parse((string)row2["quant"]);

row1["quant"] = q1+q2;

// remove a fileira copiada
dataTable.Rows.RemoveAt( idx );
modified = true;

break;
}
}
if( modified )
{
break;
}
}
dataTable.AcceptChanges();

dgItens.DataSource = dataTable;
dgItens.Refresh();
}
}

I mean, this is as much a <s>dumb</s> thorough loop as I can think is
possible -- I'm even looping unnecessarily for *each* repeated line!
And I'm even refreshing the DataTable and its associated DataGrid.

I think this reeks of DataTable trouble. But what gets me is that as
long as we stay inside the inner loop any alterations are fine.

How can I upgrade my emulator, i.e., install a service pack? Perhaps
something will click.

Cheers and thanks again!
 
P

Pedro \Shade\ Miller

Thanks for the input, Chris!

Wow, this is interesting -- I've changed both loops to decrementing
counters and I'm hitting the exception at the same row as before
(i.e., earlier)!!

First things first. I think one thing that is being missed is the fact
that the crash is *not* coming at the first indexing operation (long
q1 = row1["quant"]), but at the first *write* index operation
(row1["quant"] = q1+q2).

Test case for the code further below:

D 1
A 1
B 1
A 1
B 1
C 1

Crashes with j=2, idx=4 (i.e., the "B" lines) at the line marked
below. When I was running the other way around (from 0 incrementing)
it would work with "A" but crash on "B". Hmm. Weird.

Code:

Code:
for( int j = dataTable.Rows.Count-2; j >= 0; j-- )
{
DataRow row1 = dataTable.Rows[j];
String ean = (String)row1["ean"];
String cod = (String)( ( row1["codigo"] == null ) ? "" :
row1["codigo"] );

int idx;
for( idx=dataTable.Rows.Count-1; idx >= j+1 ; idx-- )
{
DataRow row2 = dataTable.Rows[idx];
if( ((String)row2["ean"]) == ean || (cod != "" &&
((String)row2["codigo"]) == cod ))
{
long q1 = long.Parse((string)row1["quant"]); // no problem
long q2 = long.Parse((string)row2["quant"]);

dataTable.Rows[j]["quant"] = q1+q2; // CRASH!
// remove a fileira copiada
dataTable.Rows.RemoveAt( idx );
modified = true;
break;
}
}
if( modified )
{
break;
}
}

This must be one of the lowest points in my career. :( I'm being
beaten by either a faulty framework or (probably) my own stupidity.
Wow. I can't believe I'll have to keep a collection of all the row
indices to skip/delete and do it afterwards (presuming that even
works!). This is awful.

Cheers and thanks for the help, guys.

P.
 
G

Guest

I don't think that's your problem. The reverse indexing removal is required
in any indexed iteration - moving forward will yield an index out of bounds
problem or missing data that you want removed. It's not going to cause an
access violation. Your problem lies elsewhere. Exactly where is not
obvious, but it's likely got something to do with whatever is backing your
DataTable. We don't have that piece of the puzzle, so we're only guessing
at this point.

In my experience access violations are often caused by references becoming
invalid or invalid use of disposed pointers. I have do idea where in your
code that might be happening, but that's what I'd be looking for.


--

Chris Tacke, eMVP
Join the Embedded Developer Community
http://community.opennetcf.com




Pedro "Shade" Miller said:
Thanks for the input, Chris!

Wow, this is interesting -- I've changed both loops to decrementing
counters and I'm hitting the exception at the same row as before
(i.e., earlier)!!

First things first. I think one thing that is being missed is the fact
that the crash is *not* coming at the first indexing operation (long
q1 = row1["quant"]), but at the first *write* index operation
(row1["quant"] = q1+q2).

Test case for the code further below:

D 1
A 1
B 1
A 1
B 1
C 1

Crashes with j=2, idx=4 (i.e., the "B" lines) at the line marked
below. When I was running the other way around (from 0 incrementing)
it would work with "A" but crash on "B". Hmm. Weird.

Code:

Code:
for( int j = dataTable.Rows.Count-2; j >= 0; j-- )
{
DataRow row1 = dataTable.Rows[j];
String ean = (String)row1["ean"];
String cod = (String)( ( row1["codigo"] == null ) ? "" :
row1["codigo"] );

int idx;
for( idx=dataTable.Rows.Count-1; idx >= j+1 ; idx-- )
{
DataRow row2 = dataTable.Rows[idx];
if( ((String)row2["ean"]) == ean || (cod != "" &&
((String)row2["codigo"]) == cod ))
{
long q1 = long.Parse((string)row1["quant"]); // no problem
long q2 = long.Parse((string)row2["quant"]);

dataTable.Rows[j]["quant"] = q1+q2; // CRASH!
// remove a fileira copiada
dataTable.Rows.RemoveAt( idx );
modified = true;
break;
}
}
if( modified )
{
break;
}
}

This must be one of the lowest points in my career. :( I'm being
beaten by either a faulty framework or (probably) my own stupidity.
Wow. I can't believe I'll have to keep a collection of all the row
indices to skip/delete and do it afterwards (presuming that even
works!). This is awful.

Cheers and thanks for the help, guys.

P.

You should start at the last row and move up. When you remove at the
top,
all lower rows get moved up, causing your indexing to no longer work.

e.g.
for( int j=dataTable.Rows.Count - 1; j >= 0 ; j-- )
{
..

}
 
J

Jin Chang

Thanks for the input, Chris!

Wow, this is interesting -- I've changed both loops to decrementing
counters and I'm hitting the exception at the same row as before
(i.e., earlier)!!

First things first. I think one thing that is being missed is the fact
that the crash is *not* coming at the first indexing operation (long
q1 = row1["quant"]), but at the first *write* index operation
(row1["quant"] = q1+q2).

Test case for the code further below:

D 1
A 1
B 1
A 1
B 1
C 1

Crashes with j=2, idx=4 (i.e., the "B" lines) at the line marked
below. When I was running the other way around (from 0 incrementing)
it would work with "A" but crash on "B". Hmm. Weird.

Code:

Code:
for( int j = dataTable.Rows.Count-2; j >= 0; j-- )
{
DataRow row1 = dataTable.Rows[j];
String ean = (String)row1["ean"];
String cod = (String)( ( row1["codigo"] == null ) ? "" :
row1["codigo"] );

int idx;
for( idx=dataTable.Rows.Count-1; idx >= j+1 ; idx-- )
{
DataRow row2 = dataTable.Rows[idx];
if( ((String)row2["ean"]) == ean || (cod != "" &&
((String)row2["codigo"]) == cod ))
{
long q1 = long.Parse((string)row1["quant"]); // no problem
long q2 = long.Parse((string)row2["quant"]);

dataTable.Rows[j]["quant"] = q1+q2; // CRASH!
// remove a fileira copiada
dataTable.Rows.RemoveAt( idx );
modified = true;
break;
}
}
if( modified )
{
break;
}}

This must be one of the lowest points in my career. :( I'm being
beaten by either a faulty framework or (probably) my own stupidity.
Wow. I can't believe I'll have to keep a collection of all the row
indices to skip/delete and do it afterwards (presuming that even
works!). This is awful.

Cheers and thanks for the help, guys.

P.

You should start at the last row and move up. When you remove at the top,
all lower rows get moved up, causing your indexing to no longer work.
e.g.
for( int j=dataTable.Rows.Count - 1; j >= 0 ; j-- )
{
..


Chris Tacke, eMVP
Join the Embedded Developer Communityhttp://community.opennetcf.com

Works fine when I simulated your last code by manually creating the
DataTable with data you were using. Based on this, it appears that
your loop logic is ok. So, the source of the crash is likely related
to something else -- perhaps data conversion and/or dealing with null
values.

Here's the code I used:

public partial class Form5 : Form
{
private System.Data.DataSet dataSet;

public Form5()
{
InitializeComponent();
}

private void Form5_Load(object sender, EventArgs e)
{

}

private void MakeParentTable()
{
// Create a new DataTable.
System.Data.DataTable table = new DataTable("TestTable");
// Declare variables for DataColumn and DataRow objects.
DataColumn column;
DataRow row;

// Create new DataColumn, set DataType,
// ColumnName and add to DataTable.
column = new DataColumn();
column.DataType = System.Type.GetType("System.String");
column.ColumnName = "id";
column.ReadOnly = true;
column.Unique = false;
// Add the Column to the DataColumnCollection.
table.Columns.Add(column);

// Create new DataColumn, set DataType,
// ColumnName and add to DataTable.
column = new DataColumn();
column.DataType = System.Type.GetType("System.String");
column.ColumnName = "val";
column.ReadOnly = false;
column.Unique = false;
// Add the Column to the DataColumnCollection.
table.Columns.Add(column);

// Instantiate the DataSet variable.
dataSet = new DataSet();
// Add the new DataTable to the DataSet.
dataSet.Tables.Add(table);

// Create three new DataRow objects and add
// them to the DataTable
row = table.NewRow();
row["id"] = "D";
row["val"] = "1";
table.Rows.Add(row);

row = table.NewRow();
row["id"] = "A";
row["val"] = "1";
table.Rows.Add(row);

row = table.NewRow();
row["id"] = "B";
row["val"] = "1";
table.Rows.Add(row);

row = table.NewRow();
row["id"] = "A";
row["val"] = "1";
table.Rows.Add(row);

row = table.NewRow();
row["id"] = "B";
row["val"] = "1";
table.Rows.Add(row);

row = table.NewRow();
row["id"] = "C";
row["val"] = "1";
table.Rows.Add(row);
}

private void btnInit_Click(object sender, EventArgs e)
{
MakeParentTable();
DisplayData();
}

private void btnCombine_Click(object sender, EventArgs e)
{
DataTable dataTable = dataSet.Tables["TestTable"];

bool modified = false;

for (int j = dataTable.Rows.Count - 2; j >= 0; j--)
{
DataRow row1 = dataTable.Rows[j];
String id = (String)row1["id"];

int idx;
for (idx = dataTable.Rows.Count - 1; idx >= j + 1;
idx--)
{
DataRow row2 = dataTable.Rows[idx];
if (((String)row2["id"]) == id)
{
long q1 = long.Parse((string)row1["val"]); //
no problem
long q2 = long.Parse((string)row2["val"]);

dataTable.Rows[j]["val"] = q1 + q2; // CRASH!
// remove a fileira copiada
dataTable.Rows.RemoveAt(idx);
modified = true;
break;
}
}
if (modified)
{
break;
}
}

DisplayData();
}

public void DisplayData()
{
DataTable dt = dataSet.Tables["TestTable"];

string out_text = "";

foreach (DataRow dr in dt.Rows)
out_text += dr["id"].ToString() + ", " +
dr["val"].ToString() + "\n";

label1.Text = out_text;
}
}
 
P

Pedro \Shade\ Miller

I don't think that's your problem. (...)
Your problem lies elsewhere. Exactly where is not
obvious, but it's likely got something to do with whatever is backing your
DataTable.

Yes, I agree. I'll try Jin's test code and look for differences with
my DataTable initialization. I'll post my side of things if I still
can't figure it out.

Once again, thanks for the help, guys.

Cheers,

Pedro.
 
P

Pedro \Shade\ Miller

Jin,

Works fine when I simulated your last code by manually creating the
DataTable with data you were using. Based on this, it appears that
your loop logic is ok. So, the source of the crash is likely related
to something else -- perhaps data conversion and/or dealing with null
values.

Here's the code I used:

Yeah, your code works just fine here as well. I've even changed some
things to bring it closer to the original -- messed with column
creation, dataset... I've even added a dataGrid to show it in the Form
(like the original has) and still no problem.

Regarding data conversion, watching the program run in the debugger
shows me the appropriate data is valid, i.e., I can see both q1 and q2
are storing (long)1.

I'll have to sleep on it. Thanks for the help. If I can't get it to
work tomorrow I guess I'll post more code. :-/

Cheers,

P.
 
P

Pedro \Shade\ Miller

FOUND IT! No solution so far, though:

Works fine when I simulated your last code by manually creating the
DataTable with data you were using. Based on this, it appears that
(...)
row = table.NewRow();
row["id"] = "A";
row["val"] = "1";
table.Rows.Add(row);

This is what's different. I'm using InsertAt to add rows at the top.
Trying your sample code (with a couple of modifications that didn't
cause any problems) with the following alteration:

row = table.NewRow();
row["id"] = "B";
row["val"] = 1;
table.Rows.InsertAt( row, 0 );

....results in invalid rows. If I add

table.AcceptChanges();

....after the insertions are done, the whole thing comes crashing down
*just like in my app*.

There you go -- that's where the problem's coming from. Now how do I
go about making InsertAt work? Time for more research, methinks.

Cheers,

P.
 
G

Guest

I'd open a support case with MS on this one.


--

Chris Tacke, eMVP
Join the Embedded Developer Community
http://community.opennetcf.com



Pedro "Shade" Miller said:
FOUND IT! No solution so far, though:

Works fine when I simulated your last code by manually creating the
DataTable with data you were using. Based on this, it appears that
(...)
row = table.NewRow();
row["id"] = "A";
row["val"] = "1";
table.Rows.Add(row);

This is what's different. I'm using InsertAt to add rows at the top.
Trying your sample code (with a couple of modifications that didn't
cause any problems) with the following alteration:

row = table.NewRow();
row["id"] = "B";
row["val"] = 1;
table.Rows.InsertAt( row, 0 );

...results in invalid rows. If I add

table.AcceptChanges();

...after the insertions are done, the whole thing comes crashing down
*just like in my app*.

There you go -- that's where the problem's coming from. Now how do I
go about making InsertAt work? Time for more research, methinks.

Cheers,

P.
 
P

Pedro \Shade\ Miller

I'd open a support case with MS on this one.

Solved!

I found a thread related to that:

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2914295&SiteID=1

Basically, yes, it's a 1.1 bug.

I've worked around the problem by adding an indexing column, as
suggested by one of the posters there, and sorting on it. This way I
can use Rows.Add and avoid InsertAt altogether.

Code:
dataTable.Columns.Add( "idx" );
dataTable.DefaultView.Sort = "idx desc";
//...
row["idx"] = index++;
dataTable.Rows.Add( row );

....and now it all works, including editing, merging, removing, etc.

Cheers and thanks once again!

P.
 
J

Jin Chang

I'd open a support case with MS on this one.

Solved!

I found a thread related to that:

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2914295&SiteID=1

Basically, yes, it's a 1.1 bug.

I've worked around the problem by adding an indexing column, as
suggested by one of the posters there, and sorting on it. This way I
can use Rows.Add and avoid InsertAt altogether.

Code:
dataTable.Columns.Add( "idx" );
dataTable.DefaultView.Sort = "idx desc";
//...
row["idx"] = index++;
dataTable.Rows.Add( row );

...and now it all works, including editing, merging, removing, etc.

Cheers and thanks once again!

P.

Interesting bug.
I'm glad you at least found a work-around for it.
Also, thanks for sharing that bug with us.
 
P

Pedro \Shade\ Miller

Interesting bug.
I'm glad you at least found a work-around for it.
Also, thanks for sharing that bug with us.

Sure thing, that's what makes it a community ;). Thanks again for the
help.

Cheers
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top