@@ -294,12 +294,33 @@ class WebViewWrapper {
294294 private ICoreWebView2_11 webView_11 ;
295295 private ICoreWebView2_12 webView_12 ;
296296 private ICoreWebView2_13 webView_13 ;
297+
298+ void releaseWebViews () {
299+ if (webView != null ) {
300+ webView .Release ();
301+ }
302+ if (webView_2 != null ) {
303+ webView_2 .Release ();
304+ }
305+ if (webView_10 != null ) {
306+ webView_10 .Release ();
307+ }
308+ if (webView_11 != null ) {
309+ webView_11 .Release ();
310+ }
311+ if (webView_12 != null ) {
312+ webView_12 .Release ();
313+ }
314+ if (webView_13 != null ) {
315+ webView_13 .Release ();
316+ }
317+ }
297318}
298319
299320class WebViewProvider {
300321
301- private CompletableFuture <WebViewWrapper > webViewWrapperFuture = new CompletableFuture <>() ;
302- private CompletableFuture <Void > lastWebViewTask = webViewWrapperFuture . thenRun (() -> {}); ;
322+ private CompletableFuture <WebViewWrapper > webViewWrapperFuture ;
323+ private CompletableFuture <Void > lastWebViewTask ;
303324
304325 ICoreWebView2 initializeWebView (ICoreWebView2Controller controller ) {
305326 long [] ppv = new long [1 ];
@@ -312,14 +333,38 @@ ICoreWebView2 initializeWebView(ICoreWebView2Controller controller) {
312333 webViewWrapper .webView_11 = initializeWebView_11 (webView );
313334 webViewWrapper .webView_12 = initializeWebView_12 (webView );
314335 webViewWrapper .webView_13 = initializeWebView_13 (webView );
315- webViewWrapperFuture .complete (webViewWrapper );
336+ boolean success = webViewWrapperFuture .complete (webViewWrapper );
337+ // Release the webViews if the webViewWrapperFuture has already timed out and completed exceptionally
338+ if (!success && webViewWrapperFuture .isCompletedExceptionally ()) {
339+ webViewWrapper .releaseWebViews ();
340+ return null ;
341+ }
316342 return webView ;
317343 }
318344
345+ void initializeWebViewFutureWithTimeOut () {
346+ if (webViewWrapperFuture != null ) {
347+ return ;
348+ }
349+ webViewWrapperFuture = new CompletableFuture <>();
350+ webViewWrapperFuture .orTimeout (3 , TimeUnit .SECONDS ).exceptionallyAsync (exception -> {
351+ // Needs to be executed on the display thread since the exceptionally spawns a different thread
352+ replaceWithErrorLabel ();
353+ // Throw exception on the Display thread directly to prevent CompletableFuture
354+ // to wrap the exception and throw it silently
355+ if (exception instanceof RuntimeException runtimeEx ) {
356+ browser .getDisplay ().getRuntimeExceptionHandler ().accept (runtimeEx );
357+ } else if (exception instanceof Error er ) {
358+ browser .getDisplay ().getErrorHandler ().accept (er );
359+ }
360+ return null ;
361+ }, browser .getDisplay ());
362+ lastWebViewTask = webViewWrapperFuture .thenRun (() -> {});
363+ }
364+
319365 private void abortInitialization () {
320366 webViewWrapperFuture .cancel (true );
321367 }
322-
323368 private ICoreWebView2_2 initializeWebView_2 (ICoreWebView2 webView ) {
324369 long [] ppv = new long [1 ];
325370 int hr = webView .QueryInterface (COM .IID_ICoreWebView2_2 , ppv );
@@ -365,6 +410,11 @@ private ICoreWebView2_13 initializeWebView_13(ICoreWebView2 webView) {
365410 return null ;
366411 }
367412
413+ void releaseWebView () {
414+ waitForFutureToFinish (webViewWrapperFuture );
415+ webViewWrapperFuture .join ().releaseWebViews ();
416+ }
417+
368418 ICoreWebView2 getWebView (boolean waitForPendingWebviewTasksToFinish ) {
369419 if (waitForPendingWebviewTasksToFinish ) {
370420 waitForFutureToFinish (lastWebViewTask );
@@ -500,6 +550,10 @@ void checkDeadlock() {
500550 }
501551}
502552
553+ void errorTimedOut (Throwable throwable ) {
554+ SWT .error (SWT .ERROR_UNSPECIFIED , throwable , "Edge Browser initialization timed out" );
555+ }
556+
503557WebViewEnvironment createEnvironment () {
504558 Display display = Display .getCurrent ();
505559 WebViewEnvironment existingEnvironment = webViewEnvironments .get (display );
@@ -571,8 +625,18 @@ private String getDataDir(Display display) {
571625 return dataDir ;
572626}
573627
628+ private void replaceWithErrorLabel () {
629+ Label errorLabel = new Label (browser .getParent (), SWT .WRAP );
630+ errorLabel .setForeground (browser .getDisplay ().getSystemColor (SWT .COLOR_RED ));
631+ errorLabel .setText ("Edge browser initialization failed" );
632+ errorLabel .setLocation (0 , 0 );
633+ errorLabel .setSize (browser .getSize ());
634+ browser .setVisible (false );
635+ }
636+
574637@ Override
575638public void create (Composite parent , int style ) {
639+ webViewProvider .initializeWebViewFutureWithTimeOut ();
576640 createInstance (0 );
577641}
578642
@@ -587,38 +651,34 @@ private void createInstance(int previousAttempts) {
587651}
588652
589653private IUnknown createControllerInitializationCallback (int previousAttempts ) {
590- Runnable initializationRollback = () -> {
591- webViewProvider .abortInitialization ();
592- if (environment2 != null ) {
593- environment2 .Release ();
594- environment2 = null ;
595- }
596- containingEnvironment .instances ().remove (this );
597- };
598654 return newCallback ((result , pv ) -> {
599655 if (browser .isDisposed ()) {
600- initializationRollback . run ();
656+ rollbackInitialization ();
601657 return COM .S_OK ;
602658 }
603659 if (result == OS .HRESULT_FROM_WIN32 (OS .ERROR_INVALID_STATE )) {
604- initializationRollback . run ();
660+ rollbackInitialization ();
605661 SWT .error (SWT .ERROR_INVALID_ARGUMENT , null ,
606- " Edge instance with same data folder but different environment options already exists " );
662+ "Edge Initialization Timed Out " );
607663 }
608664 switch ((int ) result ) {
609665 case COM .S_OK :
610666 new IUnknown (pv ).AddRef ();
611- setupBrowser ((int ) result , pv );
667+ boolean success = setupBrowser ((int ) result , pv );
668+ if (!success ) {
669+ rollbackInitialization ();
670+ errorTimedOut (null );
671+ }
612672 break ;
613673 case COM .E_WRONG_THREAD :
614- initializationRollback . run ();
674+ rollbackInitialization ();
615675 error (SWT .ERROR_THREAD_INVALID_ACCESS , (int ) result );
616676 break ;
617677 case COM .E_ABORT :
618- initializationRollback . run ();
678+ rollbackInitialization ();
619679 break ;
620680 default :
621- initializationRollback . run ();
681+ rollbackInitialization ();
622682 if (previousAttempts < MAXIMUM_CREATION_RETRIES ) {
623683 System .err .println (String .format ("Edge initialization failed, retrying (attempt %d / %d)" , previousAttempts + 1 , MAXIMUM_CREATION_RETRIES ));
624684 createInstance (previousAttempts + 1 );
@@ -632,10 +692,22 @@ private IUnknown createControllerInitializationCallback(int previousAttempts) {
632692 });
633693}
634694
635- void setupBrowser (int hr , long pv ) {
695+ private void rollbackInitialization () {
696+ webViewProvider .abortInitialization ();
697+ if (environment2 != null ) {
698+ environment2 .Release ();
699+ environment2 = null ;
700+ }
701+ containingEnvironment .instances ().remove (this );
702+ }
703+
704+ boolean setupBrowser (int hr , long pv ) {
636705 long [] ppv = new long [] {pv };
637706 controller = new ICoreWebView2Controller (ppv [0 ]);
638707 final ICoreWebView2 webView = webViewProvider .initializeWebView (controller );
708+ if (webView == null ) {
709+ return false ;
710+ }
639711 webView .get_Settings (ppv );
640712 settings = new ICoreWebView2Settings (ppv [0 ]);
641713
@@ -735,17 +807,15 @@ void setupBrowser(int hr, long pv) {
735807 if (browser .isFocusControl ()) {
736808 browserFocusIn (new Event ());
737809 }
810+ return true ;
738811}
739812
740813void browserDispose (Event event ) {
741814 containingEnvironment .instances .remove (this );
742815 webViewProvider .scheduleWebViewTask (() -> {
743- webViewProvider .getWebView ( false ). Release ();
816+ webViewProvider .releaseWebView ();
744817 if (environment2 != null ) environment2 .Release ();
745818 if (settings != null ) settings .Release ();
746- if (webViewProvider .isWebView_2Available ()) webViewProvider .getWebView_2 (false ).Release ();
747- if (webViewProvider .isWebView_11Available ()) webViewProvider .getWebView_11 (false ).Release ();
748- if (webViewProvider .isWebView_12Available ()) webViewProvider .getWebView_12 (false ).Release ();
749819 if (controller != null ) {
750820 // Bug in WebView2. Closing the controller from an event handler results
751821 // in a crash. The fix is to delay the closure with asyncExec.
0 commit comments