2

Background:

I am using a simple progress dialog in an Outlook Add-in to show progress while performing long operations. Since I cannot run code that uses Outlook objects in a separate thread, I cannot implement a more traditional background worker process. My add-in has been working OK until Outlook 2013 where in certain instances my progress dialog hangs. When I run the add-in in the VS debugger and cause the hang, then do a break, it appears to be stuck on the DoEvents() line that tries to force the progressbar to update.

My Question:

Can someone suggest a better system to show progress with the restriction above (long running code must run in main Outlook thread). Is there a better way to make the progress dialog responsive without using DoEvents()?

The following simple code demonstrates how I am doing this now. In the add-in code that is performing long operations on Outlook objects:

private void longRunningProcess()
{
    int max = 100;

    DlgStatus dlgstatus = new DlgStatus();
    dlgstatus.ProgressMax = max;
    dlgstatus.Show();

    for (int i = 0; i < max; i++)
    {
        //Execute long running code that MUST best run in the main (Outlook's) thread of execution...
        System.Threading.Thread.Sleep(1000); //for simulation purposes

        if (dlgstatus.Cancelled) break;
        dlgstatus.SetProgress("Processing item: " + i.ToString(), i);
    }
}

Here's the code for the simple progress dialog window:

public partial class DlgStatus : Form
{
    private bool _cancelled;

    public DlgStatus()
    {
        InitializeComponent();
    }

    public int ProgressMax
    {
        set 
        {
            progress.Maximum = value;
            Application.DoEvents();
        }
    }

    public bool Cancelled
    {
        get { return _cancelled; }
    }

    public void SetProgress(string status, int val)
    {
        lblStatus.Text = status;
        progress.Value = val;
        Application.DoEvents();  //Seems to hang here
    }

    private void btnCancel_Click(object sender, EventArgs e)
    {
        _cancelled = true;
        Application.DoEvents();
        this.Visible = false;
    }
}
NetGeni59
  • 56
  • 4
  • And why can't you start a background thread and marshal to the "outlook thread" just like you do with any other UI application? – Servy Dec 05 '12 at 20:15
  • 1
    Servy, I forgot that you can do this. I see some other web references that describe how to do this. Here's one in particular: [MSDN Forum link](http://social.msdn.microsoft.com/Forums/da-DK/outlookdev/thread/5c5eeff3-408b-4430-bb27-9aea5a0503f9) – NetGeni59 Dec 05 '12 at 20:39

1 Answers1

0

I was able to accomplish this by doing the following. The Custom form has a progressbar with the style set to Marquee.

I got the general method from http://social.msdn.microsoft.com/Forums/en/vsto/thread/59993421-cbb5-4b7b-b6ff-8a28f74a1fe5 but found that I did not need to use all the custom window handles.

private void btn_syncContacts_Click(object sender, RibbonControlEventArgs e)
{
     Thread t = new Thread(SplashScreenProc);
     t.Start();

     //long running code
     this.SyncContacts();

     syncingSplash.Invoke(new Action(this.syncingSplash.Close), null);
}

private SyncingContactsForm syncingSplash = new SyncingContactsForm();

internal void SplashScreenProc(object param)
{
    this.syncingSplash.ShowDialog();
}

It is important to note that the form does not work with the Outlook object model. It is not recommended by Microsoft to use the object model on separate threads.

jsturtevant
  • 2,560
  • 1
  • 23
  • 23
  • Thanks. I was able to adapt some code from this thread: http://stackoverflow.com/questions/4698080/spawn-a-new-thread-to-open-a-new-window-and-close-it-from-a-different-thread – NetGeni59 Jan 28 '13 at 19:39