I tested a lot. But I found no disadvantages of those 2!
But see the accepted answer.
I read here that calling
GetLastError
in managed code is unsafe because the Framework might internally "overwrite" the last error. I have never had any noticeable problems with GetLastError
and it seems for me that the .NET Framework is smart enough not to overwrite it. Therefore I have a few questions on that topic:
- in
[DllImport("kernel32.dll", SetLastError = true)]
does theSetLastError
attribute make the Framework store the error code for the use ofMarshal.GetLastWin32Error()
? - is there an example where plain
GetLastError
fails to give the correct result ? - do I really HAVE to use
Marshal.GetLastWin32Error()
? - is this "problem" Framework version related ?
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());
}
}
}
Producing errors:
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
I don't see any difference! Both behave the same except Marshal.GetLastWin32Error
stores results from App->CLR->WinApi calls as well and GetLastError
stores only results from App->WinApi calls.
Garbage Collection seems not to call any WinApi functions overwriting the last error code
- GetLastError is thread-safe. SetLastError stores an error code for each thread calling it.
- since when would GC run in my threads ?
GetLastError
works, possibly it works in all existing .NET Framework versions and implementations. So, your code is working, but this doesn't prove anything. .NET Framework developers are free to change .NET implementation by the way, thatGetLastError
will stop work one day.GetLastWin32Error
works correctly. You want to useGetlastError
hack, possibly it will always work, but this is still hack. So, the question is somewhat philosophical: can we use hacks, if it is not proved, that it is incorrect.