4
4
5
5
using System ;
6
6
using System . ComponentModel ;
7
+ using System . Threading ;
7
8
using CefSharp . Internals ;
8
9
9
10
#if OFFSCREEN
@@ -18,11 +19,21 @@ namespace CefSharp.WinForms
18
19
//WPF, Winforms and Offscreen
19
20
public partial class ChromiumWebBrowser
20
21
{
22
+ public const string BrowserNotInitializedExceptionErrorMessage =
23
+ "The ChromiumWebBrowser instance creates the underlying Chromium Embedded Framework (CEF) browser instance in an async fashion. " +
24
+ "The undelying CefBrowser instance is not yet initialized. Use the IsBrowserInitializedChanged event and check " +
25
+ "the IsBrowserInitialized property to determine when the browser has been initialized." ;
26
+
21
27
/// <summary>
22
28
/// Used as workaround for issue https://github.com/cefsharp/CefSharp/issues/3021
23
29
/// </summary>
24
30
private long canExecuteJavascriptInMainFrameId ;
25
31
32
+ /// <summary>
33
+ /// The browser initialized - boolean represented as 0 (false) and 1(true) as we use Interlocker to increment/reset
34
+ /// </summary>
35
+ private int browserInitialized ;
36
+
26
37
/// <summary>
27
38
/// A flag that indicates if you can execute javascript in the main frame.
28
39
/// Flag is set to true in IRenderProcessMessageHandler.OnContextCreated.
@@ -184,6 +195,15 @@ public partial class ChromiumWebBrowser
184
195
/// </summary>
185
196
public event EventHandler < JavascriptMessageReceivedEventArgs > JavascriptMessageReceived ;
186
197
198
+ /// <summary>
199
+ /// A flag that indicates whether the WebBrowser is initialized (true) or not (false).
200
+ /// </summary>
201
+ /// <value><c>true</c> if this instance is browser initialized; otherwise, <c>false</c>.</value>
202
+ bool IWebBrowser . IsBrowserInitialized
203
+ {
204
+ get { return InternalIsBrowserInitialized ( ) ; }
205
+ }
206
+
187
207
void IWebBrowserInternal . SetCanExecuteJavascriptOnMainFrame ( long frameId , bool canExecute )
188
208
{
189
209
//When loading pages of a different origin the frameId changes
@@ -284,5 +304,40 @@ private void SetHandlersToNullExceptLifeSpan()
284
304
ResourceRequestHandlerFactory = null ;
285
305
RenderProcessMessageHandler = null ;
286
306
}
307
+
308
+ /// <summary>
309
+ /// Check is browser is initialized
310
+ /// </summary>
311
+ /// <returns>true if browser is initialized</returns>
312
+ private bool InternalIsBrowserInitialized ( )
313
+ {
314
+ // Use CompareExchange to read the current value - if disposeCount is 1, we set it to 1, effectively a no-op
315
+ // Volatile.Read would likely use a memory barrier which I believe is unnecessary in this scenario
316
+ return Interlocked . CompareExchange ( ref browserInitialized , 0 , 0 ) == 1 ;
317
+ }
318
+
319
+ /// <summary>
320
+ /// Throw exception if browser not initialized.
321
+ /// </summary>
322
+ /// <exception cref="Exception">Thrown when an exception error condition occurs.</exception>
323
+ private void ThrowExceptionIfBrowserNotInitialized ( )
324
+ {
325
+ if ( ! InternalIsBrowserInitialized ( ) )
326
+ {
327
+ throw new Exception ( BrowserNotInitializedExceptionErrorMessage ) ;
328
+ }
329
+ }
330
+
331
+ /// <summary>
332
+ /// Throw exception if disposed.
333
+ /// </summary>
334
+ /// <exception cref="ObjectDisposedException">Thrown when a supplied object has been disposed.</exception>
335
+ private void ThrowExceptionIfDisposed ( )
336
+ {
337
+ if ( IsDisposed )
338
+ {
339
+ throw new ObjectDisposedException ( "browser" , "Browser has been disposed" ) ;
340
+ }
341
+ }
287
342
}
288
343
}
0 commit comments