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 不是需要处理此属性的异常之一,因此您应该再次删除它!
我正在使用一个 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 APISetLastError
来设置其错误状态,而您的函数绝对不会这样做。你应该删除它,因为对编组器说谎从来都不是成功的秘诀。SecurityCritical
属性与信任级别之间的进程提升有关。同样,您的应用程序与此无关,应将其删除。- 自 .Net Core(包括 .Net 5)以来,
HandleProcessCorruptedStateExceptions
属性已被弃用。因此,如果您依赖于它,那么您的程序就接近生命周期的尽头,而且您似乎还没有开始编写它。好消息是除以 0 不是需要处理此属性的异常之一,因此您应该再次删除它!