Skip to content

Commit c89c43e

Browse files
author
Maura Winstanley
committed
Update spec
1 parent fab0228 commit c89c43e

1 file changed

Lines changed: 43 additions & 42 deletions

File tree

specs/LaunchingRegisteredProtocols.md

Lines changed: 43 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
# Background
22

3-
We are exposing an event that will be raised when an attempt to launch a protocol that is registered with the OS (external protocol) is made. The host will be given the option to cancel the launch. Cancelling the launch gives the host the opportunity to hide the default dialog, display a custom dialog, and then launch the external protocol themselves.
3+
We are exposing an event that will be raised when an attempt to launch a protocol that is registered with the OS (external protocol) is made.
4+
When navigating to a URI, the URI scheme determines how to handle the URI.
5+
Some schemes like http, and https, are resolved by WebView2 and the navigation is handled in the WebView2.
6+
Other URI schemes may be registered externally to the WebView2 with the OS by other applications.
7+
Such schemes are external protocols and are handled by launching the registered application with the URI.
8+
9+
The host will be given the option to cancel the external protocol launch with the `LaunchingExternalProtocol` event.
10+
Cancelling the launch gives the host the opportunity to hide the default dialog, display a custom dialog, and then launch the external protocol themselves.
411

512
# Description
613

7-
This event will be raised before the external protocol launch occurs. When an attempt to launch an external protocol is made, the default dialog is displayed in which the user can select `Open` or `Cancel` if the host does not cancel the event. The `NavigationStarting` event will be raised before the `LaunchingExternalProtocol` event, followed by the `NavigationCompleted` event. The `SourceChanged`, `ContentLoading`, and `HistoryChanged` events will not be raised when a request is made to launch an external protocol.
14+
This event will be raised before the external protocol launch occurs.
15+
When an attempt to launch an external protocol is made, the default dialog is displayed in which the user can select `Open` or `Cancel` if the host does not cancel the event.
16+
The `NavigationStarting` event will be raised before the `LaunchingExternalProtocol` event, followed by the `NavigationCompleted` event.
17+
The `SourceChanged`, `ContentLoading`, and `HistoryChanged` events will not be raised when a request is made to launch an external protocol.
818

919
The `LaunchingExternalProtocol` event will be raised on the `CoreWebView2` interface.
1020

@@ -31,14 +41,15 @@ void RegisterLaunchingExternalProtocolHandler()
3141
{
3242
auto showDialog = [this, args]
3343
{
44+
// Set the `Cancel` property to `TRUE`, as we will either silently launch the
45+
// trusted app or display a custom dialog.
46+
args->put_Cancel(true);
3447
wil::unique_cotaskmem_string uri;
3548
CHECK_FAILURE(args->get_Uri(&uri));
3649
if (wcsicmp(uri.get(), L"calculator://") == 0)
3750
{
38-
// If this matches our desired protocol, then set the
39-
// event args to cancel the event and launch the
51+
// If this matches our desired protocol, launch the
4052
// calculator app.
41-
args->put_Cancel(true);
4253
std::wstring protocol_url = L"calculator://";
4354
SHELLEXECUTEINFO info = {sizeof(info)};
4455
info.fMask = SEE_MASK_NOASYNC;
@@ -49,16 +60,15 @@ void RegisterLaunchingExternalProtocolHandler()
4960
}
5061
else
5162
{
52-
// Otherwise use a deferral to display a custom dialog
53-
// in which the user can choose to grant permission
54-
// to launch the app and set the event args accordingly.
55-
wil::unique_cotaskmem_string initiating_uri;
56-
CHECK_FAILURE(args->get_InitiatingUri(&initiating_uri));
63+
// To display a custom dialog we cancel the launch, display
64+
// a custom dialog, and then manually launch the external protocol.
65+
wil::unique_cotaskmem_string initiating_origin;
66+
CHECK_FAILURE(args->get_InitiatingOrigin(&initiating_origin));
5767
std::wstring message = L"Launching External Protocol request";
58-
if (initiating_uri.get() == L"")
68+
if (initiating_origin.get() == L"")
5969
{
6070
message += L"from ";
61-
message += initiating_uri.get();
71+
message += initiating_origin.get();
6272
}
6373
message += L" to ";
6474
message += uri.get();
@@ -69,7 +79,6 @@ void RegisterLaunchingExternalProtocolHandler()
6979
MB_YESNOCANCEL | MB_ICONWARNING);
7080
if (response == IDYES)
7181
{
72-
args->put_Cancel(true);
7382
std::wstring protocol_url = uri.get();
7483
SHELLEXECUTEINFO info = {sizeof(info)};
7584
info.fMask = SEE_MASK_NOASYNC;
@@ -78,10 +87,6 @@ void RegisterLaunchingExternalProtocolHandler()
7887
info.nShow = SW_SHOWNORMAL;
7988
::ShellExecuteEx(&info);
8089
}
81-
else
82-
{
83-
args->put_Cancel(true);
84-
}
8590
}
8691
return S_OK;
8792
};
@@ -116,6 +121,9 @@ void RegisterLaunchingExternalProtocolHandler()
116121
{
117122
using (deferral)
118123
{
124+
// Set the `Cancel` property to `TRUE`, as we will either silently launch the
125+
// trusted app or display a custom dialog.
126+
args.Cancel = true;
119127
if (String.Equals(args.Uri, "calculator:///", StringComparison.OrdinalIgnoreCase))
120128
{
121129
// If this matches our desired protocol, then set the
@@ -127,18 +135,16 @@ void RegisterLaunchingExternalProtocolHandler()
127135
UseShellExecute = true
128136
};
129137
Process.Start(info);
130-
args.Cancel = true;
131138
}
132139
else
133140
{
134-
// Otherwise use a deferral to display a custom dialog
135-
// in which the user can choose to grant permission
136-
// to launch the app and set the event args accordingly.
141+
// To display a custom dialog we cancel the launch, display
142+
// a custom dialog, and then manually launch the external protocol.
137143
string text = "Launching External Protocol";
138-
if (args.InitiatingUri != "")
144+
if (args.InitiatingOrigin != "")
139145
{
140146
text += "from ";
141-
text += args.InitiatingUri;
147+
text += args.InitiatingOrigin;
142148
}
143149
text += " to ";
144150
text += args.Uri;
@@ -157,15 +163,12 @@ void RegisterLaunchingExternalProtocolHandler()
157163
UseShellExecute = true
158164
};
159165
Process.Start(info);
160-
args.Cancel = true;
161166
break;
162167

163168
case MessageBoxResult.No:
164-
args.Cancel = true;
165169
break;
166170

167171
case MessageBoxResult.Cancel:
168-
args.Cancel = true;
169172
break;
170173
}
171174

@@ -216,15 +219,12 @@ interface ICoreWebView2_16 : ICoreWebView2_15 {
216219
/// a checkmark box will be displayed on the default browser UI that gives the user
217220
/// the option to always allow the external protocol to launch from this origin.
218221
/// If the user checks this box, upon the next request from that origin to the
219-
/// protocol, the event will still be raised.
222+
/// protocol, the event will still be raised, but there will be no default dialog shown
223+
/// when `Cancel` is `FALSE`.
220224
///
221225
/// If the request is initiated by a cross-origin iframe without a user gesture,
222226
/// the request will be blocked and the `LaunchingExternalProtocol` event will not
223-
/// be raised.
224-
/// If the request is initiated by a browser popup window or in another case in
225-
/// which the embedded browser is null, the `LaunchingExternalProtocol` event will
226-
/// not be raised and the request will continue as normal and display the default browser
227-
/// UI dialog to the user.
227+
/// be raised.
228228
/// \snippet SettingsComponent.cpp LaunchingExternalProtocol
229229
HRESULT add_LaunchingExternalProtocol(
230230
[in] ICoreWebView2LaunchingExternalProtocolEventHandler* eventHandler,
@@ -248,41 +248,42 @@ interface ICoreWebView2LaunchingExternalProtocolEventHandler: IUnknown {
248248
/// Event args for `LaunchingExternalProtocol` event.
249249
[uuid(fc43b557-9713-4a67-af8d-a76ef3a206e8), object, pointer_default(unique)]
250250
interface ICoreWebView2LaunchingExternalProtocolEventArgs: IUnknown {
251-
/// The URI of the requested external protocol.
251+
/// The URI with the external protocol to be launched.
252252
253-
[propget] HRESULT Uri([out, retval] LPWSTR* uri);
253+
[propget] HRESULT Uri([out, retval] LPWSTR* value);
254254
255255
/// The origin initiating the external protocol launch.
256-
/// The origin will be empty if the WebView2 navigates to the external protocol.
256+
/// The origin will be empty if the WebView2 navigated to the external protocol.
257257
258-
[propget] HRESULT InitiatingOrigin([out, retval] LPWSTR* uri);
258+
[propget] HRESULT InitiatingOrigin([out, retval] LPWSTR* value);
259259
260260
/// `TRUE` when the external protocol request was initiated through a user gesture.
261261
///
262262
/// \> [!NOTE]\n\> Being initiated through a user gesture does not mean that user intended
263263
/// to access the associated resource.
264264
265-
[propget] HRESULT IsUserInitiated([out, retval] BOOL* isUserInitiated);
265+
[propget] HRESULT IsUserInitiated([out, retval] BOOL* value);
266266
267267
/// `TRUE` when the external protocol request was initiated via a non-main frame that
268268
/// has a different origin then the owning top-level page.
269269
270-
[propget] HRESULT IsCrossOriginIframe([out, retval] BOOL* isCrossOriginIframe);
270+
[propget] HRESULT IsCrossOriginIframe([out, retval] BOOL* value);
271271
272272
/// The host may set this flag to cancel the external protocol launch. If set to
273273
/// `TRUE`, the external protocol will not be launched, and the default
274-
/// dialog is not displayed.
274+
/// dialog is not displayed. This property can be used to replace the normal
275+
/// handling of launching external protocols.
275276
276-
[propget] HRESULT Cancel([out, retval] BOOL* cancel);
277+
[propget] HRESULT Cancel([out, retval] BOOL* value);
277278
278279
/// Sets the `Cancel` property. The default value is `FALSE`.
279280
280-
[propput] HRESULT Cancel([in] BOOL cancel);
281+
[propput] HRESULT Cancel([in] BOOL value);
281282
282283
/// Returns an `ICoreWebView2Deferral` object. Use this operation to
283284
/// complete the event at a later time.
284285
285-
HRESULT GetDeferral([out, retval] ICoreWebView2Deferral** deferral);
286+
HRESULT GetDeferral([out, retval] ICoreWebView2Deferral** value);
286287
}
287288
288289
```

0 commit comments

Comments
 (0)