N
TL;DRMaybe someone's been dealing with this? It's not a big problem, because you can check the window back, but I'd like to know what's going on.First, we need to check that the method has returned, and only then if the result according to the documentation contains the meaning of the error, is to cause the error. GetLastError♪ This is how Win32 API mistakes are handled. In all other cases the result of the challenge GetLastError You can't take it out.The point GetLastError That he's returning the code of the last mistake in the current flow. Why do you have the status of the error after the challenge of the method - only the Maycroft knows. There's got to be 0, and I haven't been able to reproduce your problem.But my answer is different. Win32 is only worth processing when the atribut method DllImportAttribute.SetLastError == true returned the status corresponding to the error.If you want a specific MessageBox, according to https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox ♪If the function fails, the return value is zero. To get extended error information, call https://docs.microsoft.com/en-us/windows/desktop/api/errhandlingapi/nf-errhandlingapi-getlasterror ♪The mistake should be dealt with only when he returned. 0♪How do you manage Win32's mistake?The complexity of this story is that Win32 API was written by different people in different Windows versions at different times. And the code writing standards, despite the very serious approach of Microsoft, were different. In addition, different methods return different types of data.It, therefore, would have to be sweated to arrive at a universal approach. The intent of the proposed decision is to catch a status where GetLastErrorand if the code corresponds to the error indicator, leave a normal exception containing the code and the text of the error.The decision is divided into two parts.Part 1. Attribute holding status - error indicator[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
sealed class Win32ErrorStatusAttribute : Attribute
{
public object ErrorStatus { get; }
public Win32ErrorStatusAttribute(object errorStatus)
=> ErrorStatus = errorStatus;
}
It's just here, taking something transferred to the designer and putting it our way. ErrorStatus♪You can use the attribute like that.internal class Win32
{
[Win32ErrorStatus(0)]
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern int MessageBox(IntPtr hwnd, string text, string caption, uint type);
}
I mean, we'll throw an exception if the method is zero.Part 2. Status and exclusion processingThe method that accepts the expression converted to the delegate reads the value from the attribution, compares the status returned to the attribute. If it matches, it leaves. https://docs.microsoft.com/ru-ru/dotnet/api/system.componentmodel.win32exception?view=net-5.0 ♪public static T ThrowIfWin32Error<T>(Expression<Func<T>> exp) where T : unmanaged
{
Win32ErrorStatusAttribute att = (exp.Body as MethodCallExpression).Method.GetCustomAttribute<Win32ErrorStatusAttribute>();
Func<T> func = exp.Compile();
T result = func();
if (att == null || typeof(T) != att.ErrorStatus.GetType() || !result.Equals(att.ErrorStatus))
return result;
throw new Win32Exception(Marshal.GetLastWin32Error());
}
Use of the decisionenum MessageBoxResult // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox#return-value
{
IDABORT = 3, // The Abort button was selected.
IDCANCEL = 2, // The Cancel button was selected.
IDCONTINUE = 11, // The Continue button was selected.
IDIGNORE = 5, // The Ignore button was selected.
IDNO = 7, // The No button was selected.
IDOK = 1, // The OK button was selected.
IDRETRY = 4, // The Retry button was selected.
IDTRYAGAIN = 10, // The Try Again button was selected.
IDYES = 6 // The Yes button was selected.
}
static void Main(string[] args)
{
try
{
Console.WriteLine("Calling Win32 MessageBox without error...");
int result = ThrowIfWin32Error(() => Win32.MessageBox(new IntPtr(0), "Press OK...", "Press OK Dialog", 0));
Console.WriteLine((MessageBoxResult)result);
Console.WriteLine("Calling Win32 MessageBox with error...");
result = ThrowIfWin32Error(() => Win32.MessageBox(new IntPtr(123132), "Press OK...", "Press OK Dialog", 0));
Console.WriteLine((MessageBoxResult)result);
}
catch (Win32Exception ex)
{
Console.WriteLine($"[{ex.NativeErrorCode}] {ex.Message}");
}
Console.ReadKey();
}
ConclusionCalling Win32 MessageBox without error...
IDOK
Calling Win32 MessageBox with error...
[1400] Invalid window handle.
I mean, as a result, the similar behaviour to that of the NET is an exception in case of error.There might be a problem here, or I haven't learned anything. Strongly along and across, I didn't test the code. I just wanted to explain how Windows mistakes can be handled without threatening the code.