Hi all
I stumbled over a new problem:
I have a programm with just a class that is asynchronous listening for
network connections. As soon as someone connected, a new form needs to be
created.
The Form gets created but hangs after creation. I'ts logical that that
happens because the new Form doesn't get a Message Loop.
The Message Loop is created on Application.Run() on the Main Method on the
Main Thread. The Callback is (normally) executed on another Thread so the
Form which is created there doesn't have this Message Loop and therefore
hangs.
Basically I would need to run the creation-code of the new Form on the Main
Thread. But how? I don't have a Form to call Invoke. Well I could make a
dummy form and pass that one to my Callback and invoke it there but that
doesn't seem very clean. I just need to somehow execute some code on the Main
Thread so that the Form is created there and can use the MessageLoop that is
waiting there.
Any Ideas how to solve that in a proper way?
At the end, you'll find a very simple example showing the problem. Form1 is
just needed that I can connect to the Application itself. You could also
comment out the Form1 Stuff and just use "telnet.exe localhost 1234" to
connect to the Application.
After the Connection, the Async-Callback from the class "Test" creates a new
Form with the "Create" Method. And there is where I need help. This "Create"
Method needs to run on the Main Thread so it can use it's Message Loop.
Thanks for help.
//Roman
/************ CODE ************/
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
namespace AsyncTest {
public class Form1 : Form {
private Button myButton;
public Form1() {
// Create Button
myButton = new Button();
myButton.Text = "Connect";
myButton.Click += new System.EventHandler(this.button1_Click);
// Add the Button
this.Controls.Add(myButton);
}
private void button1_Click(object sender, EventArgs e) {
// Just Connect...
TcpClient cl = new TcpClient("localhost", 1234);
// ... and disconnect
cl.Client.Close();
cl.Close();
}
protected override void OnClosed(EventArgs e) {
base.OnClosed(e);
Application.Exit();
}
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(fals e);
// Just needed for a Button to tell when to Connect, Could also
use Telnet
Form f = new Form1();
f.Show();
// Start the "listener"
Test t = new Test();
Application.Run();
}
}
class Test {
TcpListener m_tcpListener;
public Test() {
// Start Listener
m_tcpListener = new TcpListener(IPAddress.Any, 1234);
m_tcpListener.Start();
// Start Accepting
m_tcpListener.BeginAcceptTcpClient(new
AsyncCallback(AcceptTcpClientCallback), this);
}
private static void AcceptTcpClientCallback(IAsyncResult ar) {
Test cl = (Test)ar.AsyncState;
TcpListener listener = cl.m_tcpListener;
TcpClient client = listener.EndAcceptTcpClient(ar);
Console.WriteLine("Connected");
// Start Accepting again
listener.BeginAcceptTcpClient(new
AsyncCallback(AcceptTcpClientCallback), cl);
// This Method needs to run on the "main"-Thread where the
MessageLoop is running
// (which was started with Application.Run() )
cl.Create();
}
private void Create() {
Form bla = new Form();
bla.Show();
}
}
}
/************ END CODE ************/ 7 3094
Hi,
Thanks for posting at the newsgroup!
"The Message Loop is created on Application.Run() on the Main Method..."
As you have posted, this is the cause why the form failed. So we can find
one resolution to create the form in the main thread. I have one suggestion
for you:
At .Net 2.0 winform. there is one component called BackgroundWorker
provided by Microsoft for you, which can execute one long-time processing
job and the form can communicate with it very smoothly.
It provides the asynchronization to the WinForm. We can create one callback
function for its DoWork delegate which will execute the job at the
background. Then at the callback function, when some special event occur,
we can call the BackgroundWorker.ReportProgress method to report the
status. At the call of the ReportProgress method, BackgroundWorker will
invoke the callback function of its ProgressChanged delegate. Then we can
create one new form and display the information at the callback function
which is safe and the whole development will be quite easy.
The sample from Mark of Windowsforms.net will illustrate for you regarding
how to use this for your asynchronization work.
DataGridView App using BackgroundWorker for Async Data Load http://www.windowsforms.net/Default....dex=4&tabid=49
Please feel free to let me know if you have any further question on this
issue.
Have a nice day!
Best Regards,
Wei-Dong XU
Microsoft Support
---------------------------------------------------------------------------
This posting is provided "AS IS" with no warranties, and confers no rights.
---------------------------------------------------------------------------
It is my pleasure to be of any assistance.
Thanks for you answer.
But I think BackgroundWorker won't help me much because I don't have a Form
or a Control that I can refer to.
All I have is a Main-Thread and a Message-Loop running on it. And now, some
other Thread (an Async-Callback in my case) needs to create a Form which
hooks into this Message-Loop on the Main-Thread. That should be possible if I
can somehow marshal the code which creates the new Form into the Main-Thread.
And that's where I hang. I played around with ISynchronizeInvoke and created
my own class that implements it on the Main-Thread with no success.
So I would still be very pleased if someone can give me more infos or maybe
another solution.
Hi,
Thanks for the reply ! Currently I think I should write one sample code on
how to instantiate one Form at the main thread. :)
If we need the message loop in the main thread, we will need to call the
Application.Run method and then run the code to execute the underlying
wait. Perhaps I was not very clear when introducing the BackgroundWorker
which, in fact, is not a windows control. It is just one utility class for
us to execute the asynchronous operation. It encapsulates one events list
and provides very easy interface for us to respond to the special events
occuring in the asynchronous thread.
So for your issue, I have one workaround: we can create one form to start
the BackgroundWorker, using it to execute your long-time processing. At
first, we can hide the form and when you are going to display something in
the UI, you can make the form visible with the mesage. For your
convenience, I provide one sample code at the end of this reply.
In addition, if you dislike to inherit your form from Form class, please
feel free to let me know. I will try the best to be of assistance for you.
Have a nice day!
Best Regards,
Wei-Dong XU
Microsoft Support
---------------------------------------------------------------------------
This posting is provided "AS IS" with no warranties, and confers no rights.
---------------------------------------------------------------------------
It is my pleasure to be of any assistance.
//-------------------------------------------------------------------------
// please paste the code in one cs file and name the file. Compile it in
this command line:
//csc /t:winexe <your file name>.cs
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
namespace AsynchronousCallBackForm
{
class Program
{
static void Main(string[] args)
{
Application.Run(new MyForm());
}
internal class MyForm : Form
{
private BackgroundWorker bw;
private Label lbl;
private int i;
public MyForm()
{
bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new
ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted += new
RunWorkerCompletedEventHandler(bw_RunWorkerComplet ed);
lbl = new Label();
lbl.Text = string.Empty;
Controls.Add(lbl);
this.Load += new EventHandler(MyForm_Load);
}
void MyForm_Load(object sender, EventArgs e)
{
Visible = false;
bw.RunWorkerAsync();
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
while (i < Int32.MaxValue)
{
if (++i % 100 == 0)
{
BackgroundWorker bw = (BackgroundWorker)sender;
bw.ReportProgress(i);
}
Thread.Sleep(5);
}
}
void bw_ProgressChanged(object sender, ProgressChangedEventArgs
e)
{
if (!Visible)
Visible = true;
Controls[0].Text = e.ProgressPercentage.ToString();
}
void bw_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
Application.Exit();
}
}
}
}
//-------------------------------------------------------------------------
Hmm I played around with BackgroundWorker, SynchronizationContext and
ExecutionContext but couldn't achieve what I wanted.
Here's another very simplified example of what I need:
/************ CODE ************/
using System;
using System.Net.Sockets;
using System.Net;
using System.Windows.Forms;
class Program {
static void Main(string[] args) {
StartListening();
Application.Run();
}
static void StartListening() {
TcpListener m_tcpListener = new TcpListener(IPAddress.Any, 1234);
m_tcpListener.Start();
m_tcpListener.BeginAcceptTcpClient(new
AsyncCallback(AcceptTcpClientCallback), m_tcpListener);
}
private static void AcceptTcpClientCallback(IAsyncResult ar) {
TcpListener listener = (TcpListener)ar.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(ar);
listener.BeginAcceptTcpClient(new
AsyncCallback(AcceptTcpClientCallback), listener);
// This Method has to run in the "Main Thread", where
Application.Run() was fired
CreateForm();
}
static void CreateForm() {
Form myForm = new Form();
myForm.Show();
}
}
/************END CODE ************/
Just run it as an Windows Application. You won't see anything. After you
started it, just use the Command Prompt with "telnet localhost 1234"
That will fire the Async Callback which calls CreateForm and creates a new
Form. Now if you try to interact with the Form you'll see that the Form
doesn't respond.
So my problem is, that I don't know how I can marshal CreateForm() to the
Main-Thread, where the Message-Loop is running so that the newly created Form
can interact to Messages.
Hi,
I think that will be helpful to instantiate one form with visible to false
at the main thread. This way, the customer will not see the form. Then at
the 2nd thread, it only need to set the visible to true and the form will
be displayed and the user can interact with the form. All this is
demonstrated at my sample code in the last reply. Please have a test.
Thanks!
Besides, from your sample code, the application is waiting for the client
request. Its behavior is very like one server and ASP.net team have one
sample server application with the source code. That application has one UI
for the user interaction. So I'd suggest you can have a look at that
application whose form is created at the main thread. For your scenario,
let's set the visible property of the form to false will resolve your
issue.
Download ASP.NET Cassini Sample Web Server http://www.asp.net/Projects/Cassini/...ndex=0&tabid=1
Please feel free to let me know if you have any further question.
Have a nice day!
Best Regards,
Wei-Dong XU
Microsoft Support
---------------------------------------------------------------------------
This posting is provided "AS IS" with no warranties, and confers no rights.
---------------------------------------------------------------------------
It is my pleasure to be of any assistance.
Thanks, I'll have a look at the Cassini Sample Web Server.
The Problem with your code in the post before was, that, le'ts say, every
Client that connects would open a Form. So that means there could be
unlimited Forms so I need do genereate them when a Client connects.
I by now found a little Workaround which looks like:
/************ CODE ************/
using System;
using System.Net.Sockets;
using System.Net;
using System.Windows.Forms;
using System.Threading;
class Program {
static SynchronizationContext ctx;
static void Main(string[] args) {
Control ctl = new Control();
ctx = SynchronizationContext.Current;
StartListening();
Application.Run();
}
static void StartListening() {
TcpListener m_tcpListener = new TcpListener(IPAddress.Any, 1234);
m_tcpListener.Start();
m_tcpListener.BeginAcceptTcpClient(new
AsyncCallback(AcceptTcpClientCallback), m_tcpListener);
}
private static void AcceptTcpClientCallback(IAsyncResult ar) {
TcpListener listener = (TcpListener)ar.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(ar);
listener.BeginAcceptTcpClient(new
AsyncCallback(AcceptTcpClientCallback), listener);
// This Method has to run in the "Main Thread", where
Application.Run() was fired
Program.ctx.Send(new SendOrPostCallback(CreateForm), null);
}
static void CreateForm(object o) {
Form myForm = new Form();
myForm.Show();
}
}
/************ END CODE ************/
Well, the most important part is that I added an SynchronizationContext
which I set on the Main Thread and then run the CreateForm on that Context
(ctx.Send()). So this solution is working so far but has something that
annoys me:
The first Line in the Main() is a
Control ctl = new Control();
Without this line, the SynchronizationContext.Current would be null so I
can't Send something to it.
I looked around in Reflector and found in the Constructor of a Control the
Line:
WindowsFormsSynchronizationContext.InstallIfNeeded ();
Most of what's going on in this Function is Internal so I can't just call it
in my Programm.
So I guess I have to life with that.
So, do you think that this solution with the SynchronizationContext and it's
Send and the dummy Control is ok and solid?
Thanks!
//Roman
Hi,
Thanks for the replying!
I have read your code sample, that looks well at the first glance. However,
since the SynchronizationContext class is provided in .Net 2.0 for
"Provides the basic functionality for propagating a synchronization context
in various synchronization models". I think this should not be the best
resolution for your application. This is because the main thread should be
notified to create one form when one client connection is established at
the working thread; at your code, we force one synchronization to make the
main thread creating one form which will hurt your application's
performance that the working thread will need to wait for the main thread
finishes the consturction of one form.
As what you have posted, the SynchronizationContext also introduces some
new problems. So my suggestions is that: it is the best for you to add one
queue at your mainthread to receive the notification from the working
thread. When it receives any notification, it can perform the corresponding
operation. This will make your application more robust and stable. There is
one CodeProject article demonstrating for you regarding how to create
in-process asynchronous services.
Create in-process asynchronous services in C# http://www.codeproject.com/csharp/in...rvicesincs.asp
Please feel free to let me know if you have any further question on this
issue.
Have a nice day!
Best Regards,
Wei-Dong XU
Microsoft Support
---------------------------------------------------------------------------
This posting is provided "AS IS" with no warranties, and confers no rights.
---------------------------------------------------------------------------
It is my pleasure to be of any assistance. This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: Dave |
last post by:
I'm using the BeginInvoke method of a delegate to invoke
a thread asynchronously and then use the EndInvoke to
retrieve the value. This works wonderfully until a
Serviced Component is added to...
|
by: Vanessa |
last post by:
I have a question regarding async mode for calling Microsoft.XMLHTTP object.
Microsoft.XMLHTTP hangs the IE once in a while suddenly, but it will work
again after half an hour or so without doing...
|
by: IMS.Rushikesh |
last post by:
Hi Friends,
I need a XPath query, whcih ll return me subset of data....
check below xml stream
<label id="MyExpenseDetails_lbl" xlink:role="terseLabel">Short Expense
Details</label>
<label...
|
by: Passynkov, Vadim |
last post by:
I am using Asynchronous Query Processing interface from libpq library.
And I got some strange results on Solaris
My test select query is 'SELECT * from pg_user;'
and I use select system...
|
by: Devicharan |
last post by:
I have two forms, a Main Form and a Child Form.
And In the Main Form, I have a small Async Process, Which
needs to show the child form.
I use mainForm.BeginInvoke(ShowtheNewForm) to
start the...
|
by: dbcuser |
last post by:
Hi,
I have a small windows form. This has 2 labels and a button. When a
user presses a button, I copy a large file. Nowwhen the copy is going
on, if I switch windows, my main window becomes...
|
by: Daylor |
last post by:
hi.
i have multi thread application in vb.net
is there a way NET support, so i can mark the class , to be access
only for 1 thread each time ?
if there is , small sytax sample will help
...
|
by: Lespaul36 |
last post by:
I have tried many things. I still have not found anything that seems to
work. Here is the portions of my code that deal with the listening socket
maybe you have a better idea? The form still...
|
by: peterperry |
last post by:
Hi,
Below in comments is the list of controls that I have defined. The function DoOpenUser loads and shows a new Form. This process freezes the application for a while as the Form takes time to...
|
by: Frankie |
last post by:
It appears that System.Random would provide an acceptable means through
which to generate a unique value used to identify multiple/concurrent
asynchronous tasks.
The usage of the value under...
|
by: Kemmylinns12 |
last post by:
Blockchain technology has emerged as a transformative force in the business world, offering unprecedented opportunities for innovation and efficiency. While initially associated with cryptocurrencies...
|
by: Naresh1 |
last post by:
What is WebLogic Admin Training?
WebLogic Admin Training is a specialized program designed to equip individuals with the skills and knowledge required to effectively administer and manage Oracle...
|
by: antdb |
last post by:
Ⅰ. Advantage of AntDB: hyper-convergence + streaming processing engine
In the overall architecture, a new "hyper-convergence" concept was proposed, which integrated multiple engines and...
|
by: WisdomUfot |
last post by:
It's an interesting question you've got about how Gmail hides the HTTP referrer when a link in an email is clicked. While I don't have the specific technical details, Gmail likely implements measures...
|
by: Matthew3360 |
last post by:
Hi,
I have been trying to connect to a local host using php curl. But I am finding it hard to do this. I am doing the curl get request from my web server and have made sure to enable curl. I get a...
|
by: Carina712 |
last post by:
Setting background colors for Excel documents can help to improve the visual appeal of the document and make it easier to read and understand. Background colors can be used to highlight important...
|
by: Rahul1995seven |
last post by:
Introduction:
In the realm of programming languages, Python has emerged as a powerhouse. With its simplicity, versatility, and robustness, Python has gained popularity among beginners and experts...
|
by: jack2019x |
last post by:
hello, Is there code or static lib for hook swapchain present?
I wanna hook dxgi swapchain present for dx11 and dx9.
|
by: DizelArs |
last post by:
Hi all)
Faced with a problem, element.click() event doesn't work in Safari browser.
Tried various tricks like emulating touch event through a function:
let clickEvent = new Event('click', {...
| |