WPF Task/Threading issues when trying to open Outlook Email - c#

I have a WPF application that has a part where the users fill out basically an outlook-like form and then it populates an Outlook Email with the appropriate information. The problem is that while this email is open, code execution stops until the email is either sent or closed.
I am attempting to put it on a new thread but I am running into all kinds of problems in various places with getting this to work. The "body" of the email form is a rich text box and needs to be formatted prior to putting it into the Outlook email for it to show up properly.
From what I read the Clipboard calls must be put on their own STA threads, but then it returns null before they finish.
How can I get this working properly? Basically all I want is for the Outlook Email Item to be on its own thread so it doesn't block execution of the main thread while its open.
private async Task CreateEmail()
{
try
{
//create an outlook object
await Task.Run(() =>
{
MyOutlook.Application oApp = new MyOutlook.Application();
//we need to check the to strings of that various items and join them together
var toStrings = emailForm.ToMain;
toStrings += String.IsNullOrEmpty(emailForm.ToRM) ? "" : ";" + emailForm.ToRM;
toStrings += String.IsNullOrEmpty(emailForm.ToSM) ? "" : ";" + emailForm.ToSM;
MyOutlook.MailItem oMailItem = (MyOutlook.MailItem)oApp.CreateItem(MyOutlook.OlItemType.olMailItem);
oMailItem.To = toStrings;
oMailItem.CC = emailForm.CC;
oMailItem.BCC = emailForm.BCC;
oMailItem.Subject = emailForm.Subject;
oMailItem.RTFBody = GetRTBText();
oMailItem.Display(true);
});
}
catch(Exception ex)
{
ErrorWindow errWin = new ErrorWindow("There was an error creating the Outlook Email! Error: " + ex.Message);
errWin.Show();
}
}
private byte[] GetRTBText()
{
byte[] RTFArr = null;
//need to create a new STA Thread for the clipboard
Thread thread = new Thread(() => Clipboard.Clear());
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
this.Dispatcher.Invoke(() =>
{
RTBBody.SelectAll();
RTBBody.Copy();
});
Thread thread2 = new Thread(() => RTFArr = Encoding.UTF8.GetBytes (Clipboard.GetText(TextDataFormat.Rtf)));
thread2.SetApartmentState(ApartmentState.STA);
thread2.Start();
thread.Join();
return RTFArr;
}

Do not call Display(true) - that will display the message modally. Call Display(false).

Related

Starting a "new thread IsBackground = true "in Form2() and getting stuck in while(true) loop

I'm making a multithreaded chat server and chat client. The client has a Form1 called Login and a Form2 called MainProgram. The following code is from "Login". What I'm trying to do is transitioning from Login to MainProgram...
MainProgram mP = new MainProgram(clientSocket, username);
mP.Closed += (s, args) => this.Close();
this.Hide();
mP.ShowDialog();
mP.Show();
... however. When assigning mP MainProgram mP = new MainProgram(clientSocket, username); The code get's stuck in the thread specified here:
public MainProgram(TcpClient c, string u)
{
InitializeComponent();
try
{
serverStream = c.GetStream();
clientSocket = c;
username = u;
new Thread(Receive()) { IsBackground = true }.Start();
}
Here is the Thread:
private ThreadStart Receive()
{
while (true)
{
try
{
byte[] inStream = new byte[1024];
serverStream.Read(inStream, 0, inStream.Length);
string returndata = Encoding.ASCII.GetString(inStream);
returndata = returndata.Substring(0, returndata.IndexOf("$"));
Msg($"{returndata}");
}
catch(Exception e)
{
MessageBox.Show($"{e.Message}\n\n{e.ToString()}");
}
}
}
Please note that the thread is supposed to be running this while loop indefinitely, but in the background. Right now it doesn't make a new thread and runs on the MainThread. The problem is that i don't know how to start this thread without making the client get stuck in this while loop. And not transitioning.
It seems you didn't understand what is ThreadStart. This is the signature of the method that is accepted to create a thread.
When you call:
new Thread(Receive())
You're actually calling the "Receive" method in the main thread, and giving its return value to the thread constructor (which never happens because it's stuck in your infinite loop.
Instead you need to do
new Thread(new ThreadStart(Receive))
Mind the removed parenthesis.
But then you'll get a compilation error because your Receive method doesn't have the right signature. So you need to change it into:
private void Receive()
{
// ...
}

Show Loading animation while trying to connect the server

I have a simple login form which connects to a server.
When the user presses the Login button, the animated Loading GIF needs to show until either the connection is made or it fails.
In theory, I did it:
private void button_login_Click(object sender, EventArgs e)
{
button_login.Text = WORKING;
Loading(ShowMode.show, pictureBox_login_loading);
// send request
client = new TcpClient();
try
{
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5000);
client.Connect(endPoint);
// send login details .. :)
output = client.GetStream();
writer = new BinaryWriter(output);
reader = new BinaryReader(output);
// write details
writer.Write("login" "|" userID "|" privateName);
}
catch (Exception)
{
MessageBox.Show("Server is down.");
return;
}
finally
{
// Stop loading and return status
button_login.Text = DEFAULT_LOGIN_TEXT;
Loading(ShowMode.hide, pictureBox_login_loading);
}
}
Loading is a function that sets the PictureBox's Visible property to Visible. (I thought it would help)
The problem is: the gif is visible only after button_login_Click finishes its run, and right after it's invisible.
How do I make the animation gif visible right on the line it's executing?
The problem is that you are not yielding back to the GUI thread, so there is no ability to display your GIF.
I would recommend using a BackgroundWorker to connect to your client, then displaying the GIF before starting the working and stopping it in the Worker's completed call.
Sample code (note, I didn't compile this because I don't have enough of your source to do so):
button_login.Text = WORKING;
Loading(ShowMode.show, pictureBox_login_loading);
// send request
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler((obj, args) =>
{
client = new TcpClient();
try
{
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5000);
client.Connect(endPoint);
// send login details .. :)
output = client.GetStream();
writer = new BinaryWriter(output);
reader = new BinaryReader(output);
// write details
writer.Write("login" "|" userID "|" privateName);
}
catch (Exception)
{
this.Invoke(new Action(() =>MessageBox.Show("Server is down."));
}
});
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler((obj, args) =>
{
button_login.Text = DEFAULT_LOGIN_TEXT;
Loading(ShowMode.hide, pictureBox_login,loading);
});
worker.RunWorkerAsync();
This approach yields to the GUI thread allowing it to display your GIF and still monitors your connection and removes the GIF and restore button text when done.
Since it's an animation you're after, you will probably need to initiate the connection on another thread so that the UI thread is not blocked. If it were a still image, you could just call the Update() method of the picturebox to get it to show. But for your case, something like this should work:
Thread thread = new Thread(new ThreadStart(delegate
{
Invoke((Action)(()=>{ button_login.Text = WORKING; Loading(ShowMode.show, pictureBox_login_loading); }));
// send request
client = new TcpClient();
try
{
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5000);
client.Connect(endPoint);
// send login details .. :)
output = client.GetStream();
writer = new BinaryWriter(output);
reader = new BinaryReader(output);
// write details
writer.Write("login" "|" userID "|" privateName);
}
catch (Exception)
{
MessageBox.Show("Server is down.");
return;
}
finally
{
// Stop loading and return status
Invoke((Action)(()=>{ button_login.Text = DEFAULT_LOGIN_TEXT; Loading(ShowMode.hide, pictureBox_login_loading); }));
}
}));
thread.Start();
You could also use a BackgroundWorker like the other answer discussed, but I tend to reserve them for longer running tasks, such as ones that report progress with a progress bar. If it is a short(ish) task, I usually use a Thread, or Task.Factory.StartNew in .NET 4.0.

sleeping a new thread c#

so im trying to delay the sending of email from my program.
In order to keep the UI interactive, i started a new thread and called the email method in the thread. It works. It sends the emails. However i cant figure out how to sleep the thread.
Ive tried using Thread.sleep() in the actual email method, but it doesnt seem to work.
Thread oThread = new Thread(new ThreadStart(() => { sendEMailThroughOUTLOOK(recipientAddress, subjectLine, finalbody); }));
oThread.Start();
email method..
public void sendEMailThroughOUTLOOK(string recipient, string subject, string body)
{
Thread.Sleep(60000);
try
{
// Create the Outlook application.
Outlook.Application oApp = new Outlook.Application();
// Create a new mail item.
Outlook.MailItem oMsg = (Outlook.MailItem)oApp.CreateItem(Outlook.OlItemType.olMailItem);
// Set HTMLBody.
//add the body of the email
oMsg.Body = body;
oMsg.Subject = subject;
// Add a recipient.
Outlook.Recipients oRecips = (Outlook.Recipients)oMsg.Recipients;
// Change the recipient in the next line if necessary.
Outlook.Recipient oRecip = (Outlook.Recipient)oRecips.Add(recipient);
oRecip.Resolve();
// Send.
oMsg.Send();
// Clean up.
oRecip = null;
oRecips = null;
oMsg = null;
oApp = null;
}//end of try block
catch (Exception ex)
{
}//end of catch
//end of Email Method
}
There is nothing apparently wrong with the code you've posted. However, thread.Suspend() is a very old API = it has been deprecated/obsoleted since .NET 2.0, as it's not safe to do this.
The static method Thread.Sleep(N) most certainly suspends the calling thread for N milliseconds.
To clarify; calling Thread.Sleep suspends the calling thread, so in your example code, where you have;
public void sendEMailThroughOUTLOOK(string recipient, string subject, string body)
{
Thread.Sleep(60000);
...
}
The call to Thread.Sleep(60000) is suspending the thread which is executing the method sendEMailThroughOUTLOOK. And since you appear to be calling that method in it's own thread,as evidenced by;
Thread oThread = new Thread(new ThreadStart(() => { sendEMailThroughOUTLOOK(recipientAddress, subjectLine, finalbody); }));
oThread.Start();
the correct thread should be suspended.
There is no way to do something like this;
Thread t = new Thread();
t.Start();
t.Sleep(60000);
You can start, or kill a running thread, but not sleep/suspend it. As noted - this API was deprecated as it is not a safe way to implement thread synchronisation (see http://msdn.microsoft.com/en-us/library/system.threading.thread.suspend%28v=vs.71%29.aspx for an explanation of why this is not a good idea).
Since you are a bit new to programming I won't try to explain all the relevant details but I thought it was cool that you showed me a new trick with your sample so I wanted to help you out if I could.
This isn't the only way to code this but I can tell you this is a reasonable one. It uses a background worker component to keep the UI responsive while sending the email. Note the use of the background worker's provided events DoWork and RunWorkerCompleted. The setup for these events took place in the designer which is why I zipped the solution up for you so you could take a look at the whole thing (I did so with google Drive and this is my first attempt doing a public share - if the link opens for you like it does for me, you'll get a File menu from which you can select Download).
I created an inner private class and passed it to the background worker. I do this because I don't want to access the data in my UI components from code running in a different thread. This will not always cause a problem but I find it to be a good practice in general. Also, it makes it so if I want to refactor the code later it will be easier to take the lines from DoWork and put them somewhere else without any fuss.
On the more general area of multi threaded programming - it's a multi faceted subject and you don't need to get it all right away. This is my favorite tutorial (the book is great too).
using System;
using System.ComponentModel;
using System.Windows.Forms;
using Outlook = Microsoft.Office.Interop.Outlook;
namespace Emailer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void SendButton_Click(object sender, EventArgs e)
{
this.sendEmailBackgroundWorker.RunWorkerAsync(new _Email
{
Recipient = this.recipientTextBox.Text,
Subject = this.subjectTextBox.Text,
Body = this.emailToSendTextBox.Text
});
}
private class _Email
{
public string Body { get; set; }
public string Subject { get; set; }
public string Recipient { get; set; }
}
private void sendEmailBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
var email = (_Email)e.Argument;
try
{
Outlook.Application oApp = new Outlook.Application();
Outlook.MailItem oMsg = (Microsoft.Office.Interop.Outlook.MailItem)oApp.CreateItem(Outlook.OlItemType.olMailItem);
oMsg.Body = email.Body;
oMsg.Subject = email.Subject;
Outlook.Recipients oRecips = (Outlook.Recipients)oMsg.Recipients;
Outlook.Recipient oRecip = (Outlook.Recipient)oRecips.Add(email.Recipient);
oRecip.Resolve();
oMsg.Send();
oRecip = null;
oRecips = null;
oMsg = null;
oApp = null;
}
catch (Exception ex)
{
e.Result = ex;
}
e.Result = true;
}
private void sendEmailBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
string message;
if (e.Result is Exception)
message = "Error sending email: " + (e.Result as Exception).Message;
else if (e.Result is bool && (bool)e.Result)
message = "Email is sent";
else
throw new Exception("Internal Error: not expecting " + e.Result.GetType().FullName);
MessageBox.Show(message);
}
}
}

How to sync between a listening/sending tcp client thread and the main execution?

i have a simple windows service which runs and starts a thread which listen/receive heartbeat via tcp/ip. i'm having a hard time finding ways to sync between getting information from the tcp thread and using that value to update something in the main thread.
i try to use a thread.sleep method and keep on looping it for a few times while awaiting the answer back from the thread and then getting the value, but that method seems to be a bit volatile with the method sometimes working and sometimes not.
so what's a good way to sync between these two?
basically what i want to do is to start the listening tcp thread, get specific value and the update the main program.
attached are the receive function and the function which i used to start the thread.
p.s: i'm a totally noobie when it comes to tcp/ip and c# so any comments on any part of the code or the design is more than welcome :)
public virtual void Receive()
{
string eventMessage = string.Empty;
int bytesRcvd = 0;
int totalBytesRcvd = 0;
byte[] byteBuffer = new byte[maxBufferSize];
NetworkStream listenStream;
try
{
if (client.Connected)
{
listenStream = client.GetStream();
}
else
{
return;
}
while (true)
{
//message that is slot in from the object will get sent here.
if (!string.IsNullOrEmpty(MessageToSend))
{
Send(MessageToSend);
MessageToSend = string.Empty;
}
// must convert it back and look for the delimiter, cannot wait for the three heartbeat to pass
string leftoverMsg = string.Empty;
bytesRcvd = listenStream.Read(byteBuffer, totalBytesRcvd, maxBufferSize - totalBytesRcvd);
totalBytesRcvd += bytesRcvd;
//if more than heart beat size, can process to see if it's a heartbeat and proceed to send
if (totalBytesRcvd > msgHeartbeatSize)
{
eventMessage = Encoding.ASCII.GetString(byteBuffer, 0, totalBytesRcvd);
ProcessMessage(eventMessage, ref leftoverMsg, ref totalBytesRcvd, ref byteBuffer);
}
}
}
catch (ThreadAbortException thEx)
{
//do nothing as main thread has aborted and waiting to close
logger.Info(Thread.CurrentThread.Name + " is stopped. ");
}
catch (Exception exce)
{
bIsActive = false;
logger.Error(exce);
CleanUp();
}
finally
{
logger.Info(String.Format("Thread {0} Exiting. ", Thread.CurrentThread.Name));
}
}
public virtual void StartReceivingThread()
{
Thread thrReceive = new Thread(Receive);
try
{
if (!bIsActive && Connect())
{
//NOTE: exception thrown by a thread can only be captured by that thread itself
//start a listen thread
//wait until heartbeat message is accepted
thrReceive.Name = "thr" + serviceType.Name;
thrReceive.Start();
bIsActive = true;
//wait to get the heartbeat message
for (int i = 0; i < maxRetry; i++)
{
Thread.Sleep(maxTimeOutValue);
if (bIsReceivingHeartbeat)
break;
}
//if nothing happens close the connection and try again
if (!bIsReceivingHeartbeat)
{
bIsActive = false;
CleanUp();
logger.Info("Closing receiver thread - " + thrReceive.Name);
}
else
{
logger.Info("Starting receiver thread - " + thrReceive.Name);
}
}
}
catch(Exception ex)
{
logger.Error(ex);
}
//finally
//{
// logger.Info("Exiting receiver thread - " + thrReceive.Name);
//}
}
I assume bIsReceivingHeartbeat is a bool member variable of the class. If the value changed in one thread (receiver) is not visible in the other thread this is most likely due to memory barrier. I am saying this from my Java background but this is most likely true in .net as well.
Try declaring the variables volatile or use a property and make the getter and setter synchronized:
private bool bIsReceivingHeartbeat;
public bool IsReceivingHeartbeat
{
[MethodImpl(MethodImplOptions.Synchronized)]
get { return bIsReceivingHeartbeat; }
[MethodImpl(MethodImplOptions.Synchronized)]
set { bIsReceivingHeartbeat = value; }
}
And in the calling code:
if (!IsReceivingHeartbeat) ....
I am writing from Java background but the situation most likely similar
(Looks like you also posted this code in refactormycode.com.)
Anyway, instead of the loop with a sleep delay, I recommend using an Event object that pulsed by the code that sets IsReceivingHeartbeat. See the ManualResetEvent and AutoResetEvent classes in MSDN.

Application.Run() operates differently in a Release build w/o a debugger than w/ or in a Debug build

I'm having trouble with a processing thread in C#. Basically the thread manages chat windows when new messages arrive or are sent and unfortunately I'm having different situations occur based on the running environment.
When running a Debug build (either with or without a debugger), or a Release build under a debugger, the Process() function operates correctly, shows windows and receives messages fine.
However, when running a Release build without a debugger, the Application.Run() call seems to stop the processing of the main Process() thread (notice that this call happens under a sub-thread of the processing thread) and so no more processing occurs.
Through the use of the MessageBox.Show() call I have determined that Application.Run() is the last call to be made before no more message boxes are shown (and they should be as it shows how many messages are received each time the while loop runs).
Does anyone know why the Application.Run() call is behaving differently under this situation?
/// <summary>
/// Processes the IM message queue, managing the chat windows and messages.
/// </summary>
private void Process()
{
try
{
MessageBox.Show("MessageQueue process has started!");
while (this.m_Running)
{
List<Message> messages = null;
lock (this.m_Lock)
{
messages = new List<Message>(this.m_Messages);
MessageBox.Show("MessageQueue received " + this.m_Messages.Count + " messages on this spin.");
this.m_Messages.Clear();
}
// Process all the messages
foreach (Message m in messages)
{
Contact c = m.Contact;
if (!this.m_Windows.Keys.Contains(c.ID) || this.m_Windows[c.ID] == null)
{
MessageBox.Show("MessageQueue is creating a new window.");
bool complete = false;
Thread t = new Thread(() =>
{
try
{
ChatWindow w = new ChatWindow(this, c, new Contact(this.m_Client.JID, null));
w.Load += (sender, e) =>
{
if (m.IsTo)
w.AppendSentMessage(m.To, m.Data);
else if (m.IsFrom)
w.AppendRecievedMessage(m.From, m.Data);
w.UpdateStatus(c);
};
w.FormClosed += (sender, e) =>
{
this.m_Windows[c.ID] = null;
};
c.StatusUpdated += (sender, e) =>
{
RoketPack.Manager.VoidLambda lambda = () =>
{
w.UpdateStatus(c);
};
if (w.InvokeRequired)
w.Invoke(lambda);
else
lambda();
};
MessageBox.Show("MessageQueue is now showing the new window.");
w.Show();
if (!this.m_Windows.Keys.Contains(c.ID))
this.m_Windows.Add(c.ID, w);
else
this.m_Windows[c.ID] = w;
complete = true;
MessageBox.Show("MessageQueue is now running the new window.");
Application.Run(w);
MessageBox.Show("MessageQueue is now closing the window.");
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
complete = true;
}
});
t.Name = "IM Chat Window - " + c.ID;
t.IsBackground = true;
t.Start();
// We have to wait until the form has been added to the dictionary.
while (!complete) ;
}
else
{
RoketPack.Manager.VoidLambda lambda = () =>
{
if (m.IsTo)
this.m_Windows[c.ID].AppendSentMessage(m.To, m.Data);
else if (m.IsFrom)
this.m_Windows[c.ID].AppendRecievedMessage(m.From, m.Data);
MessageBox.Show("MessageQueue appended the message to the chat window.");
};
MessageBox.Show("MessageQueue received a message and is now forwarding it onto the chat window.");
if (this.m_Windows[c.ID].InvokeRequired)
this.m_Windows[c.ID].Invoke(lambda);
else
lambda();
}
}
// Sleep for 10 milliseconds.
Thread.Sleep(10);
}
}
finally
{
MessageBox.Show("MessageQueue process has terminated!");
}
}
Aside from what leppie wrote, this looks like a bad starting point:
while (!complete);
I don't know exactly what guarantees there are around hoisted variables and visibility, but tight-looping is almost always a bad idea.
It would generally be better to use a Wait/Notify approach or an Auto/ManualResetEvent.
Do you realize Application.Run does not return until your application closes?
It also seems you are calling Application.Run from a child thread.

Categories

Resources