|
| 1 | +# Background |
| 2 | + |
| 3 | + |
| 4 | +# Description |
| 5 | + |
| 6 | + |
| 7 | +# Examples |
| 8 | +## C++: Regestering IFrame Permission Requested Handler |
| 9 | + |
| 10 | +``` cpp |
| 11 | +wil::com_ptr<ICoreWebView2> m_webview; |
| 12 | + |
| 13 | +EventRegistrationToken m_frameCreatedToken = {}; |
| 14 | +EventRegistrationToken m_permissionRequestedToken = {}; |
| 15 | + |
| 16 | +void RegisterIFramePermissionRequestedHandler() |
| 17 | +{ |
| 18 | + webview4 = m_webview.try_query<ICoreWebView2_4>(); |
| 19 | + if (webview4) |
| 20 | + { |
| 21 | + CHECK_FAILURE(webview4->add_FrameCreated( |
| 22 | + Callback<ICoreWebView2FrameCreatedEventHandler>( |
| 23 | + [this](ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args) -> HRESULT { |
| 24 | + wil::com_ptr<ICoreWebView2Frame> webviewFrame; |
| 25 | + CHECK_FAILURE(args->get_Frame(&webviewFrame)); |
| 26 | + |
| 27 | + auto webviewFrame2 = webviewFrame.try_query<ICoreWebView2Frame2>(); |
| 28 | + if (webviewFrame2) |
| 29 | + { |
| 30 | + CHECK_FAILURE(webviewFrame2->add_PermissionRequested( |
| 31 | + Callback<ICoreWebView2FramePermissionRequestedEventHandler>( |
| 32 | + [this](ICoreWebView2Frame* sender, |
| 33 | + ICoreWebView2PermissionRequestedEventArgs* args) -> HRESULT { |
| 34 | + COREWEBVIEW2_PERMISSION_KIND kind = |
| 35 | + COREWEBVIEW2_PERMISSION_KIND_UNKNOWN_PERMISSION; |
| 36 | + BOOL userInitiated = FALSE; |
| 37 | + wil::unique_cotaskmem_string uri; |
| 38 | + |
| 39 | + CHECK_FAILURE(args->get_PermissionKind(&kind)); |
| 40 | + CHECK_FAILURE(args->get_IsUserInitiated(&userInitiated)); |
| 41 | + CHECK_FAILURE(args->get_Uri(&uri)); |
| 42 | + |
| 43 | + auto cached_key = std::tuple< |
| 44 | + std::wstring, COREWEBVIEW2_PERMISSION_KIND, BOOL>( |
| 45 | + std::wstring(uri.get()), kind, userInitiated); |
| 46 | + |
| 47 | + auto cached_permission = |
| 48 | + m_cached_permissions.find(cached_key); |
| 49 | + if (cached_permission != m_cached_permissions.end()) |
| 50 | + { |
| 51 | + bool allow = cached_permission->second; |
| 52 | + if (allow) |
| 53 | + { |
| 54 | + CHECK_FAILURE(args->put_State( |
| 55 | + COREWEBVIEW2_PERMISSION_STATE_ALLOW)); |
| 56 | + } |
| 57 | + else |
| 58 | + { |
| 59 | + CHECK_FAILURE(args->put_State( |
| 60 | + COREWEBVIEW2_PERMISSION_STATE_DENY)); |
| 61 | + } |
| 62 | + |
| 63 | + PutHandled(args); |
| 64 | + return S_OK; |
| 65 | + } |
| 66 | + |
| 67 | + std::wstring message = |
| 68 | + L"An iframe has requested device permission for "; |
| 69 | + message += SettingsComponent::NameOfPermissionKind(kind); |
| 70 | + message += L" to the website at "; |
| 71 | + message += uri.get(); |
| 72 | + message += L"?\n\n"; |
| 73 | + message += L"Do you want to grant permission?\n"; |
| 74 | + message += |
| 75 | + (userInitiated |
| 76 | + ? L"This request came from a user gesture." |
| 77 | + : L"This request did not come from a user " |
| 78 | + L"gesture."); |
| 79 | + |
| 80 | + int response = MessageBox( |
| 81 | + nullptr, message.c_str(), L"Permission Request", |
| 82 | + MB_YESNOCANCEL | MB_ICONWARNING); |
| 83 | + |
| 84 | + |
| 85 | + COREWEBVIEW2_PERMISSION_STATE state = |
| 86 | + COREWEBVIEW2_PERMISSION_STATE_DEFAULT; |
| 87 | + |
| 88 | + if (response == IDYES) |
| 89 | + { |
| 90 | + m_cached_permissions[cached_key] = true; |
| 91 | + state = COREWEBVIEW2_PERMISSION_STATE_ALLOW; |
| 92 | + } |
| 93 | + else if (response == IDNO) |
| 94 | + { |
| 95 | + m_cached_permissions[cached_key] = false; |
| 96 | + state = COREWEBVIEW2_PERMISSION_STATE_DENY; |
| 97 | + } |
| 98 | + |
| 99 | + CHECK_FAILURE(args->put_State(state)); |
| 100 | + |
| 101 | + PutHandled(args); |
| 102 | + return S_OK; |
| 103 | + }).Get(), |
| 104 | + &m_PermissionRequestedToken)); |
| 105 | + } |
| 106 | + |
| 107 | + return S_OK; |
| 108 | + }).Get(), |
| 109 | + &m_FrameCreatedToken)); |
| 110 | + } |
| 111 | +} |
| 112 | + |
| 113 | +static PCWSTR NameOfPermissionKind(COREWEBVIEW2_PERMISSION_KIND kind) |
| 114 | +{ |
| 115 | + switch (kind) |
| 116 | + { |
| 117 | + case COREWEBVIEW2_PERMISSION_KIND_MICROPHONE: |
| 118 | + return L"Microphone"; |
| 119 | + case COREWEBVIEW2_PERMISSION_KIND_CAMERA: |
| 120 | + return L"Camera"; |
| 121 | + case COREWEBVIEW2_PERMISSION_KIND_GEOLOCATION: |
| 122 | + return L"Geolocation"; |
| 123 | + case COREWEBVIEW2_PERMISSION_KIND_NOTIFICATIONS: |
| 124 | + return L"Notifications"; |
| 125 | + case COREWEBVIEW2_PERMISSION_KIND_OTHER_SENSORS: |
| 126 | + return L"Generic Sensors"; |
| 127 | + case COREWEBVIEW2_PERMISSION_KIND_CLIPBOARD_READ: |
| 128 | + return L"Clipboard Read"; |
| 129 | + default: |
| 130 | + return L"Unknown resources"; |
| 131 | + } |
| 132 | +} |
| 133 | + |
| 134 | +static void PutHandled(ICoreWebView2PermissionRequestedEventArgs* args) |
| 135 | +{ |
| 136 | + // In the case of an iframe requesting permission, the default behavior is |
| 137 | + // to first raise the PermissionRequested event off of the CoreWebView2Frame |
| 138 | + // and invoke it's handlers, and then raise the event off the CoreWebView2 |
| 139 | + // and invoke it's handlers. However, If we set Handled to true on the |
| 140 | + // CoreWebView2Frame event handler, then we will not raise the |
| 141 | + // PermissionRequested event off the CoreWebView2. |
| 142 | + wil::com_ptr<ICoreWebView2PermissionRequestedEventArgs2> args2; |
| 143 | + CHECK_FAILURE(args->QueryInterface(IID_PPV_ARGS(&args2))); |
| 144 | + if (args2) { |
| 145 | + CHECK_FAILURE(args2->put_Handled(true)); |
| 146 | + } |
| 147 | +} |
| 148 | +``` |
| 149 | +
|
| 150 | +## C#: TBD |
| 151 | +```c# |
| 152 | +
|
| 153 | +``` |
| 154 | + |
| 155 | +# API Details |
| 156 | +## C++ |
| 157 | +``` |
| 158 | +interface ICoreWebView2Frame2; |
| 159 | +interface ICoreWebView2FramePermissionRequestedEventHandler; |
| 160 | +interface ICoreWebView2FramePermissionRequestedEventArgs2; |
| 161 | +
|
| 162 | +/// This is an extension of the ICoreWebView2Frame interface. |
| 163 | +[uuid(3ed01620-13fc-4c2c-9eb9-62fccd689093), object, pointer_default(unique)] |
| 164 | +interface ICoreWebView2Frame2 : ICoreWebView2Frame { |
| 165 | + /// Add an event handler for the `PermissionRequested` event. |
| 166 | + /// `PermissionRequested` is raised when content in an iframe requests |
| 167 | + /// permission to access some priveleged resources. |
| 168 | + /// |
| 169 | + /// This relates to the `PermissionRequested` event on the `CoreWebView2`. |
| 170 | + /// Both these events will be raised in the case of an iframe requesting |
| 171 | + /// permission. The `CoreWebView2Frame`'s event handlers will be invoked |
| 172 | + /// before the event handlers on the `CoreWebView2`. If the `Handled` property |
| 173 | + /// of the `PermissionRequestedEventArgs` is set to TRUE within the |
| 174 | + /// `CoreWebView2Frame` event handler, then the event will not be |
| 175 | + /// raised on the `CoreWebView2`, and it's event handlers will not be invoked. |
| 176 | + /// |
| 177 | + /// In the case of nested iframes, the 'PermissionRequested' event will |
| 178 | + /// be raised from the top level iframe. |
| 179 | + /// |
| 180 | + /// If a deferral is not taken on the event args, the subsequent scripts are |
| 181 | + /// blocked until the event handler returns. If a deferral is taken, the |
| 182 | + /// scripts are blocked until the deferral is completed. |
| 183 | + /// |
| 184 | + /// \snippet ScenarioIFrameDevicePermission.cpp PermissionRequested |
| 185 | + HRESULT add_PermissionRequested( |
| 186 | + [in] ICoreWebView2FramePermissionRequestedEventHandler* handler, |
| 187 | + [out] EventRegistrationToken* token); |
| 188 | +
|
| 189 | + /// Remove an event handler previously added with `add_PermissionRequested` |
| 190 | + HRESULT remove_PermissionRequested( |
| 191 | + [in] EventRegistrationToken token); |
| 192 | +} |
| 193 | +
|
| 194 | +/// Receives `PermissionRequested` events. |
| 195 | +[uuid(603ea097-c805-43fb-aa35-80949c1e4b26), object, pointer_default(unique)] |
| 196 | +interface ICoreWebView2FramePermissionRequestedEventHandler : IUnknown { |
| 197 | + /// Provides the event args for the corresponding event. |
| 198 | + HRESULT Invoke( |
| 199 | + [in] ICoreWebView2Frame* sender, |
| 200 | + [in] ICoreWebView2PermissionRequestedEventArgs* args); |
| 201 | +} |
| 202 | +
|
| 203 | +/// This is a continuation of the `ICoreWebView2PermissionRequestedEventArgs` interface. |
| 204 | +[uuid(d52ce9b5-c603-4c33-9887-c06c77b54b3c), object, pointer_default(unique)] |
| 205 | +interface ICoreWebView2PermissionRequestedEventArgs2: ICoreWebView2PermissionRequestedEventArgs { |
| 206 | + /// By default, both the `PermissionRequested` event handlers on the |
| 207 | + /// `CoreWebView2Frame' and the `CoreWebView2` will be invoked, with the |
| 208 | + /// `CoreWebView2Frame' event handlers invoked first. The host may |
| 209 | + /// set this flag to `TRUE` within the `CoreWebView2Frame' event handlers |
| 210 | + /// to prevent the remaining `CoreWebView2` event handlers from being invoked. |
| 211 | + [propget] HRESULT Handled([out, retval] BOOL* handled); |
| 212 | +
|
| 213 | + /// Sets the `Handled` property. |
| 214 | + [propput] HRESULT Handled([in] BOOL handled); |
| 215 | +} |
| 216 | +``` |
| 217 | + |
| 218 | +## C# |
| 219 | +```c# |
| 220 | + |
| 221 | +``` |
0 commit comments