@@ -28,8 +28,8 @@ Besides using the memory address directly, the shared buffer object can be acces
2828from native side via an IStream* object that you can get from the shared buffer object.
2929
3030When 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
3333ArrayBuffer object, including transferring to a web worker to process the data on
3434the worker thread.
3535
@@ -60,10 +60,10 @@ The script code will look like this:
6060
6161 function SharedBufferReceived(e) {
6262 if (e.additionalData && e.additionalData.contosoBufferKind == "contosoDisplayBuffer") {
63- let displayBuffer = e.getBuffer() ;
63+ let displayBuffer = e.buffer ;
6464 // 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 );
6767 // Release the buffer after consuming the data.
6868 chrome.webview.releaseBuffer(displayBuffer);
6969 }
@@ -73,50 +73,211 @@ The script code will look like this:
7373``` cpp
7474
7575 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 );
8181 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.
9388 sharedBuffer->Close();
9489
9590```
96- ## WinRT and .NET
91+ ## .NET
9792```c#
98- using (CoreWebView2SharedBuffer sharedBuffer = WebViewEnvironment.CreateSharedBuffer(bufferSize ))
93+ using (CoreWebView2SharedBuffer sharedBuffer = WebViewEnvironment.CreateSharedBuffer(dataSize ))
9994 {
100- // Fill data using access Stream
101- using (Stream stream = sharedBuffer.OpenStream())
95+ // Fill buffer with data.
96+ unsafe
10297 {
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++;
106102 }
107- }
103+ }
108104 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
114114 {
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 );
117129 }
118130```
119131
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+
120281# API Details
121282## Win32 C++
122283```
@@ -127,6 +288,8 @@ interface ICoreWebView2Environment11 : IUnknown {
127288 /// Once shared, the same content of the buffer will be accessible from both
128289 /// the app process and script in WebView. Modification to the content will be visible
129290 /// 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.
130293 HRESULT CreateSharedBuffer(
131294 [in] UINT64 size,
132295 [out, retval] ICoreWebView2SharedBuffer** shared_buffer);
@@ -145,7 +308,7 @@ interface ICoreWebView2SharedBuffer : IUnknown {
145308 /// Returns a handle to the file mapping object that backs this shared buffer.
146309 /// The returned handle is owned by the shared buffer object. You should not
147310 /// 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
149312 /// or IStream object to access the buffer.
150313 /// For advanced scenarios, you could use file-mapping APIs to obtain other views
151314 /// or duplicate this handle to another application process and create a view from
@@ -156,10 +319,11 @@ interface ICoreWebView2SharedBuffer : IUnknown {
156319 /// access to the buffer is needed any more, to ensure that the underlying resources
157320 /// are released timely even if the shared buffer object itself is not released due to
158321 /// 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`.
163327 ///
164328 /// The script code should call `chrome.webview.releaseBuffer` with
165329 /// the shared buffer as the parameter to release underlying resources as soon
@@ -185,8 +349,8 @@ typedef enum COREWEBVIEW2_SHARED_BUFFER_ACCESS {
185349interface ICoreWebView2_14 : IUnknown {
186350 /// Share a shared buffer object with script of the main frame in the WebView.
187351 /// 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.
190354 /// `additionalData`: an object as the result of parsing `additionalDataAsJson` as JSON string.
191355 /// This property will be `undefined` if `additionalDataAsJson` is nullptr or empty string.
192356 /// `source`: with a value set as `chrome.webview` object.
@@ -195,11 +359,15 @@ interface ICoreWebView2_14 : IUnknown {
195359 /// If `access` is COREWEBVIEW2_SHARED_BUFFER_ACCESS_READ_ONLY, the script will only have read access to the buffer.
196360 /// If the script tries to modify the content in a read only buffer, it will cause an access
197361 /// 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 `.
199363 ///
200364 /// The script code should call `chrome.webview.releaseBuffer` with
201365 /// the shared buffer as the parameter to release underlying resources as soon
202366 /// 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.
203371 ///
204372 /// Sharing a buffer to script has security risk. You should only share buffer with trusted site.
205373 /// If a buffer is shared to a untrusted site, possible sensitive information could be leaked.
@@ -215,20 +383,24 @@ interface ICoreWebView2Frame4 : IUnknown {
215383 /// Share a shared buffer object with script of the iframe in the WebView.
216384 /// The script will receive a `SharedBufferReceived` event from chrome.webview.
217385 /// 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.
220388 /// This property will be `undefined` if `additionalDataAsJson` is nullptr or empty string.
221389 /// `source`: with a value set as `chrome.webview` object.
222390 /// If a string is provided as `additionalDataAsJson` but it is not a valid JSON string,
223391 /// the API will fail with `E_INVALIDARG`.
224392 /// If `access` is COREWEBVIEW2_SHARED_BUFFER_ACCESS_READ_ONLY, the script will only have read access to the buffer.
225393 /// If the script tries to modify the content in a read only buffer, it will cause an access
226394 /// 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 `.
228396 ///
229397 /// The script code should call `chrome.webview.releaseBuffer` with
230398 /// the shared buffer as the parameter to release underlying resources as soon
231399 /// 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.
232404 ///
233405 /// Sharing a buffer to script has security risk. You should only share buffer with trusted site.
234406 /// If a buffer is shared to a untrusted site, possible sensitive information could be leaked.
@@ -259,7 +431,7 @@ namespace Microsoft.Web.WebView2.Core
259431 /// The raw memory address of the buffer.
260432 /// You can cast it to pointer to real data types like byte* to access the memory
261433 /// 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.
263435 public IntPtr Buffer { get ; };
264436
265437 /// The native file mapping handle of the shared memory of the buffer.
@@ -274,6 +446,12 @@ namespace Microsoft.Web.WebView2.Core
274446 void Close ();
275447 }
276448
449+ enum CoreWebView2SharedBufferAccess
450+ {
451+ ReadOnly = 0 ,
452+ ReadWrite = 1
453+ }
454+
277455 runtimeclass CoreWebView2
278456 {
279457 public void PostSharedBufferToScript(
@@ -319,6 +497,12 @@ namespace Microsoft.Web.WebView2.Core
319497 // Note that we are not exposing Handle from WinRT API.
320498 }
321499
500+ enum CoreWebView2SharedBufferAccess
501+ {
502+ ReadOnly = 0 ,
503+ ReadWrite = 1
504+ }
505+
322506 runtimeclass CoreWebView2
323507 {
324508 [interface_name (" Microsoft.Web.WebView2.Core.ICoreWebView2_14" )]
0 commit comments