@@ -28,8 +28,8 @@ Besides using the memory address directly, the shared buffer object can be acces
28
28
from native side via an IStream* object that you can get from the shared buffer object.
29
29
30
30
When the application code calls ` PostSharedBufferToScript ` , the script side will
31
- receive a ` SharedBufferReceived ` event containing the buffer as an ` ArrayBuffer ` object.
32
- After receiving the shared buffer object , it can access it the same way as any other
31
+ receive a ` sharedbufferreceived ` event that you can get from it the buffer as an ` ArrayBuffer ` object.
32
+ After getting the shared buffer, it can access it the same way as any other
33
33
ArrayBuffer object, including transferring to a web worker to process the data on
34
34
the worker thread.
35
35
@@ -60,10 +60,10 @@ The script code will look like this:
60
60
61
61
function SharedBufferReceived(e) {
62
62
if (e.additionalData && e.additionalData.contosoBufferKind == "contosoDisplayBuffer") {
63
- let displayBuffer = e.getBuffer() ;
63
+ let displayBuffer = e.buffer ;
64
64
// Consume the data from the buffer (in the form of an ArrayBuffer)
65
- let view = new UInt32Array (displayBuffer);
66
- DisplaySharedBufferData(view );
65
+ let displayBufferArray = new Uint8Array (displayBuffer);
66
+ DisplaySharedBufferData(displayBufferArray );
67
67
// Release the buffer after consuming the data.
68
68
chrome.webview.releaseBuffer(displayBuffer);
69
69
}
@@ -73,50 +73,211 @@ The script code will look like this:
73
73
``` cpp
74
74
75
75
wil::com_ptr<ICoreWebView2SharedBuffer> sharedBuffer;
76
- CHECK_FAILURE (webviewEnvironment ->CreateSharedBuffer(bufferSize , &sharedBuffer));
77
- // Fill data into the shared memory via IStream.
78
- wil::com_ptr< IStream > stream ;
79
- CHECK_FAILURE(sharedBuffer->OpenStream(&stream));
80
- CHECK_FAILURE(stream->Write(data , dataSize, nullptr) );
76
+ CHECK_FAILURE (m_webviewEnvironment ->CreateSharedBuffer(dataSize , &sharedBuffer));
77
+ BYTE * buffer;
78
+ CHECK_FAILURE(sharedBuffer->get_Buffer(&buffer)) ;
79
+ // Fill buffer with data.
80
+ memcpy_s(buffer , dataSize, data, dataSize );
81
81
PCWSTR additionalDataAsJson = L"{\" contosoBufferKind\" :\" contosoDisplayBuffer\" }";
82
- if (forFrame)
83
- {
84
- m_webviewFrame->PostSharedBufferToScript(
85
- sharedBuffer.get(), COREWEBVIEW2_SHARED_BUFFER_ACCESS_READ_ONLY, additionalDataAsJson);
86
- }
87
- else
88
- {
89
- m_webView->PostSharedBufferToScript(
90
- sharedBuffer.get(), COREWEBVIEW2_SHARED_BUFFER_ACCESS_READ_ONLY, additionalDataAsJson);
91
- }
92
- // Explicitly close the one time shared buffer to ensure that the resource is released timely.
82
+ m_webView->PostSharedBufferToScript(
83
+ sharedBuffer.get(), COREWEBVIEW2_SHARED_BUFFER_ACCESS_READ_ONLY, additionalDataAsJson);
84
+
85
+ // The buffer automatically releases any resources if all references to it are released.
86
+ // As we are doing here, you could also explicitly close it when you don't access the buffer
87
+ // any more.to ensure that the resource is released timely even if there are some reference got leaked.
93
88
sharedBuffer->Close();
94
89
95
90
```
96
- ## WinRT and .NET
91
+ ## .NET
97
92
```c#
98
- using (CoreWebView2SharedBuffer sharedBuffer = WebViewEnvironment.CreateSharedBuffer(bufferSize ))
93
+ using (CoreWebView2SharedBuffer sharedBuffer = WebViewEnvironment.CreateSharedBuffer(dataSize ))
99
94
{
100
- // Fill data using access Stream
101
- using (Stream stream = sharedBuffer.OpenStream())
95
+ // Fill buffer with data.
96
+ unsafe
102
97
{
103
- using (StreamWriter writer = new StreamWriter(stream))
104
- {
105
- writer.Write(data);
98
+ byte* buffer = (byte*)(sharedBuffer.Buffer.ToPointer());
99
+ ulong dataToCopy = dataSize;
100
+ while (dataToCopy-- > 0) {
101
+ *buffer++ = *data++;
106
102
}
107
- }
103
+ }
108
104
string additionalDataAsJson = "{\"contosoBufferKind\":\"contosoDisplayBuffer\"}";
109
- if (forFrame)
110
- {
111
- m_webviewFrame.PostSharedBufferToScript(sharedBuffer, CoreWebView2SharedBufferAccess.ReadOnly, additionalDataAsJson);
112
- }
113
- else
105
+ m_webview.PostSharedBufferToScript(sharedBuffer, CoreWebView2SharedBufferAccess.ReadOnly, additionalDataAsJson);
106
+ }
107
+ ```
108
+ ## WinRT
109
+ ``` c#
110
+ using (CoreWebView2SharedBuffer sharedBuffer = WebViewEnvironment .CreateSharedBuffer (dataSize ))
111
+ {
112
+ // Fill buffer with data.
113
+ unsafe
114
114
{
115
- m_webview.PostSharedBufferToScript(sharedBuffer, CoreWebView2SharedBufferAccess.ReadOnly, additionalDataAsJson);
116
- }
115
+ using (IMemoryBufferReference reference = sharedBuffer .Buffer )
116
+ {
117
+ byte * buffer ;
118
+ uint capacity ;
119
+ ((IMemoryBufferByteAccess )reference ).GetBuffer (out buffer , out capacity );
120
+ byte * buffer = (byte * )(sharedBuffer .Buffer .ToPointer ());
121
+ ulong dataToCopy = dataSize ;
122
+ while (dataToCopy -- > 0 ) {
123
+ * buffer ++ = * data ++ ;
124
+ }
125
+ }
126
+ }
127
+ string additionalDataAsJson = " {\" contosoBufferKind\" :\" contosoDisplayBuffer\" }" ;
128
+ m_webview .PostSharedBufferToScript (sharedBuffer , CoreWebView2SharedBufferAccess .ReadOnly , additionalDataAsJson );
117
129
}
118
130
```
119
131
132
+ The example below illustrates how to use a shared buffer to send data from application to script in an iframe multiple times.
133
+
134
+ The script code will look like this:
135
+ ```
136
+ let displayBuffer;
137
+ let displayBufferArray;
138
+ window.onload = function () {
139
+ window.chrome.webview.addEventListener("sharedbufferreceived", e => {
140
+ if (e.additionalData && e.additionalData.contosoBufferKind == "contosoDisplayBuffer") {
141
+ // Release potential previous buffer to ensure that the underlying resource can be released timely.
142
+ if (displayBuffer)
143
+ chrome.webview.releaseBuffer(displayBuffer);
144
+ // Hold the shared buffer and the typed array view of it.
145
+ displayBuffer = e.buffer;
146
+ displayBufferArray = new Uint8Array(displayBuffer);
147
+ }
148
+ });
149
+ window.chrome.webview.addEventListener("message", e => {
150
+ if (e.data == "DisplayBufferUpdated") {
151
+ // Consume the updated data
152
+ DisplaySharedBufferData(displayBufferArray);
153
+ // Notify the application that the data has been consumed
154
+ window.chrome.webview.postMessage("DisplayBufferConsumed");
155
+ } else if (e.data = "ReleaseDisplayBuffer") {
156
+ // Release the buffer, don't need it anymore.
157
+ chrome.webview.releaseBuffer(displayBuffer);
158
+ // Clear variables holding the buffer.
159
+ displayBuffer = undefined;
160
+ displayBufferArray = undefined;
161
+ }
162
+ });
163
+ }
164
+
165
+ ```
166
+ ## Win32 C++
167
+ ``` cpp
168
+
169
+ void EnsureSharedBuffer (UINT64 bufferSize)
170
+ {
171
+ if (m_sharedBuffer && m_bufferSize >= bufferSize)
172
+ return;
173
+ // Close previous buffer if we have one.
174
+ if (m_sharedBuffer)
175
+ m_sharedBuffer->Close();
176
+ CHECK_FAILURE(webviewEnvironment->CreateSharedBuffer(bufferSize, &m_sharedBuffer));
177
+ CHECK_FAILURE(m_sharedBuffer->get_Size(&m_bufferSize);
178
+ PCWSTR additionalDataAsJson = L"{\" contosoBufferKind\" :\" contosoDisplayBuffer\" }";
179
+ m_webviewFrame->PostSharedBufferToScript(
180
+ m_sharedBuffer.get(), COREWEBVIEW2_SHARED_BUFFER_ACCESS_READ_ONLY, additionalDataAsJson);
181
+ }
182
+
183
+ void ReleaseDisplayBuffer()
184
+ {
185
+ if (m_sharedBuffer)
186
+ {
187
+ // Explicitly Close the shared buffer so that we don't have to wait for
188
+ // GC for the underlying shared memory to be released.
189
+ m_sharedBuffer->Close();
190
+ m_sharedBuffer = nullptr;
191
+ CHECK_FAILURE(m_webviewFrame->PostWebMessage(L"ReleaseDisplayBuffer"));
192
+ }
193
+ }
194
+
195
+ void UpdateDisplayBuffer()
196
+ {
197
+ EnsureSharedBuffer(m_dataSize);
198
+ // Fill data into the shared memory via IStream.
199
+ wil::com_ptr<IStream> stream;
200
+ CHECK_FAILURE(sharedBuffer->OpenStream(&stream));
201
+ // The sample code assumes that the data itself contains info about the size
202
+ // of data to consume and we don't have to add it into the shared buffer or
203
+ // as part of the web message.
204
+ CHECK_FAILURE(stream->Write(m_data, m_dataSize, nullptr));
205
+ CHECK_FAILURE(m_webviewFrame->PostWebMessage(L"DisplayBufferUpdated"));
206
+ }
207
+
208
+ void OnFrameWebMessageReceived(PCWSTR message)
209
+ {
210
+ std::wstring DisplayBufferConsumedMessage(L"DisplayBufferConsumed");
211
+ if (DisplayBufferConsumedMessage == message)
212
+ {
213
+ if (m_hasMoreDataToSend)
214
+ {
215
+ UpdateDisplayBuffer();
216
+ }
217
+ else
218
+ {
219
+ ReleaseDisplayBuffer();
220
+ }
221
+ }
222
+ }
223
+
224
+ ```
225
+ ## WinRT and .NET
226
+ ```c#
227
+ void EnsureSharedBuffer(ulong bufferSize)
228
+ {
229
+ if (m_sharedBuffer && m_sharedBuffer.Size >= bufferSize)
230
+ return;
231
+ // Dispose previous buffer if we have one.
232
+ if (m_sharedBuffer)
233
+ m_sharedBuffer.Dispose();
234
+ m_sharedBuffer = WebviewEnvironment.CreateSharedBuffer(bufferSize);
235
+ string additionalDataAsJson = "{\"contosoBufferKind\":\"contosoDisplayBuffer\"}";
236
+ m_webviewFrame.PostSharedBufferToScript(
237
+ m_sharedBuffer, CoreWebView2SharedBufferAccess.ReadOnly, additionalDataAsJson);
238
+ }
239
+
240
+ void ReleaseDisplayBuffer()
241
+ {
242
+ if (m_sharedBuffer)
243
+ {
244
+ // Explicitly dispose the shared buffer so that we don't have to wait for
245
+ // GC for the underlying shared memory to be released.
246
+ m_sharedBuffer.Dispose();
247
+ m_sharedBuffer = null;
248
+ CHECK_FAILURE(m_webviewFrame.PostWebMessage("ReleaseDisplayBuffer"));
249
+ }
250
+ }
251
+
252
+ void UpdateDisplayBuffer()
253
+ {
254
+ EnsureSharedBuffer(m_dataSize);
255
+ // Fill data using access Stream
256
+ using (Stream stream = m_sharedBuffer.OpenStream())
257
+ {
258
+ using (StreamWriter writer = new StreamWriter(stream))
259
+ {
260
+ writer.Write(m_data);
261
+ }
262
+ }
263
+ }
264
+
265
+ void OnFrameWebMessageReceived(string message)
266
+ {
267
+ if (message == "DisplayBufferConsumed")
268
+ {
269
+ if (m_hasMoreDataToSend)
270
+ {
271
+ UpdateDisplayBuffer();
272
+ }
273
+ else
274
+ {
275
+ ReleaseDisplayBuffer();
276
+ }
277
+ }
278
+ }
279
+ ```
280
+
120
281
# API Details
121
282
## Win32 C++
122
283
```
@@ -127,6 +288,8 @@ interface ICoreWebView2Environment11 : IUnknown {
127
288
/// Once shared, the same content of the buffer will be accessible from both
128
289
/// the app process and script in WebView. Modification to the content will be visible
129
290
/// to all parties that have access to the buffer.
291
+ /// The shared buffer is presented to the script as ArrayBuffer. All JavaScript APIs
292
+ /// that works for ArrayBuffer including Atomics APIs can be used on it.
130
293
HRESULT CreateSharedBuffer(
131
294
[in] UINT64 size,
132
295
[out, retval] ICoreWebView2SharedBuffer** shared_buffer);
@@ -145,7 +308,7 @@ interface ICoreWebView2SharedBuffer : IUnknown {
145
308
/// Returns a handle to the file mapping object that backs this shared buffer.
146
309
/// The returned handle is owned by the shared buffer object. You should not
147
310
/// call CloseHandle on it.
148
- /// Normal app should use `Buffer` or `GetStream ` to get memory address
311
+ /// Normal app should use `Buffer` or `OpenStream ` to get memory address
149
312
/// or IStream object to access the buffer.
150
313
/// For advanced scenarios, you could use file-mapping APIs to obtain other views
151
314
/// or duplicate this handle to another application process and create a view from
@@ -156,10 +319,11 @@ interface ICoreWebView2SharedBuffer : IUnknown {
156
319
/// access to the buffer is needed any more, to ensure that the underlying resources
157
320
/// are released timely even if the shared buffer object itself is not released due to
158
321
/// some leaked reference.
159
- /// After the shared buffer is closed, accessing properties of the object will fail with
160
- /// `HRESULT_FROM_WIN32(ERROR_INVALID_STATE)`. Operations like Read or Write on the IStream
161
- /// objects returned from `GetStream` will fail with `HRESULT_FROM_WIN32(ERROR_INVALID_STATE)`.
162
- /// `PostSharedBufferToScript` will also fail with `HRESULT_FROM_WIN32(ERROR_INVALID_STATE)`.
322
+ /// After the shared buffer is closed, the buffer address and file mapping handle previously
323
+ /// obtained becomes invalid and cannot be used anymore. Accessing properties of the object
324
+ /// will fail with `RO_E_CLOSED`. Operations like Read or Write on the IStream objects returned
325
+ /// from `OpenStream` will fail with `RO_E_CLOSED`. `PostSharedBufferToScript` will also
326
+ /// fail with `RO_E_CLOSED`.
163
327
///
164
328
/// The script code should call `chrome.webview.releaseBuffer` with
165
329
/// the shared buffer as the parameter to release underlying resources as soon
@@ -185,8 +349,8 @@ typedef enum COREWEBVIEW2_SHARED_BUFFER_ACCESS {
185
349
interface ICoreWebView2_14 : IUnknown {
186
350
/// Share a shared buffer object with script of the main frame in the WebView.
187
351
/// The script will receive a `SharedBufferReceived` event from chrome.webview.
188
- /// The event arg for that event will have the following methods and properties:
189
- /// `getBuffer ()`: returns an ArrayBuffer object with the backing content from the shared buffer.
352
+ /// The event arg for that event will have the following properties:
353
+ /// `buffer ()`: an ArrayBuffer object with the backing content from the shared buffer.
190
354
/// `additionalData`: an object as the result of parsing `additionalDataAsJson` as JSON string.
191
355
/// This property will be `undefined` if `additionalDataAsJson` is nullptr or empty string.
192
356
/// `source`: with a value set as `chrome.webview` object.
@@ -195,11 +359,15 @@ interface ICoreWebView2_14 : IUnknown {
195
359
/// If `access` is COREWEBVIEW2_SHARED_BUFFER_ACCESS_READ_ONLY, the script will only have read access to the buffer.
196
360
/// If the script tries to modify the content in a read only buffer, it will cause an access
197
361
/// violation in WebView renderer process and crash the renderer process.
198
- /// If the shared buffer is already closed, the API will fail with `HRESULT_FROM_WIN32(ERROR_INVALID_STATE) `.
362
+ /// If the shared buffer is already closed, the API will fail with `RO_E_CLOSED `.
199
363
///
200
364
/// The script code should call `chrome.webview.releaseBuffer` with
201
365
/// the shared buffer as the parameter to release underlying resources as soon
202
366
/// as it does not need access to the shared buffer any more.
367
+ /// The application can post the same shared buffer object to multiple web pages or iframes, or
368
+ /// post to the same web page or iframe multiple times. Each `PostSharedBufferToScript` will
369
+ /// create a separate ArrayBuffer object with its own view of the memory and is separately
370
+ /// released. The underlying shared memory will be released when all the views are released.
203
371
///
204
372
/// Sharing a buffer to script has security risk. You should only share buffer with trusted site.
205
373
/// If a buffer is shared to a untrusted site, possible sensitive information could be leaked.
@@ -215,20 +383,24 @@ interface ICoreWebView2Frame4 : IUnknown {
215
383
/// Share a shared buffer object with script of the iframe in the WebView.
216
384
/// The script will receive a `SharedBufferReceived` event from chrome.webview.
217
385
/// The event arg for that event will have the following properties:
218
- /// `sharedBuffer `: an ArrayBuffer object with the backing content from the shared buffer.
219
- /// `data `: an object as the result of parsing `additionalDataAsJson` as JSON string.
386
+ /// `buffer() `: an ArrayBuffer object with the backing content from the shared buffer.
387
+ /// `additionalData `: an object as the result of parsing `additionalDataAsJson` as JSON string.
220
388
/// This property will be `undefined` if `additionalDataAsJson` is nullptr or empty string.
221
389
/// `source`: with a value set as `chrome.webview` object.
222
390
/// If a string is provided as `additionalDataAsJson` but it is not a valid JSON string,
223
391
/// the API will fail with `E_INVALIDARG`.
224
392
/// If `access` is COREWEBVIEW2_SHARED_BUFFER_ACCESS_READ_ONLY, the script will only have read access to the buffer.
225
393
/// If the script tries to modify the content in a read only buffer, it will cause an access
226
394
/// violation in WebView renderer process and crash the renderer process.
227
- /// If the shared buffer is already closed, the API will fail with `HRESULT_FROM_WIN32(ERROR_INVALID_STATE) `.
395
+ /// If the shared buffer is already closed, the API will fail with `RO_E_CLOSED `.
228
396
///
229
397
/// The script code should call `chrome.webview.releaseBuffer` with
230
398
/// the shared buffer as the parameter to release underlying resources as soon
231
399
/// as it does not need access to the shared buffer any more.
400
+ /// The application can post the same shared buffer object to multiple web pages or iframes, or
401
+ /// post to the same web page or iframe multiple times. Each `PostSharedBufferToScript` will
402
+ /// create a separate ArrayBuffer object with its own view of the memory and is separately
403
+ /// released. The underlying shared memory will be released when all the views are released.
232
404
///
233
405
/// Sharing a buffer to script has security risk. You should only share buffer with trusted site.
234
406
/// If a buffer is shared to a untrusted site, possible sensitive information could be leaked.
@@ -259,7 +431,7 @@ namespace Microsoft.Web.WebView2.Core
259
431
/// The raw memory address of the buffer.
260
432
/// You can cast it to pointer to real data types like byte* to access the memory
261
433
/// from `unsafe` code region.
262
- /// Normal app should use `GetStream ` to get a Stream object to access the buffer.
434
+ /// Normal app should use `OpenStream ` to get a Stream object to access the buffer.
263
435
public IntPtr Buffer { get ; };
264
436
265
437
/// The native file mapping handle of the shared memory of the buffer.
@@ -274,6 +446,12 @@ namespace Microsoft.Web.WebView2.Core
274
446
void Close ();
275
447
}
276
448
449
+ enum CoreWebView2SharedBufferAccess
450
+ {
451
+ ReadOnly = 0 ,
452
+ ReadWrite = 1
453
+ }
454
+
277
455
runtimeclass CoreWebView2
278
456
{
279
457
public void PostSharedBufferToScript(
@@ -319,6 +497,12 @@ namespace Microsoft.Web.WebView2.Core
319
497
// Note that we are not exposing Handle from WinRT API.
320
498
}
321
499
500
+ enum CoreWebView2SharedBufferAccess
501
+ {
502
+ ReadOnly = 0 ,
503
+ ReadWrite = 1
504
+ }
505
+
322
506
runtimeclass CoreWebView2
323
507
{
324
508
[interface_name (" Microsoft.Web.WebView2.Core.ICoreWebView2_14" )]
0 commit comments