NullReferenceException in UnsafeNativeMethods.PeekMessage and multithreading concepts in general

  • Thread starter Stefan Kiryazov
  • Start date
S

Stefan Kiryazov

I'm developing a simple applications that extracts data from files,
that can eventually become large. I have logic that scans a particular
folder, and for each file in the folder instanciates a parser class
and processes the specified file.

I want to start a background thread with the main logic to not freeze
the UI. I am new to windows forms, so i had to try some scenarios and
I am wonder what is the best approach. Also, when i manipulate the UI
controls on the form from the worker thread it sometimes yields an
error, the cause of which i can't exactly understand. More detailed
explanation follows.

I do the following: On the click event of a specific button I start
the worker thread with:
ThreadPool.QueueUserWorkItem( new WaitCallback(ReadTree), this );

ReadTree is a static method that scans the directory and parses the
files found. While doing this, i want be showing percentage and a
progress bar. It used to work with no problem - the background thread
accesses and manipulates the controls of the form, that is passed as a
paremeter. The problem is not caused by the pool, because i tried to
start the thread also as follows:
Thread t = new Thread( new ThreadStart( ReadTree ) );
t.Start();
Then, I did some change in the logic and the UI and i found that the
application crashes, yielding a NullReferenceException in the
following code, that updates the percentage label and the progress bar
and adds a new record for the parsed file in a dataset, that is bound
to a grid in the main form:

((frmMain)state).progressBar.Increment( (Int32)fileSize );
if ( parsedBytes < ((frmMain)state).totalBytes ) parsedBytes +=
fileSize;
((frmMain)state).lblPercentage.Text = Math.Round( (
(double)parsedBytes/(double)((frmMain)state).totalBytes ) * 100
).ToString() + "%";
newRow = ((frmMain)state).dsFiles.Tables["Files"].NewRow();
newRow[0] = fileName;
((frmMain)state).dsFiles.Tables["Files"].Rows.Add( newRow );

However, if i simply run the method in the same thread there is no
problem. The error does not fire every time when i change properties
of form controls - it just happens on a particular file. No division
by zero or anything wrong with the numbers. And, as i see it, the
error is not actually taking place in the above code, but just happens
in the mean time, because if all this is in a try-catch block, the
exception is not caught. Also try-catch wrapping the starting of the
thread - also nothing. When I do the following:

try
{
Application.Run(new frmMain());
}
catch( Exception ex )
{
String txt = ex.Message;
}
I manage to catch the exception. Here are the details:
{"Object reference not set to an instance of an object."
} System.NullReferenceException


StackTrace " at System.Windows.Forms.UnsafeNativeMethods.PeekMessage(MSG&
msg, HandleRef hwnd, Int32 msgMin, Int32 msgMax, Int32 remove)
at System.Windows.Forms.ComponentManager.System.Windows.Forms.UnsafeNativeMethods+IMsoComponentManager.FPushMessageLoop(Int32
dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.ThreadContext.RunMessageLoopInner(Int32
reason, ApplicationContext context)
at System.Windows.Forms.ThreadContext.RunMessageLoop(Int32
reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at CadParser.frmMain.Main() in
e:\\projects\\mj\\immpilot\\parser\\cadparser\\main.cs:line
303" string

But curiously, when i comment the above code, no exception is being
thrown.

Another issue, that I find curious is that when i QuickView the state
object (that is, the main form) the viewer takes very long time to
load. Then, some properties are displayed correctly, while others show
"error: cannot obtain value", for example the Text property of the
label that I try to access.

I see that this is a problem caused by a background thread accessing
the forms elements, which doesn't seem to be the best approach, but
where can i read more about this problem, and what exactly happens
behind the stage.

And also, what is the best workaround concept for this. I intend to do
create a new class, that manages the scanning of the directory and the
calling of the parsing functions, which does not tuch any form
members. It will expose an event, for which the form will subscribe,
and will alter the UI appropriately, according to the EventArgs
passed. Is this the best approach? Any ideas where can i read more
about more complex situations concerning windows forms and
multithreading.

Thanks everybody.
 
S

Stoitcho Goutsev \(100\) [C# MVP]

Sorry guys for the next just one sentence
(Zdrasti Stefane, za sajalenie 6te triabva da pi6a ne english (pone kolkoto
moga :))

He Stefan,

When using Windows Forms you cannot use UI controls from thread, that has
not created the control.
This comes from Windows OS and because .NET controls use internaly Windows
controls they share the same limitation. To handle those problems Control
class exposes Invoke method as well as InvokeRequired property

If you read InvokeRequired property and it returns *true* that means the
calling thread is different than the thread created the control. In other
words you cannot use the control (ofcourse you can use any mentod and
properties, which doesn't need the services of the underlying Windows
control. However sometimes is not easy to say which members are safe to use
and which are not).
So, if InvokeRequired returns true you should call the method you want thru
control's Invoke method. This will marshal the call and it will be executed
by the UI thread created the control.

A memeber of a control class that is safe to be invoked from a worker
threads can looks something like that
delegate void FooDelegate(int a, string b)
void Foo( int a, string b)
{
if(this.InvokeRequired)
{
this.Invoke(new FooDelegate(Foo), new object[]{a, b});
return;
}

//method's logic here
}

BTW you can call any method via contro's Invoke; it doesn't have to be
member of the control class.
--
HTH
Stoitcho Goutsev (100) [C# MVP]


Stefan Kiryazov said:
I'm developing a simple applications that extracts data from files,
that can eventually become large. I have logic that scans a particular
folder, and for each file in the folder instanciates a parser class
and processes the specified file.

I want to start a background thread with the main logic to not freeze
the UI. I am new to windows forms, so i had to try some scenarios and
I am wonder what is the best approach. Also, when i manipulate the UI
controls on the form from the worker thread it sometimes yields an
error, the cause of which i can't exactly understand. More detailed
explanation follows.

I do the following: On the click event of a specific button I start
the worker thread with:
ThreadPool.QueueUserWorkItem( new WaitCallback(ReadTree), this );

ReadTree is a static method that scans the directory and parses the
files found. While doing this, i want be showing percentage and a
progress bar. It used to work with no problem - the background thread
accesses and manipulates the controls of the form, that is passed as a
paremeter. The problem is not caused by the pool, because i tried to
start the thread also as follows:
Thread t = new Thread( new ThreadStart( ReadTree ) );
t.Start();
Then, I did some change in the logic and the UI and i found that the
application crashes, yielding a NullReferenceException in the
following code, that updates the percentage label and the progress bar
and adds a new record for the parsed file in a dataset, that is bound
to a grid in the main form:

((frmMain)state).progressBar.Increment( (Int32)fileSize );
if ( parsedBytes < ((frmMain)state).totalBytes ) parsedBytes +=
fileSize;
((frmMain)state).lblPercentage.Text = Math.Round( (
(double)parsedBytes/(double)((frmMain)state).totalBytes ) * 100
).ToString() + "%";
newRow = ((frmMain)state).dsFiles.Tables["Files"].NewRow();
newRow[0] = fileName;
((frmMain)state).dsFiles.Tables["Files"].Rows.Add( newRow );

However, if i simply run the method in the same thread there is no
problem. The error does not fire every time when i change properties
of form controls - it just happens on a particular file. No division
by zero or anything wrong with the numbers. And, as i see it, the
error is not actually taking place in the above code, but just happens
in the mean time, because if all this is in a try-catch block, the
exception is not caught. Also try-catch wrapping the starting of the
thread - also nothing. When I do the following:

try
{
Application.Run(new frmMain());
}
catch( Exception ex )
{
String txt = ex.Message;
}
I manage to catch the exception. Here are the details:
{"Object reference not set to an instance of an object."
} System.NullReferenceException


StackTrace " at System.Windows.Forms.UnsafeNativeMethods.PeekMessage(MSG&
msg, HandleRef hwnd, Int32 msgMin, Int32 msgMax, Int32 remove)
at System.Windows.Forms.ComponentManager.System.Windows.Forms.UnsafeNativeMetho
ds+IMsoComponentManager.FPushMessageLoop(Int32
dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.ThreadContext.RunMessageLoopInner(Int32
reason, ApplicationContext context)
at System.Windows.Forms.ThreadContext.RunMessageLoop(Int32
reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at CadParser.frmMain.Main() in
e:\\projects\\mj\\immpilot\\parser\\cadparser\\main.cs:line
303" string

But curiously, when i comment the above code, no exception is being
thrown.

Another issue, that I find curious is that when i QuickView the state
object (that is, the main form) the viewer takes very long time to
load. Then, some properties are displayed correctly, while others show
"error: cannot obtain value", for example the Text property of the
label that I try to access.

I see that this is a problem caused by a background thread accessing
the forms elements, which doesn't seem to be the best approach, but
where can i read more about this problem, and what exactly happens
behind the stage.

And also, what is the best workaround concept for this. I intend to do
create a new class, that manages the scanning of the directory and the
calling of the parsing functions, which does not tuch any form
members. It will expose an event, for which the form will subscribe,
and will alter the UI appropriately, according to the EventArgs
passed. Is this the best approach? Any ideas where can i read more
about more complex situations concerning windows forms and
multithreading.

Thanks everybody.
 
S

Stefan Kiryazov

Mersi, Stoitcho

This puts some pieces of the puzzle on their places. I had heard of
this Invoke method but it haven't dawned on me till now.

But i still think that this issue is not well implemented - the
exception handling should have been much more powerfull.

Stoitcho Goutsev \(100\) said:
Sorry guys for the next just one sentence
(Zdrasti Stefane, za sajalenie 6te triabva da pi6a ne english (pone kolkoto
moga :))

He Stefan,

When using Windows Forms you cannot use UI controls from thread, that has
not created the control.
This comes from Windows OS and because .NET controls use internaly Windows
controls they share the same limitation. To handle those problems Control
class exposes Invoke method as well as InvokeRequired property

If you read InvokeRequired property and it returns *true* that means the
calling thread is different than the thread created the control. In other
words you cannot use the control (ofcourse you can use any mentod and
properties, which doesn't need the services of the underlying Windows
control. However sometimes is not easy to say which members are safe to use
and which are not).
So, if InvokeRequired returns true you should call the method you want thru
control's Invoke method. This will marshal the call and it will be executed
by the UI thread created the control.

A memeber of a control class that is safe to be invoked from a worker
threads can looks something like that
delegate void FooDelegate(int a, string b)
void Foo( int a, string b)
{
if(this.InvokeRequired)
{
this.Invoke(new FooDelegate(Foo), new object[]{a, b});
return;
}

//method's logic here
}

BTW you can call any method via contro's Invoke; it doesn't have to be
member of the control class.
--
HTH
Stoitcho Goutsev (100) [C# MVP]


Stefan Kiryazov said:
I'm developing a simple applications that extracts data from files,
that can eventually become large. I have logic that scans a particular
folder, and for each file in the folder instanciates a parser class
and processes the specified file.

I want to start a background thread with the main logic to not freeze
the UI. I am new to windows forms, so i had to try some scenarios and
I am wonder what is the best approach. Also, when i manipulate the UI
controls on the form from the worker thread it sometimes yields an
error, the cause of which i can't exactly understand. More detailed
explanation follows.

I do the following: On the click event of a specific button I start
the worker thread with:
ThreadPool.QueueUserWorkItem( new WaitCallback(ReadTree), this );

ReadTree is a static method that scans the directory and parses the
files found. While doing this, i want be showing percentage and a
progress bar. It used to work with no problem - the background thread
accesses and manipulates the controls of the form, that is passed as a
paremeter. The problem is not caused by the pool, because i tried to
start the thread also as follows:
Thread t = new Thread( new ThreadStart( ReadTree ) );
t.Start();
Then, I did some change in the logic and the UI and i found that the
application crashes, yielding a NullReferenceException in the
following code, that updates the percentage label and the progress bar
and adds a new record for the parsed file in a dataset, that is bound
to a grid in the main form:

((frmMain)state).progressBar.Increment( (Int32)fileSize );
if ( parsedBytes < ((frmMain)state).totalBytes ) parsedBytes +=
fileSize;
((frmMain)state).lblPercentage.Text = Math.Round( (
(double)parsedBytes/(double)((frmMain)state).totalBytes ) * 100
).ToString() + "%";
newRow = ((frmMain)state).dsFiles.Tables["Files"].NewRow();
newRow[0] = fileName;
((frmMain)state).dsFiles.Tables["Files"].Rows.Add( newRow );

However, if i simply run the method in the same thread there is no
problem. The error does not fire every time when i change properties
of form controls - it just happens on a particular file. No division
by zero or anything wrong with the numbers. And, as i see it, the
error is not actually taking place in the above code, but just happens
in the mean time, because if all this is in a try-catch block, the
exception is not caught. Also try-catch wrapping the starting of the
thread - also nothing. When I do the following:

try
{
Application.Run(new frmMain());
}
catch( Exception ex )
{
String txt = ex.Message;
}
I manage to catch the exception. Here are the details:
{"Object reference not set to an instance of an object."
} System.NullReferenceException


StackTrace " at System.Windows.Forms.UnsafeNativeMethods.PeekMessage(MSG&
msg, HandleRef hwnd, Int32 msgMin, Int32 msgMax, Int32 remove)
at System.Windows.Forms.ComponentManager.System.Windows.Forms.UnsafeNativeMetho
ds+IMsoComponentManager.FPushMessageLoop(Int32
dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.ThreadContext.RunMessageLoopInner(Int32
reason, ApplicationContext context)
at System.Windows.Forms.ThreadContext.RunMessageLoop(Int32
reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at CadParser.frmMain.Main() in
e:\\projects\\mj\\immpilot\\parser\\cadparser\\main.cs:line
303" string

But curiously, when i comment the above code, no exception is being
thrown.

Another issue, that I find curious is that when i QuickView the state
object (that is, the main form) the viewer takes very long time to
load. Then, some properties are displayed correctly, while others show
"error: cannot obtain value", for example the Text property of the
label that I try to access.

I see that this is a problem caused by a background thread accessing
the forms elements, which doesn't seem to be the best approach, but
where can i read more about this problem, and what exactly happens
behind the stage.

And also, what is the best workaround concept for this. I intend to do
create a new class, that manages the scanning of the directory and the
calling of the parsing functions, which does not tuch any form
members. It will expose an event, for which the form will subscribe,
and will alter the UI appropriately, according to the EventArgs
passed. Is this the best approach? Any ideas where can i read more
about more complex situations concerning windows forms and
multithreading.

Thanks everybody.
 

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