【问题标题】:P/Invoke runtime STD error not redirected to fileP/Invoke 运行时 STD 错误未重定向到文件
【发布时间】:2021-03-18 20:48:33
【问题描述】:

我正在使用一个 C++ DLL,我通过 C# 代码中的 P/Invokes 访问它。问题是我无法将非托管端发生的 std 错误重定向到文件。如果构建处于 DEBUG 中,但当构建处于 RELEASE 中时,STD logfile-unmanaged 不包含错误但包含且不关闭应用程序,它会像没有错误一样继续运行:

Before Error
After Error

在 C++ 中,STD 错误被重定向到如下文件:

extern "C" __declspec(dllexport) void RedirectStd()
{
    int fileNO = _fileno(stderr);
    _close(fileNO);
    int file = _open("logfile-unmanaged", O_CREAT | O_RDWR, 0644);
    _dup2(file, fileNO);
}

C++ 中的运行时错误是这样生成的:

extern "C" __declspec(dllexport) void DoException()
{
    fprintf(stderr, "Before Error\n");
    int a = 0;
    int b = 10 / a;
    fprintf(stderr, "After Error\n");
}

在 C# 中,我调用了这两种方法:

    [DllImport("TestError.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
    internal static extern void RedirectStd();

    [DllImport("TestError.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
    internal static extern void DoException();

我的主要功能:

    [HandleProcessCorruptedStateExceptions]
    [SecurityCritical]
    static void Main(string[] args) {

        Console.WriteLine("===== REDIRECT =====");
        Console.WriteLine("Native/Unmanaged exception redirected to logfile-unmanaged.");
        RedirectStd();
        Console.WriteLine("Native/Unmanaged std error redirected.");
        Console.WriteLine("");

        Console.WriteLine("===== EXCEPTION =====");

        DoException();

        Console.WriteLine("Waiting for program to crash");
        do {

        } while (true);
    }

编辑:

C# 控制台应用程序: 程序.cs

using System;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Security;

namespace ConsoleWithErrors {
    class Program {
        [DllImport("TestError.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
        internal static extern void RedirectStd();

        [DllImport("TestError.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
        internal static extern void DoException();

        [HandleProcessCorruptedStateExceptions]
        [SecurityCritical]
        static void Main(string[] args) {
            RedirectStd();
            DoException();

            Console.WriteLine("Waiting for program to crash");
            do {

            } while (true);
        }
    }
}

控制台应用程序保持打开状态,就像在非托管端没有错误一样。

【问题讨论】:

  • 日志文件的路径是什么?路径名可能无效或无法创建文件。
  • 路径名是相对的,日志文件被创建并且它只打印“Before Error\nAfter Error”。虽然错误应该明显在两条消息之间。
  • 日志文件的时间戳是你运行应用的时间吗?
  • 可能不相关,但为什么在两种 C# 方法中都返回字符串?也应该是无效的。
  • @jdweng 是的,如果我删除文件,它将自动创建。

标签: c# c++ pinvoke


【解决方案1】:

如果构建在 DEBUG 中,这很有效,但是当构建在 RELEASE 时,STD logfile-unmanaged 不包含错误

它可能已优化,因为您不使用除以零的结果。试试这样的:

extern "C" __declspec(dllexport) int DoException()
{
    fprintf(stderr, "Before Error\n");
    int a = 0;
    int b = 10 / a;
    fprintf(stderr, "After Error\n");

    return b;
}

这将使结果脱离内部链接并强制编译器发出代码。

不过,您似乎是 C# P/Invoke 的新手,所以这里有一些提示:

  • SetLastError 属性指示编组器该函数将使用 Win32 API SetLastError 设置其错误状态,而您的函数绝对不会这样做。您应该删除它,因为向编组者撒谎绝不是成功的秘诀。
  • SecurityCritical 属性与信任级别之间的进程提升有关。同样,您的应用程序与此无关,应该被删除。
  • HandleProcessCorruptedStateExceptions 属性自 .Net Core(包括 .Net 5)以来已弃用。因此,如果您依赖它,那么您的程序已接近生命周期的尽头,而且您似乎甚至还没有开始编写它。好消息是除以 0 不是需要处理此属性的异常之一,因此您应该再次删除它!

【讨论】:

  • 非常感谢您的澄清。现在一切正常。
  • 是的,“测试”代码在 C++ 中是出了名的困难,因为优化器非常积极地删除死代码。你很幸运你导出了那个函数,因为如果你在同一个 DLL 中使用它,修复将很快达到荒谬的解决方法 lol
猜你喜欢
  • 2020-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-13
  • 2018-09-12
  • 1970-01-01
相关资源
最近更新 更多