@@ -263,7 +263,7 @@ static int callAndWait(long[] ppv, ToIntFunction<IUnknown> callable) {
263263 phr [0 ] = callable .applyAsInt (completion );
264264 // "completion" callback may be called asynchronously,
265265 // so keep processing next OS message that may call it
266- processOSMessagesUntil (() -> phr [0 ] != COM .S_OK || ppv [0 ] != 0 , Display .getCurrent ());
266+ processOSMessagesUntil (() -> phr [0 ] != COM .S_OK || ppv [0 ] != 0 , Optional . empty (), Display .getCurrent ());
267267 completion .Release ();
268268 return phr [0 ];
269269}
@@ -281,7 +281,7 @@ int callAndWait(String[] pstr, ToIntFunction<IUnknown> callable) {
281281 phr [0 ] = callable .applyAsInt (completion );
282282 // "completion" callback may be called asynchronously,
283283 // so keep processing next OS message that may call it
284- processOSMessagesUntil (() -> phr [0 ] != COM .S_OK || pstr [0 ] != null , browser .getDisplay ());
284+ processOSMessagesUntil (() -> phr [0 ] != COM .S_OK || pstr [0 ] != null , Optional . empty (), browser .getDisplay ());
285285 completion .Release ();
286286 return phr [0 ];
287287}
@@ -293,12 +293,32 @@ class WebViewWrapper {
293293 private ICoreWebView2_11 webView_11 ;
294294 private ICoreWebView2_12 webView_12 ;
295295 private ICoreWebView2_13 webView_13 ;
296+
297+ void releaseWebViews () {
298+ if (webView != null ) {
299+ webView .Release ();
300+ }
301+ if (webView_2 != null ) {
302+ webView_2 .Release ();
303+ }
304+ if (webView_10 != null ) {
305+ webView_10 .Release ();
306+ }
307+ if (webView_11 != null ) {
308+ webView_11 .Release ();
309+ }
310+ if (webView_12 != null ) {
311+ webView_12 .Release ();
312+ }
313+ if (webView_13 != null ) {
314+ webView_13 .Release ();
315+ }
316+ }
296317}
297318
298319class WebViewProvider {
299-
300320 private CompletableFuture <WebViewWrapper > webViewWrapperFuture = wakeDisplayAfterFuture (new CompletableFuture <>());
301- private CompletableFuture <Void > lastWebViewTask = webViewWrapperFuture .thenRun (() -> {});;
321+ private CompletableFuture <Void > lastWebViewTask = webViewWrapperFuture .thenRun (() -> {});
302322
303323 ICoreWebView2 initializeWebView (ICoreWebView2Controller controller ) {
304324 long [] ppv = new long [1 ];
@@ -310,15 +330,19 @@ ICoreWebView2 initializeWebView(ICoreWebView2Controller controller) {
310330 webViewWrapper .webView_10 = initializeWebView_10 (webView );
311331 webViewWrapper .webView_11 = initializeWebView_11 (webView );
312332 webViewWrapper .webView_12 = initializeWebView_12 (webView );
313- webViewWrapper .webView_13 = initializeWebView_13 (webView );
314- webViewWrapperFuture .complete (webViewWrapper );
333+ webViewWrapper .webView_13 = initializeWebView_13 (webView );
334+ boolean success = webViewWrapperFuture .complete (webViewWrapper );
335+ // Release the webViews if the webViewWrapperFuture has already timed out and completed exceptionally
336+ if (!success && webViewWrapperFuture .isCompletedExceptionally ()) {
337+ webViewWrapper .releaseWebViews ();
338+ return null ;
339+ }
315340 return webView ;
316341 }
317342
318343 private void abortInitialization () {
319344 webViewWrapperFuture .cancel (true );
320345 }
321-
322346 private ICoreWebView2_2 initializeWebView_2 (ICoreWebView2 webView ) {
323347 long [] ppv = new long [1 ];
324348 int hr = webView .QueryInterface (COM .IID_ICoreWebView2_2 , ppv );
@@ -366,13 +390,18 @@ private ICoreWebView2_13 initializeWebView_13(ICoreWebView2 webView) {
366390
367391 private WebViewWrapper getWebViewWrapper (boolean waitForPendingWebviewTasksToFinish ) {
368392 if (waitForPendingWebviewTasksToFinish ) {
369- processOSMessagesUntil (lastWebViewTask ::isDone , browser .getDisplay ());
393+ processOSMessagesUntil (lastWebViewTask ::isDone , Optional . empty (), browser .getDisplay ());
370394 }
371395 return webViewWrapperFuture .join ();
372396 }
373397
398+ void releaseWebView () {
399+ processOSMessagesUntil (webViewWrapperFuture ::isDone , Optional .of (() -> webViewWrapperFuture .completeExceptionally (createTimeOutException ())), browser .getDisplay ());
400+ webViewWrapperFuture .join ().releaseWebViews ();
401+ }
402+
374403 private WebViewWrapper getWebViewWrapper () {
375- processOSMessagesUntil (webViewWrapperFuture ::isDone , browser .getDisplay ());
404+ processOSMessagesUntil (webViewWrapperFuture ::isDone , Optional . of (() -> webViewWrapperFuture . completeExceptionally ( createTimeOutException ())), browser .getDisplay ());
376405 return webViewWrapperFuture .join ();
377406 }
378407
@@ -457,7 +486,7 @@ private <T> CompletableFuture<T> wakeDisplayAfterFuture(CompletableFuture<T> fut
457486 * events for initialization. Thus, this method does not implement an ordinary
458487 * readAndDispatch loop, but waits for an OS event to be processed.
459488 */
460- private static void processOSMessagesUntil (Supplier <Boolean > condition , Display display ) {
489+ private static void processOSMessagesUntil (Supplier <Boolean > condition , Optional < Runnable > timeoutHandler , Display display ) {
461490 MSG msg = new MSG ();
462491 AtomicBoolean timeoutOccurred = new AtomicBoolean ();
463492 // The timer call also wakes up the display to avoid being stuck in display.sleep()
@@ -470,10 +499,15 @@ private static void processOSMessagesUntil(Supplier<Boolean> condition, Display
470499 }
471500 }
472501 if (!condition .get ()) {
502+ timeoutHandler .ifPresent (handler -> handler .run ());
473503 SWT .error (SWT .ERROR_UNSPECIFIED , null , " Waiting for Edge operation to terminate timed out" );
474504 }
475505}
476506
507+ private static SWTException createTimeOutException () {
508+ return new SWTException (SWT .ERROR_UNSPECIFIED , " Waiting for Edge operation to terminate timed out" );
509+ }
510+
477511static ICoreWebView2CookieManager getCookieManager () {
478512 WebViewEnvironment environmentWrapper = webViewEnvironments .get (Display .getCurrent ());
479513 if (environmentWrapper == null ) {
@@ -503,6 +537,10 @@ void checkDeadlock() {
503537 }
504538}
505539
540+ void errorTimedOut (Throwable throwable ) {
541+ SWT .error (SWT .ERROR_UNSPECIFIED , throwable , "Edge Browser initialization timed out" );
542+ }
543+
506544WebViewEnvironment createEnvironment () {
507545 Display display = Display .getCurrent ();
508546 WebViewEnvironment existingEnvironment = webViewEnvironments .get (display );
@@ -609,12 +647,16 @@ private IUnknown createControllerInitializationCallback(int previousAttempts) {
609647 if (result == OS .HRESULT_FROM_WIN32 (OS .ERROR_INVALID_STATE )) {
610648 initializationAbortion .run ();
611649 SWT .error (SWT .ERROR_INVALID_ARGUMENT , null ,
612- " Edge instance with same data folder but different environment options already exists " );
650+ "Edge Initialization Timed Out " );
613651 }
614652 switch ((int ) result ) {
615653 case COM .S_OK :
616654 new IUnknown (pv ).AddRef ();
617- setupBrowser ((int ) result , pv );
655+ boolean success = setupBrowser ((int ) result , pv );
656+ if (!success ) {
657+ rollbackInitialization ();
658+ errorTimedOut (null );
659+ }
618660 break ;
619661 case COM .E_WRONG_THREAD :
620662 initializationAbortion .run ();
@@ -624,7 +666,7 @@ private IUnknown createControllerInitializationCallback(int previousAttempts) {
624666 initializationAbortion .run ();
625667 break ;
626668 default :
627- initializationRollback . run ();
669+ rollbackInitialization ();
628670 if (previousAttempts < MAXIMUM_CREATION_RETRIES ) {
629671 System .err .println (String .format ("Edge initialization failed, retrying (attempt %d / %d)" , previousAttempts + 1 , MAXIMUM_CREATION_RETRIES ));
630672 createInstance (previousAttempts + 1 );
@@ -638,10 +680,22 @@ private IUnknown createControllerInitializationCallback(int previousAttempts) {
638680 });
639681}
640682
641- void setupBrowser (int hr , long pv ) {
683+ private void rollbackInitialization () {
684+ webViewProvider .abortInitialization ();
685+ if (environment2 != null ) {
686+ environment2 .Release ();
687+ environment2 = null ;
688+ }
689+ containingEnvironment .instances ().remove (this );
690+ }
691+
692+ boolean setupBrowser (int hr , long pv ) {
642693 long [] ppv = new long [] {pv };
643694 controller = new ICoreWebView2Controller (ppv [0 ]);
644695 final ICoreWebView2 webView = webViewProvider .initializeWebView (controller );
696+ if (webView == null ) {
697+ return false ;
698+ }
645699 webView .get_Settings (ppv );
646700 settings = new ICoreWebView2Settings (ppv [0 ]);
647701
@@ -741,19 +795,15 @@ void setupBrowser(int hr, long pv) {
741795 if (browser .isFocusControl ()) {
742796 browserFocusIn (new Event ());
743797 }
798+ return true ;
744799}
745800
746801void browserDispose (Event event ) {
747802 containingEnvironment .instances .remove (this );
748803 webViewProvider .scheduleWebViewTask (() -> {
749- webViewProvider .getWebView ( false ). Release ();
804+ webViewProvider .releaseWebView ();
750805 if (environment2 != null ) environment2 .Release ();
751806 if (settings != null ) settings .Release ();
752- if (webViewProvider .isWebView_2Available ()) webViewProvider .getWebView_2 (false ).Release ();
753- if (webViewProvider .isWebView_10Available ()) webViewProvider .getWebView_10 (false ).Release ();
754- if (webViewProvider .isWebView_11Available ()) webViewProvider .getWebView_11 (false ).Release ();
755- if (webViewProvider .isWebView_12Available ()) webViewProvider .getWebView_12 (false ).Release ();
756- if (webViewProvider .isWebView_13Available ()) webViewProvider .getWebView_13 (false ).Release ();
757807 if (controller != null ) {
758808 // Bug in WebView2. Closing the controller from an event handler results
759809 // in a crash. The fix is to delay the closure with asyncExec.
0 commit comments