【问题标题】:C# - cc3260mt.dll throws ArithmeticException whenever I load itC# - cc3260mt.dll 在我加载时抛出 ArithmeticException
【发布时间】:2014-02-12 09:40:07
【问题描述】:

我有一个 WPF 应用程序,我必须加载 DLL cc3260mt.dll 我使用 LoadLibrary() 调用它,但无论出于何种原因,我都会收到 ArithmeticException。

这是我的代码的样子:

public partial class MainWindow : Window
{
    [DllImport("kernel32.dll")]
    static extern IntPtr LoadLibrary(string dllToLoad);
    [DllImport("kernel32.dll")]
    static extern IntPtr FreeLibrary(IntPtr hModule);

    public MainWindow()
    {
        InitializeComponent();

        try
        {
            string cc3260mtPath = "dll/cc3260mt.dll";
            IntPtr cc3260Link = LoadLibrary(cc3260mtPath);
        }
        catch (Exception ex)
        {
            Console.WriteLine("ERROR : " + ex.Message);
        }

    } // <-- This is where I get the Exception.
}

当我一步一步运行我的代码时,我可以清楚地看到当我退出我的 MainWindow() 类时出现了异常。
你们知道是什么让我遇到了这个例外吗?

【问题讨论】:

标签: c# wpf visual-studio-2012 dll loadlibrary


【解决方案1】:

这是旧 Borland C 或 C++ 程序的 C 运行时支持库。是的,它所做的事情通常与 .NET 代码(尤其是 WPF)不兼容,它对浮点单元控制寄存器进行了重新编程。它启用硬件异常,当浮点操作失败时触发。在 WPF 中特别有问题,因为它喜欢使用 Double.NaN 很多。这会生成一个 FPU 异常,CLR 会拦截它并将其作为 ArithmeticException 重新引发。

您必须撤消此 DLL 所做的操作并恢复 FPU 控制字。这是有问题的,.NET 不能让您直接访问这样的硬件。但是,您可以使用一个技巧,当 CLR 处理异常时,它会自动重新编程 FPU。因此,您可以有意生成异常并捕获它。像这样:

    IntPtr cc3260Link = LoadLibrary(cc3260mtPath);
    try { throw new Exception("Ignore this please, resetting the FPU"); }
    catch (Exception ex) {}

请注意这样做的后果,您现在可以运行本机代码,而不会出现它通常依赖的异常。也许这会奏效。

【讨论】:

  • 非常感谢,现在它正在运行,我的 WPF 应用程序运行正常。我会记住你的笔记并注意它。
  • +1 不断惊叹于您知识的深度和广度。
  • 另外请注意,来自已加载库 (DLLMain) 的入口点代码将在创建的任何新线程上再次运行,这不会被原始线程上抛出的异常解决,如上面建议。为了完全解决这个问题,有必要创建一个新的 DLL,在其入口点重置 FPU 控制字,并在“坏”DLL 之后加载该 DLL。然后,在任何新线程上,将依次调用两个入口点,从而使新线程具有预期的 FPU 控制字。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-23
  • 1970-01-01
相关资源
最近更新 更多