invalidOperationException while using delegate in thread - c#

I divided my programme in 3 layers; GUI, BL, IO and tried to grap files from my server to my pc. I made it multi threaded and zorks fine, but when i tried to add a delegate to it for sending messages from my IO to my GUI, it troubels me. It said something like:
It is not allowed to perform an operation through various threads: it
was from another thread had access to the control label download
progress than the thread on which the element is created.
What i have is this:
GUI
private void buttonDownload_Click(object sender, EventArgs e)
{
download = new BL_DataTransfer(Wat.FILM, titel, this.downloadDel);
t = new Thread(new ThreadStart(download.DownLoadFiles));
t.Start();
}
private void UpdateDownloadLabel(string File)
{
labelDownloadProgress.Text = "Downloading: " + File;
}
BL
public void DownLoadFiles()
{
//bestanden zoeken op server
string map = BASEDIR + this.wat.ToString() + #"\" + this.titel + #"\";
string[] files = IO_DataTransfer.GrapFiles(map);
//pad omvormen
string[] downloadFiles = this.VeranderNaarDownLoadPad(files,this.titel);
IO_DataTransfer.DownloadFiles(#".\" + this.titel + #"\", files, downloadFiles, this.obserdelegate);
}
IO
public static void DownloadFiles(string map, string[] bestanden, string[] uploadPlaats, ObserverDelegate observerDelegete)
{
try
{
Directory.CreateDirectory(map);
for (int i = 0; i < bestanden.Count(); i++)
{
observerDelegete(bestanden[i]);
File.Copy(bestanden[i], uploadPlaats[i]);
}
}
catch (UnauthorizedAccessException uoe) { }
catch (FileNotFoundException fnfe) { }
catch (Exception e) { }
}
Delgate
public delegate void ObserverDelegate(string fileName);

Assuming that it's the update of the label that's failing you need to marshal the event onto the UI thread. To do this change your update code to be:
private void UpdateDownloadLabel(string File)
{
if (labelDownloadProgress.InvokeRequired)
{
labelDownloadProgress.Invoke(new Action(() =>
{
labelDownloadProgress.Text = "Downloading: " + File;
});
}
else
{
labelDownloadProgress.Text = "Downloading: " + File;
}
}
I've ended up creating an extension method for this that I can call - thus reducing the amount of repeated code in my applications:
public static void InvokeIfRequired(this Control control, Action action)
{
if (control.InvokeRequired)
{
control.Invoke(action);
}
else
{
action();
}
}
Which is then called like this:
private void UpdateDownloadLabel(string File)
{
this.labelDownloadProgress.InvokeIfRequired(() =>
labelDownloadProgress.Text = "Downloading: " + File);
}

if UpdateDownloadLabel function is in some control code-file, use pattern like this:
private void UpdateDownloadLabel(string File)
{
this.Invoke(new Action(()=> {
labelDownloadProgress.Text = "Downloading: " + File;
})));
}
You need to invoke assignment on UI thread in order to be able to change something on label.

Related

Async function freezes UI thread

I have an async function which still freezes / lags the UI thread for me when I execute it. This is my function calling it.
private void TcpListenerLogic(object sender, string e)
{
Application.Current.Dispatcher.BeginInvoke((Action)async delegate {
try
{
dynamic results = JsonConvert.DeserializeObject<dynamic>(e);
if (results.test_id != null)
{
// Get properties for new anchor
string testInformation = await CommunicationCommands.getJsonFromURL(
"http://" + ServerIP + ":" + ServerPort + "/api/" + results.test_id);
}
}
catch (Exception exception)
{
// Writing some Trace.WriteLine()'s
}
});
}
And this is the async function that freezes my UI Thread
public static async Task<string> getJsonFromURL(string url)
{
try
{
string returnString = null;
using (System.Net.WebClient client = new System.Net.WebClient())
{
returnString = await client.DownloadStringTaskAsync(url);
}
return returnString;
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
return null;
}
}
I already tried to make everything in TcpListenerLogic run in a new Thread:
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
}).Start();
Which resulted in the whole UI completely freezing. And I tried to make TcpListenerLogic async and await the dispatcher, which also made everything freeze permanently. I also tried to make TcpListenerLogic async and leave the dispatcher. The dispatcher is only there because I normally have some UI code in there, which I left out for my tests.
I have ventured far through the internet, but no BackgroundWorker, ThreadPool or other methods helped me in my endeavour.
If anyone has help for this particular problem, or a resource that would improve my understanding of async functions in C#, I would much appreciate it.
Edit
As requested a deeper insight in how this event handler is called.
I have System.Net.Websocket, which is connected to the Backend API I am working with and triggers an event, everytime he receives new Data. To guarantee the socket listens as longs as it is open, there is a while loop which checks for the client state:
public event EventHandler<string> TcpReceived;
public async void StartListener(string ip, int port, string path)
{
try
{
using (client = new ClientWebSocket())
{
try
{ // Connect to backend
Uri serverUri = new Uri("ws://" + ip + ":" + port.ToString() + path );
await client.ConnectAsync(serverUri, CancellationToken.None);
}
catch (Exception ex)
{
BackendSettings.IsConnected = false;
Debug.WriteLine("Error connecting TCP Socket: " + ex.ToString());
}
state = client.State;
// Grab packages send in backend
while (client.State == WebSocketState.Open || client.State == WebSocketState.CloseSent)
{
try
{
// **Just formatting the received data until here and writing it into the "message" variable**//
TcpReceived(this, message);
// Close connection on command
if (result.MessageType == WebSocketMessageType.Close)
{
Debug.WriteLine("Closing TCP Socket.");
shouldstayclosed = true;
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
break;
}
state = client.State;
}
catch
{
BackendSettings.IsConnected = false;
state = client.State;
}
}
state = client.State;
}
}
catch (Exception ex)
{
// Some error messages and settings handling
}
}
The Event has a handler attached:
TcpReceived += TcpListener_TcpReceived;
And this is the Handler, which calls the previously seen "TcpListenereLogic".
private void TcpListener_TcpReceived(object sender, string e)
{
TcpListenerLogic(sender, e);
//App.Current.Dispatcher.BeginInvoke(new Action(() => {
// TcpListenerLogic(sender, e);
//}));
//new Thread(() =>
//{
// Thread.CurrentThread.IsBackground = true;
// TcpListenerLogic(sender, e);
//}).Start();
}
I previously had the "TcpListenereLogic" as the handler, but I wanted to try different methods to call it. I also left in the commented out part, to show how the call of "TcpListenereLogic" looked already. All my attempts were with all mentioned setups and sadly lead to nothing.
Thank you very much #TheodorZoulias for helping me to find the solution to my problem.
It turns out it wasn't the async function itself, but rather how often it gets called. It got called roughly ~120 times every second.
My solution starts by calling the Listener method over a new Thread:
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
MainWindow.tcpListener.StartListener(ip, portNumber, "/api/");
}).Start();
To limit the amount of calls that happen every second I added a dispatcher timer, that resets a bool after it has been used for a call, by my Event.
readonly System.Windows.Threading.DispatcherTimer packageIntervallTimer =
new System.Windows.Threading.DispatcherTimer();
bool readyForNewPackage = true;
private void ReadyForPackage(object sender, EventArgs e)
{
readyForNewPackage = true;
}
public async void StartListener(string ip, int port, string path)
{
packageIntervallTimer.Interval = TimeSpan.FromMilliseconds(50);
packageIntervallTimer.Tick += (s, e) => { Task.Run(() => ReadyForPackage(s, e)); };
packageIntervallTimer.Start();
Then I wrapped everything inside the while loop into an if condition based on the bool, the most important part was to have my "event EventHandler TcpReceived" in there:
// Grab packages sent in backend
while (client.State == WebSocketState.Open || client.State == WebSocketState.CloseSent)
{
if (readyForNewPackage == true)
{
readyForNewPackage = false;
try
{
....
TcpReceived(this, message);
....
}
catch
{
...
}
}
}
I added my TcpListenerLogic to the Eventhandler:
TcpReceived += TcpListenerLogic;
And my TcpListenerLogic now looked like this (names have been changed):
private async void TcpListenerLogic(object sender, string e)
{
try
{
dynamic results = JsonConvert.DeserializeObject<dynamic>(e);
if (results.test_id != null)
{
string testID = "";
if (results.test_id is JValue jValueTestId)
{
testID = jValueTestId.Value.ToString();
}
else if (results.test_id is string)
{
testID = results.test_id;
}
// Get properties for new object
string information = await CommunicationCommands.getJsonFromURL(
"http://" + ServerIP + ":" + ServerPort + "/api/" + testID );
if (information != null)
{
await App.Current.Dispatcher.BeginInvoke(new Action(() =>
{
// Create object out of the json string
TestStatus testStatus = new TestStatus();
testStatus.Deserialize(information);
if (CommunicationCommands.isNameAlreadyInCollection(testStatus.name) == false)
{
// Add new object to the list
CommunicationCommands.allFoundTests.Add(testStatus);
}
}));
{
}
catch (Exception exception)
{
....
}
}
Adding a new Thread to execute any step results in problems, so keep in mind that all this uses the thread created at the beginning for "StartListener"

C# Backgroundworker ReportProgress() not executing

Hello I am trying to populate a progress bar but the ReportProgress call its not been executed for some reason.
Here is my code
//create status_Worker
status_Worker = new BackgroundWorker();
status_Worker.DoWork += new DoWorkEventHandler(Status_DoWork);
status_Worker.ProgressChanged += new ProgressChangedEventHandler(Worker_ProgressChanged);
status_Worker.WorkerReportsProgress = true;
status_Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Worker_RunWorkerCompleted);
private void Status_DoWork(object sender, DoWorkEventArgs e)
{
//make call to Logger class getStatus method
_logger.getStatus(sender);
}
private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressbar1.Value = e.ProgressPercentage;
}
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
return;
}
else
{
Start_button.IsEnabled = true;
}
}
private void Start_button_Click(object sender, RoutedEventArgs e)
{
//initiate status_Worker when button is clicked
status_Worker.RunWorkerAsync();
Start_button.IsEnabled = false;
}
Now inside the Logger class I have the getStatus() method. i make a call to a local server to get status of the files been processed and all that works and I see the values been updated automatically on my MainWindow.Status.
public async Task getStatus(object sender)
{
BackgroundWorker statusWorker = (BackgroundWorker)sender;
//Making a call to ReportProgress here works and it shows the progress bar
//statusWorker.ReportProgress(99);
//REQUEST STATUS from a server
//Status format
//CurrentParser, NumberOfFilesToParse,CountOfCompletedFiles,Status, NumberOfProcessRunning
int CountOfCompletedFiles;
int NumberOfFilesToParse;
int percent;
string status = "Running";
string[] stats;
char[] delimiterChars = { ' ', ',', '.', ':', '\t' };
while(status!="Complete")
{
var getstatus = await request.GetStringAsync("http://localhost:8085/status");
logs.Add(getstatus);
stats = getstatus.Split(delimiterChars);
NumberOfFilesToParse = Int32.Parse(stats[1]);
CountOfCompletedFiles = Int32.Parse(stats[2]);
status = stats[3];
Thread.Sleep(1000);
MainWindow.main.Status = "Files to process: " + NumberOfFilesToParse + " Files completed: " + CountOfCompletedFiles + " Status: " + status;
if(NumberOfFilesToParse!=0 && status!="Complete")
{
percent = (CountOfCompletedFiles * 100) / NumberOfFilesToParse;
//a call to ReportProgress here stalls the program at this point
//statusWorker.ReportProgress(percent);
}
}
MainWindow.main.Status = "Completed!";
}
A call to ReportProgress at the start of the getStatus method works but a call to ReportProgress during or after my while loop results in process stalling at that point. Even when using static numbers ReportProgress(99) it only executes at the beginning
Your Status_DoWork method is doing fire-and-forget. It's calling an async Task method and then ignoring the Task it returns.
One of the problems you've run into is that BackgroundWorker simply doesn't work with async. What's actually happening is that as soon as the first await is reached in getStatus, it returns an incomplete Task to Status_DoWork, which then exits. This causes the BackgroundWorker to finish, so raising progress events no longer makes sense for that BackgroundWorker.
The modern replacement for BackgroundWorker is Task.Run, which includes support for progress reporting. Ideally, you would only use Task.Run for CPU-bound methods, not the I/O-bound methods:
private void Start_button_Click(object sender, RoutedEventArgs e)
{
Start_button.IsEnabled = false;
var progress = new Progress<int>(update => progressbar1.Value = update);
try
{
await _logger.getStatus(progress);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
Start_button.IsEnabled = true;
}
}
public async Task getStatus(IProgress<int> progress)
{
int CountOfCompletedFiles;
int NumberOfFilesToParse;
int percent;
string status = "Running";
string[] stats;
char[] delimiterChars = { ' ', ',', '.', ':', '\t' };
while(status!="Complete")
{
var getstatus = await request.GetStringAsync("http://localhost:8085/status");
logs.Add(getstatus);
stats = getstatus.Split(delimiterChars);
NumberOfFilesToParse = Int32.Parse(stats[1]);
CountOfCompletedFiles = Int32.Parse(stats[2]);
status = stats[3];
await Task.Run(() => Thread.Sleep(1000)); // process file in Task.Run
MainWindow.main.Status = "Files to process: " + NumberOfFilesToParse + " Files completed: " + CountOfCompletedFiles + " Status: " + status;
if(NumberOfFilesToParse!=0 && status!="Complete")
{
percent = (CountOfCompletedFiles * 100) / NumberOfFilesToParse;
progress.Report(percent);
}
}
MainWindow.main.Status = "Completed!";
}

Update GUI controls from a background thread of another class

I am creating an windows based application which download the data from server.
I am using background thread which is created on different class to perform these download operation.And I want to continuously show the download status on rich textbox i.e on main thread.But i am unable to do this,get an Cross-thread operation not valid.
Please help me to resolve this problem.
method on Form1.cs
public void UpdateRichText(string Text)
{
SetRichText(Text);
}
public delegate void SetRichTextTextDelegate(string text);
public void SetRichText(object number)
{
if (InvokeRequired)
{
this.BeginInvoke(new SetRichTextTextDelegate(SetRichText),text);
return;
}
richTextBox1.Text += number.ToString() + "\n";
}
private void button3_Click_1(object sender, EventArgs e)
{
demo d = new demo();
d.display();
}
methods on demo.cs
Form1 f = new Form1();
public void display()
{
Thread t = new Thread(new ThreadStart(call));
t.Start();
}
public void call()
{
//when i call this method every time if(InvokeRequired) is false.
f.UpdateRichText("Called from Thread");
}
Try changing your check to:
if (richTextBox1.InvokeRequired)
{
richTextBox1.BeginInvoke(new SetRichTextTextDelegate(SetRichText),text);
Try using the following
if (richTextBox1.InvokeRequired)
{
richTextBox1.Invoke(new Action(delegate { richTextBox1.Text += number.ToString() + "\n"; richTextBox1.ScrollToCaret(); }));
}
else
{
richTextBox1.Text += number.ToString() + "\n";
richTextBox1.ScrollToCaret();
}
richTextBox1.Text += number.ToString() + "\n"; Can be changed as follows,
rtbEvents.AppendText(Environment.NewLine + number.ToString() );

C# Making a program finish processes before advancing

In C#, how do you make a program only process one thing at a time? I've been working on a patching system, and I think I have the coding all correct but can't test it because a lot of the functions are trying to process all at once when they need to be processing in an order. The program doesn't even let the display shown up before it starts trying to process everything. Because none of them return a value other then the main function all the functions are set to void. I thought about maybe using a return value inside of a loop to make sure the program is finished with that step first before moving on but it still leaves the problem of the program not even showing up until everything is done processing which its suppose to show the progress of everything. Any suggestions of tips?
Edit: I don't know what to post in the code, so im posting all the main functions:
public void DSP_Load(object sender, EventArgs e)
{
if (v1 >= v2)
{
File_Progress_Title.Text = "100%";
Update_Status.Text = "Divine Shadows is currently up to date.";
Application.DoEvents();
Process.Start("Divine Shadows.exe");
Close();
}
else
{
Update_Status.Text = "Checking For Updates...";
Application.DoEvents();
if (!Directory.Exists(tempFilePath))
{
Directory.CreateDirectory(tempFilePath);
}
using (SqlCon = new MySqlConnection(connString))
{
SqlCon.Open();
string command = "SELECT * FROM version where version > '" + v1 + "' ORDER BY version LIMIT 1";
MySqlCommand GetLatestVersion = new MySqlCommand(command, SqlCon);
using (MySqlDataReader DR = GetLatestVersion.ExecuteReader())
{
while(DR.Read())
{
do
{
string LatestVersion = Convert.ToString(DR.GetValue(1));
string WebURL = Convert.ToString(DR.GetValue(2));
update.DownloadFileAsync(new Uri(WebURL), tempFilePath + "patch" + LatestVersion + ".zip");
update.DownloadProgressChanged += new DownloadProgressChangedEventHandler(download);
update.DownloadFileCompleted += new AsyncCompletedEventHandler(extration);
Application.Restart();
}
while (v1 < v2);
Process.Start("Divine Shadows.exe");
Close();
}
}
}
}
}
public void download(object sender, DownloadProgressChangedEventArgs e)
{
if (v1 >= v2)
{
File_Progress_Title.Text = "100%";
Update_Status.Text = "Divine Shadows is currently up to date.";
Application.DoEvents();
Process.Start("Divine Shadows.exe");
Close();
}
else
{
Update_Status.Text = "Downloading Updates...";
Application.DoEvents();
File_Progress_Display.Value = e.ProgressPercentage;
File_Progress_Title.Text = Convert.ToString(e.ProgressPercentage) + "%";
}
}
public void extration(object sender, AsyncCompletedEventArgs e)
{
if (v1 >= v2)
{
File_Progress_Title.Text = "100%";
Update_Status.Text = "Divine Shadows is currently up to date.";
Application.DoEvents();
Process.Start("Divine Shadows.exe");
Close();
}
else
{
Update_Status.Text = "Installing Updates, Please Wait...";
Application.DoEvents();
UnzipFile(extactFile, extractLocation);
}
}
public static void UnzipFile(string extactFile, string extractLocation)
{
try
{
FastZip fastZip = new FastZip();
fastZip.CreateEmptyDirectories = false;
fastZip.ExtractZip(extactFile, extractLocation, FastZip.Overwrite.Always, null, null, null, false);
}
catch (Exception ex)
{
throw new Exception("Error unzipping file \"" + extactFile + "\"", ex);
}
File.Delete(extactFile);
}
Your problem is not WebClient() specific, its about how your application is working with threads.
In general, winforms applications have one GUI Thread. This thread is used to executed your methods and also updating the user interface. If you start a long term process, the gui thread gets locked till the operation is finished. Thats the reason why your display is not shown.
You can solve that problem by implementing the BackgroundWorker. On that website you can also find an example how to implement it. Let the BackgroundWorker do your patching process and use events inside the BackgroundWorker.RunWorkerAsync() method to update your GUI.
If you are using c#4 or newer you can use the Task Parallel Library to perform tasks asynchronously, thus leaving your UI response while thing are being downloaded. First of all you need a reference:
using System.Threading.Tasks;
And some code:
public void YourMainFunction()
{
var urls = new List<string>();
urls.Add("http://google.com");
urls.Add("http://yahoo.com");
foreach(var url in urls)
{
Task.Factory.StartNew<DownloadResult>(() =>
DownloadIt(url))
.ContinueWith(WorkDone, TaskScheduler.FromCurrentSynchronizationContext());
}
}
private class DownloadResult
{
public string Url {get; set;}
public string Result {get; set;}
}
private DownloadResult DownloadIt(string url)
{
var downloadResult = new DownloadResult{ Url = url };
var client = new WebClient();
downloadResult.Result = client.DownloadString(url);
return downloadResult;
}
private void WorkDone(Task<DownloadResult> task)
{
if(task.IsFaulted)
{
//An exception was thrown
MessageBox.Show(task.Exception.ToString());
return;
}
//Everything went well
var downloadResult = task.Result;
//Here you can update your UI to reflect progress.
MessageBox.Show(downloadResult.Result);
}

Cross thread problem?

My error
Cross-thread operation not
valid: Control 'MailTree' accessed
from a thread other than the thread it
was created on.
with my code
My idea is when SaveMail method has finish store 1 mes then add this mes to listview.
private delegate int SaveMailDelegate(ImapX.Message mes);
public int SaveMail(ImapX.Message mess)
{
if (!File.Exists("D:\\" + Username + "\\" + MailTree.SelectedNode.Text + "\\" + mes.MessageUid.ToString() + ".eml"))
{
mess.Process();
mess.SaveAsEmlToFile("D:\\" + Username + "\\" + MailTree.SelectedNode.Text + "\\", mes.MessageUid.ToString()); //Store messages to a Location
}
// mes.MessageUid=mess.MessageUid;
return 1;
}
Mime EncodingMail(string NodeName,string focusitem)
{
Mime m = new Mime();
m=Mime.Parse("D:\\" + Username+ "\\"+NodeName+"\\"+focusitem+".eml");
return m;
}
private void AddMesToMailList()
{
ListViewItem item = new ListViewItem();
Mime m = EncodingMail(MailTree.SelectedNode.Text, mes);
item.Text = mes.MessageUid.ToString();
item.SubItems.Add(m.MainEntity.Subject);
ReturnMime(m);
if (mailfromname != null)
item.SubItems.Add(mailfromname);
else item.SubItems.Add(mailfrom);
item.SubItems.Add(m.MainEntity.Date.ToString());
item.SubItems.Add(mailfrom);
MailList.Items.Add(item);
}
private void SaveMailDone(IAsyncResult iar)
{
SaveMailDelegate del = iar.AsyncState as SaveMailDelegate;
if (del != null)
{
int result = del.EndInvoke(iar);
AddMesToMailList();
}
}
private void MailTree_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)
{
MailList.Items.Clear();
for (int i = 0; i < client.Folders.Count; i++)
{
(ContextMenuListView.Items[1] as ToolStripMenuItem).DropDownItems[i].Click += new EventHandler(MainForm_Click);
}
if (MailTree.SelectedNode.Text == Username)
{
webBrowser1.Visible = false;//webBrowser1.DocumentText = "Hello Baby";
AttachmentList.Visible = false;
groupBox1.Visible = false;
}
else
{
webBrowser1.Visible = true;
groupBox1.Visible = true;
try
{
messages = client.Folders[MailTree.SelectedNode.Text].Search("ALL", false); // Search mail in your choossen Folder
AmoutOfMail = messages.Count(); //Amout of Mail in this Folder
for (int i = 0; i < AmoutOfMail; i++)
{
mes=messages[i];
SaveMailDelegate del = new SaveMailDelegate(this.SaveMail);
del.BeginInvoke(mes, new AsyncCallback(this.SaveMailDone), del);
}
}
catch (Exception)
{ }
}
}
You cannot directly access a control from another thread, you will have to invoke it.
private delegate void ControlCallback(string s);
public void CallControlMethod(string text)
{
if (control.InvokeRequired)
{
ControlCallback call = new ControlCallback((s) =>
{
// do control stuff
});
control.Invoke(call, new object[] { text });
}
else
{
// do control stuff
}
}
you can't access the UI on a different thread than what it was created on. From inside your secondary thread (the one that runs your callback handler) you will need to call Form.BeginInvoke to register a method that will be run on the UI thread. From that method you can update your UI controls
I think AddMesToMailList() is trying to modify the view elements but it is on a wrong thread.
Try something like this
void AddMesToMailList()
{
if (this.InvokeRequired)
{
this.BeginInvoke(new Action(AddMesToMailList));
return;
}
// do stuff that original AddMesToMailList() did.
}
EDIT:
SaveMail is a little complicated as it has a return value but you can try this
public int SaveMail(ImapX.Message mess)
{
if(this.InvokeRequired)
{
return (int) this.Invoke(
new Func<ImapX.Message, int>( m => SaveMail(mess)) );
}
else
{
if (!File.Exists(#"D:\" + Username + "\\" + MailTree.SelectedNode.Text + "\\" + mes.MessageUid.ToString() + ".eml"))
{
mess.Process();
mess.SaveAsEmlToFile(#"D:\" + Username + "\\" + MailTree.SelectedNode.Text + "\\", mes.MessageUid.ToString()); //Store messages to a Location
}
// mes.MessageUid=mess.MessageUid;
return 1;
}
}

Categories

Resources