C# 如何在c中处理线程内的dll函数调用#

C# 如何在c中处理线程内的dll函数调用#,c#,multithreading,dll,C#,Multithreading,Dll,我正在后台线程中调用一个DLL函数 问题是当DLL丢失时,我的应用程序直接崩溃。我也尝试了try-catch,但应用程序还是崩溃了 当我在主UI线程上调用DLL函数时,我的应用程序将处理异常 如何在后台线程中处理异常 mythread = new Thread(CM); mythread.IsBackground = true; mythread.Start(); private void CM() { // Perform a protection check wi

我正在后台线程中调用一个DLL函数

问题是当DLL丢失时,我的应用程序直接崩溃。我也尝试了try-catch,但应用程序还是崩溃了

当我在主UI线程上调用DLL函数时,我的应用程序将处理异常

如何在后台线程中处理异常

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

在这里快速回答

某些DLL在启动它的第一个线程中具有亲和力。我过去所做的就是在后台使用循环保持线程的活动状态。然后在加载DLL的线程中侦听事件。您可能需要重新构造代码以侦听事件,而不是调用DLL调用

希望有帮助

我添加了一些示例代码,您可以尝试一下,看看会发生什么。它并不完美,但它应该帮助说明如何保持线程的活力。还有其他方法可以做到这一点,但我只想让示例保持简单

    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
                    }
                }
            }
        }
    }
快速回答这里

某些DLL在启动它的第一个线程中具有亲和力。我过去所做的就是在后台使用循环保持线程的活动状态。然后在加载DLL的线程中侦听事件。您可能需要重新构造代码以侦听事件,而不是调用DLL调用

希望有帮助

我添加了一些示例代码,您可以尝试一下,看看会发生什么。它并不完美,但它应该帮助说明如何保持线程的活力。还有其他方法可以做到这一点,但我只想让示例保持简单

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

属于“你永远不应该做的事情”的范畴。这是一个部署错误,您总是需要一个响亮的消息来告诉某人去修复它。但无论如何,问题是try/catch的位置不正确。该异常是由即时编译器引发的,它将在开始运行之前尝试生成机器代码。使用线程执行此操作会使它变得更加复杂,只有CLR才能捕获它

您必须提供帮助,您必须有意识地编写一个小存根方法,您可以依靠它始终工作。然后它又必须调用有风险的代码。现在您有了注入必要的try/catch的方法。您还必须确保这在发布版本中起作用,这需要您减缓抖动并防止它内联危险的方法。这需要一个属性。像这样:

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
}

使用的原始代码抛出,无法工作。永远不要跳过留下面包屑的需要,这样你就可以知道线程没有完成它应该做的事情。某种类型的记录器或EventLog类是绝对最低要求。

属于“永远不应该做的事情”类别。这是一个部署错误,您总是需要一个响亮的消息来告诉某人去修复它。但无论如何,问题是try/catch的位置不正确。该异常是由即时编译器引发的,它将在开始运行之前尝试生成机器代码。使用线程执行此操作会使它变得更加复杂,只有CLR才能捕获它

您必须提供帮助,您必须有意识地编写一个小存根方法,您可以依靠它始终工作。然后它又必须调用有风险的代码。现在您有了注入必要的try/catch的方法。您还必须确保这在发布版本中起作用,这需要您减缓抖动并防止它内联危险的方法。这需要一个属性。像这样:

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
}


使用的原始代码抛出,无法工作。永远不要跳过留下面包屑的需要,这样你就可以知道线程没有完成它应该做的事情。某种类型的记录器或EventLog类是绝对最低要求。

您可以共享您尝试过的内容吗您正在加载的DLL是什么?我正在将我的DLL复制到exe文件夹位置。您是否真的捕获到异常,或者它是否失效?用断点检查。哦,在抛出后,我想是的,我没能捕捉到。但是有可能从bck线程捕获异常吗?你能分享你尝试过的吗?你正在加载的DLL是什么?我正在将我的DLL复制到exe文件夹位置。你真的捕获了异常吗?还是它失败了?用断点检查。哦,在抛出后,我想是的,我没能捕捉到。但有可能从bck线程捕获异常吗?这很有意义。但请你发一些示例代码好吗?它很复杂,我会尝试在我有机会的时候为你准备一个示例。但请你发一些示例代码好吗?这很复杂,我会在有机会的时候给你准备一个例子,即使我不扔。我的应用程序还是会崩溃?目的是让LogFatalError()方法不会崩溃你的应用程序,而只是报告它,以便有人能找出你的应用程序出现错误的原因。评论的模糊性提供了更多的理由说明为什么你根本不应该这么做。所以没有其他方法可以防止崩溃?总之,我的应用程序中已经有了一个事件记录器。我至少可以在那里记录这次事故。顺便说一句,谢谢你的建议。即使我不扔。我的应用程序还是会崩溃?目的是让LogFatalError()方法不会崩溃你的应用程序,而只是报告它,以便有人能找出你的应用程序出现错误的原因。评论的模糊性提供了更多的理由说明为什么你根本不应该这么做。所以没有其他方法可以防止崩溃?总之,我的应用程序中已经有了一个事件记录器。我至少可以在那里记录这次事故。顺便说一句,谢谢你的建议。