Skip to content

Commit b64279b

Browse files
authored
Update SharedBuffer.md
1 parent 300b862 commit b64279b

File tree

1 file changed

+100
-67
lines changed

1 file changed

+100
-67
lines changed

specs/SharedBuffer.md

Lines changed: 100 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,48 @@ Shared Buffer Between Native Application Code and Script
22
===
33

44
# Background
5-
For some advanced scenarios, there is a need to exchange large amounts of data between the WebView2 application process and trusted web pages that are considered as part of the app. Some examples:
6-
- Web page generates a large amount of data, and passes it to the native side to be further processed or fed to other parts of the app or OS. For example, the web page generates 100MBs of high DPI images to be printed and needs to pass that to the native code to print. See https://github.com/MicrosoftEdge/WebView2Feedback/issues/89.
7-
- Native side generates a large amount of data for the web side to consume. The data might or might not come directly from files. For example the native side has generated terrabytes of data to produce different graphs on the web side. See https://github.com/MicrosoftEdge/WebView2Feedback/issues/1005.
8-
To support these scenarios, we are adding an Edge WebView2 API to support sharing buffers between the WebView2 host app process and WebView2 renderer process, based on shared memory from the OS.
5+
For some advanced scenarios, there is a need to exchange large amounts of data
6+
between the WebView2 application process and trusted web pages that are considered
7+
as part of the app. Some examples:
8+
- Web page generates a large amount of data, and passes it to the native side to be
9+
further processed or fed to other parts of the app or OS. For example, the web page
10+
generates 100MBs of high DPI images to be printed and needs to pass that to the native
11+
code to print. See https://github.com/MicrosoftEdge/WebView2Feedback/issues/89.
12+
- Native side generates a large amount of data for the web side to consume. The data
13+
might or might not come directly from files. For example the native side has generated
14+
terrabytes of data to produce different graphs on the web side.
15+
See https://github.com/MicrosoftEdge/WebView2Feedback/issues/1005.
916

10-
The application code can use the APIs to create a shared buffer object, and share to scripts as [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) object.
17+
To support these scenarios, we are adding an Edge WebView2 API to support sharing
18+
buffers between the WebView2 host app process and WebView2 renderer process, based
19+
on shared memory from the OS.
20+
21+
The application code can use the APIs to create a shared buffer object, and share to
22+
scripts as [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) object.
1123
Then both the native application code and the script will be able to access the same memory.
1224

1325
# Conceptual pages (How To)
1426

15-
Besides using the memory address directly, the shared buffer object can be accessed from native side via an IStream* object that you can get from the shared object.
27+
Besides using the memory address directly, the shared buffer object can be accessed
28+
from native side via an IStream* object that you can get from the shared object.
1629

17-
When the application code calls `PostSharedBufferToScript`, the script side will receive a `SharedBufferReceived` event containing the buffer as an `ArrayBuffer` object.
18-
After receiving the shared buffer object, it can access it the same way as any other ArrayBuffer object, including transering to a web worker to process the data on
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
33+
ArrayBuffer object, including transering to a web worker to process the data on
1934
the worker thread.
2035

21-
As shared buffer normally represent a large memory, instead of waiting for garbage collection to release the memory along with the owning objects, the application
22-
should try to release the buffer as soon as it doesn't need access to it. This can be done by calling Close() method on the shared buffer object, or
36+
As shared buffer normally represent a large memory, instead of waiting for garbage
37+
collection to release the memory along with the owning objects, the application
38+
should try to release the buffer as soon as it doesn't need access to it.
39+
This can be done by calling Close() method on the shared buffer object, or
2340
`chrome.webview.releaseSharedBuffer` from script.
2441

25-
As the memory could contain sensitive information and corrupted memory could crash the application, the application should only share buffer with trusted sites.
42+
As the memory could contain sensitive information and corrupted memory could crash
43+
the application, the application should only share buffer with trusted sites.
2644

27-
The application can use other messaging channel like `PostWebMessageAsJson` and `chrome.webview.postMessage` to inform the other side the desire to have a shared
45+
The application can use other messaging channel like `PostWebMessageAsJson` and
46+
`chrome.webview.postMessage` to inform the other side the desire to have a shared
2847
buffer and the status of the buffer (data is produced or consumed).
2948

3049
# Examples
@@ -53,11 +72,11 @@ The script code will look like this:
5372
## Win32 C++
5473
```cpp
5574

56-
wil::com_ptr<ICoreWebView2StagingEnvironment2> environment;
75+
wil::com_ptr<ICoreWebView2Environment11> environment;
5776
CHECK_FAILURE(
5877
m_appWindow->GetWebViewEnvironment()->QueryInterface(IID_PPV_ARGS(&environment)));
5978

60-
wil::com_ptr<ICoreWebView2StagingSharedBuffer> sharedBuffer;
79+
wil::com_ptr<ICoreWebView2SharedBuffer> sharedBuffer;
6180
CHECK_FAILURE(environment->CreateSharedBuffer(bufferSize, &sharedBuffer));
6281
// Fill data into the shared memory via IStream.
6382
wil::com_ptr<IStream> stream;
@@ -80,32 +99,32 @@ The script code will look like this:
8099
```
81100
## WinRT and .NET
82101
```c#
83-
var sharedBuffer = WebViewEnvironment.CreateSharedBuffer(bufferSize);
84-
// Fill data using access Stream
85-
using (Stream stream = sharedBuffer.GetStream())
102+
using (CoreWebView2SharedBuffer sharedBuffer = WebViewEnvironment.CreateSharedBuffer(bufferSize))
86103
{
87-
using (StreamWriter writer = new StreamWriter(stream))
104+
// Fill data using access Stream
105+
using (Stream stream = sharedBuffer.GetStream())
88106
{
89-
writer.Write(bufferData);
107+
using (StreamWriter writer = new StreamWriter(stream))
108+
{
109+
writer.Write(bufferData);
110+
}
111+
}
112+
string additionalDataAsJson = "{\"read_only\":true}";
113+
if (forFrame)
114+
{
115+
m_webviewFrame.PostSharedBufferToScript(sharedBuffer, /*isReadOnlyToScript*/true, additionalDataAsJson);
116+
}
117+
else
118+
{
119+
m_webview.PostSharedBufferToScript(sharedBuffer, /*isReadOnlyToScript*/true, additionalDataAsJson);
90120
}
91121
}
92-
string additionalDataAsJson = "{\"read_only\":true}";
93-
if (forFrame)
94-
{
95-
m_webviewFrame.PostSharedBufferToScript(sharedBuffer, /*isReadOnlyToScript*/true, additionalDataAsJson);
96-
}
97-
else
98-
{
99-
m_webview.PostSharedBufferToScript(sharedBuffer, /*isReadOnlyToScript*/true, additionalDataAsJson);
100-
}
101-
// Explicitly close the one time shared buffer to ensure that the resource is released timely.
102-
sharedBuffer.Close();
103122
```
104123

105124
# API Details
106125
## Win32 C++
107126
```
108-
interface ICoreWebView2StagingEnvironment2 : IUnknown {
127+
interface ICoreWebView2Environment11 : IUnknown {
109128
/// Create a shared memory based buffer with the specified size in bytes.
110129
/// The buffer can be shared with web contents in WebView by calling
111130
/// `PostSharedBufferToScript` on `CoreWebView2` or `CoreWebViewFrame` object.
@@ -115,10 +134,10 @@ interface ICoreWebView2StagingEnvironment2 : IUnknown {
115134
/// For 32bit application, the creation will fail with E_INVALIDARG if `size` is larger than 4GB.
116135
HRESULT CreateSharedBuffer(
117136
[in] UINT64 size,
118-
[out, retval] ICoreWebView2StagingSharedBuffer** shared_buffer);
137+
[out, retval] ICoreWebView2SharedBuffer** shared_buffer);
119138
}
120139
121-
interface ICoreWebView2StagingSharedBuffer : IUnknown {
140+
interface ICoreWebView2SharedBuffer : IUnknown {
122141
/// The size of the shared buffer in bytes.
123142
[propget] HRESULT Size([out, retval] UINT64* value);
124143
@@ -141,69 +160,78 @@ interface ICoreWebView2StagingSharedBuffer : IUnknown {
141160
/// are released timely even if the shared buffer object itself is not released due to
142161
/// some leaked reference.
143162
/// After the shared buffer is closed, accessing properties of the object will fail with
144-
/// `HRESULT_FROM_WIN32(ERROR_INVALID_STATE)`. Operations like Read or Write on the IStream objects
145-
/// returned from `GetStream` will fail with `HRESULT_FROM_WIN32(ERROR_INVALID_STATE)`.
163+
/// `HRESULT_FROM_WIN32(ERROR_INVALID_STATE)`. Operations like Read or Write on the IStream
164+
/// objects returned from `GetStream` will fail with `HRESULT_FROM_WIN32(ERROR_INVALID_STATE)`.
146165
/// `PostSharedBufferToScript` will also fail with `HRESULT_FROM_WIN32(ERROR_INVALID_STATE)`.
147166
///
148167
/// The script code should call `chrome.webview.releaseSharedBuffer` with
149168
/// the shared buffer as the parameter to release underlying resources as soon
150169
/// as it does not need access the shared buffer any more.
151170
/// When script tries to access the buffer after calling `chrome.webview.releaseSharedBuffer`,
152-
/// JavaScript `TypeError` exception will be raised complaining about accessing a detached ArrayBuffer,
153-
/// the same exception when trying to access a transferred ArrayBuffer.
171+
/// JavaScript `TypeError` exception will be raised complaining about accessing a
172+
/// detached ArrayBuffer, the same exception when trying to access a transferred ArrayBuffer.
154173
///
155-
/// Closing the buffer object on native side doesn't impact access from Script and releasing the buffer
156-
/// from script doesn't impact access to the buffer from native side.
157-
/// The underlying shared memory will be released by the OS when both native and script side releases the buffer.
174+
/// Closing the buffer object on native side doesn't impact access from Script and releasing
175+
/// the buffer from script doesn't impact access to the buffer from native side.
176+
/// The underlying shared memory will be released by the OS when both native and script side
177+
/// releases the buffer.
158178
HRESULT Close();
159179
}
160180
161-
interface ICoreWebView2Staging7 : IUnknown {
181+
interface ICoreWebView2_14 : IUnknown {
162182
/// Share a shared buffer object with script of the main frame in the WebView.
163183
/// The script will receive a `SharedBufferReceived` event from chrome.webview.
164184
/// The event arg for that event will have the following properties:
165185
/// `sharedBuffer`: an ArrayBuffer object with the backing content from the shared buffer.
166-
/// `data`: an object representing `additionalDataAsJson`. This property will be `undefined`
167-
/// if `additionalDataAsJson` is nullptr or empty string.
186+
/// `data`: an object as the result of parsing `additionalDataAsJson` as JSON string.
187+
/// This property will be `undefined` if `additionalDataAsJson` is nullptr or empty string.
168188
/// `source`: with a value set as `chrome.webview` object.
189+
/// If a string is provided as `additionalDataAsJson` but it is not a valid JSON string,
190+
/// the API will fail with `E_INVALIDARG`.
169191
/// If `isReadOnlyToScript` is true, the script will only have read access to the buffer.
170-
/// If the script tries to modify the content in a read only buffer, it will cause an access violation
171-
/// in WebView renderer process and crash the renderer process.
172-
/// If the shared buffer is already closed, the API will fail with HRESULT_FROM_WIN32(ERROR_INVALID_STATE).
192+
/// If the script tries to modify the content in a read only buffer, it will cause an access
193+
/// violation in WebView renderer process and crash the renderer process.
194+
/// If the shared buffer is already closed, the API will fail with `HRESULT_FROM_WIN32(ERROR_INVALID_STATE)`.
173195
///
174196
/// The script code should call `chrome.webview.releaseSharedBuffer` with
175197
/// the shared buffer as the parameter to release underlying resources as soon
176198
/// as it does not need access to the shared buffer any more.
177199
///
178200
/// Sharing a buffer to script has security risk. You should only share buffer with trusted site.
179-
///
201+
/// If a buffer is shared to a untrusted site, possible sensitive information could be leaked.
202+
/// If a buffer is shared as modifiable by the script and the script modifies it in an unexpected way,
203+
/// it could result in corrupted data that might even crash the application.
180204
HRESULT PostSharedBufferToScript(
181-
[in] ICoreWebView2StagingSharedBuffer* sharedBuffer,
205+
[in] ICoreWebView2SharedBuffer* sharedBuffer,
182206
[in] BOOL isReadOnlyToScript,
183207
[in] LPCWSTR additionalDataAsJson);
184208
}
185209
186-
interface ICoreWebView2StagingFrame2 : IUnknown {
210+
interface ICoreWebView2Frame4 : IUnknown {
187211
/// Share a shared buffer object with script of the iframe in the WebView.
188212
/// The script will receive a `SharedBufferReceived` event from chrome.webview.
189213
/// The event arg for that event will have the following properties:
190214
/// `sharedBuffer`: an ArrayBuffer object with the backing content from the shared buffer.
191-
/// `data`: an object representing `additionalDataAsJson`. This property will be `undefined`
192-
/// if `additionalDataAsJson` is nullptr or empty string.
215+
/// `data`: an object as the result of parsing `additionalDataAsJson` as JSON string.
216+
/// This property will be `undefined` if `additionalDataAsJson` is nullptr or empty string.
193217
/// `source`: with a value set as `chrome.webview` object.
218+
/// If a string is provided as `additionalDataAsJson` but it is not a valid JSON string,
219+
/// the API will fail with `E_INVALIDARG`.
194220
/// If `isReadOnlyToScript` is true, the script will only have read access to the buffer.
195-
/// If the script tries to modify the content in a read only buffer, it will cause an access violation
196-
/// in WebView renderer process and crash the renderer process.
197-
/// If the shared buffer is already closed, the API will fail with HRESULT_FROM_WIN32(ERROR_INVALID_STATE).
221+
/// If the script tries to modify the content in a read only buffer, it will cause an access
222+
/// violation in WebView renderer process and crash the renderer process.
223+
/// If the shared buffer is already closed, the API will fail with `HRESULT_FROM_WIN32(ERROR_INVALID_STATE)`.
198224
///
199225
/// The script code should call `chrome.webview.releaseSharedBuffer` with
200226
/// the shared buffer as the parameter to release underlying resources as soon
201227
/// as it does not need access to the shared buffer any more.
202228
///
203229
/// Sharing a buffer to script has security risk. You should only share buffer with trusted site.
204-
///
230+
/// If a buffer is shared to a untrusted site, possible sensitive information could be leaked.
231+
/// If a buffer is shared as modifiable by the script and the script modifies it in an unexpected way,
232+
/// it could result in corrupted data that might even crash the application.
205233
HRESULT PostSharedBufferToScript(
206-
[in] ICoreWebView2StagingSharedBuffer* sharedBuffer,
234+
[in] ICoreWebView2SharedBuffer* sharedBuffer,
207235
[in] BOOL isReadOnlyToScript,
208236
[in] LPCWSTR additionalDataAsJson);
209237
}
@@ -225,15 +253,16 @@ namespace Microsoft.Web.WebView2.Core
225253
public ulong Size { get; };
226254

227255
/// The raw memory address of the buffer.
228-
/// You can cast it to pointer to real data types like byte* to access the memory from `unsafe` code region.
256+
/// You can cast it to pointer to real data types like byte* to access the memory
257+
/// from `unsafe` code region.
229258
/// Normal app should use `GetStream` to get a Stream object to access the buffer.
230259
public IntPtr Buffer { get; };
231260

232261
/// The native file mapping handle of the shared memory of the buffer.
233262
/// Normal app should use `GetStream` to get a Stream object to access the buffer.
234-
/// For advanced scenario, you could use native APIs to duplicate this handle to another application
235-
/// process and create a mapping from the duplicated handle in that process to access
236-
/// the buffer from that separate process.
263+
/// For advanced scenario, you could use native APIs to duplicate this handle to
264+
/// another application process and create a mapping from the duplicated handle in
265+
/// that process to access the buffer from that separate process.
237266
public IntPtr Handle { get; };
238267

239268
public Stream GetStream();
@@ -246,12 +275,14 @@ namespace Microsoft.Web.WebView2.Core
246275

247276
runtimeclass CoreWebView2
248277
{
249-
public void PostSharedBufferToScript(CoreWebView2SharedBuffer sharedBuffer, bool isReadOnlyToScript, string additionalDataAsJson);
278+
public void PostSharedBufferToScript(
279+
CoreWebView2SharedBuffer sharedBuffer, bool isReadOnlyToScript, string additionalDataAsJson);
250280
}
251281

252282
class CoreWebView2Frame
253283
{
254-
public void PostSharedBufferToScript(CoreWebView2SharedBuffer sharedBuffer, bool isReadOnlyToScript, string additionalDataAsJson);
284+
public void PostSharedBufferToScript(
285+
CoreWebView2SharedBuffer sharedBuffer, bool isReadOnlyToScript, string additionalDataAsJson);
255286
}
256287
}
257288

@@ -263,7 +294,7 @@ namespace Microsoft.Web.WebView2.Core
263294

264295
runtimeclass CoreWebView2Environment
265296
{
266-
[interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2StagingEnvironment2")]
297+
[interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2Environment11")]
267298
{
268299
CoreWebView2SharedBuffer CreateSharedBuffer(UInt64 size);
269300
}
@@ -292,17 +323,19 @@ namespace Microsoft.Web.WebView2.Core
292323

293324
runtimeclass CoreWebView2
294325
{
295-
[interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2Staging7")]
326+
[interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2_14")]
296327
{
297-
void PostSharedBufferToScript(CoreWebView2SharedBuffer sharedBuffer, Boolean isReadOnlyToScript, String additionalDataAsJson);
328+
void PostSharedBufferToScript(
329+
CoreWebView2SharedBuffer sharedBuffer, Boolean isReadOnlyToScript, String additionalDataAsJson);
298330
}
299331
}
300332

301333
runtimeclass CoreWebView2Frame
302334
{
303-
[interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2StagingFrame2")]
335+
[interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2Frame4")]
304336
{
305-
void PostSharedBufferToScript(CoreWebView2SharedBuffer sharedBuffer, Boolean isReadOnlyToScript, String additionalDataAsJson);
337+
void PostSharedBufferToScript(
338+
CoreWebView2SharedBuffer sharedBuffer, Boolean isReadOnlyToScript, String additionalDataAsJson);
306339
}
307340
}
308341
}

0 commit comments

Comments
 (0)