【发布时间】:2013-07-28 21:39:24
【问题描述】:
我测试了很多。但我发现这 2 个没有缺点!
但请参阅接受的答案。
我读到here 在托管代码中调用
GetLastError 是不安全的,因为框架可能在内部“覆盖”最后一个错误。我对GetLastError 从来没有任何明显的问题,而且在我看来,.NET Framework 足够聪明,不会覆盖它。因此,我对该主题有几个问题:
-
[DllImport("kernel32.dll", SetLastError = true)]中的SetLastError属性是否使框架存储错误代码以供Marshal.GetLastWin32Error()使用? - 有没有简单的
GetLastError无法给出正确结果的例子? - 我真的必须使用
Marshal.GetLastWin32Error()吗? - 这个“问题”框架版本是否相关?
public class ForceFailure
{
[DllImport("kernel32.dll")]
static extern uint GetLastError();
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetVolumeLabel(string lpRootPathName, string lpVolumeName);
public static void Main()
{
if (SetVolumeLabel("XYZ:\\", "My Imaginary Drive "))
System.Console.WriteLine("It worked???");
else
{
// the first last error check is fine here:
System.Console.WriteLine(GetLastError());
System.Console.WriteLine(Marshal.GetLastWin32Error());
}
}
}
产生错误:
if (SetVolumeLabel("XYZ:\\", "My Imaginary Drive "))
Console.WriteLine("It worked???");
else
{
// bad programming but ok GetlLastError is overwritten:
Console.WriteLine(Marshal.GetLastWin32Error());
try
{
using (new FileStream("sdsdafsdfsdfs sdsd ", FileMode.Open)) { }
}
catch { }
Console.WriteLine(GetLastError());
}
if (SetVolumeLabel("XYZ:\\", "My Imaginary Drive "))
Console.WriteLine("It worked???");
else
{
// bad programming and Marshal.GetLastWin32Error() is overwritten as well:
Console.WriteLine(GetLastError());
try
{
using (new FileStream("sdsdafsdfsdfs sdsd ", FileMode.Open)) { }
}
catch { }
Console.WriteLine(Marshal.GetLastWin32Error());
}
// turn off concurrent GC
GC.Collect(); // doesn't effect any of the candidates
Console.WriteLine(" -> " + GetLastError());
Console.WriteLine(" -> " + GetLastError());
Console.WriteLine(Marshal.GetLastWin32Error());
Console.WriteLine(Marshal.GetLastWin32Error());
// when you exchange them -> same behaviour just turned around
我看不出有什么不同!除了Marshal.GetLastWin32Error 也存储来自 App->CLR->WinApi 调用的结果和GetLastError 仅存储来自 App->WinApi 调用的结果之外,两者的行为相同。
垃圾收集似乎没有调用任何覆盖最后一个错误代码的 WinApi 函数
- GetLastError 是线程安全的。 SetLastError 为调用它的每个线程存储一个错误代码。
- GC 什么时候会在我的线程中运行?
【问题讨论】:
-
GetLastError有效,它可能适用于所有现有的 .NET Framework 版本和实现。因此,您的代码正在运行,但这并不能证明任何事情。 .NET Framework 开发人员可以随意更改 .NET 实现,GetLastError有一天会停止工作。 -
.NET 开发人员只保证
GetLastWin32Error工作正常。你想使用GetlastErrorhack,它可能总是有效,但这仍然是hack。所以,这个问题有点哲学:如果没有证明,我们可以使用 hacks,它是不正确的。 -
@AlexFarber 那将是一个糟糕的 .NET Framework 版本。我可以想象很多软件都使用简单的 GetLastError 运行,因为程序员还没有听说过 Marshal.GetLastWin32Error 或其他什么。进行您提到的更新会破坏所有这些软件。
-
@AlexFarber 见this。我想确切地知道我是否必须或不必通过现有代码中对 GetLastError 的所有使用。目前还没有证据证明它是不安全的。
-
GetLastError() 是线程安全的,来自 Microsoft 的信息:“最后一个错误代码是在每个线程的基础上维护的。多个线程不会覆盖彼此的最后一个错误代码”。
标签: c# winapi marshalling unmanaged managed