private string GetDetails(object error, string message) { if (engine.processDebugManager != null) { try { var syntaxError = false; var scriptError = error as IActiveScriptError; if (scriptError != null) { EXCEPINFO excepInfo; scriptError.GetExceptionInfo(out excepInfo); if (HResult.GetFacility(excepInfo.scode) == HResult.FACILITY_CONTROL) { syntaxError = engine.SyntaxErrorMap.ContainsKey(HResult.GetCode(excepInfo.scode)); } } if (syntaxError) { var details = message; var errorLocation = GetErrorLocation(error); if (!string.IsNullOrWhiteSpace(errorLocation)) { details += "\n" + errorLocation; } var stackTrace = engine.GetStackTraceInternal(); if (!string.IsNullOrWhiteSpace(stackTrace)) { details += "\n" + stackTrace; } return(details); } else { var stackTrace = engine.GetStackTraceInternal(); if (!string.IsNullOrWhiteSpace(stackTrace)) { return(message + "\n" + stackTrace); } var errorLocation = GetErrorLocation(error); if (!string.IsNullOrWhiteSpace(errorLocation)) { return(message + "\n" + errorLocation); } } } catch (Exception exception) { Debug.Assert(false, "Exception caught during error processing", exception.ToString()); } } return(message); }
/// <summary> /// Turns HRESULT errors into the appropriate exception (that maps with existing .NET behavior as much as possible). /// There are additional IOException derived errors for ease of client error handling. /// </summary> public static Exception GetException(this HResult hr, string?path = null) { string message = path == null ? $"{Error.HResultToString(hr)}" : $"{Error.HResultToString(hr)} '{path}'"; return(hr switch { HResult.E_ACCESSDENIED => new UnauthorizedAccessException(message), HResult.E_INVALIDARG => new ArgumentException(message), _ => hr.GetFacility() == Facility.Win32 ? Error.WindowsErrorToException((WindowsError)hr.GetCode(), message, path) : new WInteropIOException(message, hr), });
// /// <summary>Returns <see langword="false"/> if the user cancelled-out of the dialog. Returns <see langword="true"/> if the user completed the dialog. All other cases result in a thrown <see cref="Win32Exception"/> or <see cref="ExternalException"/> depending on the HRESULT returned from <see cref="IModalWindow.Show(IntPtr)"/>.</summary> // public static Boolean ShowDialogOrThrow<TModalWindow>( this IModalWindow dialog, IntPtr parentHWnd ) // where TModalWindow : IModalWindow // { // HResult hresult = dialog.Show( parentHWnd ); // return ShowDialogOrThrow( hresult ); // } // // // Curious - this gives me runtime errors when calling `Show` on `IModalWindow` directly. // public static Boolean ShowDialogOrThrow( this IModalWindow dialog, IntPtr parentHWnd ) // { // HResult hresult = dialog.Show( parentHWnd ); // return ShowDialogOrThrow( hresult ); // } /// <summary>Returns <see langword="false"/> if the user cancelled-out of the dialog. Returns <see langword="true"/> if the user completed the dialog. All other cases result in a thrown <see cref="Win32Exception"/> or <see cref="ExternalException"/> depending on the HRESULT returned from <see cref="IModalWindow.Show(IntPtr)"/>.</summary> public static Boolean ValidateDialogShowHResult(this HResult dialogHResult) { if (dialogHResult.TryGetWin32ErrorCode(out Win32ErrorCodes win32Code)) { if (win32Code == Win32ErrorCodes.Success) { // OK. return(true); } else if (win32Code == Win32ErrorCodes.ErrorCancelled) { // Cancelled return(false); } else { // Other Win32 error: String msg = String.Format(CultureInfo.CurrentCulture, "Unexpected Win32 error code 0x{0:X2} in HRESULT 0x{1:X4} returned from IModalWindow.Show(...).", (Int32)win32Code, (Int32)dialogHResult); throw new Win32Exception(error: (Int32)win32Code, message: msg); } } else if (dialogHResult.IsValidHResult()) { const UInt16 RPC_E_SERVERFAULT = 0x0105; if (dialogHResult.GetFacility() == HResultFacility.Rpc && dialogHResult.GetCode() == RPC_E_SERVERFAULT) { // This error happens when calling `IModalWindow.Show` instead of using the `Show` method on a different interface, like `IFileOpenDialog.Show`. String msg = String.Format(CultureInfo.CurrentCulture, "Unexpected RPC HRESULT: 0x{0:X4} (RPC Error {1:X2}) returned from IModalWindow.Show(...). This particular RPC error suggests the dialog was accessed via the wrong COM interface.", (Int32)dialogHResult, RPC_E_SERVERFAULT); throw new ExternalException(msg, errorCode: (Int32)dialogHResult); } else { // Fall-through to below: } } else { // Fall-through to below: } { // Other HRESULT (non-Win32 error): // https://stackoverflow.com/questions/11158379/how-can-i-throw-an-exception-with-a-certain-hresult String msg = String.Format(CultureInfo.CurrentCulture, "Unexpected HRESULT: 0x{0:X4} returned from IModalWindow.Show(...).", (Int32)dialogHResult); throw new ExternalException(msg, errorCode: (Int32)dialogHResult); } }
/// <summary> /// Turns HRESULT errors into the appropriate exception (that maps with existing .NET behavior as much as possible). /// There are additional IOException derived errors for ease of client error handling. /// </summary> public static Exception GetException(this HResult hr, string path = null) { string message = path == null ? $"{Error.HResultToString(hr)}" : $"{Error.HResultToString(hr)} '{path}'"; switch (hr) { case HResult.E_ACCESSDENIED: return(new UnauthorizedAccessException(message)); case HResult.E_INVALIDARG: return(new ArgumentException(message)); default: return(hr.GetFacility() == Facility.Win32 ? Error.WindowsErrorToException((WindowsError)hr.GetCode(), message, path) : new WInteropIOException(message, hr)); } }
/// <summary> /// Try to get the string for an HRESULT /// </summary> public static string HResultToString(HResult hr) { string message; if (hr.GetFacility() == Facility.Win32) { // Win32 Error, extract the code message = FormatMessage( messageId: (uint)hr.GetCode(), source: IntPtr.Zero, flags: FormatMessageFlags.FromSystem); } else { // Hope that we get a rational IErrorInfo Exception?exception = Marshal.GetExceptionForHR((int)hr); message = exception?.Message ?? "Invalid HRESULT value"; } return(Enum.IsDefined(typeof(HResult), hr) ? $"HRESULT {hr} [0x{(int)hr:X} ({(int)hr:D})]: {message}" : $"HRESULT [0x{(int)hr:X} ({(int)hr:D})]: {message}"); }
private bool TryGetScriptError(Exception exception, out IScriptEngineException scriptError) { // WORKAROUND: Windows Script items often throw ugly exceptions. The code here // attempts to clean up specific cases. while (exception is TargetInvocationException) { exception = exception.InnerException; } scriptError = exception as IScriptEngineException; if (scriptError != null) { return(true); } if (exception is COMException comException) { var result = comException.ErrorCode; if (((result == HResult.SCRIPT_E_REPORTED) || (result == HResult.CLEARSCRIPT_E_HOSTEXCEPTION)) && (engine.CurrentScriptFrame != null)) { scriptError = engine.CurrentScriptFrame.ScriptError ?? engine.CurrentScriptFrame.PendingScriptError; if (scriptError != null) { return(true); } var hostException = engine.CurrentScriptFrame.HostException; if (hostException != null) { scriptError = new ScriptEngineException(engine.Name, hostException.Message, null, HResult.CLEARSCRIPT_E_HOSTEXCEPTION, false, true, null, hostException); return(true); } } else if (HResult.GetFacility(result) == HResult.FACILITY_CONTROL) { // These exceptions often have awful messages that include COM error codes. // The engine itself may be able to provide a better message. if (engine.RuntimeErrorMap.TryGetValue(HResult.GetCode(result), out var runtimeErrorMessage) && (runtimeErrorMessage != exception.Message)) { scriptError = new ScriptEngineException(engine.Name, runtimeErrorMessage, null, HResult.CLEARSCRIPT_E_SCRIPTITEMEXCEPTION, false, false, null, exception.InnerException); return(true); } if (engine.SyntaxErrorMap.TryGetValue(HResult.GetCode(result), out var syntaxErrorMessage) && (syntaxErrorMessage != exception.Message)) { scriptError = new ScriptEngineException(engine.Name, syntaxErrorMessage, null, HResult.CLEARSCRIPT_E_SCRIPTITEMEXCEPTION, false, false, null, exception.InnerException); return(true); } } else if ((result == HResult.DISP_E_MEMBERNOTFOUND) || (result == HResult.DISP_E_UNKNOWNNAME)) { // this usually indicates invalid object or property access in JScript scriptError = new ScriptEngineException(engine.Name, "Invalid object or property access", null, HResult.CLEARSCRIPT_E_SCRIPTITEMEXCEPTION, false, false, null, exception.InnerException); return(true); } } else { if ((exception is ArgumentException argumentException) && (argumentException.ParamName == null)) { // this usually indicates invalid object or property access in VBScript scriptError = new ScriptEngineException(engine.Name, "Invalid object or property access", null, HResult.CLEARSCRIPT_E_SCRIPTITEMEXCEPTION, false, false, null, exception.InnerException); return(true); } } return(false); }