views:

68

answers:

4

Hi there,

I have a function to download a mailmessage as MSG file from DocuShare server. The function works perfectly when called from a main thread. However, when I call the function in a separate thread, the download fails. When I step in to the code, I can see that the function is being called, all the parameters are evaluated correctly and the return value is what I expect. Unfortunately, I see, no files get downloaded.

Codes:

    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);
            }
        }
    }

Any ideas?

Thanks Prakash

+4  A: 

Maybe you need a STA thread for this. I had a similar problem once and the following solved my problem:

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();

Maybe this will solve your problem as well.

testalino
Yes, this is the likely problem. But an STA thread also requires a message loop. Pretty good odds that the OP's code still deadlocks without one. Use Application.Run().
Hans Passant
I called the function in a thread in ApartmentState.STA mode, it worked. Thanks testalino.
Prakash
A: 

Your thread should be a class member instead of a method variable.

When your method completes, the thread variable goes out of scope and could get cleaned up without completing.

Brad Bruce
Threads are top-level (root) objects and don't get terminated just because a variable goes out of scope.
Marc Gravell
+1  A: 

You are trying to access Control's properties in non UI threads,

for example in lines,

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

you are trying to access UI Control's Text properties in different thread, which actually throws an exception.

Each of the control's values you want to access in different thread, you have to wrap it in some sort of arguements and pass it to the thread.

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;   
Akash Kava
It's accurate but not in fact the problem. The Text property is special, it is being cached and can in fact be read (but not written) from a worker thread.
Hans Passant
@Hans, I have my doubt, but I will still check on it.
Akash Kava
A: 

Create a copy of .Text properties of the controls and reference only them in your second thread.

You'll lock your application or get an exception if you use different thread to access any of the controls.

Other way around is to use .Invoke(), but in your case you really don't need to go there.

Daniel Mošmondor