【问题标题】:Catch exception thrown from Delphi DLL in C#在 C# 中捕获从 Delphi DLL 抛出的异常
【发布时间】:2014-11-26 10:58:38
【问题描述】:

我最近遇到的一个问题如下。

我有一个用 Delphi 编写的 .DLL 这个 DLL 有一个 Divide 函数(它接受两个整数作为参数) 并按应有的方式返回其值。

function Divide( aFirstValue, aSecondValue : Integer ) : Double; stdcall;
begin
  result := aFirstValue / aSecondValue;
end;

现在如果我使用以下参数 '5, 0' 那么它会抛出 DivideByZeroException(这是正确的 :))

但是当我从 C# 调用相同的 .DLL 时,它根本不会捕获任何异常。

[DllImport("DelphiDLL.DLL", EntryPoint = "Divide", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern float Divide(Int32 a, Int32 b);

private void Button_Click_2(object sender, System.EventArgs e)
{
    try
    {
       TB.Text += "Divide(a,b) = ";
       float temp;
       temp = Divide(Convert.ToInt32(aTB.Text), Convert.ToInt32(bTB.Text));

       Console.WriteLine(Marshal.GetLastWin32Error());

       TB.Text += Convert.ToString(temp) + "\r\n";
    }
    catch (DivideByZeroException eMsg)
    {

    }
}

【问题讨论】:

  • 有什么退回来的吗?
  • 是的,在 C# 中它显示 Infinite 所以返回一个值,但它也可能是 0.0....nth
  • divisor 为零时不调用divide 方法如何?无论如何,您知道输入无效吗?
  • @SriramSakthivel - 这将处理 this 问题,但不能解决为什么没有将异常返回到调用 c# 方法的问题。
  • @SriramSakthivel 不要因为 OP 使用一个简单的例子来证明他的问题而抨击他。他的问题说得很清楚。至少他努力提供简单清晰的代码示例。这比大量寻求帮助而无需努力提炼问题的问题要好得多。 (我已经编辑了标题以删除对特定异常的引用,因为根据问题的主体,这显然并不重要。)

标签: c# delphi dll pinvoke dllimport


【解决方案1】:

您不能希望在 DLL 之外捕获该异常。这种形式的二进制互操作的规则之一是不能跨模块边界抛出异常。

解决方案是修复 DLL。在 DLL 中捕获异常并返回错误代码以指示失败。实际上,您应该保护所有入口点不引发异常。不要只捕获零除异常,将它们全部捕获并将其转换为错误代码返回值。

function CalcQuotient(a, b: Integer; out quotient: Double): Integer; stdcall;
begin
  try
    quotient := a / b;
    Result := 0;// you'd use a constant with a sensible name rather than a magic value
  except
    on E: Exception do begin
      Result := GetErrorCode(E);
      // where GetErrorCode is your function that converts exceptions into error codes
    end;
  end;
end;

关于您的 p/invoke 用法的一些旁白:

  1. 当所有参数都不包含文本时,无需指定CharSet
  2. SetLastError = true 不正确,应删除。该函数不调用SetLastError。因此,对Marshal.GetLastWin32Error() 的调用是错误的,应该被删除。

【讨论】:

  • 大卫,正如你所说的“你不能希望”,这是否意味着这是不可能的,或者仍然有希望的火花?就是想。我会看看错误代码。
  • @Blaatz0r 也许有一些偷偷摸摸的方法可以抓住它们,但我对此表示怀疑。无论如何,你不应该扔它们,所以不要!
  • @Blaatz0r Delphi 中引发的异常是EZeroDivide。这是一个特定于 Delphi 世界的对象。 C# 将无法正确使用它。是的,一些标准异常类型可以从 Delphi 映射到 C#,例如 EZeroDivide --> DivideByZeroException,但这仍然会使自定义异常类型无法解释。它们只能通过一些最低公分母来映射。一些互操作框架可能能够在 Delphi 和 C# 之间编组异常。但在皮下,他们会做与大卫回答中所展示的相同的事情。
  • @CraigYoung 在输入 C# 变体时,您在 Delphi 异常 (EZeroDivide) 上的权利浮现在脑海中,这就是我编写 DivideByZeroException 的原因:)
猜你喜欢
  • 2011-05-07
  • 2012-12-02
  • 2011-06-27
  • 2012-01-21
  • 2010-11-26
  • 1970-01-01
  • 1970-01-01
  • 2010-12-16
  • 2013-06-24
相关资源
最近更新 更多