|
| 1 | +# Background |
| 2 | +Since the current ExecuteStrip interface is a little shabby, it is necessary |
| 3 | +to provide a new interface to let the user get more infomation, and easier to use. |
| 4 | +The new interface will provide the exception infomation if the script execute |
| 5 | +failed, and provide a new method to try to get the string to resolve the problem |
| 6 | +that the old interface is not friendly to the string return type. |
| 7 | + |
| 8 | +In this document we describe the updated API. We'd appreciate your feedback. |
| 9 | + |
| 10 | +# Description |
| 11 | +We propose extending `CoreWebView2` to provide an `ExecuteScriptWithResult` |
| 12 | +method. The method will return a struct to manage the execute result, which can |
| 13 | +get the raw result and string if execute success, and can get exception when |
| 14 | +execute failed. |
| 15 | + |
| 16 | +# Examples |
| 17 | +The following code snippets demonstrate how the ExecuteScriptWithResult can be used: |
| 18 | +## Win32 C++ |
| 19 | +``` cpp |
| 20 | +void ScriptComponent::ExecuteScriptWithResult(LPCWSTR script) |
| 21 | +{ |
| 22 | + wil::com_ptr<ICoreWebView2Staging2> webview2 = |
| 23 | + m_webView.try_query<ICoreWebView2Staging2>(); |
| 24 | + |
| 25 | + // The main interface for excute script, the first param is the string |
| 26 | + // which user want to execute, the second param is the callback to process |
| 27 | + // the result, here use a lamada to the param. |
| 28 | + webview2->ExecuteScriptWithResult( |
| 29 | + script, |
| 30 | + // The callback function has two param, the first one is the status of call. |
| 31 | + // it will always be the S_OK for now, and the second is the result struct. |
| 32 | + Callback<ICoreWebView2StagingExecuteScriptWithResultCompletedHandler>( |
| 33 | + [this]( |
| 34 | + HRESULT errorCode |
| 35 | + ICoreWebView2StagingExecuteScriptResult* result) -> HRESULT |
| 36 | + { |
| 37 | + if (errorCode != S_OK || result == nullptr) |
| 38 | + { |
| 39 | + MessageBox(nullptr, L"Call interface failed!", L"ExecuteScript Result", MB_OK); |
| 40 | + return S_OK; |
| 41 | + } |
| 42 | + else |
| 43 | + { |
| 44 | + wil::com_ptr<ICoreWebView2StagingExecuteScriptException> exception; |
| 45 | + BOOL is_success; |
| 46 | + |
| 47 | + // User should always invoke the get_IsSuccess firstly to get the execution status. |
| 48 | + if (result->get_IsSuccess(&is_success) != S_OK) |
| 49 | + { |
| 50 | + MessageBox(nullptr, L"Get execute status failed!", L"ExecuteScript Result", MB_OK); |
| 51 | + return S_OK; |
| 52 | + } |
| 53 | + |
| 54 | + // If execute success, then we can get the raw json data, and try to get the string. |
| 55 | + if (is_success) |
| 56 | + { |
| 57 | + wil::unique_cotaskmem_string rawJsonData; |
| 58 | + // Get the raw json. |
| 59 | + if (result->get_ResultAsJson(&rawJsonData) == S_OK) |
| 60 | + { |
| 61 | + MessageBox( |
| 62 | + nullptr, rawJsonData.get(), L"ExecuteScript Result", MB_OK); |
| 63 | + } |
| 64 | + else |
| 65 | + { |
| 66 | + MessageBox( |
| 67 | + nullptr, L"Get raw json data failed", L"ExecuteScript Result", MB_OK); |
| 68 | + } |
| 69 | + |
| 70 | + // Get the string, and if the result is not the string type, |
| 71 | + // it will return the E_INVALIDARG. |
| 72 | + wil::unique_cotaskmem_string stringData; |
| 73 | + if (result->TryGetResultAsString(&stringData) == S_OK) { |
| 74 | + MessageBox( |
| 75 | + nullptr, stringData.get(), L"ExecuteScript Result", MB_OK); |
| 76 | + } |
| 77 | + else |
| 78 | + { |
| 79 | + MessageBox( |
| 80 | + nullptr, L"Get string failed", L"ExecuteScript Result", MB_OK); |
| 81 | + } |
| 82 | + } |
| 83 | + else // If execute failed, then we can get the exception struct to get the reason of failed. |
| 84 | + { |
| 85 | + if (result->get_Exception(&exception) == S_OK) |
| 86 | + { |
| 87 | + // Get the exception name, this could return the empty string, such as `throw 1`. |
| 88 | + wil::unique_cotaskmem_string exceptionName; |
| 89 | + if (exception && exception->get_Name(&exceptionName) == S_OK) |
| 90 | + { |
| 91 | + MessageBox( |
| 92 | + nullptr, exceptionName.get(), L"ExecuteScript Result", MB_OK); |
| 93 | + } |
| 94 | + |
| 95 | + // Get the exception message, this could return the empty string, such as `throw 1`. |
| 96 | + wil::unique_cotaskmem_string exceptionMessage; |
| 97 | + if (exception && exception->get_Message(&exceptionMessage) == S_OK) |
| 98 | + { |
| 99 | + MessageBox( |
| 100 | + nullptr, exceptionMessage.get(), L"ExecuteScript Result", MB_OK); |
| 101 | + } |
| 102 | + |
| 103 | + // Get the exception detail, it's a json struct data with all exception infomation |
| 104 | + // , we can parse it and get the detail what we need. |
| 105 | + wil::unique_cotaskmem_string exceptionDetail; |
| 106 | + if (exception && exception->get_Detail(&exceptionDetail) == S_OK) |
| 107 | + { |
| 108 | + MessageBox( |
| 109 | + nullptr, exceptionDetail.get(), L"ExecuteScript Result", MB_OK); |
| 110 | + } |
| 111 | + } |
| 112 | + else |
| 113 | + { |
| 114 | + MessageBox( |
| 115 | + nullptr, L"Get exception failed", L"ExecuteScript Result", MB_OK); |
| 116 | + } |
| 117 | + } |
| 118 | + |
| 119 | + } |
| 120 | + } |
| 121 | + ) |
| 122 | + ) |
| 123 | +} |
| 124 | + |
| 125 | +``` |
| 126 | +## .NET and WinRT |
| 127 | + |
| 128 | +```c# |
| 129 | +void ExecuteScriptWithResultAsync(String script) |
| 130 | +{ |
| 131 | + var environment = webView2Control.CoreWebView2.Environment; |
| 132 | + CoreWebView2ExecuteScriptResult result = await ExecuteScriptWithResultAsync(script); |
| 133 | + |
| 134 | + bool isSuccess = result.IsSuccess; |
| 135 | + if (isSuccess) |
| 136 | + { |
| 137 | + Debug.WriteLine($"execute script success."); |
| 138 | + |
| 139 | + Debug.WriteLine($"json result received: {result.ResultAsJson}"); |
| 140 | + try |
| 141 | + { |
| 142 | + string stringResult = result.TryGetResultAsString(); |
| 143 | + Debug.WriteLine($"get string result success: {stringResult}"); |
| 144 | + } |
| 145 | + catch (ArgumentException) |
| 146 | + { |
| 147 | + Debug.WriteLine($"Non-string message received"); |
| 148 | + } |
| 149 | + } |
| 150 | + else |
| 151 | + { |
| 152 | + Debug.WriteLine($"execute script failed."); |
| 153 | + CoreWebView2ExecuteScriptException exception = result.Exception; |
| 154 | + Debug.WriteLine($"exception name: {exception.Name}"); |
| 155 | + Debug.WriteLine($"exception message: {exception.Message}"); |
| 156 | + Debug.WriteLine($"exception Detail: {exception.Detail}"); |
| 157 | + } |
| 158 | +} |
| 159 | +``` |
| 160 | + |
| 161 | +# API Details |
| 162 | +## Win32 C++ |
| 163 | +```c++ |
| 164 | +/// This is the exception struct when ExecuteScriptWithResult return false, user can |
| 165 | +/// use get_Exception to get it. |
| 166 | +[uuid(82F22B72-1B22-403E-A0B9-A8816C9C8E45), object, pointer_default(unique)] |
| 167 | +interface ICoreWebView2StagingExecuteScriptException : IUnknown { |
| 168 | + |
| 169 | + /// This will return the exception className, it would be got from the |
| 170 | + /// `result.exceptionDetail.exception.className` in json result, this |
| 171 | + /// could be empty if the exception doesn't have the specified element, |
| 172 | + /// such as user active throw an exception like `throw "abc"`. |
| 173 | + [propget] HRESULT Name([out, retval] LPWSTR* value); |
| 174 | + |
| 175 | + /// This will return the exception message, it would be got from the |
| 176 | + /// `result.exceptionDetail.exception.description` in json result, this |
| 177 | + /// could be empty if the exception doesn't have the specified element, |
| 178 | + /// such as user active throw an exception like `throw "abc"`. |
| 179 | + [propget] HRESULT Message([out, retval] LPWSTR* value); |
| 180 | + |
| 181 | + /// This will return the exception detail, it's a json struct with complete information for |
| 182 | + /// exception, if get_Name and get_Exception is not enough, user can use this interface and |
| 183 | + /// get what they want. |
| 184 | + [propget] HRESULT Detail([out, retval] LPWSTR* detail); |
| 185 | +} |
| 186 | + |
| 187 | +/// This is the result for ExecuteScriptWithResult. |
| 188 | +[uuid(D2C59C5C-AD36-4CF4-87CF-2F5359F6D4CB), object, pointer_default(unique)] |
| 189 | +interface ICoreWebView2StagingExecuteScriptResult : IUnknown { |
| 190 | + |
| 191 | + /// This property is true if ExecuteScriptWithResult successfully executed script with |
| 192 | + /// no unhandled exceptions and the result is available in the ResultAsJson property |
| 193 | + /// or via the TryGetResultAsString method. |
| 194 | + /// If it is false then the script execution had an unhandled exception which you |
| 195 | + /// can get via the Exception property. |
| 196 | + [propget] HRESULT IsSuccess([out, retval] BOOL* value); |
| 197 | + |
| 198 | + /// If IsSuccess return true, then this interface will return the raw json data for user |
| 199 | + /// var the jsonResult, otherwise return E_INVALIDARG. |
| 200 | + [propget] HRESULT ResultAsJson([out, retval] LPWSTR* jsonResult); |
| 201 | + |
| 202 | + /// If IsSuccess return true, this interface can let user try to get string result when |
| 203 | + /// the result type is string, otherwise return E_INVALIDARG. |
| 204 | + HRESULT TryGetResultAsString([out, retval] LPWSTR* stringResult); |
| 205 | + |
| 206 | + /// If IsSuccess return failed, user can use this interface to get exception to handle, |
| 207 | + /// otherwise return E_INVALIDARG. |
| 208 | + [propget] HRESULT Exception( |
| 209 | + [out, retval] ICoreWebView2StagingExecuteScriptException** exception); |
| 210 | +} |
| 211 | + |
| 212 | +/// This is the callback for ExecuteScriptWithResult |
| 213 | +[uuid(CECDD25B-E6E8-4A4E-B890-BBF95932564F), object, pointer_default(unique)] |
| 214 | +interface ICoreWebView2StagingExecuteScriptWithResultCompletedHandler : IUnknown { |
| 215 | + |
| 216 | + /// Provides the event args for the execute result. |
| 217 | + HRESULT Invoke( |
| 218 | + [in] HRESULT errorCode, |
| 219 | + [in] ICoreWebView2StagingExecuteScriptResult* result); |
| 220 | +} |
| 221 | + |
| 222 | +/// This is the interface for getting string and exception with ExecuteScriptWithResult |
| 223 | +[uuid(67E0B57B-1AC7-4395-9793-5E4EF9C4B7D9), object, pointer_default(unique)] |
| 224 | +interface ICoreWebView2Staging2 : IUnknown { |
| 225 | + |
| 226 | + /// New execute javascript for user can get the string result and can get exception |
| 227 | + /// if execution fails. |
| 228 | + HRESULT ExecuteScriptWithResult( |
| 229 | + [in] LPCWSTR javaScript, |
| 230 | + [in] ICoreWebView2StagingExecuteScriptWithResultCompletedHandler* handler); |
| 231 | +} |
| 232 | +``` |
| 233 | + |
| 234 | +## .NET and WinRT |
| 235 | +```c# |
| 236 | +namespace Microsoft.Web.WebView2.Core |
| 237 | +{ |
| 238 | + runtimeclass CoreWebView2; |
| 239 | + runtimeclass CoreWebView2ExecuteScriptResult; |
| 240 | + runtimeclass CoreWebView2ExecuteScriptException; |
| 241 | + |
| 242 | + runtimeclass CoreWebView2 |
| 243 | + { |
| 244 | + Windows.Foundation.IAsyncOperation<CoreWebView2ExecuteScriptResult> |
| 245 | + ExecuteScriptWithResultAsync(String javaScript); |
| 246 | + } |
| 247 | + |
| 248 | + runtimeclass CoreWebView2ExecuteScriptResult |
| 249 | + { |
| 250 | + bool IsSuccess { get; }; |
| 251 | + |
| 252 | + String ResultAsJson { get; }; |
| 253 | + |
| 254 | + String TryGetResultAsString(); |
| 255 | + } |
| 256 | + |
| 257 | + runtimeclass CoreWebView2ExecuteScriptException |
| 258 | + { |
| 259 | + String Name { get; }; |
| 260 | + |
| 261 | + String Message { get; }; |
| 262 | + |
| 263 | + String Detail { get; }; |
| 264 | + } |
| 265 | +} |
| 266 | +``` |
| 267 | + |
| 268 | + |
0 commit comments