Webview2 control - Chromium browser for Purebasic (Windows) [Jan 1, 2024]

Everything else that doesn't fall into one of the other PB categories.
vmars316
Enthusiast
Enthusiast
Posts: 464
Joined: Fri Jun 29, 2012 12:24 am
Contact:

Re: Webview2 control - Chromium browser for Purebasic (Windows)

Post by vmars316 »

"x64 is the bigger one." Thanks
vmars.us Win11 x64 , Martin Guitar 000-16 (1995)
"All things in moderation , except for love and forgiveness."
vmars316
Enthusiast
Enthusiast
Posts: 464
Joined: Fri Jun 29, 2012 12:24 am
Contact:

Re: Webview2 control - Chromium browser for Purebasic (Windows)

Post by vmars316 »

Hi ,
I tested out KidSafeBrowser quite thoroughly on the same computer used to program it .
Yesterday I had a chance to Test it on two other computers .
And they both gave an Error msg "Unable to create WebView2 environment" .
Does that mean I need to include "Ms Edge WebView Runtime" on all user computers .
Or did I leave a component out ?
I did include KidSafeBrowser.exe.WebView2 , gdiplus , WebView2Loader.lib , WebView2Loader.dll in the download .
Thanks
vmars.us Win11 x64 , Martin Guitar 000-16 (1995)
"All things in moderation , except for love and forgiveness."
Justin
Addict
Addict
Posts: 829
Joined: Sat Apr 26, 2003 2:49 pm

Re: Webview2 control - Chromium browser for Purebasic (Windows)

Post by Justin »

Yes, the Webview runtime must be installed in every computer:

https://developer.microsoft.com/en-us/m ... /webview2/
vmars316
Enthusiast
Enthusiast
Posts: 464
Joined: Fri Jun 29, 2012 12:24 am
Contact:

Re: Webview2 control - Chromium browser for Purebasic (Windows)

Post by vmars316 »

Thanks
vmars.us Win11 x64 , Martin Guitar 000-16 (1995)
"All things in moderation , except for love and forgiveness."
User avatar
Derren
Enthusiast
Enthusiast
Posts: 313
Joined: Sat Jul 23, 2011 1:13 am
Location: Germany

Re: Webview2 control - Chromium browser for Purebasic (Windows)

Post by Derren »

Yay, I can finally use it.

One questions. Is there a way to change (catch) the error message for a missing DLL? And to possibly rename the DLL (if the license permits this)?
I couldn't find the call for the DLL in the code, perhaps it's hidden in some lib file or other.

Since the DLL is necessary even with the installed runtime package, it would be nice to include it in the programm and save to disk in case it was removed.

Thanks :)

btw: any progress in makink this a native "Gadget" in PureBasic, I might have missed?
Justin
Addict
Addict
Posts: 829
Joined: Sat Apr 26, 2003 2:49 pm

Re: Webview2 control - Chromium browser for Purebasic (Windows)

Post by Justin »

Hi,

i used the import system to load the dll the code is in WebView2Loader.pbi, to check the error you can try to check the dll existence or maybe use the OpenLibrary() system instead.

With the import system you can change the dll name but you have to generate a .lib with the same name with polib:
polib /MACHINE:X64 /OUT:yourname.lib yourname.dll

Luis made a very good module to load dlls from inside the executable, i haven't tested with this one but with another worked:
https://www.purebasic.fr/english/viewto ... lit=memdll
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Webview2 control - Chromium browser for Purebasic (Windows)

Post by infratec »

Hi Justin,

I tried your stuff and to make it run I needed to modify the WebView2Loader.pbi:

Code: Select all

; CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
; 	Import "x64\WebView2Loader.lib"
; 	
; CompilerElse
; 	Import "x86\WebView2Loader.lib"
; CompilerEndIf
; 
; 	CreateCoreWebView2Environment(environment_created_handler.i)
; 	CreateCoreWebView2EnvironmentWithOptions(browserExecutableFolder.s, userDataFolder.s, environmentOptions.i, environment_created_handler.i)
; 	GetAvailableCoreWebView2BrowserVersionString(browserExecutableFolder.s, versionInfo.i)
; 	CompareBrowserVersions(version1.s, version2.s, result.i)
; EndImport


Prototype.i Prototype_CreateCoreWebView2Environment(environment_created_handler.i)
Prototype.i Prototype_CreateCoreWebView2EnvironmentWithOptions(browserExecutableFolder.s, userDataFolder.s, environmentOptions.i, environment_created_handler.i)
Prototype.i Prototype_GetAvailableCoreWebView2BrowserVersionString(browserExecutableFolder.s, versionInfo.i)
Prototype.i Prototype_CompareBrowserVersions(version1.s, version2.s, result.i)

Global.i CreateCoreWebView2Environment.Prototype_CreateCoreWebView2Environment
Global.i CreateCoreWebView2EnvironmentWithOptions.Prototype_CreateCoreWebView2EnvironmentWithOptions
Global.i GetAvailableCoreWebView2BrowserVersionString.Prototype_GetAvailableCoreWebView2BrowserVersionString
Global.i CompareBrowserVersions.Prototype_CompareBrowserVersions


Global WebView2DLL.i
WebView2DLL = OpenLibrary(#PB_Any, "WebView2Loader.dll")
If WebView2DLL
  CreateCoreWebView2Environment = GetFunction(WebView2DLL, "CreateCoreWebView2Environment")
  CreateCoreWebView2EnvironmentWithOptions = GetFunction(WebView2DLL, "CreateCoreWebView2EnvironmentWithOptions")
  GetAvailableCoreWebView2BrowserVersionString = GetFunction(WebView2DLL, "GetAvailableCoreWebView2BrowserVersionString")
  CompareBrowserVersions = GetFunction(WebView2DLL, "CompareBrowserVersions")
EndIf
With the original Import I run into Unresolved externals. No idea why.

Ok, then it was possible to run your examples.
But I needed 2 WebGadgets,
So I implemented a 'real' Gadget:

Code: Select all

CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf


; https://developer.microsoft.com/de-de/microsoft-edge/webview2/
; https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.winforms.webview2

IncludeFile "PBWebView2.pb"


Prototype.i Prototype_NavigationCallback(Gadget.i, URL$)


Structure WebView2Gadget_Structure
  wvEnvironment.ICoreWebView2Environment
  wvController.ICoreWebView2Controller
  wvCore.ICoreWebView2_12
  wvOptions.ICoreWebView2EnvironmentOptions
  wvSettings.ICoreWebView2Settings6
  wvDownloadOperation.ICoreWebView2DownloadOperation
  *eventNavigationCompleted.WV2_EVENT_HANDLER
  *eventNavigationStarting.WV2_EVENT_HANDLER
  *eventWebResourceRequested.WV2_EVENT_HANDLER
  *eventDocumentTitleChanged.WV2_EVENT_HANDLER
  *eventStatusBarTextChanged.WV2_EVENT_HANDLER
  *eventContextMenuRequested.WV2_EVENT_HANDLER
  *eventDownloadStarting.WV2_EVENT_HANDLER
  *eventDownloadBytesReceivedChanged.WV2_EVENT_HANDLER
  *eventDownloadStateChanged.WV2_EVENT_HANDLER
  Gadget.i
  Window.i
  UserDataFolder$
  URL$
  NavigationCallback.Prototype_NavigationCallback
EndStructure


Global NewMap WebView2GadgetMap.WebView2Gadget_Structure()



Procedure WebView2SetgadgetText(Gadget.i, URL$)
  
  Protected *Gadget.WebView2Gadget_Structure
  
  *Gadget = FindMapElement(WebView2GadgetMap(), Str(Gadget))
  If *Gadget
    *Gadget\URL$ = URL$
    *Gadget\wvCore\Navigate(URL$)
  EndIf
  
EndProcedure




Procedure.s WebView2GetgadgetText(Gadget.i)
  
  Protected *Gadget.WebView2Gadget_Structure, Result$
  
  *Gadget = FindMapElement(WebView2GadgetMap(), Str(Gadget))
  If *Gadget
    Result$ = *Gadget\URL$
  EndIf
  
  ProcedureReturn Result$
  
EndProcedure




Procedure WebView2SetGadgetState(Gadget.i, State.i)
  
  Protected.l CanGoBack, CanGoForward
  Protected *Gadget.WebView2Gadget_Structure
  
  
  *Gadget = FindMapElement(WebView2GadgetMap(), Str(Gadget))
  If *Gadget
    Select State
      Case #PB_Web_Back
        *Gadget\wvCore\get_CanGoBack(@CanGoBack)
        If CanGoBack
          *Gadget\wvCore\GoBack()
        EndIf
      Case #PB_Web_Forward
        *Gadget\wvCore\get_CanGoForward(@CanGoForward)
        If CanGoForward
          *Gadget\wvCore\GoForward()
        EndIf
      Case #PB_Web_Stop
        *Gadget\wvCore\Stop()
      Case #PB_Web_Refresh
        *Gadget\wvCore\Reload()
    EndSelect
  EndIf
  
EndProcedure



Procedure WebView2SetGadgetItemText(Gadget.i, Entry.i, Text$, Column.i=0)
  
  Protected *Gadget.WebView2Gadget_Structure
  
  
  *Gadget = FindMapElement(WebView2GadgetMap(), Str(Gadget))
  If *Gadget
    Select Entry        
      Case #PB_Web_HtmlCode
        *Gadget\wvCore\ExecuteScript(Text$, #Null)
    EndSelect
  EndIf
  
EndProcedure




Procedure.s WebView2GetGadgetItemText(Gadget.i, Entry.i, Column.i=0)
  
  Protected *Gadget.WebView2Gadget_Structure, Result$, *Text, Script$, Text$
  
  
  *Gadget = FindMapElement(WebView2GadgetMap(), Str(Gadget))
  If *Gadget
    Select Entry
      Case #PB_Web_PageTitle
        *Gadget\wvCore\get_DocumentTitle(@*Text)
        If *Text
          Result$ = PeekS(*Text)
          CoTaskMemFree_(*Text)
        EndIf
        
      Case #PB_Web_StatusMessage
        *Gadget\wvCore\get_StatusBarText(@*Text)
        If *Text
          Result$ = PeekS(*Text)
          CoTaskMemFree_(*Text)
        EndIf
        
      Case #PB_Web_SelectedText
        Script$ = "window.getSelection().toString()"
        Text$ = wv2_Core_ExecuteScriptSync(*Gadget\wvCore, Script$)
        If Text$
		      Result$ = json_GetString(Text$)
	      EndIf
        
      Case #PB_Web_HtmlCode
        Script$ = "document.documentElement.outerHTML"
        Text$ = wv2_Core_ExecuteScriptSync(*Gadget\wvCore, Script$)
        If Text$
		      Result$ = json_GetString(Text$)
	      EndIf
        
    EndSelect
  EndIf
  
  ProcedureReturn Result$
  
EndProcedure




Procedure WebView2SetGadgetAttribute(Gadget.i, Attribute.i, Value.i)
  
  Protected *Gadget.WebView2Gadget_Structure
  
  
  *Gadget = FindMapElement(WebView2GadgetMap(), Str(Gadget))
  If *Gadget
    Select Attribute
      Case #PB_Web_NavigationCallback
        *Gadget\NavigationCallback = Value
    EndSelect
  EndIf
  
EndProcedure




Procedure.i WebView2GetGadgetAttribute(Gadget.i, Attribute.i, Value.i)
  
  Protected *Gadget.WebView2Gadget_Structure, Result.i
  
  
  *Gadget = FindMapElement(WebView2GadgetMap(), Str(Gadget))
  If *Gadget
    Select Attribute
      Case #PB_Web_NavigationCallback
        Result = *Gadget\NavigationCallback
      Case #PB_Web_Progress
        *Gadget\wvDownloadOperation\get_BytesReceived(@Result)
      Case #PB_Web_ProgressMax
        *Gadget\wvDownloadOperation\get_TotalBytesToReceive(@Result)
    EndSelect
  EndIf
  
  ProcedureReturn Result
  
EndProcedure




Procedure WebView2Gadget_Resize()
  
  Protected Gadget.i
  Protected wvBounds.RECT
  Protected *Gadget.WebView2Gadget_Structure
  
  
  ;Debug "WebView2Gadget_Resize"
  Gadget = EventGadget()
  ;Debug "Gadget: " + Str(Gadget)
  
  Gadget = EventGadget()
  
  *Gadget = FindMapElement(WebView2GadgetMap(), Str(Gadget))
  If *Gadget
    
    If *Gadget\wvController
      
      BringWindowToTop_(GadgetID(*Gadget\Gadget)) ; else problem if it overlaps an other gGadget
      
      wvBounds\left = 0
      wvBounds\top = 0
      wvBounds\bottom = wvBounds\top + DesktopScaledY(GadgetHeight(Gadget))
      wvBounds\right = wvBounds\left + DesktopScaledX(GadgetWidth(Gadget))
      
      wv2_Controller_put_Bounds(*Gadget\wvController, @wvBounds)
    EndIf
    
  EndIf
  
EndProcedure


Procedure WebView2GadgetNavigationStarting(*this.WV2_EVENT_HANDLER, sender.ICoreWebView2, args.ICoreWebView2NavigationStartingEventArgs)
  
  Protected *Gadget.WebView2Gadget_Structure, *uri
  
  
  ;Debug "WebView2GadgetNavigationStarting"
  ;Debug "Gadget: " + Str(*this\context)
  
  *Gadget = FindMapElement(WebView2GadgetMap(), Str(*this\context))
  If *Gadget
    
    If args\get_uri(@*uri) = #S_OK
      *Gadget\URL$ = PeekS(*uri)
      CoTaskMemFree_(*uri)
      
      If *Gadget\NavigationCallback
        If Not *Gadget\NavigationCallback(*this\context, *Gadget\URL$)
          args\put_Cancel(#True)
        EndIf
      EndIf
      
    EndIf
    
  EndIf
EndProcedure


Procedure WebView2GadgetNavigationCompleted(*this.WV2_EVENT_HANDLER, sender.ICoreWebView2, args.ICoreWebView2NavigationCompletedEventArgs)
  ;Debug "WebView2GadgetNavigationCompleted"
  ;Debug "Gadget: " + Str(*this\context)
EndProcedure




Procedure WebView2GadgetDocumentTitleChanged(*this.WV2_EVENT_HANDLER, sender.ICoreWebView2, args.ICoreWebView2NavigationCompletedEventArgs)
  
  Protected *Gadget.WebView2Gadget_Structure
  
  
  ;Debug "WebView2GadgetDocumentTitleChanged"
  ;Debug "Gadget: " + Str(*this\context)
  
  *Gadget = FindMapElement(WebView2GadgetMap(), Str(*this\context))
  If *Gadget
    PostEvent(#PB_Event_Gadget, *Gadget\Window, *Gadget\Gadget, #PB_EventType_TitleChange)
  EndIf
  
EndProcedure




Procedure WebView2GadgetStatusBarTextChanged(*this.WV2_EVENT_HANDLER, sender.ICoreWebView2, args.ICoreWebView2NavigationCompletedEventArgs)
  
  Protected *Gadget.WebView2Gadget_Structure
  
  
  ;Debug "WebView2GadgetStatusBarTextChanged"
  ;Debug "Gadget: " + Str(*this\context)
  
  *Gadget = FindMapElement(WebView2GadgetMap(), Str(*this\context))
  If *Gadget
    PostEvent(#PB_Event_Gadget, *Gadget\Window, *Gadget\Gadget, #PB_EventType_StatusChange)
  EndIf
  
EndProcedure




Procedure WebView2GadgetDownloadBytesReceivedChanged(*this.WV2_EVENT_HANDLER, sender.ICoreWebView2, args.ICoreWebView2NavigationCompletedEventArgs)
  
  Protected *Gadget.WebView2Gadget_Structure, BytesReceived.i
  
  
  Debug "WebView2GadgetBytesReceivedChanged"
  Debug "Gadget: " + Str(*this\context)
  
  *Gadget = FindMapElement(WebView2GadgetMap(), Str(*this\context))
  If *Gadget
    *Gadget\wvDownloadOperation\get_BytesReceived(@BytesReceived)
    Debug BytesReceived
    PostEvent(#PB_Event_Gadget, *Gadget\Window, *Gadget\Gadget, #PB_EventType_DownloadProgress, BytesReceived)
  EndIf
  
EndProcedure




Procedure WebView2GadgetDownloadStateChanged(*this.WV2_EVENT_HANDLER, sender.ICoreWebView2, args.ICoreWebView2NavigationCompletedEventArgs)
  
  Protected *Gadget.WebView2Gadget_Structure, State.i
  
  
  Debug "WebView2GadgetBytesReceivedChanged"
  Debug "Gadget: " + Str(*this\context)
  
  *Gadget = FindMapElement(WebView2GadgetMap(), Str(*this\context))
  If *Gadget
    *Gadget\wvDownloadOperation\get_State(@State)
    Select State
      Case #COREWEBVIEW2_DOWNLOAD_STATE_IN_PROGRESS
        Debug "Progress"
        PostEvent(#PB_Event_Gadget, *Gadget\Window, *Gadget\Gadget, #PB_EventType_DownloadProgress)
      Case #COREWEBVIEW2_DOWNLOAD_STATE_INTERRUPTED, #COREWEBVIEW2_DOWNLOAD_STATE_COMPLETED
        Debug "Interrupted or Completed"
        PostEvent(#PB_Event_Gadget, *Gadget\Window, *Gadget\Gadget, #PB_EventType_DownloadEnd)
    EndSelect
  EndIf
  
EndProcedure




Procedure WebView2GadgetDownloadStarting(*this.WV2_EVENT_HANDLER, sender.ICoreWebView2, args.ICoreWebView2DownloadStartingEventArgs)
  
  Protected *Gadget.WebView2Gadget_Structure
  
  
  Debug "WebView2GadgetDownloadStarting"
  Debug "Gadget: " + Str(*this\context)
  
  *Gadget = FindMapElement(WebView2GadgetMap(), Str(*this\context))
  If *Gadget
    
    If *Gadget\wvDownloadOperation
      *Gadget\wvDownloadOperation\remove_StateChanged(#Null)
      *Gadget\wvDownloadOperation\remove_BytesReceivedChanged(#Null)
      *Gadget\wvDownloadOperation\Release()
    EndIf
    
    args\get_DownloadOperation(@*Gadget\wvDownloadOperation)
    *Gadget\eventDownloadBytesReceivedChanged = wv2_EventHandler_New(@WebView2GadgetDownloadBytesReceivedChanged(), *this\context)
    *Gadget\wvDownloadOperation\add_BytesReceivedChanged(*Gadget\eventDownloadBytesReceivedChanged, #Null)
    
    *Gadget\eventDownloadStateChanged = wv2_EventHandler_New(@WebView2GadgetDownloadStateChanged(), *this\context)
    *Gadget\wvDownloadOperation\add_StateChanged(*Gadget\eventDownloadStateChanged, #Null)
    
    PostEvent(#PB_Event_Gadget, *Gadget\Window, *Gadget\Gadget, #PB_EventType_DownloadStart)
  EndIf
  
EndProcedure




Procedure WebView2GadgetContextMenuRequested(*this.WV2_EVENT_HANDLER, sender.ICoreWebView2, args.ICoreWebView2DownloadStartingEventArgs)
  
  Protected *Gadget.WebView2Gadget_Structure
  
  
  Debug "WebView2GadgetDownloadStarting"
  Debug "Gadget: " + Str(*this\context)
  
  *Gadget = FindMapElement(WebView2GadgetMap(), Str(*this\context))
  If *Gadget
    PostEvent(#PB_Event_Gadget, *Gadget\Window, *Gadget\Gadget, #PB_EventType_PopupMenu)
  EndIf
  
EndProcedure




Procedure Webview2Controller_Created(*this.WV2_EVENT_HANDLER, result.l, controller.ICoreWebView2Controller)
  
  Protected *Gadget.WebView2Gadget_Structure, *Get, wvBounds.RECT
  
  
  Debug "Webview2Controller_Created"
  Debug "Gadget: " + Str(*this\context)
  
  *Gadget = FindMapElement(WebView2GadgetMap(), Str(*this\context))
  If *Gadget
    
    If result = #S_OK
      
      controller\QueryInterface(?IID_ICoreWebView2Controller, @*Gadget\wvController)
      *Gadget\wvController\get_CoreWebView2(@*Gadget\wvCore)
            
      ; Setup events
      *Gadget\eventNavigationCompleted = wv2_EventHandler_New(@WebView2GadgetNavigationCompleted(), *this\context)
      *Gadget\wvCore\add_NavigationCompleted(*Gadget\eventNavigationCompleted, #Null)
      
      *Gadget\eventNavigationStarting = wv2_EventHandler_New(@WebView2GadgetNavigationStarting(), *this\context)
      *Gadget\wvCore\add_NavigationStarting(*Gadget\eventNavigationStarting, #Null)
      
      *Gadget\eventDocumentTitleChanged = wv2_EventHandler_New(@WebView2GadgetDocumentTitleChanged(), *this\context)
      *Gadget\wvCore\add_DocumentTitleChanged(*Gadget\eventDocumentTitleChanged, #Null)
      
      *Gadget\eventDownloadStarting = wv2_EventHandler_New(@WebView2GadgetDownloadStarting(), *this\context)
      *Gadget\wvCore\add_DownloadStarting(*Gadget\eventDownloadStarting, #Null)
      
      *Gadget\eventStatusBarTextChanged = wv2_EventHandler_New(@WebView2GadgetStatusBarTextChanged(), *this\context)
      *Gadget\wvCore\add_StatusBarTextChanged(*Gadget\eventStatusBarTextChanged, #Null)
      
      *Gadget\eventContextMenuRequested = wv2_EventHandler_New(@WebView2GadgetContextMenuRequested(), *this\context)
      *Gadget\wvCore\add_ContextMenuRequested(*Gadget\eventContextMenuRequested, #Null)
      
      ; Settings
      ; https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/winrt/microsoft_web_webview2_core/corewebview2settings
      *Gadget\wvCore\get_Settings(@*Gadget\wvSettings)
      *Gadget\wvSettings\put_AreBrowserAcceleratorKeysEnabled(#False) ; 
      *Gadget\wvSettings\put_IsStatusBarEnabled(#False) ; don't show the links t the bottom
      *Gadget\wvSettings\put_AreDevToolsEnabled(#False) ; don't allow DevTools
      ;*Gadget\wvSettings\put_AreDefaultContextMenusEnabled(#False) ; disable browser context popup
      *Gadget\wvSettings\put_IsBuiltInErrorPageEnabled(#False)
      
      ; Resize it
      wvBounds\left = 0
      wvBounds\top = 0
      wvBounds\bottom = wvBounds\top + DesktopScaledY(GadgetHeight(*this\context))
      wvBounds\right = wvBounds\left + DesktopScaledX(GadgetWidth(*this\context))
      
      wv2_Controller_put_Bounds(*Gadget\wvController, @wvBounds)
      
      ; Go to startpage
      *Gadget\wvCore\Navigate(*Gadget\URL$)
      
      wv2_EventHandler_Release(*this)
      
      *Gadget\wvOptions\get_AdditionalBrowserArguments(@*Get)
      Debug PeekS(*Get)
      CoTaskMemFree_(*Get)
      
    Else
      MessageRequester("Error", "Failed to create WebView2Controller.")
      End
    EndIf 
    
  EndIf
  
EndProcedure



Procedure WebView2Environment_Created(*this.WV2_EVENT_HANDLER, result.l, environment.ICoreWebView2Environment)
  
  Protected *Gadget.WebView2Gadget_Structure
  
  Debug "WebView2Environment_Created"
  Debug "Gadget: " + Str(*this\context)
  
  
  *Gadget = FindMapElement(WebView2GadgetMap(), Str(*this\context))
  If *Gadget
    
    If result = #S_OK
      environment\QueryInterface(?IID_ICoreWebView2Environment, @*Gadget\wvEnvironment)
      *Gadget\wvEnvironment\CreateCoreWebView2Controller(GadgetID(*Gadget\Gadget), wv2_EventHandler_New(@Webview2Controller_Created(), *this\Context))
      
      wv2_EventHandler_Release(*this)
      *Gadget\wvEnvironment\Release()
    Else
      MessageRequester("Error", "Failed to create WebView2Environment.")
      End
    EndIf
    
  EndIf
  
EndProcedure




Procedure WebView2CleanUp()
  
  Protected UserDataFolder$
  
  
  Debug "WebView2CleanUp"
  
  ForEach WebView2GadgetMap()
    WebView2GadgetMap()\wvController\Close()
    WebView2GadgetMap()\wvController\Release()
    
    
    If WebView2GadgetMap()\wvSettings
      WebView2GadgetMap()\wvSettings\Release()
    EndIf
    
    If WebView2GadgetMap()\wvCore
      WebView2GadgetMap()\wvCore\Release()
    EndIf
    
    If WebView2GadgetMap()\eventNavigationCompleted
      wv2_EventHandler_Release(WebView2GadgetMap()\eventNavigationCompleted)
    EndIf
    
    If WebView2GadgetMap()\eventNavigationStarting
      wv2_EventHandler_Release(WebView2GadgetMap()\eventNavigationStarting)
    EndIf
    
    If WebView2GadgetMap()\eventWebResourceRequested
      wv2_EventHandler_Release(WebView2GadgetMap()\eventWebResourceRequested)
    EndIf
    
    If WebView2GadgetMap()\eventDocumentTitleChanged
      wv2_EventHandler_Release(WebView2GadgetMap()\eventDocumentTitleChanged)
    EndIf
    
    If WebView2GadgetMap()\wvOptions
      WebView2GadgetMap()\wvOptions\Release()
    EndIf
    
    If WebView2GadgetMap()\eventDownloadStarting
      wv2_EventHandler_Release(WebView2GadgetMap()\eventDownloadStarting)
    EndIf
    
    If WebView2GadgetMap()\eventDownloadBytesReceivedChanged
      wv2_EventHandler_Release(WebView2GadgetMap()\eventDownloadBytesReceivedChanged)
    EndIf
    
    If WebView2GadgetMap()\eventDownloadStateChanged
      wv2_EventHandler_Release(WebView2GadgetMap()\eventDownloadStateChanged)
    EndIf
    
    If WebView2GadgetMap()\wvDownloadOperation
      WebView2GadgetMap()\wvDownloadOperation\Release()
    EndIf
    
  Next
  
  Delay(1000) ; shit, but needed
  
  ForEach WebView2GadgetMap()
    Debug "cmd /c " + #DQUOTE$ + "rd /s /q " + WebView2GadgetMap()\UserDataFolder$ + #DQUOTE$
    RunProgram("cmd", "/c " + #DQUOTE$ + "rd /s /q " + WebView2GadgetMap()\UserDataFolder$ + #DQUOTE$, "", #PB_Program_Hide)
  Next
  
EndProcedure




Procedure.i WebView2Gadget(Gadget.i, x.i, y.i, width.i, height.i, URL$)
  
  Protected.i Window, InternalGadget, Options$
  
  
  Debug "WebView2Gadget()"
  
  If WebView2DLL
    If wv2_GetBrowserVersion("") <> ""
      
      If Gadget = #PB_Any
        InternalGadget = ContainerGadget(Gadget, x, y, width, height, #PB_Container_BorderLess)
        If InternalGadget = 0
          InternalGadget = -1
        EndIf
      Else
        If ContainerGadget(Gadget, x, y, width, height, #PB_Container_Single)
          InternalGadget = Gadget
        Else
          InternalGadget = -1
        EndIf
      EndIf
      
      If InternalGadget <> -1
        CloseGadgetList()
        
        AddMapElement(WebView2GadgetMap(), Str(InternalGadget))
        
        WebView2GadgetMap()\Gadget = InternalGadget
        WebView2GadgetMap()\Window = GetActiveWindow()
        WebView2GadgetMap()\URL$ = URL$
        
        BindGadgetEvent(InternalGadget, @WebView2Gadget_Resize(), #PB_EventType_Resize)
        
        Options$ + "--inprivate "
        Options$ + "--disable-extensions "
        Options$ + "--disable-notifications "
        Options$ + "--disable-sync "
        Options$ + "--disable-features=Translate "
        Options$ + "--enable-features=msEdgeDeleteBrowsingDataOnExit "
        Options$ + "--hide-scrollbars "
        Options$ + "--no-Default-browser-check "
        Options$ + "--no-first-run "
        Options$ + "--no-experiments "
        Options$ + "--no-pings "
        Options$ + "--no-proxy-server "
        Options$ + "--noerrdialogs "
        Options$ + "--new-window"
        
        WebView2GadgetMap()\wvOptions = wv2_EnvironmentOptions_New()
        WebView2GadgetMap()\wvOptions\put_AdditionalBrowserArguments(Options$)
        
        ;WebView2GadgetMap()\wvOptions\put_Language("de")
        
        WebView2GadgetMap()\UserDataFolder$ = GetUserDirectory(#PB_Directory_ProgramData) + GetFilePart(ProgramFilename(), #PB_FileSystem_NoExtension) + #PS$ + "WebView_" + Str(Gadget)
        CreateCoreWebView2EnvironmentWithOptions("", WebView2GadgetMap()\UserDataFolder$, WebView2GadgetMap()\wvOptions, wv2_EventHandler_New(@WebView2Environment_Created(), InternalGadget))
        ;CreateCoreWebView2EnvironmentWithOptions("", "", #Null, wv2_EventHandler_New(@WebView2Environment_Created(), InternalGadget))
        ;CreateCoreWebView2EnvironmentWithOptions("", "", WebView2GadgetMap()\wvOptions, wv2_EventHandler_New(@WebView2Environment_Created(), InternalGadget))
        
      Else
        InternalGadget = 0
      EndIf
      
    Else
      MessageRequester("Error","WebView2 Not installed")
      End
    EndIf
  Else
    MessageRequester("Error","WebView2 DLL not loaded")
  EndIf
  
  ProcedureReturn InternalGadget
  
EndProcedure



CompilerIf #PB_Compiler_IsMainFile
  ;-Demo
  
  Procedure NavigationCallback(Gadget, Url$)
    
    Protected Result.i
    
    
    Result = #True
    If FindString(LCase(Url$), "www.spiderbasic.com")
      
      MessageRequester("Info", "Blocked: " + Url$)
      
      Result = #False
    EndIf
    
    ProcedureReturn Result
    
  EndProcedure
  
  
  
  Procedure ResizeIt()
    ResizeGadget(1, #PB_Ignore, #PB_Ignore, WindowWidth(0) / 2 - 5, WindowHeight(0) - 20)
    ResizeGadget(2, WindowWidth(0) / 2 + 5, #PB_Ignore, WindowWidth(0) / 2 - 5, WindowHeight(0) - 20)
  EndProcedure
  
  
  Define Event.i, EventGadget.i
  
  OpenWindow(0, 0, 0, 1230, 820, "WebView2 Gadget", #PB_Window_ScreenCentered|#PB_Window_MinimizeGadget|#PB_Window_SizeGadget)
  
  WebView2Gadget(1, 10, 10, 600, 800, "https://www.purebasic.fr/english")
  WebView2Gadget(2, 620, 10, 600, 800, "https://www.purebasic.fr/german")
  
  BindEvent(#PB_Event_SizeWindow, @ResizeIt())
  
  AddWindowTimer(0, 1, 5000)
  
  
  ;-Main loop
  Repeat
    Event = WaitWindowEvent()
    Select Event
      Case #PB_Event_Gadget
        EventGadget = EventGadget()
        Select EventGadget
          Case 1, 2
            Select EventType()
              Case #PB_EventType_TitleChange
                Debug "Gadget " + Str(EventGadget) + " TitleChanged"
                Debug "Title gadget " + Str(EventGadget) + ": " + WebView2GetGadgetItemText(EventGadget, #PB_Web_PageTitle)
              Case #PB_EventType_DownloadStart
                Debug "Gadget " + Str(EventGadget) + " download started"
              Case #PB_EventType_StatusChange
                Debug "Gadget " + Str(EventGadget) + " status changed"
                Debug "Status gadget " + Str(EventGadget) + ": " + WebView2GetGadgetItemText(EventGadget, #PB_Web_StatusMessage)
              Case #PB_EventType_DownloadStart
                Debug "Gadget " + Str(EventGadget) + "download started"
            EndSelect
        EndSelect
      Case #PB_Event_Timer
        Select EventTimer()
          Case 1
            RemoveWindowTimer(0, 1)
            Debug "Url    gadget 1: " + WebView2GetgadgetText(1)
            Debug "Url    gadget 2: " + WebView2GetgadgetText(2)
            AddWindowTimer(0, 2, 5000)
            
          Case 2
            RemoveWindowTimer(0, 2)
            Debug "Set URL of gadget 1 to https://www.purebasic.fr"
            WebView2SetgadgetText(1, "https://www.purebasic.fr")
            AddWindowTimer(0, 3, 5000)
            
          Case 3
            RemoveWindowTimer(0, 3)
            Debug "Refresh gadget 1"
            WebView2SetGadgetState(1, #PB_Web_Refresh)
            AddWindowTimer(0, 4, 5000)
            
          Case 4
            RemoveWindowTimer(0, 4)
            Debug "Back gadget 1"
            WebView2SetGadgetState(1, #PB_Web_Back)
            AddWindowTimer(0, 5, 5000)
            
          Case 5
            RemoveWindowTimer(0, 5)
            Debug "Forward gadget 1"
            WebView2SetGadgetState(1, #PB_Web_Forward)
            AddWindowTimer(0, 6, 5000)
            
          Case 6
            RemoveWindowTimer(0, 6)
            Debug "Activate NavigationCallback and block spiderbasic"
            Debug "Set URL of Gadget 2 to https://www.spiderbasic.com"
            WebView2SetgadgetAttribute(2, #PB_Web_NavigationCallback, @NavigationCallback())
            WebView2SetgadgetText(2, "https://www.spiderbasic.com")
            AddWindowTimer(0, 7, 5000)
            
          Case 7
            RemoveWindowTimer(0, 7)
            Debug "Remove NavigationCallback"
            Debug "Set URL of gadget 2 to https://www.spiderbasic.com"
            WebView2SetgadgetAttribute(2, #PB_Web_NavigationCallback, #Null)
            WebView2SetgadgetText(2, "https://www.spiderbasic.com")
            AddWindowTimer(0, 8, 5000)
            
          Case 8
            RemoveWindowTimer(0, 8)
            Debug "Get html code from gadget 1"
            Debug WebView2GetGadgetItemText(1, #PB_Web_HtmlCode)
            ;Debug WebView2GetGadgetItemText(1, #PB_Web_SelectedText)
            AddWindowTimer(0, 9, 5000)
            
          Case 9
            RemoveWindowTimer(0, 9)
            Debug "Inject code in gadget 1"
            WebView2SetGadgetItemText(1, #PB_Web_HtmlCode, "alert('This demo was presented by infratec');")
            
        EndSelect
    EndSelect
  Until Event = #PB_Event_CloseWindow
  
  CloseWindow(0)
  
  WebView2CleanUp()
  
CompilerEndIf
For the new stuff it was needed to extend WebView2.pbi: (Insert it at line 1512)

Code: Select all

;- ICoreWebView2_8

DataSection
	IID_ICoreWebView2_8:
	Data.l $E9632730
	Data.w $6E1E, $43AB
	Data.b $B7, $B8, $7B, $2C, $9E, $62, $E0, $94
EndDataSection

Interface ICoreWebView2_8 Extends ICoreWebView2_7
  add_IsMutedChanged(*eventHandler, *token)
  remove_IsMutedChanged(token.l)
  get_IsMuted(*value)
  put_IsMuted(value.l)
  add_IsDocumentPlayingAudioChanged(*eventHandler, *token)
  remove_IsDocumentPlayingAudioChanged(token.l)
  get_IsDocumentPlayingAudio(*value)
EndInterface 


;- ICoreWebView2_9

DataSection
	IID_ICoreWebView2_9:
	Data.l $4d7b2eab
	Data.w $9fdc, $468d
	Data.b $b9, $98, $a9, $26, $0b, $5e, $d6, $51
EndDataSection

Interface ICoreWebView2_9 Extends ICoreWebView2_8
  add_IsDefaultDownloadDialogOpenChanged(*handler, *token)
  remove_IsDefaultDownloadDialogOpenChanged(token.l)
  get_IsDefaultDownloadDialogOpen(*value)
  OpenDefaultDownloadDialog()
  CloseDefaultDownloadDialog()
  get_DefaultDownloadDialogCornerAlignment(*value)
  put_DefaultDownloadDialogCornerAlignment(value.l)
  get_DefaultDownloadDialogMargin(*value)
  put_DefaultDownloadDialogMargin(value.l)
EndInterface


;- ICoreWebView2_10

DataSection
	IID_ICoreWebView2_10:
	Data.l $b1690564
	Data.w $6f5a, $4983
	Data.b $8e, $48, $31, $d1, $14, $3f, $ec, $db
EndDataSection

Interface ICoreWebView2_10 Extends ICoreWebView2_9
  add_BasicAuthenticationRequested(*eventHandler, *token)
  remove_BasicAuthenticationRequested(token.l)
EndInterface 


;- ICoreWebView2_11

DataSection
	IID_ICoreWebView2_11:
	Data.l $0be78e56
	Data.w $c193, $4051
	Data.b $b9, $43, $23, $b4, $60, $c0, $8b, $db
EndDataSection

Interface ICoreWebView2_11 Extends ICoreWebView2_10
  CallDevToolsProtocolMethodForSession(sessionId.p-Unicode, methodName.p-Unicode, parametersAsJson.p-Unicode, *handler)
  add_ContextMenuRequested(*eventHandler, *token)
  remove_ContextMenuRequested(token.l)
EndInterface


;- ICoreWebView2_12

DataSection
	IID_ICoreWebView2_12:
	Data.l $35D69927
	Data.w $BCFA, $4566
	Data.b $93, $49, $6B, $3E, $0D, $15, $4C, $AC
EndDataSection

Interface ICoreWebView2_12 Extends ICoreWebView2_11
  add_StatusBarTextChanged(*eventHandler, *token)
  remove_StatusBarTextChanged(token.l)
  get_StatusBarText(*value)
EndInterface


;- ICoreWebView2_13

DataSection
	IID_ICoreWebView2_13:
	Data.l $F75F09A8
	Data.w $667E, $4983
	Data.b $88, $D6, $C8, $77, $3F, $31, $5E, $84
EndDataSection

Interface ICoreWebView2_13 Extends ICoreWebView2_12
  get_Profile(*value)
EndInterface


;- ICoreWebView2_14

DataSection
	IID_ICoreWebView2_14:
	Data.l $6DAA4F10
	Data.w $4A90, $4753
	Data.b $88, $98, $77, $C5, $DF, $53, $41, $65
EndDataSection

Interface ICoreWebView2_14 Extends ICoreWebView2_13
  add_ServerCertificateErrorDetected(*eventHandler, *token)
  remove_ServerCertificateErrorDetected(token.l)
  ClearServerCertificateErrorActions(*handler)
EndInterface


;- ICoreWebView2_15

DataSection
	IID_ICoreWebView2_15:
	Data.l $517B2D1D
	Data.w $7DAE, $4A66
	Data.b $A4, $F4, $10, $35, $2F, $FB, $95, $18
EndDataSection

Interface ICoreWebView2_15 Extends ICoreWebView2_14
  add_FaviconChanged(*eventHandler, *token)
  remove_FaviconChanged(token.l)
  get_FaviconUri(*value)
  GetFavicon(format.l, *completedHandler)
EndInterface

Feel free to add it if you want.

But unfortunately I can not use it in production.
I installed the webview2 runtime on different PCs , but I ran into trouble on 50% of the PCs.
So it is not a solution for customers. :cry:
Last edited by infratec on Mon Dec 12, 2022 3:58 pm, edited 9 times in total.
Justin
Addict
Addict
Posts: 829
Joined: Sat Apr 26, 2003 2:49 pm

Re: Webview2 control - Chromium browser for Purebasic (Windows)

Post by Justin »

I tried your example and worked here, i only had to modify the wv2_EventHandler_New() function because the last version uses only 2 parameters i removed the first one.
What kind of errors are you getting on those PCs? Wich OS?
About the import issue try to download the last version and put your code in the examples folder and run it from there it shoud work.
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Webview2 control - Chromium browser for Purebasic (Windows)

Post by infratec »

Ups... I thought I downloaded it fresh from git.

All PCs I tried was Win10 x64 22H2 latest available patches installed.

I used your x86 version, because I don't know the windows version of the customers.

On the PCs where it does not work I see no error messages, but the program shows the 'frame' of the first container and nothing happens.
Sometimes the program is 'not reponding' and I have to kill it.
In one case the gadgets were displayed after arround 2 minutes.
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Webview2 control - Chromium browser for Purebasic (Windows)

Post by infratec »

I downloaded now the latest version from Git and adjusted my code above.

But still with this version I can not use your Import in WebView2Loader.pbi.

It results in 2 unresolved externals:
error: Unresolved external symbol '_CreateCoreWebView2EnvironmentWithOptions@16'.
error: Unresolved external symbol '_GetAvailableCoreWebView2BrowserVersionString@8'.
As written, if I use OpenLibrary() it works.
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Webview2 control - Chromium browser for Purebasic (Windows)

Post by infratec »

I extended the WebView2Gadget above with:

Code: Select all

Procedure WebView2SetgadgetText(Gadget.i, URL$)
Procedure.s WebView2GetgadgetText(Gadget.i)
Procedure WebView2SetGadgetState(Gadget.i, State.i)
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Webview2 control - Chromium browser for Purebasic (Windows)

Post by infratec »

Added above:

Code: Select all

Procedure WebView2SetGadgetItemText(Gadget.i, Entry.i, Text$, Column.i=0)
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Webview2 control - Chromium browser for Purebasic (Windows)

Post by infratec »

Added above:

Code: Select all

Procedure WebView2SetgadgetAttribute(Gadget.i, Attribute.i, Value.i)
At the moment only for #PB_Web_NavigationCallback
User avatar
ChrisR
Addict
Addict
Posts: 1127
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: Webview2 control - Chromium browser for Purebasic (Windows)

Post by ChrisR »

infratec wrote: Thu Dec 08, 2022 8:47 am But still with this version I can not use your Import in WebView2Loader.pbi.

As written, if I use OpenLibrary() it works.
Same here with x86 pbcompiler.
with x64 ASM Compiler, your dual WebView2Gadget example works fine, without seeing any specific slowness here.
With the C Backend, I have the following error
Edit: OK, ASM Compiler only VCall.pb is wittren in asm
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Webview2 control - Chromium browser for Purebasic (Windows)

Post by infratec »

Updated the listing above.
Some strange behaviours are fixed now.
Options and Settings are added.
Post Reply