Hello,
How do I call WSAGetLastError() from WinAPI so I get the valid text error?
Hello,
How do I call WSAGetLastError() from WinAPI so I get the valid text error?
It doesn't make very much sense to call that function from managed code. It makes sense in unmanaged code because you know the exact last Win32 function that was called, so you know what function must have set the last error. In managed code, you don't know what functions have been called.
You could probably use P/Invoke to call the function; it just wouldn't do you any good. What are you trying to accomplish?
WSAGetLastError
is just a wrapper for the Win32 GetLastError
function.
If you're doing things with P/Invoke, you can use the SetLastError
parameter to the DllImport
attribute. It tells .NET that the imported function will call SetLastError()
, and that the value should be collected.
If the imported function fails, you can get at the last error with Marshal.GetLastWin32Error()
. Alternatively, you can just throw new Win32Exception()
, which uses this value automatically.
If you're not doing things with P/Invoke, you're out of luck: there's no guarantee that the last error value will be preserved long enough to make it back through multiple layers of .NET code. In fact, I'll link to Adam Nathan: never define a PInvoke signature for GetLastError.
[DllImport("ws2_32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern Int32 WSAGetLastError();
Also, on pinvoke.net it's said:
You should never PInvoke to GetLastError. Call Marshal.GetLastWin32Error instead!
// This is how I saw on the web to put GetLastError into the C# exception mechanism // and how to get it back out again...
try
{
// some p/invoke call that is going to fail with a windows error ...
mHndActivatedDevice = MyNameSpace.Interop.Device.Device.ActivateDevice(
"Drivers\\BuiltIn\\SomeDriverName", IntPtr.Zero, 0, IntPtr.Zero);
}
catch(System.ComponentModel.Win32Exception exc) // as suggested by John Saunders
{
// you can get the last error like this:
int lastError = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
Console.WriteLine("error:" + lastError.ToString());
// but it is also inside the exception, you can get it like this
Console.WriteLine(exc.NativeErrorCode.ToString());
Console.WriteLine(exc.ToString());
}
// where ActivateDevice is defined thus:
namespace MyNameSpace.Interop.Device { using System; using System.Runtime.InteropServices; using System.ComponentModel;
sealed class Device
{
public static IntPtr ActivateDevice(String lpszDevKey, IntPtr lpRegEnts, UInt32 cRegEnts, IntPtr lpvParam)
{
// this is a little wrapper around the p/invoke to
// ActivateDeviceEx which checks the error
// and throws an exception, thus C#-ifying the Win32 API call.
IntPtr hndDriver = ActivateDeviceEx(lpszDevKey, lpRegEnts, cRegEnts, lpvParam);
if (IntPtr.Zero == hndDriver)
{
Int32 err = Marshal.GetLastWin32Error();
throw new Win32Exception(err);
}
return hndDriver;
}
[DllImport("Coredll.dll", EntryPoint = "ActivateDeviceEx",
SetLastError = true, CharSet = CharSet.Unicode)]
private static extern IntPtr ActivateDeviceEx(String lpszDevKey,
IntPtr lpRegEnts, UInt32 cRegEnts, IntPtr lpvParam);
private Device() { }
}
}