Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Correctly Multi-Thread a DLL Called at Run-Time in C#

All,

I wish to write a plugin .dll to be used/called by a .NET application called at runtime. My .dll is a WinForm and displays the (computationally expensive) operations being undertaken. The .dll is called from the main application are invoked via .NET System.Reflection. I have to provide to the calling application the NameSpace, Class and the Method I want to invoke.

I would like to multi-thread my .dll so that it is more UI friendly and I am only really familiar with BackgroundWorkers.

EDIT: Extension to question.

So, I call the .dll as follows:

if (classType != null)
{
    if (bDllIsWinForm)
    {
        classInst = Activator.CreateInstance(classType);
        Form dllWinForm = (Form)classInst;
        dllWinForm.Show();

        // Invoke required method.
        MethodInfo methodInfo = classType.GetMethod(strMethodName);
        if (methodInfo != null)
        {
            object result = null;
            // The method being called in this example is 'XmlExport'.
            result = methodInfo.Invoke(classInst, new object[] { dllParams });
            return result.ToString();
        }
    }
    else
    {
        // Else not a WinForm do simalar.
    }   
}

So then in the WinForm .dll I want to multi-thread the time consuming work so that I can display what is going on. So in the .dll, using BackgroundWorker I have:

BackgroundWorker bgWorker; // Global.    

public string XmlExport(object[] connectionString)
{
    try
    {
        bgWorker = new BackgroundWorker { WorkerReportsProgress = true, WorkerSupportsCancellation = true };
        bgWorker.DoWork +=  new DoWorkEventHandler(bgWorker_DoWork);
        bgWorker.ProgressChanged += new ProgressChangedEventHandler(bgWorker_ProgressChanged);
        bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);

        // Wait until workerThread is done.
        threadDoneEvent = new AutoResetEvent(false);
        bgWorker.RunWorkerAsync();
        threadDoneEvent.WaitOne();
        return strResult; // Global String strResult
    }
    catch (Exception)
    {
        throw;
    }
}

Then I have the DoWork event handler:

void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker thisWorker = sender as BackgroundWorker;
    strResult = (string)this.XmlExportBgw(ref thisWorker); // Or should I use bgWorker?
    e.Result = strResult;
}

public string XmlExportThreaded(ref BackgroundWorker thisWorker) 
{
    try
    {
        // Some expesive work...

        // UI.
        InfoBall infoBall = new InfoBall(); // Class containing processing information.
        // Set infoBall parameters here...
        (thisWorker as BackgroundWorker).ReportProgress(infoBall.progressBarValue, infoBall);

        // Some more expensive work...

        // UI.
        (thisWorker as BackgroundWorker).ReportProgress(infoBall.progressBarValue, infoBall);
    }
    //...
}

The `ProgressChanged' event is

void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    // UI.
    InfoBall someBall = (InfoBall)e.UserState;

   // Update process information.
   if (someBall.showRichTextBox)
   {
       this.richTextBox.AppendText(someBall.richTextBoxText);
       this.richTextBox.ScrollToCaret();
   }
   return;
}

In addition to the above code I have the usual RunWorkerCompleted etc.

The calling application has been written to allow the user to call thereown .NET .dlls at runtime. The .dll I am trying to put together is a time intensive one and one that will only be supplied to particular users. I have run the above code and the problem is that it will not update the user interface correctly. That is that you cannot manipulate (resize, click etc.) the Form and it does not print and progress information until the very end of the processing when it only prints the final message out multiple times. However, it is correctly producing the .xml files I require. What am I doing wrong? Should I be invoking the .dll method from a separate thread?

Any help would be greatly appreciated. Thanks very much for your time.

like image 717
MoonKnight Avatar asked Dec 02 '11 05:12

MoonKnight


1 Answers

I am not sure what kind of methods you are tryng to execute in that dll. I am assuming they are not asynchronous meaning your main thread (application) will stop until they are done executing. An easy example could be demonstrated with the Messagebox.show("myMessage"); method. For example how could you execute 3 message boxes at once? it will not be possible without using multiple threads. Hope this methods helps:

    public void SomeMethod()
    {


        Thread thread = new Thread(new ThreadStart(() =>
        {
            // this code is going to be executed in a separate thread
            MessageBox.Show("hello");    

            // place additional code that you need to be executed on a separate thread in here            

        }));

        thread.Start();
    }

then if I call that method 3 times as:

enter image description here

I will now be running 4 threads on my program. The main thread plus the 3 calls that I created.

like image 144
Tono Nam Avatar answered Sep 22 '22 14:09

Tono Nam