如何在 C# 程序中使用标准 Windows 定义

Posted

技术标签:

【中文标题】如何在 C# 程序中使用标准 Windows 定义【英文标题】:How to use the standard Windows defines in a C# program 【发布时间】:2015-09-15 10:52:02 【问题描述】:

在 C# 程序中,我实现了以下功能:

int Test();

在程序(用 C++ 编写)的本机部分中定义如下:

HRESULT Test();

或者可能:

DWORD Test();

因此,在实现功能时,我需要从 C# 部分返回 HRESULT 和其他标准 Windows 代码。目前我已经实现如下:

public int Test()

  return 0x00000102; // WAIT_TIMEOUT

问题是如何在 C# 中使用人类可读的代码?我想写类似:return WAIT_TIMEOUT; 的东西,就像我在 C++ 中写的一样。

我正在寻找一种不需要下载外部库或类似内容的解决方案。仅标准 .NET。

顺便说一句,WAIT_TIMEOUT 不是HRESULT,但我希望你能理解这个问题——问题不是关于特殊情况,而是关于标准 Windows 常量。我只是想使用 C# 中的标准 Windows 定义(E_NOTIMPLWAIT_OBJECT_0S_FALSE 等)

【问题讨论】:

使用枚举或常量。 C++函数HRESULT Test一般对应C#void Test,有一个例外。它确实取决于指定的合同,但在没有其他文档的情况下,C++ 方面的合同是失败是由否定的HRESULT 传达的。而在 C# 中,该失败是通过异常传达的。 @thefiloe,我很高兴使用它们,但我在 C# 中找不到它们。我应该手动定义每个常量吗?我认为微软已经为 .NET 完成了这项工作。 我稍微修改了这个问题。我正在尝试找到一种方法(适用于这两种情况)来使用 PSDK 标头中已经存在的所有这些定义。在 C# 中可以吗? @Cheers: S_FALSE 使用频率很高。所有IEnumXxx 接口(如IEnumString)都将其用作哨兵,报告已到达受控序列的末尾(例如,参见IEnumString::Next)。 【参考方案1】:
   return 0x00000102; // WAIT_TIMEOUT

您需要从修复代码开始,这不是正确的 HRESULT。它们设置了高位以指示遇到错误情况。现在,您的 C++ 代码将假定您的 C# 方法没有失败,通常使用 SUCCEEDED() 或 FAILED() 宏来完成。

查看 WinError.h SDK 包含文件。它记录了 HRESULT 的结构,并定义了众所周知的 winapi 错误代码和 HRESULT。它还定义了 HRESULT_FROM_WIN32(),这是一个帮助宏,将 win32 错误代码打包到适当的 HRESULT 中。

您可以在 C# 代码中执行相同的操作,如下所示:

static class Win32Interop  
    const int WAIT_TIMEOUT = 0x102;

    static void ThrowWin32Error(int err) 
        unchecked 
            int hr = (int)0x80070000 + err;
            System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(hr);
        
    

现在你可以写了:

public void test() 
    ThrowWin32Error(WAIT_TIMEOUT);

以这种看似复杂的方式执行此操作可确保异常具有合理的描述性 Message 属性,并且您可以在 C++ 代码中提供比明显的 HRESULT 值更丰富的错误信息。使用 IErrorInfo 接口来执行此操作。另请注意,许多内置的 .NET 异常已经具有正确的 HResult 值。所以简单地抛出那个异常就足够了。要发现并不容易,您必须查看参考源。

请记住,使用不是由 win32 函数实际生成的 Win32 错误代码是非常具有误导性的。任何试图诊断 0x80070102 的人总是会寻找失败的操作系统调用。如果您的 C# 代码没有,那么就会出现非常严重的令人头疼的问题。因此,我建议您这样做:

public void test() 
    throw new TimeoutException();

这会在您的 C++ 代码中产生 COR_E_TIMEOUT (0x80131505)。调用 C# 代码时无论如何都需要熟悉的 HRESULT 类型。这些错误代码在 CorError.h SDK 包含文件中定义。

【讨论】:

注意HRESULT 值无效。 "WinError.h":我看它的方式是在Visual Studio中输入“#include ”,右键单击标题名称,然后打开标题。这可以以更简单的方式完成吗?我认为,键入“#include”部分不应该是必要的 看起来不错。尝试了System.ComponentModel.Win32Exception(WAIT_TIMEOUT),结果在 C++ 代码中得到了 E_FAIL。我做错了什么? @KirillV.Lyadvinsky:你是从 C++ 调用 C# 函数吗?如果是,究竟是如何调用的? [顺便说一句。抱歉,我已经删除了我之前对您问题的评论。这显然是基于错误的印象。] 据我了解,没有包含为标准 PSDK 宏定义的常量的标准 .NET 类?【参考方案2】:

选项 1:

使用枚举。您可以在这里找到一些错误代码:Common HRESULT values。

选项 2:

使用VSConstants 类,错误代码已经在那里定义为 int 常量。

选项 3:

为了更符合 .NET,您的公共 C# 方法应该抛出类似 .NET 的异常,而不是使用错误代码。为此,您可以使用Marshal.ThrowExceptionForHR(int) 方法,也可以根据this 页面进行一些映射。

【讨论】:

【参考方案3】:

我认为您正在寻找WinAPI defines for C#。不确定这是否足够,但总的来说,这个网站还有一些其他的定义和类似 C# 的东西。

【讨论】:

我在那里只看到 Window 消息常量,没有看到 HRESULT 名称? 在那里找不到WAIT_TIMEOUT 抱歉,因为推广最糟糕的互操作网站而不得不投反对票。 pinvoke.net 通常是错误的。当您让 .NET 开发人员尝试围绕诸如对齐约束之类的世俗概念进行思考时,您就会得到这样的结果。不要使用 pinvoke.net。不要宣传 pinvoke.net。并且不要在 *** 上提供仅链接的答案。

以上是关于如何在 C# 程序中使用标准 Windows 定义的主要内容,如果未能解决你的问题,请参考以下文章

如何在 WPF C# GUI 中使用跨平台 C++

如何在 C# 中以编程方式安装 Windows 服务?

如何从 C++ 后台任务(Windows 通用应用程序)调用 C# 函数?

c# winform程序,我定义一个类,一个窗体,如何在类中访问一个窗体的控件。

C# WinForm自定义进度条

如何在 VS 2013 中使用 c# 在 Windows 窗体应用程序中插入数据?