【问题标题】:C++/CLI and GetLastErrorC++/CLI 和 GetLastError
【发布时间】:2015-08-07 08:05:58
【问题描述】:

我在 Visual Studio 2010 中为我的 C++ 库创建了一个 C++ 测试项目。测试项目使用 C++/CLI (/clr set),我在检索我的库函数设置的最后一个错误时遇到问题; GetLastError 总是返回零。

在下面的示例中,我想测试我的 Write 函数是否设置了正确的返回值和最后一个错误:

[TestMethod]
void Write_InvalidHandle_Error()
{
    char buffer[] = "Hello";
    DWORD actual = -1;
    DWORD expected = ERROR_INVALID_HANDLE;
    int actualRetVal = 0;
    int expectedRetVal = -1;
    HANDLE handle = INVALID_HANDLE_VALUE;

    actualRetVal = Write(handle, buffer);
    actual = GetLastError();
    Assert::AreEqual(expectedRetVal, actualRetVal);
    Assert::AreEqual(expected, actual);
}

我检查了我的 Write 函数,它确实设置了正确的返回值和最后一个错误,但在我的测试方法中没有检索到后者。即使我将 Write 函数更改为仅设置错误并返回问题(并且在我的测试方法中调用 GetLastError 之前我没有调用其他函数):

int Write(HANDLE h, const char* buf)
{
    SetLastError(ERROR_INVALID_HANDLE);
    return -1;
}

知道如何解决这个问题吗?我认为 C++/CLI 存在问题,因为当我在此测试场景(纯 C++)之外使用我的库时,GetLastError 有效。

【问题讨论】:

  • 能否提供Write函数的源码?
  • @LukasT 我添加了可能仍然会产生问题的最简单的实现。我认为问题与 C++/CLI 有关,因为我的代码在我不涉及它时(即不运行测试项目)可以工作。
  • 所以归结为在c++-cli环境中调用SetLastError(VAL)而GetLastError返回0的情况?
  • 是的,因为它在不使用测试项目时有效。

标签: visual-c++ c++-cli


【解决方案1】:

跨托管/非托管边界依赖 GetLastError()/SetLastError() 是有问题的。

使用 P/Invoke 和 DllImport attribute 时,您可以(必须)设置 SetLastError 属性以访问托管端的本机错误代码。

但是,当使用 C++/CLI 时,编译器会为您处理所有编组,并且不会显式设置该标志。

您可以在this blog post 中阅读有关它的更多详细信息。它的要点是:

如果您在 C++ 中显式使用 DllImport,则适用与使用相同的规则 C#。但是当您直接从托管 C++ 代码调用非托管 API 时, GetLastError 和 Marshal.GetLastWin32Error 都不会可靠地工作。

Marcus Heege 的“Expert Visual C++/CLI”第 9 章也详细介绍了这一点,is available on Google Books:

如前所述,对于这些本地本地函数,C++/CLI 自动生成不带 lasterror 标志的 P/Invoke 元数据, 因为很少使用 GetLastError 值来 在项目中传达错误代码。然而,MSDN GetLastError 文档允许您使用 SetLastError 和 GetLastError 用于您自己的函数。因此,这种优化可以 理论上会导致错误的 GetLastError 值。

基本上,不要这样做!

我建议使用(本机)C++ 异常在托管代码和非托管代码之间传达错误。 C++/CLI 很好地支持这些。如果您不能直接修改 Write() 函数,您可以在使用 GetLastError() 的非托管端创建一个包装函数,然后在必要时抛出异常。

【讨论】:

  • 我的库在正常使用期间从不与 C++/CLI 接触,只有在我想运行单元测试时才接触,因为这就是 Visual Studio 2010 中的 C++ 测试项目的工作方式。我真的不想改变我图书馆里的任何东西,但至少我知道我现在的选择是什么。谢谢
猜你喜欢
  • 1970-01-01
  • 2013-08-15
  • 2013-02-11
  • 2013-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-20
相关资源
最近更新 更多