P/Invoke 运行时 STD 错误未重定向到文件

P/Invoke runtime STD error not redirected to file

我正在使用一个 C++ DLL,我使用 P/Invokes 从 C# 代码访问它。问题是我无法将非托管端发生的标准错误重定向到文件。如果构建处于 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# 控制台应用程序: program.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);
        }
    }
}

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

This works well if the build is in DEBUG but when the build is in RELEASE the STD logfile-unmanaged does not contain the error

它可能被优化掉了,因为你没有使用被零除的结果。尝试这样的事情:

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 属性与信任级别之间的进程提升有关。同样,您的应用程序与此无关,应将其删除。
  • 自 .Net Core(包括 .Net 5)以来,HandleProcessCorruptedStateExceptions 属性已被弃用。因此,如果您依赖于它,那么您的程序就接近生命周期的尽头,而且您似乎还没有开始编写它。好消息是除以 0 不是需要处理此属性的异常之一,因此您应该再次删除它!