Is this Application.Run() correct?

J

jm

This works, but I don't know why.

static void Main()
{
// Queue the task.
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc),new
Form1());
Application.Run();
}

static void ThreadProc(Object stateInfo)
{
// When no state object was passed to QueueUserWorkItem, so
// stateInfo is null.
Form1 f1 = (Form1) stateInfo; //the passed form
f1.notifyIcon1.Icon = new
Icon(System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("Listener1.connecting.ico"));
clsListening myLis = new clsListening(f1);
myLis.StartListening(f1);
}

I had to do it this way because I could not pass "this" to the class
because ThreadProc was static and new WaitCallBack(ThreadProc)
required a static method.

What I don't understand is how the thread part can run before the
Application.Run() can. How can it be executing code before it is
running?

Also, let me see if I am correct. The ThreadPool.QueueUserWorkItem
sends the an instantiated new Form1() to the ThreadProc. stateInfo
becomes that object. I then assign that object to the type Form1 f1
(cast to Form1 so I know what kind of object (object stateInfo) is)
and then I get to work with my form.

It works, but am I correct here?

Thank you for helping me.
 
J

Jon Skeet [C# MVP]

jm said:
This works, but I don't know why.

static void Main()
{
// Queue the task.
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc),new
Form1());
Application.Run();
}

static void ThreadProc(Object stateInfo)
{
// When no state object was passed to QueueUserWorkItem, so
// stateInfo is null.
Form1 f1 = (Form1) stateInfo; //the passed form
f1.notifyIcon1.Icon = new
Icon(System.Reflection.Assembly.GetExecutingAssembly().GetManifestRes
ourceStream("Listener1.connecting.ico"));
clsListening myLis = new clsListening(f1);
myLis.StartListening(f1);
}

I had to do it this way because I could not pass "this" to the class
because ThreadProc was static and new WaitCallBack(ThreadProc)
required a static method.

What I don't understand is how the thread part can run before the
Application.Run() can. How can it be executing code before it is
running?

The thread pool runs separately of the message queue. Application.Run
just starts a message pump for the given form, and waits until it
closes down.
Also, let me see if I am correct. The ThreadPool.QueueUserWorkItem
sends the an instantiated new Form1() to the ThreadProc. stateInfo
becomes that object. I then assign that object to the type Form1 f1
(cast to Form1 so I know what kind of object (object stateInfo) is)
and then I get to work with my form.

It works, but am I correct here?

Apart from some terminology, that's basically right, yes.

Why are you doing it, out of interest?
 
J

Jon Skeet [C# MVP]

Jon Skeet said:
The thread pool runs separately of the message queue. Application.Run
just starts a message pump for the given form, and waits until it
closes down.

<snip>

I've just had another look at the code, and what you're doing it *not*
all right - you shouldn't be touching the form from any thread other
than the one which created it. You shouldn't be changing the icons etc
from a threadpool thread.
 
J

jm

Jon Skeet said:
<snip>

I've just had another look at the code, and what you're doing it *not*
all right - you shouldn't be touching the form from any thread other
than the one which created it. You shouldn't be changing the icons etc
from a threadpool thread.

I thought I only created it in the Threadpool since I didn't do it in
Application.Run().
 
J

Jon Skeet [C# MVP]

jm said:
I thought I only created it in the Threadpool since I didn't do it in
Application.Run().

No, you created it in the main thread, then passed it to the thread
pool thread.
 
J

jm

Jon Skeet said:
No, you created it in the main thread, then passed it to the thread
pool thread.

Could you point me to something I could read up on to learn more about
what I am doing wrong? I'm not sure what I should have done here.

Thanks.
 
J

j m

I have a listening class that I modified from MSDN. I have Form1 with
the notifyIcon1 contextmenu, etc.

When the program loads I create Form1, but I do not run it. I only
wanted it to run as an icon in the system Tray. I also didn't want it
in Application.Run() because I needed to call my listening class from
the threadpool. I call from the threadpool because I want it to start
listening (with the while(true) in the listening class.) The Threapool
kicks off the new Form1() and the listener.

I put the new Form1() in Threadpool because I had to have some way to
instantiate Form1 *and* be able to reference it in my listening class.
Since the ThreadProc threadpool method is static, I could not send via
the "this" keyword, thus all my sending to the the Threadpool.

By sending it this way, I am still working (I thought, anyway) with the
original form at Main and can access the context menu at its events,
etc. (I have a context menu with events.)

Thanks again.
 
J

Jon Skeet [C# MVP]

j m said:
I have a listening class that I modified from MSDN. I have Form1 with
the notifyIcon1 contextmenu, etc.

When the program loads I create Form1, but I do not run it. I only
wanted it to run as an icon in the system Tray. I also didn't want it
in Application.Run() because I needed to call my listening class from
the threadpool. I call from the threadpool because I want it to start
listening (with the while(true) in the listening class.) The Threapool
kicks off the new Form1() and the listener.

I put the new Form1() in Threadpool because I had to have some way to
instantiate Form1 *and* be able to reference it in my listening class.
Since the ThreadProc threadpool method is static, I could not send via
the "this" keyword, thus all my sending to the the Threadpool.

By sending it this way, I am still working (I thought, anyway) with the
original form at Main and can access the context menu at its events,
etc. (I have a context menu with events.)

No - the problem is that you're changing things from the thread pool
thread, and you shouldn't be. Any time you need to change something in
the UI from a thread other than the one which created it, you need to
use Control.Invoke or Control.BeginInvoke.
 
J

j m

I'm sorry I asked that it is just that there are very few examples of
how to use Control.Invoke. MSDN didn't have any examples.
 
J

j m

I changed it to this:

if (f1.InvokeRequired)
{
start stuff and change the notifyIcon1
}

But it did not run. In other words, I thought it was telling me that I
did not require InvokeRequired. I didn't understand.

BTW, thanks for all the help you have given.
 
J

jm

Jon Skeet said:
No - the problem is that you're changing things from the thread pool
thread, and you shouldn't be. Any time you need to change something in
the UI from a thread other than the one which created it, you need to
use Control.Invoke or Control.BeginInvoke.


Jon, At the risk of becoming more annoying, I have decided to post
this last snippet. I appreciate any feedback you can give. I got
this from idea from MSDN. All seems to work well:

private void Form1_Load(object sender, System.EventArgs e)
{
this.notifyIcon1.Icon = new Icon
(System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream
("Listener1.connecting.ico"));
LoadStatus(this); //my stuff
ThreadStart starter = new ThreadStart(this.DoStuff);
Thread t = new Thread(starter);
t.Start();
}

private void DoStuff()
{

clsListening myLis = new clsListening(this);
myLis.StartListening(this);

}

Look legit? Thanks again.
 
J

Jon Skeet [C# MVP]

jm said:
Jon, At the risk of becoming more annoying, I have decided to post
this last snippet. I appreciate any feedback you can give. I got
this from idea from MSDN. All seems to work well:

private void Form1_Load(object sender, System.EventArgs e)
{
this.notifyIcon1.Icon = new Icon
(System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream
("Listener1.connecting.ico"));
LoadStatus(this); //my stuff
ThreadStart starter = new ThreadStart(this.DoStuff);
Thread t = new Thread(starter);
t.Start();
}

private void DoStuff()
{

clsListening myLis = new clsListening(this);
myLis.StartListening(this);

}

Look legit? Thanks again.

All of that looks reasonable - it's what happens in clsListening that's
potentially dangerous. It mustn't update the form directly - only
through Control.Invoke.
 
W

Willy Denoyette [MVP]

Sorry to chime in so lately, but it seems like you don't want to show a form
when calling Application.Run() (no Form as Argument). The results in a
message loop without a Form attached (no underlying window handle) and you
won't be able to post/send messages to the Form, or simply said there is no
way to "communicate" with the form. Question is, is this by purpose?

Willy.
 
J

j m

I actually changed it to the code I posted and did create and instance
of the Form in Application.Run(new Form1()); The problem is that in my
clsListening class I send my form via the "this" keyword and in that
class (which I started with a thread) I reference the notifyIcon object
and events. As I understand it, that is wrong. I am supposed to use
control Invoke.

I just can't figure out how to do it.

I passed my form to my clsListening via "this" when I started my thread.
The clsListening class constructor simply receives this and has a global
variable so I can reference the form anywhere in the class.

Send via Form1 with "this":

So, I have my constructor (from memory):

Namespace clsListener {

Form1 _Form;

class clsListener (Form1 form){
_Form = form;
}
...

another method:

get some results...

_Form.notifyIcon.Icon =...
_Form.notifyIcon.text =...
MessageBox.Show("Some message...");
...

But I am not supposed to do this. It works great, but I know it is
wrong. I wish it wouldn't compile.

Thank you for any help.
 
J

Jon Skeet [C# MVP]

Willy Denoyette said:
Sorry to chime in so lately, but it seems like you don't want to show
a form when calling Application.Run() (no Form as Argument). The
results in a message loop without a Form attached (no underlying
window handle) and you won't be able to post/send messages to the
Form, or simply said there is no way to "communicate" with the form.
Question is, is this by purpose?

I *think* it should all work fine, actually - it's just that the
message pump won't terminate automatically when the form closes.

It's certainly slightly unusual though.
 
W

Willy Denoyette [MVP]

Jon Skeet said:
I *think* it should all work fine, actually - it's just that the
message pump won't terminate automatically when the form closes.
Jon,

Sorry but it won't. just add a Form1_Closed (or FormClosing or TextChanged,
or whatever valid ) eventhandler and try to call Form.Close() from the
Notify context menu handler. Set a breakpoint in the eventhandler and you
will see it won't get called when run just run the message pump
(Application.Run()). Now call Run with a form reference, and you will see
that your handlers are getting called.
The reason for this is that the WM_XXXX messages can't get dispached to the
right window as there is NO window (no HWND, no GDI DC no GDI Region)
associated with the form.

Willy.
 
J

Jon Skeet [C# MVP]

Willy Denoyette said:
Sorry but it won't. just add a Form1_Closed (or FormClosing or TextChanged,
or whatever valid ) eventhandler and try to call Form.Close() from the
Notify context menu handler. Set a breakpoint in the eventhandler and you
will see it won't get called when run just run the message pump
(Application.Run()). Now call Run with a form reference, and you will see
that your handlers are getting called.
The reason for this is that the WM_XXXX messages can't get dispached to the
right window as there is NO window (no HWND, no GDI DC no GDI Region)
associated with the form.

What if the form had had Show() called on it first? I didn't say that
you'd need to do something to show the form before starting the message
pump, which I meant to - but surely at that stage there *is* a HWND
etc. I haven't got time to test this at the moment, and it's not
terribly important, so don't worry if you don't have a lot of time to
explain :)
 
J

j m

I changed my Form to not use the Threadpool at all and instead use
Application.Run(new Form1()); (please see earlier in the thread).

I then started the thread in the Form_Load.

The problem, for me anyway, is that I am calling that Form1 that started
the thread from the clsListen.

Here is what I don't understand, then: If I can start a thread like
this and pass it my form via "this," keyword, constructor in the class
ready to receive, then why can't I reference it? Why does it work at
all (which though it is wrong, it is working)?

It does not appear that I should ever be able to pass a thread
*anything* with the "this" keyword as I can never reference back to the
"this" that I sent it. At least not the UI part of it. I am guessing I
could use other variable/controls' values on the form to make
calculations, just not physically updating a control on the form.
 

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