diff --git a/src/Authoring/WinRT.Host/WinRT.Host.vcxproj b/src/Authoring/WinRT.Host/WinRT.Host.vcxproj index 2dd3c14d0..94fcb4c7e 100644 --- a/src/Authoring/WinRT.Host/WinRT.Host.vcxproj +++ b/src/Authoring/WinRT.Host/WinRT.Host.vcxproj @@ -1,298 +1,298 @@ - - - - - - Debug - ARM64 - - - Debug - Win32 - - - Release - ARM64 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 16.0 - Win32Proj - {7e33bcb7-19c5-4061-981d-ba695322708a} - WinRTHost - - - - DynamicLibrary - v143 - v142 - Unicode - - - true - - - false - true - - - true - - - true - - - false - true - - - false - true - - - - - - - - - - - - - - - - - - - - - - - - - - - false - WinRT.Host - - - false - WinRT.Host - - - false - WinRT.Host - - - false - WinRT.Host - - - false - WinRT.Host - - - false - WinRT.Host - - - - Level3 - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - MultiThreaded - - - Windows - true - false - module.def - libcpmt.lib;advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies);WindowsApp.lib - /ignore:4099 %(AdditionalOptions) - false - libcpmtd.lib - UseLinkTimeCodeGeneration - - - - - Level3 - true - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - MultiThreaded - - - Windows - true - true - true - false - module.def - advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies);WindowsApp.lib - /ignore:4099 %(AdditionalOptions) - false - UseLinkTimeCodeGeneration - - - - - Level3 - true - NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - MultiThreaded - ProgramDatabase - - - Windows - true - false - module.def - libcpmt.lib;advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies);WindowsApp.lib - /ignore:4099 %(AdditionalOptions) - false - libcpmtd.lib - UseLinkTimeCodeGeneration - - - - - Level3 - true - NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - MultiThreaded - ProgramDatabase - - - Windows - true - false - module.def - libcpmt.lib;advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies);WindowsApp.lib - /ignore:4099 %(AdditionalOptions) - false - libcpmtd.lib - UseLinkTimeCodeGeneration - - - - - Level3 - true - true - true - NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - MultiThreaded - - - Windows - true - true - true - false - module.def - advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies);WindowsApp.lib - /ignore:4099 %(AdditionalOptions) - false - UseLinkTimeCodeGeneration - - - - - Level3 - true - true - true - NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - MultiThreaded - - - Windows - true - true - true - false - module.def - advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies);WindowsApp.lib - /ignore:4099 %(AdditionalOptions) - false - UseLinkTimeCodeGeneration - - - - - - /GL- %(AdditionalOptions) - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - - - - - - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - + + + + + + Debug + ARM64 + + + Debug + Win32 + + + Release + ARM64 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {7e33bcb7-19c5-4061-981d-ba695322708a} + WinRTHost + + + + DynamicLibrary + v143 + v142 + Unicode + + + true + + + false + true + + + true + + + true + + + false + true + + + false + true + + + + + + + + + + + + + + + + + + + + + + + + + + + false + WinRT.Host + + + false + WinRT.Host + + + false + WinRT.Host + + + false + WinRT.Host + + + false + WinRT.Host + + + false + WinRT.Host + + + + Level3 + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + MultiThreaded + + + Windows + true + false + module.def + libcpmt.lib;advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies);WindowsApp.lib + /ignore:4099 %(AdditionalOptions) + false + libcpmtd.lib + UseLinkTimeCodeGeneration + + + + + Level3 + true + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + MultiThreaded + + + Windows + true + true + true + false + module.def + advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies);WindowsApp.lib + /ignore:4099 %(AdditionalOptions) + false + UseLinkTimeCodeGeneration + + + + + Level3 + true + NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + MultiThreaded + ProgramDatabase + + + Windows + true + false + module.def + libcpmt.lib;advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies);WindowsApp.lib + /ignore:4099 %(AdditionalOptions) + false + libcpmtd.lib + UseLinkTimeCodeGeneration + + + + + Level3 + true + NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + MultiThreaded + ProgramDatabase + + + Windows + true + false + module.def + libcpmt.lib;advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies);WindowsApp.lib + /ignore:4099 %(AdditionalOptions) + false + libcpmtd.lib + UseLinkTimeCodeGeneration + + + + + Level3 + true + true + true + NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + MultiThreaded + + + Windows + true + true + true + false + module.def + advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies);WindowsApp.lib + /ignore:4099 %(AdditionalOptions) + false + UseLinkTimeCodeGeneration + + + + + Level3 + true + true + true + NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + MultiThreaded + + + Windows + true + true + true + false + module.def + advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies);WindowsApp.lib + /ignore:4099 %(AdditionalOptions) + false + UseLinkTimeCodeGeneration + + + + + + /GL- %(AdditionalOptions) + + + + + + + + + + + Create + Create + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj.filters b/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj.filters index 0320e9389..44172eb24 100644 --- a/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj.filters +++ b/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj.filters @@ -1,39 +1,39 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - - - Source Files - - - Source Files - - - - - - - - - - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + + + Source Files + + + Source Files + + + + + + + + + + + \ No newline at end of file diff --git a/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.cpp b/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.cpp index 24b0763cc..ae5bad157 100644 --- a/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.cpp +++ b/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.cpp @@ -34,6 +34,8 @@ namespace winrt::TestComponentCSharp::implementation void CustomDisposableTest::Close() { + // Leaving in for testing purposes + // throw winrt::hresult_access_denied(); } CustomBindableVectorTest::CustomBindableVectorTest() diff --git a/src/Tests/TestComponentCSharp/TestComponentCSharp.vcxproj b/src/Tests/TestComponentCSharp/TestComponentCSharp.vcxproj index 0cf3eaf6b..b6cf53385 100644 --- a/src/Tests/TestComponentCSharp/TestComponentCSharp.vcxproj +++ b/src/Tests/TestComponentCSharp/TestComponentCSharp.vcxproj @@ -1,151 +1,151 @@ - - - - - - - high - true - true - true - {7e3a9ab3-8cbb-4b9c-ba76-0fe7108dcaeb} - TestComponentCSharp - TestComponentCSharp - en-US - true - Windows Store - 10.0 - - - - - Debug - ARM64 - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM64 - - - Release - Win32 - - - Release - x64 - - - - DynamicLibrary - Unicode - false - - - true - - - - - - - - - - - - - Console - TestComponentCSharp.def - TestComponentCSharp.def - TestComponentCSharp.def - TestComponentCSharp.def - TestComponentCSharp.def - TestComponentCSharp.def - - - MultiThreadedDLL - - - MultiThreadedDLL - MultiThreadedDLL - - - - - - - - - - - - - TestComponentCSharp.idl - - - - - - - - - - - - - - - - - - - - Create - - - TestComponentCSharp.idl - - - - - - - - - - - - - - - - - - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - - + + + + + + + high + true + true + true + {7e3a9ab3-8cbb-4b9c-ba76-0fe7108dcaeb} + TestComponentCSharp + TestComponentCSharp + en-US + true + Windows Store + 10.0 + + + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + DynamicLibrary + Unicode + false + + + true + + + + + + + + + + + + + Console + TestComponentCSharp.def + TestComponentCSharp.def + TestComponentCSharp.def + TestComponentCSharp.def + TestComponentCSharp.def + TestComponentCSharp.def + + + MultiThreadedDLL + + + MultiThreadedDLL + MultiThreadedDLL + + + + + + + + + + + + + TestComponentCSharp.idl + + + + + + + + + + + + + + + + + + + + Create + + + TestComponentCSharp.idl + + + + + + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + \ No newline at end of file diff --git a/src/WinRT.Runtime/IInspectable.net5.cs b/src/WinRT.Runtime/IInspectable.net5.cs index c059dcf78..ad3eae9ab 100644 --- a/src/WinRT.Runtime/IInspectable.net5.cs +++ b/src/WinRT.Runtime/IInspectable.net5.cs @@ -15,21 +15,21 @@ partial class IInspectable : IWinRTObject { IObjectReference IWinRTObject.NativeObject => _obj; bool IWinRTObject.HasUnwrappableNativeObject => true; - + private volatile ConcurrentDictionary _queryInterfaceCache; private ConcurrentDictionary MakeQueryInterfaceCache() { - System.Threading.Interlocked.CompareExchange(ref _queryInterfaceCache, new ConcurrentDictionary(), null); + System.Threading.Interlocked.CompareExchange(ref _queryInterfaceCache, new ConcurrentDictionary(), null); return _queryInterfaceCache; } ConcurrentDictionary IWinRTObject.QueryInterfaceCache => _queryInterfaceCache ?? MakeQueryInterfaceCache(); private volatile ConcurrentDictionary _additionalTypeData; private ConcurrentDictionary MakeAdditionalTypeData() { - System.Threading.Interlocked.CompareExchange(ref _additionalTypeData, new ConcurrentDictionary(), null); + System.Threading.Interlocked.CompareExchange(ref _additionalTypeData, new ConcurrentDictionary(), null); return _additionalTypeData; } ConcurrentDictionary IWinRTObject.AdditionalTypeData => _additionalTypeData ?? MakeAdditionalTypeData(); } -} +} \ No newline at end of file diff --git a/src/WinRT.Runtime2/ABI/System/Exception.cs b/src/WinRT.Runtime2/ABI/System/Exception.cs index 44cb7da66..40bdf4327 100644 --- a/src/WinRT.Runtime2/ABI/System/Exception.cs +++ b/src/WinRT.Runtime2/ABI/System/Exception.cs @@ -70,7 +70,7 @@ public static Exception ConvertToUnmanaged(global::System.Exception? value) /// The managed value public static global::System.Exception? ConvertToManaged(Exception value) { - return RestrictedErrorInfo.GetExceptionForHR(value.Value); + return RestrictedErrorInfo.GetExceptionForHR(value.Value, out _); } } diff --git a/src/WinRT.Runtime2/Exceptions/Microsoft.UI.Xaml/ElementNotAvailableException.cs b/src/WinRT.Runtime2/Exceptions/Microsoft.UI.Xaml/ElementNotAvailableException.cs new file mode 100644 index 000000000..0e3f2eab6 --- /dev/null +++ b/src/WinRT.Runtime2/Exceptions/Microsoft.UI.Xaml/ElementNotAvailableException.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using WindowsRuntime.InteropServices; + +namespace Microsoft.UI.Xaml; + +/// +/// Represents an exception that occurs when an element is not available. +/// +/// +/// Sets to +/// to enable consistent interop/error mapping. +/// +internal sealed class ElementNotAvailableException : Exception +{ + /// + /// Initializes a new instance of the class + /// with a default error message indicating the element is not available. + /// + public ElementNotAvailableException() + : base("The element is not available.") + { + HResult = WellKnownErrorCodes.E_ELEMENTNOTAVAILABLE; + } + + /// + /// Initializes a new instance of the class + /// with a specified error message. + /// + /// The error message that explains the reason for the exception. + public ElementNotAvailableException(string message) + : base(message) + { + HResult = WellKnownErrorCodes.E_ELEMENTNOTAVAILABLE; + } +} diff --git a/src/WinRT.Runtime2/Exceptions/Microsoft.UI.Xaml/ElementNotEnabledException.cs b/src/WinRT.Runtime2/Exceptions/Microsoft.UI.Xaml/ElementNotEnabledException.cs new file mode 100644 index 000000000..55d3ec33f --- /dev/null +++ b/src/WinRT.Runtime2/Exceptions/Microsoft.UI.Xaml/ElementNotEnabledException.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using WindowsRuntime.InteropServices; + +namespace Microsoft.UI.Xaml; + +/// +/// Represents an exception that occurs when an element is not enabled. +/// +/// +/// Sets to +/// to enable consistent interop/error mapping. +/// +internal sealed class ElementNotEnabledException : Exception +{ + /// + /// Initializes a new instance of the class + /// with a default error message indicating the element is not enabled. + /// + public ElementNotEnabledException() + : base("The element is not enabled.") + { + HResult = WellKnownErrorCodes.E_ELEMENTNOTENABLED; + } + + /// + /// Initializes a new instance of the class + /// with a specified error message. + /// + /// The error message that explains the reason for the exception. + public ElementNotEnabledException(string message) + : base(message) + { + HResult = WellKnownErrorCodes.E_ELEMENTNOTENABLED; + } +} diff --git a/src/WinRT.Runtime2/Exceptions/Microsoft.UI.Xaml/LayoutCycleException.cs b/src/WinRT.Runtime2/Exceptions/Microsoft.UI.Xaml/LayoutCycleException.cs new file mode 100644 index 000000000..cfd0b7212 --- /dev/null +++ b/src/WinRT.Runtime2/Exceptions/Microsoft.UI.Xaml/LayoutCycleException.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using WindowsRuntime.InteropServices; + +namespace Microsoft.UI.Xaml; + +/// +/// Represents an exception that occurs when a layout cycle is detected during GUI layout. +/// +/// +/// Sets to +/// to enable consistent interop/error mapping. +/// +internal sealed class LayoutCycleException : Exception +{ + /// + /// Initializes a new instance of the class + /// with a default error message indicating a layout cycle occurred. + /// + public LayoutCycleException() + : base("A cycle occurred while laying out the GUI.") + { + HResult = WellKnownErrorCodes.E_LAYOUTCYCLE; + } + + /// + /// Initializes a new instance of the class + /// with a specified error message. + /// + /// The error message that explains the reason for the exception. + public LayoutCycleException(string message) + : base(message) + { + HResult = WellKnownErrorCodes.E_LAYOUTCYCLE; + } +} diff --git a/src/WinRT.Runtime2/Exceptions/Microsoft.UI.Xaml/XamlParseException.cs b/src/WinRT.Runtime2/Exceptions/Microsoft.UI.Xaml/XamlParseException.cs new file mode 100644 index 000000000..cee4a3965 --- /dev/null +++ b/src/WinRT.Runtime2/Exceptions/Microsoft.UI.Xaml/XamlParseException.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using WindowsRuntime.InteropServices; + +namespace Microsoft.UI.Xaml; + +/// +/// Represents an exception that occurs when XAML parsing fails. +/// +/// +/// Sets to +/// to enable consistent interop/error mapping. +/// +internal sealed class XamlParseException : Exception +{ + /// + /// Initializes a new instance of the class + /// with a default error message indicating XAML parsing failure. + /// + public XamlParseException() + : base("XAML parsing failed.") + { + HResult = WellKnownErrorCodes.E_XAMLPARSEFAILED; + } + + /// + /// Initializes a new instance of the class + /// with a specified error message. + /// + /// The error message that explains the reason for the exception. + public XamlParseException(string message) + : base(message) + { + HResult = WellKnownErrorCodes.E_XAMLPARSEFAILED; + } +} diff --git a/src/WinRT.Runtime2/Exceptions/Windows.UI.Xaml/ElementNotAvailableException.cs b/src/WinRT.Runtime2/Exceptions/Windows.UI.Xaml/ElementNotAvailableException.cs new file mode 100644 index 000000000..4ada8bce8 --- /dev/null +++ b/src/WinRT.Runtime2/Exceptions/Windows.UI.Xaml/ElementNotAvailableException.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using WindowsRuntime.InteropServices; + +namespace Windows.UI.Xaml; + +/// +/// Represents an exception that occurs when an element is not available. +/// +/// +/// Sets to +/// to enable consistent interop/error mapping. +/// +internal sealed class ElementNotAvailableException : Exception +{ + /// + /// Initializes a new instance of the class + /// with a default error message indicating the element is not available. + /// + public ElementNotAvailableException() + : base("The element is not available.") + { + HResult = WellKnownErrorCodes.E_ELEMENTNOTAVAILABLE; + } + + /// + /// Initializes a new instance of the class + /// with a specified error message. + /// + /// The error message that explains the reason for the exception. + public ElementNotAvailableException(string message) + : base(message) + { + HResult = WellKnownErrorCodes.E_ELEMENTNOTAVAILABLE; + } +} diff --git a/src/WinRT.Runtime2/Exceptions/Windows.UI.Xaml/ElementNotEnabledException.cs b/src/WinRT.Runtime2/Exceptions/Windows.UI.Xaml/ElementNotEnabledException.cs new file mode 100644 index 000000000..926ebae7d --- /dev/null +++ b/src/WinRT.Runtime2/Exceptions/Windows.UI.Xaml/ElementNotEnabledException.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using WindowsRuntime.InteropServices; + +namespace Windows.UI.Xaml; + +/// +/// Represents an exception that occurs when an element is not enabled. +/// +/// +/// Sets to +/// to enable consistent interop/error mapping. +/// +internal sealed class ElementNotEnabledException : Exception +{ + /// + /// Initializes a new instance of the class + /// with a default error message indicating the element is not enabled. + /// + public ElementNotEnabledException() + : base("The element is not enabled.") + { + HResult = WellKnownErrorCodes.E_ELEMENTNOTENABLED; + } + + /// + /// Initializes a new instance of the class + /// with a specified error message. + /// + /// The error message that explains the reason for the exception. + public ElementNotEnabledException(string message) + : base(message) + { + HResult = WellKnownErrorCodes.E_ELEMENTNOTENABLED; + } +} diff --git a/src/WinRT.Runtime2/Exceptions/Windows.UI.Xaml/LayoutCycleException.cs b/src/WinRT.Runtime2/Exceptions/Windows.UI.Xaml/LayoutCycleException.cs new file mode 100644 index 000000000..972fe3ec6 --- /dev/null +++ b/src/WinRT.Runtime2/Exceptions/Windows.UI.Xaml/LayoutCycleException.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using WindowsRuntime.InteropServices; + +namespace Windows.UI.Xaml; + +/// +/// Represents an exception that occurs when a layout cycle is detected during GUI layout. +/// +/// +/// Sets to +/// to enable consistent interop/error mapping. +/// +internal sealed class LayoutCycleException : Exception +{ + /// + /// Initializes a new instance of the class + /// with a default error message indicating a layout cycle occurred. + /// + public LayoutCycleException() + : base("A cycle occurred while laying out the GUI.") + { + HResult = WellKnownErrorCodes.E_LAYOUTCYCLE; + } + + /// + /// Initializes a new instance of the class + /// with a specified error message. + /// + /// The error message that explains the reason for the exception. + public LayoutCycleException(string message) + : base(message) + { + HResult = WellKnownErrorCodes.E_LAYOUTCYCLE; + } +} diff --git a/src/WinRT.Runtime2/Exceptions/Windows.UI.Xaml/XamlParseException.cs b/src/WinRT.Runtime2/Exceptions/Windows.UI.Xaml/XamlParseException.cs new file mode 100644 index 000000000..563df2906 --- /dev/null +++ b/src/WinRT.Runtime2/Exceptions/Windows.UI.Xaml/XamlParseException.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using WindowsRuntime.InteropServices; + +namespace Windows.UI.Xaml; + +/// +/// Represents an exception that occurs when XAML parsing fails. +/// +/// +/// Sets to +/// to enable consistent interop/error mapping. +/// +internal sealed class XamlParseException : Exception +{ + /// + /// Initializes a new instance of the class + /// with a default error message indicating XAML parsing failure. + /// + public XamlParseException() + : base("XAML parsing failed.") + { + HResult = WellKnownErrorCodes.E_XAMLPARSEFAILED; + } + + /// + /// Initializes a new instance of the class + /// with a specified error message. + /// + /// The error message that explains the reason for the exception. + public XamlParseException(string message) + : base(message) + { + HResult = WellKnownErrorCodes.E_XAMLPARSEFAILED; + } +} diff --git a/src/WinRT.Runtime2/InteropServices/Exceptions/ExceptionHelpers.cs b/src/WinRT.Runtime2/InteropServices/Exceptions/ExceptionHelpers.cs new file mode 100644 index 000000000..570f75620 --- /dev/null +++ b/src/WinRT.Runtime2/InteropServices/Exceptions/ExceptionHelpers.cs @@ -0,0 +1,243 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Collections; +using WindowsRuntime.InteropServices.Marshalling; + +namespace WindowsRuntime.InteropServices; + +#pragma warning disable IDE0051 // TODO + +/// +/// Provides helper methods for working with restricted error information and language-specific exceptions +/// in Windows Runtime interop scenarios. +/// +/// +/// These methods manage COM pointers, propagate language exceptions, and attach restricted error info +/// to managed exceptions for diagnostic and interop purposes. +/// +internal static unsafe class ExceptionHelpers +{ + /// + /// Retrieves the current restricted error info object and sets it for propagation if available. + /// + /// + /// A representing the restricted error info object, + /// or default if none is available. + /// + internal static unsafe WindowsRuntimeObjectReferenceValue BorrowRestrictedErrorInfo() + { + void* restrictedErrorInfoPtr; + WindowsRuntimeImports.GetRestrictedErrorInfo(&restrictedErrorInfoPtr).Assert(); + + if (restrictedErrorInfoPtr == null) + { + return default; + } + + WindowsRuntimeImports.SetRestrictedErrorInfo(restrictedErrorInfoPtr).Assert(); + + return new(restrictedErrorInfoPtr); + } + + /// + /// Attempts to retrieve a managed language exception from a restricted error info pointer. + /// This is a helper method specifically to be used by exception propagation scenarios where we carefully + /// manage the lifetime of the CCW for the exception object to avoid cycles and thereby leaking it. + /// + /// Pointer to the language error info COM object. + /// The HRESULT associated with the error. + /// + /// The managed if found; otherwise, null. + /// + internal static unsafe Exception? GetLanguageException(void* languageErrorInfoPtr, HRESULT hresult) + { + // Check the error info first for the language exception. + Exception? exception = GetLanguageExceptionInternal(languageErrorInfoPtr, hresult); + if (exception is not null) + { + return exception; + } + + // If propagated exceptions are supported, traverse it and check if any one of those is our exception to reuse. + if (WellKnownErrorCodes.Succeeded(IUnknownVftbl.QueryInterfaceUnsafe( + languageErrorInfoPtr, + in WellKnownWindowsInterfaceIIDs.IID_ILanguageExceptionErrorInfo2, + out void* languageErrorInfo2Ptr))) + { + void* currentLanguageExceptionErrorInfo2Ptr = null; + + // TODO: Potential double free currentLanguageExceptionErrorInfo2Ptr if GetPreviousLanguageExceptionErrorInfoUnsafe fails on. Find a better way to handle this. + try + { + if (WellKnownErrorCodes.Succeeded(ILanguageExceptionErrorInfo2Vftbl.GetPropagationContextHeadUnsafe(languageErrorInfo2Ptr, ¤tLanguageExceptionErrorInfo2Ptr))) + { + + while (currentLanguageExceptionErrorInfo2Ptr != null) + { + Exception? propagatedException = GetLanguageExceptionInternal(currentLanguageExceptionErrorInfo2Ptr, hresult); + if (propagatedException is not null) + { + return propagatedException; + } + + void* previousLanguageExceptionErrorInfo2Ptr = currentLanguageExceptionErrorInfo2Ptr; + try + { + _ = ILanguageExceptionErrorInfo2Vftbl.GetPreviousLanguageExceptionErrorInfoUnsafe(currentLanguageExceptionErrorInfo2Ptr, ¤tLanguageExceptionErrorInfo2Ptr); + } + finally + { + WindowsRuntimeObjectMarshaller.Free(previousLanguageExceptionErrorInfo2Ptr); + } + } + } + } + finally + { + WindowsRuntimeObjectMarshaller.Free(currentLanguageExceptionErrorInfo2Ptr); + WindowsRuntimeObjectMarshaller.Free(languageErrorInfo2Ptr); + } + } + + return null; + } + + + /// + /// Internal helper to retrieve a managed language exception from a COM pointer. + /// + /// Pointer to the language error info COM object. + /// The HRESULT associated with the error. + /// + /// The managed if found; otherwise, null. + /// + internal static unsafe Exception? GetLanguageExceptionInternal(void* languageErrorInfoPtr, HRESULT hresult) + { + if (languageErrorInfoPtr == null) + { + return null; + } + + void* languageExceptionPtr = null; + try + { + if (WellKnownErrorCodes.Succeeded(ILanguageExceptionErrorInfoVftbl.GetLanguageExceptionUnsafe(languageErrorInfoPtr, &languageExceptionPtr))) + { + if (WindowsRuntimeMarshal.TryGetManagedObject(languageExceptionPtr, out object? exceptionObject)) + { + Exception? exception = exceptionObject as Exception; + if (RestrictedErrorInfo.GetHRForException(exception) == hresult) + { + return exception; + } + } + } + } + finally + { + WindowsRuntimeObjectMarshaller.Free(languageExceptionPtr); + } + + return null; + } + + + /// + /// Adds restricted error info metadata to the dictionary. + /// + /// The exception to augment. + /// The restricted error info object reference. + /// Indicates whether a language-specific error object exists. + internal static void AddExceptionDataForRestrictedErrorInfo( + Exception exception, + WindowsRuntimeObjectReference restrictedErrorObject, + bool hasRestrictedLanguageErrorObject) + { + IDictionary dict = exception.Data; + if (dict != null) + { + // Keep the error object alive so that user could retrieve error information + // using Data["RestrictedErrorReference"] + dict["__RestrictedErrorObjectReference"] = restrictedErrorObject; + dict["__HasRestrictedLanguageErrorObject"] = hasRestrictedLanguageErrorObject; + } + } + + internal static void AddExceptionDataForRestrictedErrorInfo( + Exception exception, + string? description, + string? restrictedError, + string? restrictedErrorReference, + string? restrictedCapabilitySid, + WindowsRuntimeObjectReference? restrictedErrorObject, + bool hasRestrictedLanguageErrorObject = false, + Exception? internalGetGlobalErrorStateException = null) + { + IDictionary dict = exception.Data; + if (dict != null) + { + if (description != null) + { + dict["Description"] = description; + } + if (restrictedError != null) + { + dict["RestrictedDescription"] = restrictedError; + } + if (restrictedErrorReference != null) + { + dict["RestrictedErrorReference"] = restrictedErrorReference; + } + if (restrictedCapabilitySid != null) + { + dict["RestrictedCapabilitySid"] = restrictedCapabilitySid; + } + + // Keep the error object alive so that user could retrieve error information + // using Data["RestrictedErrorReference"] + dict["__RestrictedErrorObjectReference"] = restrictedErrorObject; + dict["__HasRestrictedLanguageErrorObject"] = hasRestrictedLanguageErrorObject; + + if (internalGetGlobalErrorStateException != null) + { + dict["_InternalCsWinRTException"] = internalGetGlobalErrorStateException; + } + } + } + + /// + /// Attempts to retrieve restricted error info metadata from an exception. + /// + /// The exception to inspect. + /// On return, the restricted error info object reference if present. + /// On return, indicates whether the error originated from a language exception. + /// true if restricted error info was found; otherwise, false. + internal static bool TryGetRestrictedLanguageErrorInfo( + Exception exception, + out WindowsRuntimeObjectReference? restrictedErrorObject, + out bool isLanguageException) + { + restrictedErrorObject = null; + isLanguageException = false; + IDictionary dictionary = exception.Data; + + if (dictionary != null) + { + if (dictionary.Contains("__RestrictedErrorObjectReference")) + { + restrictedErrorObject = dictionary["__RestrictedErrorObjectReference"] as WindowsRuntimeObjectReference; + } + + if (dictionary.Contains("__HasRestrictedLanguageErrorObject")) + { + isLanguageException = (bool)dictionary["__HasRestrictedLanguageErrorObject"]!; + } + + return restrictedErrorObject is not null; + } + + return false; + } +} \ No newline at end of file diff --git a/src/WinRT.Runtime2/InteropServices/Exceptions/IRestrictedErrorInfoMethods.cs b/src/WinRT.Runtime2/InteropServices/Exceptions/IRestrictedErrorInfoMethods.cs new file mode 100644 index 000000000..2888b24be --- /dev/null +++ b/src/WinRT.Runtime2/InteropServices/Exceptions/IRestrictedErrorInfoMethods.cs @@ -0,0 +1,134 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace WindowsRuntime.InteropServices; + +/// +/// Provides low-level helpers to call IRestrictedErrorInfo methods through a vtable pointer, +/// and to safely marshal returned BSTR values to managed strings. +/// +/// +/// These helpers assume "thisPtr" param points to a valid COM object implementing +/// the IRestrictedErrorInfo interface and that HRESULTs are validated via the +/// Assert() helper on the returned status code. Any BSTRs returned by the COM methods +/// are converted to and then released with . +/// +internal static class IRestrictedErrorInfoMethods +{ + /// + /// Retrieves error details from an IRestrictedErrorInfo instance. + /// + /// A raw pointer to the COM object implementing IRestrictedErrorInfo. + /// On return, receives the human-readable error description (may be empty). + /// On return, receives the HRESULT error code. + /// On return, receives the restricted error description (may be empty). + /// On return, receives the capability SID (may be empty). + /// + /// All returned BSTRs are freed regardless of success or failure. Empty strings are returned if + /// any corresponding native pointer is null. + /// + public static unsafe void GetErrorDetails( + void* thisPtr, + out string? description, + out int error, + out string? restrictedDescription, + out string? capabilitySid) + { + char* _description = null; + char* _restrictedDescription = null; + char* _capabilitySid = null; + + try + { + fixed (int* pError = &error) + { + ((IRestrictedErrorInfoVftbl*)*(void***)thisPtr)->GetErrorDetails( + thisPtr, + &_description, + pError, + &_restrictedDescription, + &_capabilitySid).Assert(); + } + + description = BStrStringMarshaller.ConvertToManaged((ushort*)_description); + restrictedDescription = BStrStringMarshaller.ConvertToManaged((ushort*)_restrictedDescription); + capabilitySid = BStrStringMarshaller.ConvertToManaged((ushort*)_capabilitySid); + } + finally + { + BStrStringMarshaller.Free((ushort*)_description); + BStrStringMarshaller.Free((ushort*)_restrictedDescription); + BStrStringMarshaller.Free((ushort*)_capabilitySid); + } + } + + /// + /// Retrieves only the HRESULT error code from an IRestrictedErrorInfo instance. + /// + /// A raw pointer to the COM object implementing IRestrictedErrorInfo. + /// On return, receives the HRESULT error code. + /// + /// Although this overload ignores textual outputs, the native method still returns BSTRs. + /// Those are always freed to prevent leaks. + /// + public static unsafe void GetErrorDetails( + void* thisPtr, + out int error) + { + char* _description = null; + char* _restrictedDescription = null; + char* _capabilitySid = null; + + try + { + fixed (int* pError = &error) + { + ((IRestrictedErrorInfoVftbl*)*(void***)thisPtr)->GetErrorDetails( + thisPtr, + &_description, + pError, + &_restrictedDescription, + &_capabilitySid).Assert(); + } + } + finally + { + BStrStringMarshaller.Free((ushort*)_description); + BStrStringMarshaller.Free((ushort*)_restrictedDescription); + BStrStringMarshaller.Free((ushort*)_capabilitySid); + } + } + + /// + /// Gets the reference string (source) associated with the error from an IRestrictedErrorInfo instance. + /// + /// A raw pointer to the COM object implementing IRestrictedErrorInfo. + /// + /// The reference string returned by the COM object, or if the native pointer is null. + /// + /// + /// The returned BSTR is always released even if it is null or the call fails after validation. + /// + public static unsafe string GetReference(void* thisPtr) + { + char* _retval = null; + + try + { + ((IRestrictedErrorInfoVftbl*)*(void***)thisPtr)->GetReference( + thisPtr, + &_retval).Assert(); + + string? description = BStrStringMarshaller.ConvertToManaged((ushort*)_retval); + + return description ?? string.Empty; + } + finally + { + BStrStringMarshaller.Free((ushort*)_retval); + } + } +} diff --git a/src/WinRT.Runtime2/InteropServices/FreeThreadedMarshaler.cs b/src/WinRT.Runtime2/InteropServices/FreeThreadedMarshaler.cs index b6ef7ac00..a95a5ec8e 100644 --- a/src/WinRT.Runtime2/InteropServices/FreeThreadedMarshaler.cs +++ b/src/WinRT.Runtime2/InteropServices/FreeThreadedMarshaler.cs @@ -98,16 +98,26 @@ public static FreeThreadedMarshaler InstanceForCurrentThread [MethodImpl(MethodImplOptions.NoInlining)] static FreeThreadedMarshaler InitializeInstanceForCurrentThread() { - // Create the free-threaded marshaler - void* marshalerPtr; + void* marshalUnknownPtr; - WindowsRuntimeImports.CoCreateFreeThreadedMarshaler(punkOuter: null, ppunkMarshal: &marshalerPtr).Assert(); + // Create the free-threaded marshaler (the return will only be an 'IUnknown' interface pointer) + WindowsRuntimeImports.CoCreateFreeThreadedMarshaler(punkOuter: null, ppunkMarshal: &marshalUnknownPtr).Assert(); - // The returned marshaler is documented to be free-threaded, so we can instantiate 'FreeThreadedObjectReference' - // directly. This also should allow inlining all virtual calls to the object in this class, in the stubs below. - FreeThreadedObjectReference objectReference = new(marshalerPtr, referenceTrackerPtr: null); + try + { + // We need an explicit 'QueryInterface' call to actually get the 'IMarshal' interface pointer to use + IUnknownVftbl.QueryInterfaceUnsafe(marshalUnknownPtr, in WellKnownWindowsInterfaceIIDs.IID_IMarshal, out void* marshalPtr).Assert(); + + // The returned marshaler is documented to be free-threaded, so we can instantiate 'FreeThreadedObjectReference' + // directly. This also should allow inlining all virtual calls to the object in this class, in the stubs below. + FreeThreadedObjectReference objectReference = new(marshalPtr, referenceTrackerPtr: null); - return instanceForCurrentThread = new FreeThreadedMarshaler(objectReference); + return instanceForCurrentThread = new FreeThreadedMarshaler(objectReference); + } + finally + { + _ = IUnknownVftbl.ReleaseUnsafe(marshalUnknownPtr); + } } return instanceForCurrentThread ?? InitializeInstanceForCurrentThread(); diff --git a/src/WinRT.Runtime2/InteropServices/Marshalling/RestrictedErrorInfoExceptionMarshaller.cs b/src/WinRT.Runtime2/InteropServices/Marshalling/RestrictedErrorInfoExceptionMarshaller.cs index a49339e5e..daf147d6f 100644 --- a/src/WinRT.Runtime2/InteropServices/Marshalling/RestrictedErrorInfoExceptionMarshaller.cs +++ b/src/WinRT.Runtime2/InteropServices/Marshalling/RestrictedErrorInfoExceptionMarshaller.cs @@ -39,6 +39,6 @@ public static HRESULT ConvertToUnmanaged(Exception value) /// A managed exception. public static Exception? ConvertToManaged(HRESULT value) { - return RestrictedErrorInfo.GetExceptionForHR(value); + return RestrictedErrorInfo.GetExceptionForHR(value, out _); } } \ No newline at end of file diff --git a/src/WinRT.Runtime2/InteropServices/Platform/WindowsRuntimeImports.cs b/src/WinRT.Runtime2/InteropServices/Platform/WindowsRuntimeImports.cs index 6d7747d35..a634e9d8a 100644 --- a/src/WinRT.Runtime2/InteropServices/Platform/WindowsRuntimeImports.cs +++ b/src/WinRT.Runtime2/InteropServices/Platform/WindowsRuntimeImports.cs @@ -81,4 +81,28 @@ internal static unsafe partial class WindowsRuntimeImports /// [LibraryImport("kernel32", SetLastError = true)] public static partial int FreeLibrary(HMODULE hLibModule); + + /// + [LibraryImport("api-ms-win-core-winrt-error-l1-1-1.dll")] + public static partial HRESULT RoReportUnhandledError(void* pRestrictedErrorInfo); + + /// https://learn.microsoft.com/windows/win32/api/roerrorapi/nf-roerrorapi-rooriginatelanguageexception + [LibraryImport("api-ms-win-core-winrt-error-l1-1-1.dll")] + public static partial int RoOriginateLanguageException(HRESULT error, HSTRING message, void* languageException); + + /// + [LibraryImport("api-ms-win-core-winrt-error-l1-1-1.dll")] + public static partial HRESULT GetRestrictedErrorInfo(void** ppRestrictedErrorInfo); + + /// + [LibraryImport("api-ms-win-core-winrt-error-l1-1-1.dll")] + public static partial HRESULT SetRestrictedErrorInfo(void* pRestrictedErrorInfo); + + /// + [LibraryImport("kernel32.dll")] + public static partial uint FormatMessageW(uint dwFlags, void* lpSource, uint dwMessageId, uint dwLanguageId, char** lpBuffer, uint nSize, void* pArguments); + + /// + [LibraryImport("kernel32.dll")] + public static partial void* LocalFree(void* hMem); } diff --git a/src/WinRT.Runtime2/InteropServices/RestrictedErrorInfo.cs b/src/WinRT.Runtime2/InteropServices/RestrictedErrorInfo.cs index b6a76dcd6..dd013fdb8 100644 --- a/src/WinRT.Runtime2/InteropServices/RestrictedErrorInfo.cs +++ b/src/WinRT.Runtime2/InteropServices/RestrictedErrorInfo.cs @@ -2,7 +2,12 @@ // Licensed under the MIT License. using System; +using System.Diagnostics; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; +using WindowsRuntime.InteropServices.Marshalling; #pragma warning disable IDE0060 // TODO @@ -18,6 +23,7 @@ public static unsafe class RestrictedErrorInfo /// Converts an HRESULT error code to a corresponding object. /// /// The HRESULT to be converted. + /// restoredExceptionFromGlobalState Out param. /// /// An instance that represents the converted HRESULT, /// or if the HRESULT value doesn't represent an error code. @@ -28,10 +34,190 @@ public static unsafe class RestrictedErrorInfo /// calls (both in managed and native code). This improves the debugging experience. /// /// - public static Exception? GetExceptionForHR(HRESULT errorCode) + public static Exception GetExceptionForHR(HRESULT errorCode, out bool restoredExceptionFromGlobalState) { - // TODO - return null; + restoredExceptionFromGlobalState = false; + string? description = null; + string? restrictedError = null; + string? restrictedErrorReference = null; + string? restrictedCapabilitySid = null; + string? errorMessage = null; + Exception? exception; + Exception? internalGetGlobalErrorStateException = null; + WindowsRuntimeObjectReference? restrictedErrorInfoToSave = null; + + + using WindowsRuntimeObjectReferenceValue restrictedErrorInfoValue = ExceptionHelpers.BorrowRestrictedErrorInfo(); + + try + { + void* restrictedErrorInfoValuePtr = restrictedErrorInfoValue.GetThisPtrUnsafe(); + + if (restrictedErrorInfoValuePtr != null) + { + if (WellKnownErrorCodes.Succeeded(IUnknownVftbl.QueryInterfaceUnsafe( + restrictedErrorInfoValuePtr, + in WellKnownWindowsInterfaceIIDs.IID_ILanguageExceptionErrorInfo, + out void* languageErrorInfoPtr))) + { + try + { + exception = ExceptionHelpers.GetLanguageException(languageErrorInfoPtr, errorCode); + + if (exception is not null) + { + restoredExceptionFromGlobalState = true; + WindowsRuntimeObjectReference? restrictedErrorInfo = WindowsRuntimeObjectReference.CreateUnsafe(restrictedErrorInfoValuePtr, WellKnownWindowsInterfaceIIDs.IID_IRestrictedErrorInfo); + + if (restrictedErrorInfo != null) + { + ExceptionHelpers.AddExceptionDataForRestrictedErrorInfo(exception, restrictedErrorInfo, true); + } + + return exception; + } + } + finally + { + WindowsRuntimeObjectMarshaller.Free(languageErrorInfoPtr); + } + } + + restrictedErrorInfoToSave = WindowsRuntimeObjectReference.CreateUnsafe(restrictedErrorInfoValuePtr, WellKnownWindowsInterfaceIIDs.IID_IRestrictedErrorInfo); + + IRestrictedErrorInfoMethods.GetErrorDetails(restrictedErrorInfoValuePtr, out description, out HRESULT hrLocal, out restrictedError, out restrictedCapabilitySid); + + restrictedErrorReference = IRestrictedErrorInfoMethods.GetReference(restrictedErrorInfoValuePtr); + + if (errorCode == hrLocal) + { + // For cross language WinRT exceptions, general information will be available in the description, + // which is populated from IRestrictedErrorInfo::GetErrorDetails and more specific information will be available + // in the restrictedError which also comes from IRestrictedErrorInfo::GetErrorDetails. If both are available, we + + // need to concatinate them to produce the final exception message. + if (!string.IsNullOrEmpty(description)) + { + errorMessage += description; + + if (!string.IsNullOrEmpty(restrictedError)) + { + errorMessage += Environment.NewLine; + } + } + + if (!string.IsNullOrEmpty(restrictedError)) + { + errorMessage += restrictedError; + } + } + } + } + catch (Exception e) + { + // If we fail to get the error info or the exception from it, + // we fallback to using the hresult to create the exception. + // But we do store it in the exception data for debugging purposes. + Debug.Assert(false, e.Message, e.StackTrace); + internalGetGlobalErrorStateException = e; + } + + if (string.IsNullOrWhiteSpace(errorMessage)) + { + char* message = null; + + if (WindowsRuntimeImports.FormatMessageW(0x13FF /* FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK */, + null, + (uint)errorCode, + 0, + &message, + 0, + null) > 0) + { + errorMessage = $"{new string(message)}(0x{errorCode:X8})"; + + // LocalHandle isn't needed since FormatMessage uses LMEM_FIXED, + // and while we can use Marshal.FreeHGlobal since it uses LocalFree internally, + // it's not guranteed that this behavior stays the same in the future, + // especially considering the method's name, so it's safer to use LocalFree directly. + _ = WindowsRuntimeImports.LocalFree(message); + } + } + + + exception = errorCode switch + { + // InvalidOperationException + WellKnownErrorCodes.E_CHANGED_STATE or + WellKnownErrorCodes.E_ILLEGAL_STATE_CHANGE or + WellKnownErrorCodes.E_ILLEGAL_METHOD_CALL or + WellKnownErrorCodes.E_ILLEGAL_DELEGATE_ASSIGNMENT or + WellKnownErrorCodes.APPMODEL_ERROR_NO_PACKAGE or + WellKnownErrorCodes.COR_E_INVALIDOPERATION => !string.IsNullOrEmpty(errorMessage) ? new InvalidOperationException(errorMessage) : new InvalidOperationException(), + + // XamlParseException + WellKnownErrorCodes.E_XAMLPARSEFAILED => WindowsRuntimeFeatureSwitches.UseWindowsUIXamlProjections + ? !string.IsNullOrEmpty(errorMessage) ? new Windows.UI.Xaml.XamlParseException(errorMessage) : new Windows.UI.Xaml.XamlParseException() + : !string.IsNullOrEmpty(errorMessage) ? new Microsoft.UI.Xaml.XamlParseException(errorMessage) : new Microsoft.UI.Xaml.XamlParseException(), + + // LayoutCycleException + WellKnownErrorCodes.E_LAYOUTCYCLE => WindowsRuntimeFeatureSwitches.UseWindowsUIXamlProjections + ? !string.IsNullOrEmpty(errorMessage) ? new Windows.UI.Xaml.LayoutCycleException(errorMessage) : new Windows.UI.Xaml.LayoutCycleException() + : !string.IsNullOrEmpty(errorMessage) ? new Microsoft.UI.Xaml.LayoutCycleException(errorMessage) : new Microsoft.UI.Xaml.LayoutCycleException(), + + // ElementNotAvailableException + WellKnownErrorCodes.E_ELEMENTNOTAVAILABLE => WindowsRuntimeFeatureSwitches.UseWindowsUIXamlProjections + ? !string.IsNullOrEmpty(errorMessage) ? new Windows.UI.Xaml.ElementNotAvailableException(errorMessage) : new Windows.UI.Xaml.ElementNotAvailableException() + : !string.IsNullOrEmpty(errorMessage) ? new Microsoft.UI.Xaml.ElementNotAvailableException(errorMessage) : new Microsoft.UI.Xaml.ElementNotAvailableException(), + + // ElementNotEnabledException + WellKnownErrorCodes.E_ELEMENTNOTENABLED => WindowsRuntimeFeatureSwitches.UseWindowsUIXamlProjections + ? !string.IsNullOrEmpty(errorMessage) ? new Windows.UI.Xaml.ElementNotEnabledException(errorMessage) : new Windows.UI.Xaml.ElementNotEnabledException() + : !string.IsNullOrEmpty(errorMessage) ? new Microsoft.UI.Xaml.ElementNotEnabledException(errorMessage) : new Microsoft.UI.Xaml.ElementNotEnabledException(), + + // COMException for invalid window handle with guidance + WellKnownErrorCodes.ERROR_INVALID_WINDOW_HANDLE => new COMException( + "Invalid window handle (0x80070578). Consider WindowNative, InitializeWithWindow. See https://aka.ms/cswinrt/interop#windows-sdk.", + WellKnownErrorCodes.ERROR_INVALID_WINDOW_HANDLE), + + // Other common exceptions + WellKnownErrorCodes.RO_E_CLOSED => !string.IsNullOrEmpty(errorMessage) ? new ObjectDisposedException(string.Empty, errorMessage) : new ObjectDisposedException(string.Empty), + WellKnownErrorCodes.E_POINTER => !string.IsNullOrEmpty(errorMessage) ? new NullReferenceException(errorMessage) : new NullReferenceException(), + WellKnownErrorCodes.E_NOTIMPL => !string.IsNullOrEmpty(errorMessage) ? new NotImplementedException(errorMessage) : new NotImplementedException(), + WellKnownErrorCodes.E_ACCESSDENIED => !string.IsNullOrEmpty(errorMessage) ? new UnauthorizedAccessException(errorMessage) : new UnauthorizedAccessException(), + WellKnownErrorCodes.E_INVALIDARG => !string.IsNullOrEmpty(errorMessage) ? new ArgumentException(errorMessage) : new ArgumentException(), + WellKnownErrorCodes.E_NOINTERFACE => !string.IsNullOrEmpty(errorMessage) ? new InvalidCastException(errorMessage) : new InvalidCastException(), + WellKnownErrorCodes.E_OUTOFMEMORY => !string.IsNullOrEmpty(errorMessage) ? new OutOfMemoryException(errorMessage) : new OutOfMemoryException(), + WellKnownErrorCodes.E_BOUNDS => !string.IsNullOrEmpty(errorMessage) ? new ArgumentOutOfRangeException(errorMessage) : new ArgumentOutOfRangeException(), + WellKnownErrorCodes.E_NOTSUPPORTED => !string.IsNullOrEmpty(errorMessage) ? new NotSupportedException(errorMessage) : new NotSupportedException(), + WellKnownErrorCodes.ERROR_ARITHMETIC_OVERFLOW => !string.IsNullOrEmpty(errorMessage) ? new ArithmeticException(errorMessage) : new ArithmeticException(), + WellKnownErrorCodes.ERROR_FILENAME_EXCED_RANGE => !string.IsNullOrEmpty(errorMessage) ? new PathTooLongException(errorMessage) : new PathTooLongException(), + WellKnownErrorCodes.ERROR_FILE_NOT_FOUND => !string.IsNullOrEmpty(errorMessage) ? new FileNotFoundException(errorMessage) : new FileNotFoundException(), + WellKnownErrorCodes.ERROR_HANDLE_EOF => !string.IsNullOrEmpty(errorMessage) ? new EndOfStreamException(errorMessage) : new EndOfStreamException(), + WellKnownErrorCodes.ERROR_PATH_NOT_FOUND => !string.IsNullOrEmpty(errorMessage) ? new DirectoryNotFoundException(errorMessage) : new DirectoryNotFoundException(), + WellKnownErrorCodes.ERROR_STACK_OVERFLOW => !string.IsNullOrEmpty(errorMessage) ? new StackOverflowException(errorMessage) : new StackOverflowException(), + WellKnownErrorCodes.ERROR_BAD_FORMAT => !string.IsNullOrEmpty(errorMessage) ? new BadImageFormatException(errorMessage) : new BadImageFormatException(), + WellKnownErrorCodes.ERROR_CANCELLED => !string.IsNullOrEmpty(errorMessage) ? new OperationCanceledException(errorMessage) : new OperationCanceledException(), + WellKnownErrorCodes.ERROR_TIMEOUT => !string.IsNullOrEmpty(errorMessage) ? new TimeoutException(errorMessage) : new TimeoutException(), + + // Fallback to COMException + _ => !string.IsNullOrEmpty(errorMessage) ? new COMException(errorMessage, errorCode) : new COMException($"0x{errorCode:X8}", errorCode), + }; + + // Ensure HResult matches. + exception.HResult = errorCode; + + ExceptionHelpers.AddExceptionDataForRestrictedErrorInfo( + exception, + description, + restrictedError, + restrictedErrorReference, + restrictedCapabilitySid, + restrictedErrorInfoToSave, + false, + internalGetGlobalErrorStateException); + + return exception; } /// @@ -47,7 +233,25 @@ public static unsafe class RestrictedErrorInfo /// public static void ThrowExceptionForHR(HRESULT errorCode) { - // TODO + if (errorCode < 0) + { + Throw(errorCode); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void Throw(int errorCode) + { + Exception? exception = GetExceptionForHR(errorCode, out bool restoredExceptionFromGlobalState); + + if (restoredExceptionFromGlobalState) + { + ExceptionDispatchInfo.Capture(exception).Throw(); + } + else + { + throw exception; + } + } } /// @@ -62,17 +266,123 @@ public static void ThrowExceptionForHR(HRESULT errorCode) /// public static HRESULT GetHRForException(Exception? exception) { - // TODO - return 0; + ArgumentNullException.ThrowIfNull(exception); + + HRESULT hresult = exception.HResult; + + try + { + if (ExceptionHelpers.TryGetRestrictedLanguageErrorInfo(exception, out WindowsRuntimeObjectReference? restrictedErrorObject, out _)) + { + if (restrictedErrorObject != null) + { + using WindowsRuntimeObjectReferenceValue restrictedErrorObjectValue = restrictedErrorObject.AsValue(); + IRestrictedErrorInfoMethods.GetErrorDetails(restrictedErrorObjectValue.GetThisPtrUnsafe(), out hresult); + } + } + } + catch (Exception e) + { + // If we fail to get the hresult from the error info, we fallback to the exception hresult. + Debug.Assert(false, e.Message, e.StackTrace); + } + + return hresult switch + { + WellKnownErrorCodes.COR_E_OBJECTDISPOSED => WellKnownErrorCodes.RO_E_CLOSED, + WellKnownErrorCodes.COR_E_OPERATIONCANCELED => WellKnownErrorCodes.ERROR_CANCELLED, + WellKnownErrorCodes.COR_E_ARGUMENTOUTOFRANGE or WellKnownErrorCodes.COR_E_INDEXOUTOFRANGE => WellKnownErrorCodes.E_BOUNDS, + WellKnownErrorCodes.COR_E_TIMEOUT => WellKnownErrorCodes.ERROR_TIMEOUT, + _ => hresult, + }; } /// /// Stores info on the input exception through the IRestrictedErrorInfo infrastructure, to retrieve it later. /// /// The input instance to store. - public static void SetErrorInfo(Exception exception) + public static unsafe void SetErrorInfo(Exception exception) { - // TODO + try + { + // If the exception has an IRestrictedErrorInfo, use that as our error info + // to allow to propagate the original error through WinRT with the end to end information + // rather than losing that context. + if (ExceptionHelpers.TryGetRestrictedLanguageErrorInfo(exception, out WindowsRuntimeObjectReference? restrictedErrorObject, out bool isLanguageException)) + { + // Capture the C# language exception if it hasn't already been captured previously either during the throw or during a propagation. + // Given the C# exception itself captures propagation context on rethrow, we don't do it each time. + if (!isLanguageException && restrictedErrorObject != null && + WellKnownErrorCodes.Succeeded(IUnknownVftbl.QueryInterfaceUnsafe( + restrictedErrorObject.GetThisPtrUnsafe(), + in WellKnownWindowsInterfaceIIDs.IID_ILanguageExceptionErrorInfo2, + out void* languageErrorInfo2Ptr))) + { + try + { + using WindowsRuntimeObjectReferenceValue managedExceptionWrapper = WindowsRuntimeObjectMarshaller.ConvertToUnmanaged(exception); + + ((ILanguageExceptionErrorInfo2Vftbl*)*(void***)languageErrorInfo2Ptr)->CapturePropagationContext( + languageErrorInfo2Ptr, + managedExceptionWrapper.GetThisPtrUnsafe()).Assert(); + } + finally + { + WindowsRuntimeObjectMarshaller.Free(languageErrorInfo2Ptr); + } + } + else if (isLanguageException) + { + // Remove object reference to avoid cycles between error info holding exception + // and exception holding error info. We currently can't avoid this cycle + // when the C# exception is caught on the C# side. + exception.Data.Remove("__RestrictedErrorObjectReference"); + exception.Data.Remove("__HasRestrictedLanguageErrorObject"); + } + if (restrictedErrorObject != null) + { + using WindowsRuntimeObjectReferenceValue restrictedErrorObjectValue = restrictedErrorObject.AsValue(); + + _ = WindowsRuntimeImports.SetRestrictedErrorInfo(restrictedErrorObjectValue.GetThisPtrUnsafe()); + } + } + else + { + string message = exception.Message; + + if (string.IsNullOrEmpty(message)) + { + Type exceptionType = exception.GetType(); + + if (exceptionType != null) + { + message = exceptionType.Name; + } + } + + fixed (char* lpMessage = message) + { + HStringMarshaller.ConvertToUnmanagedUnsafe(lpMessage, message.Length, out HStringReference hstring); + + WindowsRuntimeObjectReferenceValue managedExceptionWrapper = WindowsRuntimeObjectMarshaller.ConvertToUnmanaged(exception); + + try + { + _ = WindowsRuntimeImports.RoOriginateLanguageException(GetHRForException(exception), hstring.HString, managedExceptionWrapper.GetThisPtrUnsafe()); + } + finally + { + _ = Marshal.Release((nint)managedExceptionWrapper.DetachThisPtrUnsafe()); + } + + } + } + } + catch (Exception e) + { + // If we fail to set the error info, we continue on reporting the original exception. + Debug.Assert(false, e.Message, e.StackTrace); + } } /// @@ -80,8 +390,17 @@ public static void SetErrorInfo(Exception exception) /// /// The input instance to flow to the global error handler. /// - public static void ReportUnhandledError(Exception exception) + public static unsafe void ReportUnhandledError(Exception exception) { - // TODO + SetErrorInfo(exception); + + using WindowsRuntimeObjectReferenceValue restrictedErrorInfoValue = ExceptionHelpers.BorrowRestrictedErrorInfo(); + + void* restrictedErrorInfoValuePtr = restrictedErrorInfoValue.GetThisPtrUnsafe(); + + if (restrictedErrorInfoValuePtr != null) + { + _ = WindowsRuntimeImports.RoReportUnhandledError(restrictedErrorInfoValuePtr); + } } } \ No newline at end of file diff --git a/src/WinRT.Runtime2/InteropServices/Vtables/ILanguageExceptionErrorInfo2Vftbl.cs b/src/WinRT.Runtime2/InteropServices/Vtables/ILanguageExceptionErrorInfo2Vftbl.cs new file mode 100644 index 000000000..fadbced4c --- /dev/null +++ b/src/WinRT.Runtime2/InteropServices/Vtables/ILanguageExceptionErrorInfo2Vftbl.cs @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace WindowsRuntime.InteropServices; + +/// +/// Enables language projections to provide and retrieve error information as with ILanguageExceptionErrorInfo, with the additional benefit of working across language boundaries. +/// +/// +[StructLayout(LayoutKind.Sequential)] +internal unsafe struct ILanguageExceptionErrorInfo2Vftbl +{ + public delegate* unmanaged[MemberFunction] QueryInterface; + public delegate* unmanaged[MemberFunction] AddRef; + public delegate* unmanaged[MemberFunction] Release; + public delegate* unmanaged[MemberFunction] GetLanguageException; + public delegate* unmanaged[MemberFunction] GetPreviousLanguageExceptionErrorInfo; + public delegate* unmanaged[MemberFunction] CapturePropagationContext; + public delegate* unmanaged[MemberFunction] GetPropagationContextHead; + + /// + /// Retrieves the previous language exception error information object + /// + /// The target COM object. + /// + /// Pointer to an ILanguageExceptionErrorInfo2 object that contains the previous error information object. + /// + /// The HRESULT for the operation. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HRESULT GetPreviousLanguageExceptionErrorInfoUnsafe(void* thisPtr, void** previousLanguageExceptionErrorInfo) + { + return ((ILanguageExceptionErrorInfo2Vftbl*)*(void***)thisPtr)->GetPreviousLanguageExceptionErrorInfo( + thisPtr, + previousLanguageExceptionErrorInfo); + } + + /// + /// Retrieves the propagation context head. + /// + /// The target COM object. + /// + /// On success, returns an ILanguageExceptionErrorInfo2 object that represents the head of the propagation context. + /// + /// The HRESULT for the operation. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HRESULT GetPropagationContextHeadUnsafe(void* thisPtr, void** propagatedLanguageExceptionErrorInfoHead) + { + return ((ILanguageExceptionErrorInfo2Vftbl*)*(void***)thisPtr)->GetPropagationContextHead( + thisPtr, + propagatedLanguageExceptionErrorInfoHead); + } +} \ No newline at end of file diff --git a/src/WinRT.Runtime2/InteropServices/Vtables/ILanguageExceptionErrorInfoVftbl.cs b/src/WinRT.Runtime2/InteropServices/Vtables/ILanguageExceptionErrorInfoVftbl.cs new file mode 100644 index 000000000..ea94b9df6 --- /dev/null +++ b/src/WinRT.Runtime2/InteropServices/Vtables/ILanguageExceptionErrorInfoVftbl.cs @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace WindowsRuntime.InteropServices; + +/// +/// Enables retrieving the IUnknown pointer stored in the error info with the call to RoOriginateLanguageException. +/// +/// +[StructLayout(LayoutKind.Sequential)] +internal unsafe struct ILanguageExceptionErrorInfoVftbl +{ + public delegate* unmanaged[MemberFunction] QueryInterface; + public delegate* unmanaged[MemberFunction] AddRef; + public delegate* unmanaged[MemberFunction] Release; + public delegate* unmanaged[MemberFunction] GetLanguageException; + + /// + /// Gets the stored IUnknown object from the error object. + /// + /// The target COM object. + /// The stored IUnknown object from the error object. + /// The HRESULT for the operation. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HRESULT GetLanguageExceptionUnsafe(void* thisPtr, void** languageException) + { + return ((ILanguageExceptionErrorInfoVftbl*)*(void***)thisPtr)->GetLanguageException( + thisPtr, + languageException); + } +} \ No newline at end of file diff --git a/src/WinRT.Runtime2/InteropServices/Vtables/IRestrictedErrorInfoVftbl.cs b/src/WinRT.Runtime2/InteropServices/Vtables/IRestrictedErrorInfoVftbl.cs new file mode 100644 index 000000000..c73bc86c1 --- /dev/null +++ b/src/WinRT.Runtime2/InteropServices/Vtables/IRestrictedErrorInfoVftbl.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Runtime.InteropServices; + +namespace WindowsRuntime.InteropServices; + +/// +/// Represents the details of an error, including restricted error information. +/// +/// +[StructLayout(LayoutKind.Sequential)] +internal unsafe struct IRestrictedErrorInfoVftbl +{ + public delegate* unmanaged[MemberFunction] QueryInterface; + public delegate* unmanaged[MemberFunction] AddRef; + public delegate* unmanaged[MemberFunction] Release; + public delegate* unmanaged[MemberFunction] GetErrorDetails; + public delegate* unmanaged[MemberFunction] GetReference; +} \ No newline at end of file diff --git a/src/WinRT.Runtime2/InteropServices/WellKnownErrorCodes.g.cs b/src/WinRT.Runtime2/InteropServices/WellKnownErrorCodes.g.cs index e76d00247..efb30dc5c 100644 --- a/src/WinRT.Runtime2/InteropServices/WellKnownErrorCodes.g.cs +++ b/src/WinRT.Runtime2/InteropServices/WellKnownErrorCodes.g.cs @@ -36,6 +36,93 @@ internal partial class WellKnownErrorCodes /// The operation attempted to access data outside the valid range. public const HRESULT E_BOUNDS = unchecked((int)0x8000000B); + /// .NET: Object has been disposed. + public const HRESULT COR_E_OBJECTDISPOSED = unchecked((int)0x80131622); + + /// .NET: The operation was canceled. + public const HRESULT COR_E_OPERATIONCANCELED = unchecked((int)0x8013153B); + + /// .NET: Argument is out of range. + public const HRESULT COR_E_ARGUMENTOUTOFRANGE = unchecked((int)0x80131502); + + /// .NET: Index was outside the bounds of the array. + public const HRESULT COR_E_INDEXOUTOFRANGE = unchecked((int)0x80131508); + + /// .NET: The operation timed out. + public const HRESULT COR_E_TIMEOUT = unchecked((int)0x80131505); + + /// .NET: Operation is invalid in the current state. + public const HRESULT COR_E_INVALIDOPERATION = unchecked((int)0x80131509); + + /// The object has been closed. + public const HRESULT RO_E_CLOSED = unchecked((int)0x80000013); + + /// Illegal state change. + public const HRESULT E_ILLEGAL_STATE_CHANGE = unchecked((int)0x8000000D); + + /// Method call is invalid in the current state. + public const HRESULT E_ILLEGAL_METHOD_CALL = unchecked((int)0x8000000E); + + /// Delegate assignment is not allowed. + public const HRESULT E_ILLEGAL_DELEGATE_ASSIGNMENT = unchecked((int)0x80000018); + + /// The process has no package identity. + public const HRESULT APPMODEL_ERROR_NO_PACKAGE = unchecked((int)0x80073D54); + + /// XAML parsing failed. + public const HRESULT E_XAMLPARSEFAILED = unchecked((int)0x802B000A); + + /// Layout cycle detected. + public const HRESULT E_LAYOUTCYCLE = unchecked((int)0x802B0014); + + /// Element is not enabled. + public const HRESULT E_ELEMENTNOTENABLED = unchecked((int)0x802B001E); + + /// Element is not available. + public const HRESULT E_ELEMENTNOTAVAILABLE = unchecked((int)0x802B001F); + + /// Invalid window handle. + public const HRESULT ERROR_INVALID_WINDOW_HANDLE = unchecked((int)0x80070578); + /// Not implemented. public const HRESULT E_NOTIMPL = unchecked((int)0x80004001); + + /// Access denied. + public const HRESULT E_ACCESSDENIED = unchecked((int)0x80070005); + + /// One or more arguments are invalid. + public const HRESULT E_INVALIDARG = unchecked((int)0x80070057); + + /// Out of memory. + public const HRESULT E_OUTOFMEMORY = unchecked((int)0x8007000E); + + /// The request is not supported. + public const HRESULT E_NOTSUPPORTED = unchecked((int)0x80070032); + + /// Arithmetic operation resulted in an overflow. + public const HRESULT ERROR_ARITHMETIC_OVERFLOW = unchecked((int)0x80070216); + + /// Filename or extension is too long. + public const HRESULT ERROR_FILENAME_EXCED_RANGE = unchecked((int)0x800700CE); + + /// The system cannot find the file specified. + public const HRESULT ERROR_FILE_NOT_FOUND = unchecked((int)0x80070002); + + /// Reached the end of the file. + public const HRESULT ERROR_HANDLE_EOF = unchecked((int)0x80070026); + + /// The system cannot find the path specified. + public const HRESULT ERROR_PATH_NOT_FOUND = unchecked((int)0x80070003); + + /// Stack overflow. + public const HRESULT ERROR_STACK_OVERFLOW = unchecked((int)0x800703E9); + + /// Invalid image format. + public const HRESULT ERROR_BAD_FORMAT = unchecked((int)0x8007000B); + + /// The operation was canceled. + public const HRESULT ERROR_CANCELLED = unchecked((int)0x800704C7); + + /// This operation returned because the timeout period expired. + public const HRESULT ERROR_TIMEOUT = unchecked((int)0x800705B4); } \ No newline at end of file diff --git a/src/WinRT.Runtime2/InteropServices/WellKnownErrorCodes.tt b/src/WinRT.Runtime2/InteropServices/WellKnownErrorCodes.tt index 1b53b0411..46c565959 100644 --- a/src/WinRT.Runtime2/InteropServices/WellKnownErrorCodes.tt +++ b/src/WinRT.Runtime2/InteropServices/WellKnownErrorCodes.tt @@ -23,7 +23,36 @@ var entries = new (string Name, uint Value, string Description)[] ("DISP_E_OVERFLOW", 0x8002000A, "Numeric overflow."), ("E_CHANGED_STATE", 0x8000000C, "A concurrent or interleaved operation changed the state of the object, invalidating this operation."), ("E_BOUNDS", 0x8000000B, "The operation attempted to access data outside the valid range."), - ("E_NOTIMPL", 0x80004001, "Not implemented.") + ("COR_E_OBJECTDISPOSED", 0x80131622, ".NET: Object has been disposed."), + ("COR_E_OPERATIONCANCELED", 0x8013153B, ".NET: The operation was canceled."), + ("COR_E_ARGUMENTOUTOFRANGE", 0x80131502, ".NET: Argument is out of range."), + ("COR_E_INDEXOUTOFRANGE", 0x80131508, ".NET: Index was outside the bounds of the array."), + ("COR_E_TIMEOUT", 0x80131505, ".NET: The operation timed out."), + ("COR_E_INVALIDOPERATION", 0x80131509, ".NET: Operation is invalid in the current state."), + ("RO_E_CLOSED", 0x80000013, "The object has been closed."), + ("E_ILLEGAL_STATE_CHANGE", 0x8000000D, "Illegal state change."), + ("E_ILLEGAL_METHOD_CALL", 0x8000000E, "Method call is invalid in the current state."), + ("E_ILLEGAL_DELEGATE_ASSIGNMENT", 0x80000018, "Delegate assignment is not allowed."), + ("APPMODEL_ERROR_NO_PACKAGE", 0x80073D54, "The process has no package identity."), + ("E_XAMLPARSEFAILED", 0x802B000A, "XAML parsing failed."), + ("E_LAYOUTCYCLE", 0x802B0014, "Layout cycle detected."), + ("E_ELEMENTNOTENABLED", 0x802B001E, "Element is not enabled."), + ("E_ELEMENTNOTAVAILABLE", 0x802B001F, "Element is not available."), + ("ERROR_INVALID_WINDOW_HANDLE", 0x80070578, "Invalid window handle."), + ("E_NOTIMPL", 0x80004001, "Not implemented."), + ("E_ACCESSDENIED", 0x80070005, "Access denied."), + ("E_INVALIDARG", 0x80070057, "One or more arguments are invalid."), + ("E_OUTOFMEMORY", 0x8007000E, "Out of memory."), + ("E_NOTSUPPORTED", 0x80070032, "The request is not supported."), + ("ERROR_ARITHMETIC_OVERFLOW", 0x80070216, "Arithmetic operation resulted in an overflow."), + ("ERROR_FILENAME_EXCED_RANGE", 0x800700CE, "Filename or extension is too long."), + ("ERROR_FILE_NOT_FOUND", 0x80070002, "The system cannot find the file specified."), + ("ERROR_HANDLE_EOF", 0x80070026, "Reached the end of the file."), + ("ERROR_PATH_NOT_FOUND", 0x80070003, "The system cannot find the path specified."), + ("ERROR_STACK_OVERFLOW", 0x800703E9, "Stack overflow."), + ("ERROR_BAD_FORMAT", 0x8007000B, "Invalid image format."), + ("ERROR_CANCELLED", 0x800704C7, "The operation was canceled."), + ("ERROR_TIMEOUT", 0x800705B4, "This operation returned because the timeout period expired.") }; for (int i = 0; i < entries.Length; i++)