kaviarasan
kaviarasan

Reputation: 115

How to handle dll function calls inside a thread in c#

I am calling one of the DLL function inside a background thread.

The issue is when DLL is missing my application directly crashes. I tried with try-catch also but still, the application gets crashed?

When I call DLL function on the main UI thread then my application handles the exception.

How to handle the exception inside a background thread?

mythread = new Thread(CM);
mythread.IsBackground = true;
mythread.Start();

 private void CM()
    {
        // Perform a protection check with default options
        try
        {
            ret_code = myclass.CheckProtection(myclass.CheckProtectionOptions.Default);
        }
        catch(Exception cm)
        {
            throw cm;
        }

}

Upvotes: 0

Views: 1249

Answers (2)

Dai Bok
Dai Bok

Reputation: 3606

Quick answer here.

Some DLLs have an affinity the the first thread that starts it up. What I have done in the past is keep that thread alive in the background, with a loop. You then listen for events in that DLL loaded thread. You may need to restructure you code a bit to listen for events, instead of invoking DLL calls.

Hope that helps?

I have added some sample code, you could try that, and see what happens. Its not perfect, but it should help illustrate how to keep the thread alive. There are other ways of doing this, but I just want to keep the example simple

    using System;
    using System.Reflection;
    using System.Threading;

    namespace ConsoleApplication3
    {
        internal class Program
        {
            private static void Main(string[] args)
            {
                var newThread = new Thread(DllLoader.DoWork);
                newThread.Start();

                //My other application Logic
            }

            public class DllLoader
            {
                public enum ThingsICanDo
                {
                    Jump,
                    Duck,
                    Run,
                    Quit
                }

                private static bool appStillRunning;
                private static object myInstanceDllType;

                private static void CheckForStuffToDo()
                {
                    //Much better to use events, and pass the message inthe event
                    // then do what the message wants, and but I am keeping this breif 
                    // for this example.
                    var DoNext = (ThingsICanDo) Enum.Parse(typeof (ThingsICanDo), Console.ReadLine(), true);
                    switch (DoNext)
                    {
                        case ThingsICanDo.Jump:
                            //Do jump stuff
                            Console.WriteLine("Jump");
                            //myInstanceDllType.JumpStuff();
                            break;
                        case ThingsICanDo.Duck:
                            Console.WriteLine("Duck");
                            //myInstanceDllType.DuckStuff();
                            //Do duck stuff
                            break;
                        case ThingsICanDo.Run:
                            Console.WriteLine("Run");
                            //myInstanceDllType.RunStuff();
                            //Do run stuff
                            break;
                        case ThingsICanDo.Quit:
                            //Do exit stuff
                            Console.WriteLine("Bye");
                            Thread.CurrentThread.Abort();
                            break;
                    }
                }

                public static void DoWork()
                {
                    var externalAssembly = Assembly.LoadFrom("/path/my.Dll");
                    myInstanceDllType = Activator.CreateInstance("DLLTypeINeed");
                    while (appStillRunning)
                    {
                        try
                        {
                            CheckForStuffToDo();
                        }
                        catch (Exception e)
                        {
                            //Log e
                            Console.WriteLine(e);
                        }
                        Thread.Sleep(1000);
                            //Much better to use semaphore.wait or something similar, but this is a simple example
                    }
                }
            }
        }
    }

Upvotes: 1

Hans Passant
Hans Passant

Reputation: 941675

Belongs in the category of "things you should never do". It is a deployment error, you always need a loud message to tell somebody to get that fixed. But anyhoo, the problem is that the try/catch is placed incorrectly. The exception is thrown by the just-in-time compiler, it will keel over trying to produce the machine code before it starts running. Doing this with a thread makes it extra complicated, it could only ever be the CLR that could catch it.

You'll have to help, you have to intentionally write a little stub method that you can rely on to always work. And it in turn must then call the risky code. Now you have a way to inject the necessary try/catch. You also have to make sure that this works in a Release build, which requires you to slow down the jitter and prevent it from inlining the risky method. That requires an attribute. Like this:

using System.Runtime.CompilerServices;
...
mythread = new Thread(CMStub);
mythread.IsBackground = true;
mythread.Start();
...

void CMStub() {
    try {
        CM();
    }
    catch (Exception ex) {
        LogFatalError(ex);    // Don't throw!
    }
}

[MethodImpl(MethodImplOptions.Noinlining)]
void CM() {
    // risky code here
}

The original code used throw, that cannot work. Never skip the need to leave a breadcrumb so you can tell that the thread did not do what it was supposed to do. Some kind of logger or the EventLog class is an absolute minimum requirement.

Upvotes: 1

Related Questions