Yaron 53 Posted December 1, 2021 I am using the microsoft's WebView2 API to embed the chromium based edge browser inside my Delphi 7 application (using Winsoft's WebView2 wrapper component). My problem is that WebView2's ExecuteScript function returns results asynchronously through a call-back function, which is a problem because my app needs to setup a few things based on the javascript function's result and can't proceed until the data is available. I couldn't find any way in Delphi to process the results synchronously without calling "Application.ProcessMessages" in a loop until the result function is triggered (I can't use "Sleep" because then the result function will never be triggered). Of course calling "Application.ProcessMessages" in a loop is not very desirable, so I'm wondering if there's a better approach? Share this post Link to post
FPiette 383 Posted December 1, 2021 You should think "event driven" and no "synchronous". Put all your code after the ExecuteScript call into another function. Then call that function from the callback. Probably your application will need other changes to become fully event driven without using any "wait loop" hack. 3 Share this post Link to post
Yaron 53 Posted December 1, 2021 I'm not sure how event driven would help me here, I have to wait until specific data is returned from a javascript function before allowing the code to proceed. Here's a real life example: 1. A user presses "play" in my app to play content. 2. I execute a javascript function to return data on the content (e.g. duration in seconds). 3. I now need to display the a position bar on a timeline to the user, which uses a combination of duration and the current position (which isn't always "0" when starting playback of live feeds). As soon as the user presses "play", I want to block all UI interaction until I get my data back from the javascript function. Sure, I can artificially block UI interaction by disabling every UI entry point, but that would be a messy workaround when all I need is the javascript function to return the result synchronously. Share this post Link to post
Edwin Yip 154 Posted December 1, 2021 Sorry, but I'm able to help as I don't use it, but may I start a small not-so-off-topic discussion? When I first read from your post that winsoft has a WebView2 wrapper which supports old version of Delphi, I was exciting, thought that old Delphi can finally have the "TEdgeBrowser" component introduced in newer Delphi. Than I realized that in order to use it, the client PC would have to download a 123 MB WebView2 runtime! Oh, in that case, I think I'll keep using our good old Cef4Delphi... I'm puzzled, it seems that TEdgeBrowser also request that 120+ MB WebView2 run-time. I mean, why bother? Why not just use cef4delphi which provides you much more power and flexibility? This is a genuine question. Share this post Link to post
Der schöne Günther 316 Posted December 1, 2021 24 minutes ago, Yaron said: As soon as the user presses "play", I want to block all UI interaction until I get my data back from the javascript function. Why would you want to do that? Is a progress bar that vital? Why not just Go fetch progress On Result: paint progress bar Which is what @FPiette has outlined with moving the code that works with the JavaScript result into a seperate function and calling that one from your callback. Share this post Link to post
FPiette 383 Posted December 1, 2021 Quote I have to wait until specific data is returned from a JavaScript function before allowing the code to proceed. You don't wait. As I said, put the code to be executed after JavaScript finished execution in a function and call that function from the callback. A call back function in Delphi terminology is an event handler.. Quote Here's a real life example: 1. A user presses "play" in my app to play content. 2. I execute a JavaScript function to return data on the content (e.g. duration in seconds). 3. I now need to display the a position bar on a timeline to the user, which uses a combination of duration and the current position (which isn't always "0" when starting playback of live feeds). Your app doesn't wait that the user press the "play" button. You get an event when the button is pressed and from there, you start the task you have to do, that is execute JavaScript. Then, you don't wait for the JavaScript execution, you just return. The code to be executed (A position bar on the timeline) once JavaScript is done is called from the WebView2 callback (That is an event). Quote As soon as the user presses "play", I want to block all UI interaction until I get my data back from the JavaScript function. From the "play" button click event, you disable the button and you re-enable it once you get the JavaScript done. 1 Share this post Link to post
Yaron 53 Posted December 1, 2021 @FPiette My application has over 100 keyboard macros, many dynamically created UI elements (skinned buttons) and even a TCP/IP control API (used for remote control) that can trigger events that should not be activated while a new media is in the process of loading, I can't simply disable one button, I have to disable 100's of elements and several event triggers that may execute unwanted functionality while waiting for the javascript callback event to trigger. Sure, I can do that, but it would take a lot more work than just having WebView2 return a result synchronously like TWebBrowser is able to do. @Edwin Yip I considered CEF4Delphi, but from my initial investigation, there were several show-stoppers, including the possible illegality of including audio/video codecs required by YouTube in the compiled binary, something I'm not willing to do. With regards to the 120+ MB WebView2 download, it won't be a thing in Windows 11 as WebView2 comes pre-installed on Win11. For Win10, I offer my users a quick setup option to download and install the evergreen version of WebView2 without much hassle. 1 Share this post Link to post
FPiette 383 Posted December 1, 2021 2 hours ago, Yaron said: I have to disable 100's of elements and several event triggers that may execute unwanted functionality while waiting for the javascript callback event to trigger. One possibility I see is to open a modal form just after the call to ExecuteScript and have that form closed by the callback. The modal form could be empty or even so small that the user won't notice it or it can be a place for a progress bar, a cancel button or just a "please wait" message. Share this post Link to post
Stano 143 Posted December 1, 2021 The modal form can also be off-screen. Form.Height := 1; Form.Widht := 1; Form.Top := -100; Form.Left := -100; I even use it. The reason is its unwanted rendering and flickering. Share this post Link to post
Fr0sT.Brutal 900 Posted December 2, 2021 You also can run custom message loop that will process WV's messages and stash/drop/whatever all others. Or, just switch the main window off with EnableWindow (that's how modality works in fact). Share this post Link to post
BobTheBuilder 0 Posted March 2, 2022 This is a bit of an old topic but since I found it via a google search people in the future will likely see it too, so here are my two cents: Using a modal form is almost the same as having a loop with Application.ProcessMessages in it. The .ShowModal function literally contains this a repeat-until loop with Application.ProcessMessages inside of it. BUT: If you don't use a modal form then Application.ProcessMessages will execute things like clicking on buttons on other forms than the modal form which isn't desired while you wait for the javascript response. Meanwhile .ShowModal blocks the use of all other forms except the form it was called from. So either use a modal form as the easy way out or add a boolean that is set while waiting for the response in a loop with Application.ProcessMessages. All event functions for gui interaction should check that and exit if it is true. Problem solved. Share this post Link to post