从.NET设置特定的COM HRESULT值

3
我正在创建一个.NET程序集,需要从VB6等环境中调用COM。
大部分功能都正常,我现在在微调错误处理。
我想要做的是为我的异常创建特定的HRESULT值,例如使用如0x88880001等值来处理异常情况。 我想使用一个通用的"前缀"(如0x8888),然后将我的内部错误代码(从十进制1001开始)添加到该编号中。
因此,我的内部错误1001应变成HRESULT = 0x888803E9等等。
我有自己定制的.NET异常类,并且我知道可以在基本的ApplicationException类上设置受保护的HResult属性,但不知为何不能使我的"前缀"加上我的错误代码工作....
使用System;
public class CustomException : ApplicationException
{
    public CustomException(string message, int errorCode) : base(message)
    {
        base.HResult = (uint) 0x88880000 + errorCode;
    }
}

无论我在这里尝试什么 - 我都无法得到一个代表0x888803E9的int值(对于base.HResult,它是一个int),以便将其存储到我的基类中... 我错过了什么?
2个回答

7
C#编译器会对你进行干扰,以防止你触发溢出错误。很多这种类型的代码都无法通过溢出检查,这是你在错误处理代码中不想遇到的意外情况 :) 注意,当选中Project > Properties > Build > Advanced > "Check for arithmetic overflow/underflow"选项时,投票答案中的代码将停止运行。这是一个没有被充分使用的选项。
你需要使用unchecked关键字来抑制此运行时检查:
  base.HResult = unchecked((int)(0x88880000U + errorCode));

或者您可以在编译时抑制它:

  const int ErrorBase = unchecked((int)0x88880000);
  base.HResult = ErrorBase + errorCode;

非常抱歉:您将生成的HRESULT不是有效的代码,它没有正确的设施代码。该代码提供了错误来源的提示。Interop代码应使用0x80040000作为错误基础选择FACILITY_ITF。但不确定是否会因0x88880000而遇到任何问题,您生成的消息字符串最为重要。不幸的是,ISupportErrorInfo往往在客户端代码中被忽略,因此无法保证任何人实际上看到它。


谢谢,看起来这个方法很有效 - 不管项目设置如何! :-) 真不敢相信在 C# 项目中这个设置默认是 关闭 的...... 在 VB 中或许可以,但在 C# 中,真的吗? - marc_s
默认情况下,VB中启用了它。不幸的是,溢出检查非常昂贵,会有很大损失。 - Hans Passant

2
base.HResult = (int)((uint)0x88880000 + errorCode);

base.HResult是一个System.Int32。

然而,您的数字比Int32大,因此会发生溢出。不确定您需要什么以及是否可以使用checked

但是,这似乎没问题:

void Main()
{
    var ce = new CustomException("uh oh", 1001);
    Console.WriteLine(ce.HResult);
    // Convert integer as a hex in a string variable
    string hexValue = ce.HResult.ToString("X");
    // Convert the hex string back to the number
    int decAgain = int.Parse(hexValue, System.Globalization.NumberStyles.HexNumber);        
    Console.WriteLine(hexValue);
    Console.WriteLine(decAgain);
}


public class CustomException : Exception
{
    public CustomException(string message, int errorCode) : base(message)
    {
        base.HResult = (int)((uint)0x88880000 + errorCode);
    }
}

最佳实践是所有异常都应该继承自Exception类。

你尝试过这段代码吗?它会在(int)((uint)0x88880000 + errorCode)处抛出一个 OverflowException异常。 - acelent
可能你正在使用由@Hans Passant描述的设置在VS中,但不是在LINQPad中。 - jacoblambert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接