2010-10-13 45 views
1

我有一个函数可以从DocuShare服务器下载邮件消息作为MSG文件。当从主线程调用该函数时,该函数完美工作。但是,当我在一个单独的线程中调用该函数时,下载失败。当我介入代码时,我可以看到该函数正在被调用,所有参数都被正确计算,返回值就是我所期望的。不幸的是,我看到,没有文件被下载。C#2.0函数在单独线程中调用时不起作用

代码:

private void btnDownloadMails_Click(object sender, EventArgs e) 
    { 

     //Thread t = new Thread(new ThreadStart(DownloadMailAsMsg)); 
     //t.Start(); //Does not work 

     DownloadMailAsMsg(); // Works fine   
    } 

    void DownloadMailAsMsg() 
    { 

     DSServerMap.Server dsserver = new DSServerMap.Server(); 
     if (!SelectMappedServer(ref dsserver, textServer.Text.ToString())) 
      return; 

     long status = 0;    
     dsserver.DocuShareAddress = textServer.Text; 
     dsserver.UserName = textUser.Text; 
     dsserver.Password = textPwd.Text; 
     status = dsserver.Logon(); 

     if (status == 0) 
     { 
      IItemObj objParentItem; 
      string[] emailHan = { "MailMessage-12", "MailMessage-13", "MailMessage-31" }; 
      foreach (string handnum in emailHan) 
      { 
       objParentItem = (IItemObj)dsserver.CreateObject(handnum); 
       DSGATEWAYLib.IGatewayHandler gateway = (DSGATEWAYLib.IGatewayHandler)dsserver.Open(); 

       objParentItem.AttachGateway(gateway, true); 
       objParentItem.Name = @"D:\em\m_" + handnum + ".msg";      
       int flag = objParentItem.DSDownload(0); 
      } 
     } 
    } 

任何想法?

感谢 普拉卡什

+1

但是,我怀疑这是否是主要原因:您甚至不应该在非UI线程上讨论所有那些'.Text'属性。理想情况下,您应该先获得并将其传递给工作人员。 – 2010-10-13 10:46:56

回答

4

也许你需要的一个STA线程。我有一个类似的问题一次,以下解决了我的问题:

Thread t = new Thread((ThreadStart)delegate 
         { // MAPI does only work in STA threads. Therefore an STA thread needs to be created explicitly for the SendMail call. 
          //...do work here 
         }); 
t.SetApartmentState(ApartmentState.STA); 
t.Start(); 

也许这也会解决您的问题。

+0

是的,这是可能的问题。但是STA线程也需要消息循环。 OP的代码在没有一个的情况下仍然死锁的可能性很大。使用Application.Run()。 – 2010-10-13 12:24:29

+0

我在ApartmentState.STA模式的线程中调用了该函数,它工作正常。谢谢testalino。 – Prakash 2010-10-19 05:09:58

0

你的线程应该是类成员而不是方法变量。

当您的方法完成时,线程变量超出范围,可能会无法完成清理。

+0

线程是顶级(根)对象,不会因为变量超出范围而终止。 – 2010-10-13 10:50:53

1

您试图访问非UI线程控件的属性,

例如线,

dsserver.DocuShareAddress = textServer.Text; 
    dsserver.UserName = textUser.Text; 
    dsserver.Password = textPwd.Text; 

你想在不同的线程,这实际上抛出一个异常访问UI控件的Text属性。

要在不同线程中访问控件的每个值,必须将其包含在某种参数中并将其传递给线程。

class MyServerParameters{ 
    string Server; 
    string Username; 
    string Password; 
} 


private void btnDownloadMails_Click(object sender, EventArgs e)  
{  

    MyServerParameters p = new MyServerParameters(); 
    // we are still in UI thread so copy your values 
    // to p 
    p.Server = textServer.Text;   
    p.Username = textUser.Text;   
    p.Password = textPwd.Text;   
    Thread t = new Thread(new ParametricThreadStart(DownloadMailAsMsg));  
    // pass p to another thread 
    t.Start(p); // this will work... 

} 


void DownloadMailAsMsg(object mp) 
{ 
    // access p back like this... 
    MyServerParameters p = mp as MyServerParameters; 


    dsserver.DocuShareAddress = p.Server;  
    dsserver.UserName = p.Username;  
    dsserver.Password = p.Password; 
+0

这是准确的,但实际上并不是问题所在。 Text属性是特殊的,它被缓存,实际上可以从工作线程读取(但不能写入)。 – 2010-10-13 12:22:27

+0

@Hans,我怀疑,但我仍然会检查它。 – 2010-10-14 11:11:33

0

只有他们在您的第二个线程创建的控制和参考的.Text性质的副本。

如果您使用不同的线程访问任何控件,您将锁定您的应用程序或发生异常。

其他解决方法是使用.Invoke(),但在你的情况下,你真的不需要去那里。

相关问题