Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Customize ERROR_INVALID_WINDOW_HANDLE exception text to make window interop helpers discoverable #941

Merged
merged 5 commits into from
Jul 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion docs/interop.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,28 @@ SetString(MarshalString.GetAbi(marshalStr));
```

#### Interop Interfaces
The CLR still supports marshaling COM (IUnknown), but not WinRT (IInspectable), interop interfaces. The Windows SDK projection provides definitions for several COM interop interfaces, including ***Windows.Storage.Streams.IBufferByteAccess***, ***WinRT.Interop.IWindowNative***, and ***WinRT.Interop.IInitializeWithWindow***. The Windows SDK projection also provides wrappers for all WinRT interop interfaces included in the Universal API Contract, such as ***Windows.Security.Credentials.UI.UserConsentVerifierInterop***. For custom or extension SDK interop interfaces, C#/WinRT supports two marshaling techniques.
The CLR still supports marshaling COM (IUnknown), but not WinRT (IInspectable), interop interfaces. The Windows SDK projection provides several interop interface helpers for common scenarios. For custom or extension SDK interop interfaces, C#/WinRT supports two marshaling techniques.

##### Windows SDK

The Windows SDK projection provides wrappers for common COM interop interfaces, such as ***Windows.Storage.Streams.IBufferByteAccess***, ***WinRT.Interop.IWindowNative***, and ***WinRT.Interop.IInitializeWithWindow***.

The following sample demonstrates creating a folder picker with an owning window:

```csharp
var window = new Microsoft.UI.Xaml.Window();
// ...
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(window);
var folderPicker = new Windows.Storage.Pickers.FolderPicker();
folderPicker.FileTypeFilter.Add("*");
WinRT.Interop.InitializeWithWindow.Initialize(folderPicker, hwnd);
var folder = await folderPicker.PickSingleFolderAsync();
```

The Windows SDK projection also provides wrappers for all WinRT interop interfaces included in the Universal API Contract, such as ***Windows.Security.Credentials.UI.UserConsentVerifierInterop***

For more info, see:
[Call WinRT COM interop interfaces from .NET 5+ apps](https://docs.microsoft.com/en-us/windows/apps/desktop/modernize/winrt-com-interop-csharp)

##### Projected
If possible, the interop interface should be defined in IDL and a C#/WinRT projection produced for it. This automatically generates all marshaling logic so that calling code can pass and receive projected types. This definition of `IUserConsentVerifierInterop` from one of our test components is an example of this:
Expand Down
8 changes: 8 additions & 0 deletions src/WinRT.Runtime/ExceptionHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public static class ExceptionHelpers
internal const int E_LAYOUTCYCLE = unchecked((int)0x802B0014);
internal const int E_ELEMENTNOTENABLED = unchecked((int)0x802B001E);
internal const int E_ELEMENTNOTAVAILABLE = unchecked((int)0x802B001F);
internal const int ERROR_INVALID_WINDOW_HANDLE = unchecked((int)0x80070578);

[DllImport("oleaut32.dll")]
private static extern int SetErrorInfo(uint dwReserved, IntPtr perrinfo);
Expand Down Expand Up @@ -154,6 +155,13 @@ private static Exception GetExceptionForHR(int hr, bool useGlobalErrorState, out
case E_ELEMENTNOTENABLED:
ex = new Microsoft.UI.Xaml.Automation.ElementNotEnabledException();
break;
case ERROR_INVALID_WINDOW_HANDLE:
ex = new System.Runtime.InteropServices.COMException(
@"Invalid window handle. (0x80070578)
Consider WindowNative, InitializeWithWindow
See https://aka.ms/cswinrt/interop#windows-sdk",
ERROR_INVALID_WINDOW_HANDLE);
break;
default:
ex = Marshal.GetExceptionForHR(hr, iErrorInfo?.ThisPtr ?? (IntPtr)(-1));
break;
Expand Down