Я много тестировал. Но я не нашел недостатков этих двух! Но см. Принятый ответ.
Я читаю здесь, что вызов
GetLastError
в управляемом коде небезопасен, потому что Framework может внутренне "перезаписать" последнюю ошибку. У меня никогда не было заметных проблем с GetLastError
, и мне кажется, что .NET Framework достаточно умен, чтобы не перезаписывать его. Поэтому у меня есть несколько вопросов по этой теме:
- в
[DllImport("kernel32.dll", SetLastError = true)]
ли атрибутSetLastError
делает Framework хранилищем код ошибки для использованияMarshal.GetLastWin32Error()
? - Есть ли пример, когда plain
GetLastError
не дает правильный результат? - Я использую реально использовать
Marshal.GetLastWin32Error()
? - является ли эта "проблема" связана с версией Framework?
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 запускается в моих потоках?