Any idea for #PB_Web_Busy with WebViewGadget? or other WebPageLoaded procedure?
Any idea for #PB_Web_Busy with WebViewGadget? or other WebPageLoaded procedure?
Is there any way to emulate WebGadget -> GetGadgetAttribute(*Gadget, #PB_Web_Busy) s in the new gadget WebViewGadget?
Or another way to ensure that a website has loaded completely.
Thank you in advance!
PD: PB 6.20 beta 4
Or another way to ensure that a website has loaded completely.
Thank you in advance!
PD: PB 6.20 beta 4
PB 6.21 beta, PureVision User
Re: Any idea for #PB_Web_Busy with WebViewGadget? or other WebPageLoaded procedure?
For the classic WebGadget I use this procedure:
But I have no idea how to convert it for WebViewGadget 
Code: Select all
Procedure Web_NoBusy(idGadgetWeb.i, timeOutMax.i = 20000)
Protected timerIni
timerIni = ElapsedMilliseconds()
While GetGadgetAttribute(idGadgetWeb, #PB_Web_Busy) <> 0
WindowEvent()
Delay(10)
If ElapsedMilliseconds() - timerIni > timeOutMax
Break
EndIf
Wend
EndProcedure

PB 6.21 beta, PureVision User
Re: Any idea for #PB_Web_Busy with WebViewGadget? or other WebPageLoaded procedure?
With the WebViewGadget() you can use the code injection trick. So query “DOMContentLoaded” via addEventListener and have it reported back
https://www.purebasic.fr/english/viewto ... ed#p620606
https://www.purebasic.fr/english/viewto ... ed#p620606
"Daddy, I'll run faster, then it is not so far..."
Re: Any idea for #PB_Web_Busy with WebViewGadget? or other WebPageLoaded procedure?
Nice! Thank you, I'll try at night. Have a nice weekend!!dige wrote: Fri Jan 31, 2025 2:05 pm With the WebViewGadget() you can use the code injection trick. So query “DOMContentLoaded” via addEventListener and have it reported back
https://www.purebasic.fr/english/viewto ... ed#p620606
PB 6.21 beta, PureVision User
Re: Any idea for #PB_Web_Busy with WebViewGadget? or other WebPageLoaded procedure?
Code: Select all
;----------------------------------------------------------------------------------------
; https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/navigation-events
DataSection
IID_IUnknown:
Data.l $00000000
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46
EndDataSection
Structure IUnknownBase_Structure
*pVtbl
*pQueryInterface
*pAddRef
*pRelease
*pInvoke
lRefCount.l
Token.q
EndStructure
Structure ICoreWebView2NavigationCompletedEventHandler_Structure Extends IUnknownBase_Structure
*pFunction
EndStructure
Structure ICoreWebView2ContentLoadingEventHandler_Structure Extends IUnknownBase_Structure
*pFunction
EndStructure
Global NewMap NavigationCompletedEventHandler.ICoreWebView2NavigationCompletedEventHandler_Structure()
Procedure.l ICoreWebView2NavigationCompletedEventHandler_QueryInterface(*this.IUnknownBase_Structure, *riid.IID, *ppvObject.Integer)
If *ppvObject And *riid
If CompareMemory(*riid, ?IID_IUnknown, SizeOf(IID))
*this\lRefCount + 1
*ppvObject\i = *this
Else
*ppvObject\i = 0
ProcedureReturn #E_NOINTERFACE
EndIf
Else
ProcedureReturn #E_POINTER
EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.l ICoreWebView2NavigationCompletedEventHandler_AddRef(*this.IUnknownBase_Structure)
*this\lRefCount + 1
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l ICoreWebView2NavigationCompletedEventHandler_Release(*this.IUnknownBase_Structure)
*this\lRefCount - 1
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l ICoreWebView2NavigationCompletedEventHandler_Invoke(*this.ICoreWebView2NavigationCompletedEventHandler_Structure, *sender.ICoreWebView2, *args.ICoreWebView2NavigationCompletedEventArgs)
Protected isSuccess, *uri, uri.s
If *args And *args\get_IsSuccess(@isSuccess) = #S_OK And isSuccess
If *sender
If *sender\get_Source(@*uri) = #S_OK
If *uri
uri = PeekS(*uri)
If *this\pFunction
CallFunctionFast(*this\pFunction, @uri)
EndIf
CoTaskMemFree_(*uri)
EndIf
EndIf
EndIf
EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.i WebViewSetNavigateCompleteEventHandler(WebView, *EventHandler)
Protected Result.i
Protected Controller.ICoreWebView2Controller, Core.ICoreWebView2
Protected *NavigationCompletedEventHandler.ICoreWebView2NavigationCompletedEventHandler_Structure
Protected Token.q
If GadgetType(WebView) = #PB_GadgetType_WebView And *EventHandler <> #Null
Controller = GetGadgetAttribute(WebView, #PB_WebView_ICoreController)
If Controller
If Controller\get_CoreWebView2(@Core) = #S_OK And Core <> #Null
If FindMapElement(NavigationCompletedEventHandler(), Str(WebView))
If NavigationCompletedEventHandler()\Token
Core\remove_NavigationCompleted(NavigationCompletedEventHandler()\Token)
EndIf
DeleteMapElement(NavigationCompletedEventHandler())
EndIf
*NavigationCompletedEventHandler = AddMapElement(NavigationCompletedEventHandler(), Str(WebView))
If *NavigationCompletedEventHandler
*NavigationCompletedEventHandler\pVtbl = *NavigationCompletedEventHandler + OffsetOf(IUnknownBase_Structure\pQueryInterface)
*NavigationCompletedEventHandler\pQueryInterface = @ICoreWebView2NavigationCompletedEventHandler_QueryInterface()
*NavigationCompletedEventHandler\pAddRef = @ICoreWebView2NavigationCompletedEventHandler_AddRef()
*NavigationCompletedEventHandler\pRelease = @ICoreWebView2NavigationCompletedEventHandler_Release()
*NavigationCompletedEventHandler\pInvoke = @ICoreWebView2NavigationCompletedEventHandler_Invoke()
*NavigationCompletedEventHandler\pFunction = *EventHandler
If Core\add_NavigationCompleted(*NavigationCompletedEventHandler, @*NavigationCompletedEventHandler\Token) = #S_OK
Result = #True
Else
DeleteMapElement(NavigationCompletedEventHandler())
EndIf
EndIf
EndIf
Core\Release()
EndIf
EndIf
ProcedureReturn Result
EndProcedure
Global NewMap ContentLoadingEventHandler.ICoreWebView2ContentLoadingEventHandler_Structure()
Procedure.l ICoreWebView2ContentLoadingEventHandler_QueryInterface(*this.IUnknownBase_Structure, *riid.IID, *ppvObject.Integer)
If *ppvObject And *riid
If CompareMemory(*riid, ?IID_IUnknown, SizeOf(IID))
*this\lRefCount + 1
*ppvObject\i = *this
Else
*ppvObject\i = 0
ProcedureReturn #E_NOINTERFACE
EndIf
Else
ProcedureReturn #E_POINTER
EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.l ICoreWebView2ContentLoadingEventHandler_AddRef(*this.IUnknownBase_Structure)
*this\lRefCount + 1
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l ICoreWebView2ContentLoadingEventHandler_Release(*this.IUnknownBase_Structure)
*this\lRefCount - 1
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l ICoreWebView2ContentLoadingEventHandler_Invoke(*this.ICoreWebView2ContentLoadingEventHandler_Structure, *sender.ICoreWebView2, *args.ICoreWebView2ContentLoadingEventArgs)
Protected isSuccess, *uri, uri.s
;If *args And *args\get_IsSuccess(@isSuccess) = #S_OK And isSuccess
If *sender
If *sender\get_Source(@*uri) = #S_OK
If *uri
uri = PeekS(*uri)
If *this\pFunction
CallFunctionFast(*this\pFunction, @uri)
EndIf
CoTaskMemFree_(*uri)
EndIf
EndIf
EndIf
;EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.i WebViewSetContentLoadingEventHandler(WebView, *EventHandler)
Protected Result.i
Protected Controller.ICoreWebView2Controller, Core.ICoreWebView2
Protected *ContentLoadingEventHandler.ICoreWebView2ContentLoadingEventHandler_Structure
Protected Token.q
If GadgetType(WebView) = #PB_GadgetType_WebView And *EventHandler <> #Null
Controller = GetGadgetAttribute(WebView, #PB_WebView_ICoreController)
If Controller
If Controller\get_CoreWebView2(@Core) = #S_OK
If Core
If FindMapElement(ContentLoadingEventHandler(), Str(WebView))
If ContentLoadingEventHandler()\Token
Core\remove_ContentLoading(ContentLoadingEventHandler()\Token)
EndIf
DeleteMapElement(ContentLoadingEventHandler())
EndIf
*ContentLoadingEventHandler = AddMapElement(ContentLoadingEventHandler(), Str(WebView))
If *ContentLoadingEventHandler
*ContentLoadingEventHandler\pVtbl = *ContentLoadingEventHandler + OffsetOf(IUnknownBase_Structure\pQueryInterface)
*ContentLoadingEventHandler\pQueryInterface = @ICoreWebView2ContentLoadingEventHandler_QueryInterface()
*ContentLoadingEventHandler\pAddRef = @ICoreWebView2ContentLoadingEventHandler_AddRef()
*ContentLoadingEventHandler\pRelease = @ICoreWebView2ContentLoadingEventHandler_Release()
*ContentLoadingEventHandler\pInvoke = @ICoreWebView2ContentLoadingEventHandler_Invoke()
*ContentLoadingEventHandler\pFunction = *EventHandler
If Core\add_ContentLoading(*ContentLoadingEventHandler, @*ContentLoadingEventHandler\Token) = #S_OK
;Debug *ContentLoadingEventHandler\Token
Result = #True
Else
DeleteMapElement(ContentLoadingEventHandler())
EndIf
EndIf
Core\Release()
EndIf
EndIf
EndIf
EndIf
ProcedureReturn Result
EndProcedure
;----------------------------------------------------------------------------------------
Global WebView2_Busy.i
Procedure ContentLoading(uri.s)
Debug "Loading: " + uri
WebView2_Busy = #True
EndProcedure
Procedure NaviComplete(uri.s)
Debug "Loaded: " + uri
WebView2_Busy = #False
EndProcedure
OpenWindow(0, 0, 0, 1000, 900, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
StringGadget(0, 0, 0, 400, 30, "https://www.purebasic.com")
ButtonGadget(1, 410, 0, 50, 30, "Go")
WebViewGadget(2, 0, 35, 1000, 900)
WebViewSetContentLoadingEventHandler(2, @ContentLoading())
WebViewSetNavigateCompleteEventHandler(2, @NaviComplete())
SetGadgetText(2, "file://" + #PB_Compiler_Home + "examples/sources/Data/WebView/webview.html")
AddWindowTimer(0, 1, 100)
Repeat
Event = WaitWindowEvent()
If Event = #PB_Event_Timer
If EventTimer() = 1
If WebView2_Busy
Debug "WebView is Busy"
EndIf
EndIf
EndIf
If Event = #PB_Event_Gadget
If EventGadget() = 1
SetGadgetText(2, Trim(GetGadgetText(0)))
EndIf
EndIf
Until Event = #PB_Event_CloseWindow
Re: Any idea for #PB_Web_Busy with WebViewGadget? or other WebPageLoaded procedure?
Great! Thx a lot infratec! 

"Daddy, I'll run faster, then it is not so far..."
Re: Any idea for #PB_Web_Busy with WebViewGadget? or other WebPageLoaded procedure?
@infratec, @dige Thank you so much for bailing me out!
This last code works great for me!
This last code works great for me!

PB 6.21 beta, PureVision User
Re: Any idea for #PB_Web_Busy with WebViewGadget? or other WebPageLoaded procedure?
I'm trying your code but it only works when a full webpage is loaded, no?
In this example, if I change in the left window the name "Jani" to "Peter", and click in "Run" button It don't detect any change in the web.
Code: Select all
;----------------------------------------------------------------------------------------
; https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/navigation-events
DataSection
IID_IUnknown:
Data.l $00000000
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46
EndDataSection
Structure IUnknownBase_Structure
*pVtbl
*pQueryInterface
*pAddRef
*pRelease
*pInvoke
lRefCount.l
Token.q
EndStructure
Structure ICoreWebView2NavigationCompletedEventHandler_Structure Extends IUnknownBase_Structure
*pFunction
EndStructure
Structure ICoreWebView2ContentLoadingEventHandler_Structure Extends IUnknownBase_Structure
*pFunction
EndStructure
Global NewMap NavigationCompletedEventHandler.ICoreWebView2NavigationCompletedEventHandler_Structure()
Procedure.l ICoreWebView2NavigationCompletedEventHandler_QueryInterface(*this.IUnknownBase_Structure, *riid.IID, *ppvObject.Integer)
If *ppvObject And *riid
If CompareMemory(*riid, ?IID_IUnknown, SizeOf(IID))
*this\lRefCount + 1
*ppvObject\i = *this
Else
*ppvObject\i = 0
ProcedureReturn #E_NOINTERFACE
EndIf
Else
ProcedureReturn #E_POINTER
EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.l ICoreWebView2NavigationCompletedEventHandler_AddRef(*this.IUnknownBase_Structure)
*this\lRefCount + 1
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l ICoreWebView2NavigationCompletedEventHandler_Release(*this.IUnknownBase_Structure)
*this\lRefCount - 1
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l ICoreWebView2NavigationCompletedEventHandler_Invoke(*this.ICoreWebView2NavigationCompletedEventHandler_Structure, *sender.ICoreWebView2, *args.ICoreWebView2NavigationCompletedEventArgs)
Protected isSuccess, *uri, uri.s
If *args And *args\get_IsSuccess(@isSuccess) = #S_OK And isSuccess
If *sender
If *sender\get_Source(@*uri) = #S_OK
If *uri
uri = PeekS(*uri)
If *this\pFunction
CallFunctionFast(*this\pFunction, @uri)
EndIf
CoTaskMemFree_(*uri)
EndIf
EndIf
EndIf
EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.i WebViewSetNavigateCompleteEventHandler(WebView, *EventHandler)
Protected Result.i
Protected Controller.ICoreWebView2Controller, Core.ICoreWebView2
Protected *NavigationCompletedEventHandler.ICoreWebView2NavigationCompletedEventHandler_Structure
Protected Token.q
If GadgetType(WebView) = #PB_GadgetType_WebView And *EventHandler <> #Null
Controller = GetGadgetAttribute(WebView, #PB_WebView_ICoreController)
If Controller
If Controller\get_CoreWebView2(@Core) = #S_OK And Core <> #Null
If FindMapElement(NavigationCompletedEventHandler(), Str(WebView))
If NavigationCompletedEventHandler()\Token
Core\remove_NavigationCompleted(NavigationCompletedEventHandler()\Token)
EndIf
DeleteMapElement(NavigationCompletedEventHandler())
EndIf
*NavigationCompletedEventHandler = AddMapElement(NavigationCompletedEventHandler(), Str(WebView))
If *NavigationCompletedEventHandler
*NavigationCompletedEventHandler\pVtbl = *NavigationCompletedEventHandler + OffsetOf(IUnknownBase_Structure\pQueryInterface)
*NavigationCompletedEventHandler\pQueryInterface = @ICoreWebView2NavigationCompletedEventHandler_QueryInterface()
*NavigationCompletedEventHandler\pAddRef = @ICoreWebView2NavigationCompletedEventHandler_AddRef()
*NavigationCompletedEventHandler\pRelease = @ICoreWebView2NavigationCompletedEventHandler_Release()
*NavigationCompletedEventHandler\pInvoke = @ICoreWebView2NavigationCompletedEventHandler_Invoke()
*NavigationCompletedEventHandler\pFunction = *EventHandler
If Core\add_NavigationCompleted(*NavigationCompletedEventHandler, @*NavigationCompletedEventHandler\Token) = #S_OK
Result = #True
Else
DeleteMapElement(NavigationCompletedEventHandler())
EndIf
EndIf
EndIf
Core\Release()
EndIf
EndIf
ProcedureReturn Result
EndProcedure
Global NewMap ContentLoadingEventHandler.ICoreWebView2ContentLoadingEventHandler_Structure()
Procedure.l ICoreWebView2ContentLoadingEventHandler_QueryInterface(*this.IUnknownBase_Structure, *riid.IID, *ppvObject.Integer)
If *ppvObject And *riid
If CompareMemory(*riid, ?IID_IUnknown, SizeOf(IID))
*this\lRefCount + 1
*ppvObject\i = *this
Else
*ppvObject\i = 0
ProcedureReturn #E_NOINTERFACE
EndIf
Else
ProcedureReturn #E_POINTER
EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.l ICoreWebView2ContentLoadingEventHandler_AddRef(*this.IUnknownBase_Structure)
*this\lRefCount + 1
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l ICoreWebView2ContentLoadingEventHandler_Release(*this.IUnknownBase_Structure)
*this\lRefCount - 1
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l ICoreWebView2ContentLoadingEventHandler_Invoke(*this.ICoreWebView2ContentLoadingEventHandler_Structure, *sender.ICoreWebView2, *args.ICoreWebView2ContentLoadingEventArgs)
Protected isSuccess, *uri, uri.s
;If *args And *args\get_IsSuccess(@isSuccess) = #S_OK And isSuccess
If *sender
If *sender\get_Source(@*uri) = #S_OK
If *uri
uri = PeekS(*uri)
If *this\pFunction
CallFunctionFast(*this\pFunction, @uri)
EndIf
CoTaskMemFree_(*uri)
EndIf
EndIf
EndIf
;EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.i WebViewSetContentLoadingEventHandler(WebView, *EventHandler)
Protected Result.i
Protected Controller.ICoreWebView2Controller, Core.ICoreWebView2
Protected *ContentLoadingEventHandler.ICoreWebView2ContentLoadingEventHandler_Structure
Protected Token.q
If GadgetType(WebView) = #PB_GadgetType_WebView And *EventHandler <> #Null
Controller = GetGadgetAttribute(WebView, #PB_WebView_ICoreController)
If Controller
If Controller\get_CoreWebView2(@Core) = #S_OK
If Core
If FindMapElement(ContentLoadingEventHandler(), Str(WebView))
If ContentLoadingEventHandler()\Token
Core\remove_ContentLoading(ContentLoadingEventHandler()\Token)
EndIf
DeleteMapElement(ContentLoadingEventHandler())
EndIf
*ContentLoadingEventHandler = AddMapElement(ContentLoadingEventHandler(), Str(WebView))
If *ContentLoadingEventHandler
*ContentLoadingEventHandler\pVtbl = *ContentLoadingEventHandler + OffsetOf(IUnknownBase_Structure\pQueryInterface)
*ContentLoadingEventHandler\pQueryInterface = @ICoreWebView2ContentLoadingEventHandler_QueryInterface()
*ContentLoadingEventHandler\pAddRef = @ICoreWebView2ContentLoadingEventHandler_AddRef()
*ContentLoadingEventHandler\pRelease = @ICoreWebView2ContentLoadingEventHandler_Release()
*ContentLoadingEventHandler\pInvoke = @ICoreWebView2ContentLoadingEventHandler_Invoke()
*ContentLoadingEventHandler\pFunction = *EventHandler
If Core\add_ContentLoading(*ContentLoadingEventHandler, @*ContentLoadingEventHandler\Token) = #S_OK
;Debug *ContentLoadingEventHandler\Token
Result = #True
Else
DeleteMapElement(ContentLoadingEventHandler())
EndIf
EndIf
Core\Release()
EndIf
EndIf
EndIf
EndIf
ProcedureReturn Result
EndProcedure
;----------------------------------------------------------------------------------------
Global WebView2_Busy.i
Procedure ContentLoading(uri.s)
Debug "Loading: " + uri
WebView2_Busy = #True
EndProcedure
Procedure NaviComplete(uri.s)
Debug "Loaded: " + uri
WebView2_Busy = #False
EndProcedure
OpenWindow(0, 0, 0, 1000, 900, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
StringGadget(0, 0, 0, 400, 30, "https://www.w3schools.com/xml/tryit.asp?filename=tryxml_parsertest2")
ButtonGadget(1, 410, 0, 50, 30, "Go")
WebViewGadget(2, 0, 35, 1000, 900)
WebViewSetContentLoadingEventHandler(2, @ContentLoading())
WebViewSetNavigateCompleteEventHandler(2, @NaviComplete())
SetGadgetText(2, "https://www.w3schools.com/xml/tryit.asp?filename=tryxml_parsertest2")
AddWindowTimer(0, 1, 100)
Repeat
Event = WaitWindowEvent()
If Event = #PB_Event_Timer
If EventTimer() = 1
If WebView2_Busy
Debug "WebView is Busy"
EndIf
EndIf
EndIf
If Event = #PB_Event_Gadget
If EventGadget() = 1
SetGadgetText(2, Trim(GetGadgetText(0)))
EndIf
EndIf
Until Event = #PB_Event_CloseWindow
I understand that the mistake is mine when I wrote the title and content of this post, because I implied that I was only looking to detect when a page finished loading, and not also when that page experienced a change.
Thank you and sorry for my bad english
PB 6.21 beta, PureVision User
Re: Any idea for #PB_Web_Busy with WebViewGadget? or other WebPageLoaded procedure?
following in @infratec 's footst, I just tried adding a new procedure: WebViewSetSourceChangedEventHandler() to try detect when a page experienced a change, but it don't works either... I'll continue with my experiments

Code: Select all
;----------------------------------------------------------------------------------------
; https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/navigation-events
DataSection
IID_IUnknown:
Data.l $00000000
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46
EndDataSection
Structure IUnknownBase_Structure
*pVtbl
*pQueryInterface
*pAddRef
*pRelease
*pInvoke
lRefCount.l
Token.q
EndStructure
Structure ICoreWebView2NavigationCompletedEventHandler_Structure Extends IUnknownBase_Structure
*pFunction
EndStructure
Structure ICoreWebView2ContentLoadingEventHandler_Structure Extends IUnknownBase_Structure
*pFunction
EndStructure
Structure ICoreWebView2SourceChangedEventHandler_Structure Extends IUnknownBase_Structure
*pFunction
EndStructure
Global NewMap NavigationCompletedEventHandler.ICoreWebView2NavigationCompletedEventHandler_Structure()
Procedure.l ICoreWebView2NavigationCompletedEventHandler_QueryInterface(*this.IUnknownBase_Structure, *riid.IID, *ppvObject.Integer)
If *ppvObject And *riid
If CompareMemory(*riid, ?IID_IUnknown, SizeOf(IID))
*this\lRefCount + 1
*ppvObject\i = *this
Else
*ppvObject\i = 0
ProcedureReturn #E_NOINTERFACE
EndIf
Else
ProcedureReturn #E_POINTER
EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.l ICoreWebView2NavigationCompletedEventHandler_AddRef(*this.IUnknownBase_Structure)
*this\lRefCount + 1
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l ICoreWebView2NavigationCompletedEventHandler_Release(*this.IUnknownBase_Structure)
*this\lRefCount - 1
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l ICoreWebView2NavigationCompletedEventHandler_Invoke(*this.ICoreWebView2NavigationCompletedEventHandler_Structure, *sender.ICoreWebView2, *args.ICoreWebView2NavigationCompletedEventArgs)
Protected isSuccess, *uri, uri.s
If *args And *args\get_IsSuccess(@isSuccess) = #S_OK And isSuccess
If *sender
If *sender\get_Source(@*uri) = #S_OK
If *uri
uri = PeekS(*uri)
If *this\pFunction
CallFunctionFast(*this\pFunction, @uri)
EndIf
CoTaskMemFree_(*uri)
EndIf
EndIf
EndIf
EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.i WebViewSetNavigateCompleteEventHandler(WebView, *EventHandler)
Protected Result.i
Protected Controller.ICoreWebView2Controller, Core.ICoreWebView2
Protected *NavigationCompletedEventHandler.ICoreWebView2NavigationCompletedEventHandler_Structure
Protected Token.q
If GadgetType(WebView) = #PB_GadgetType_WebView And *EventHandler <> #Null
Controller = GetGadgetAttribute(WebView, #PB_WebView_ICoreController)
If Controller
If Controller\get_CoreWebView2(@Core) = #S_OK And Core <> #Null
If FindMapElement(NavigationCompletedEventHandler(), Str(WebView))
If NavigationCompletedEventHandler()\Token
Core\remove_NavigationCompleted(NavigationCompletedEventHandler()\Token)
EndIf
DeleteMapElement(NavigationCompletedEventHandler())
EndIf
*NavigationCompletedEventHandler = AddMapElement(NavigationCompletedEventHandler(), Str(WebView))
If *NavigationCompletedEventHandler
*NavigationCompletedEventHandler\pVtbl = *NavigationCompletedEventHandler + OffsetOf(IUnknownBase_Structure\pQueryInterface)
*NavigationCompletedEventHandler\pQueryInterface = @ICoreWebView2NavigationCompletedEventHandler_QueryInterface()
*NavigationCompletedEventHandler\pAddRef = @ICoreWebView2NavigationCompletedEventHandler_AddRef()
*NavigationCompletedEventHandler\pRelease = @ICoreWebView2NavigationCompletedEventHandler_Release()
*NavigationCompletedEventHandler\pInvoke = @ICoreWebView2NavigationCompletedEventHandler_Invoke()
*NavigationCompletedEventHandler\pFunction = *EventHandler
If Core\add_NavigationCompleted(*NavigationCompletedEventHandler, @*NavigationCompletedEventHandler\Token) = #S_OK
Result = #True
Else
DeleteMapElement(NavigationCompletedEventHandler())
EndIf
EndIf
EndIf
Core\Release()
EndIf
EndIf
ProcedureReturn Result
EndProcedure
Global NewMap ContentLoadingEventHandler.ICoreWebView2ContentLoadingEventHandler_Structure()
Procedure.l ICoreWebView2ContentLoadingEventHandler_QueryInterface(*this.IUnknownBase_Structure, *riid.IID, *ppvObject.Integer)
If *ppvObject And *riid
If CompareMemory(*riid, ?IID_IUnknown, SizeOf(IID))
*this\lRefCount + 1
*ppvObject\i = *this
Else
*ppvObject\i = 0
ProcedureReturn #E_NOINTERFACE
EndIf
Else
ProcedureReturn #E_POINTER
EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.l ICoreWebView2ContentLoadingEventHandler_AddRef(*this.IUnknownBase_Structure)
*this\lRefCount + 1
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l ICoreWebView2ContentLoadingEventHandler_Release(*this.IUnknownBase_Structure)
*this\lRefCount - 1
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l ICoreWebView2ContentLoadingEventHandler_Invoke(*this.ICoreWebView2ContentLoadingEventHandler_Structure, *sender.ICoreWebView2, *args.ICoreWebView2ContentLoadingEventArgs)
Protected isSuccess, *uri, uri.s
;If *args And *args\get_IsSuccess(@isSuccess) = #S_OK And isSuccess
If *sender
If *sender\get_Source(@*uri) = #S_OK
If *uri
uri = PeekS(*uri)
If *this\pFunction
CallFunctionFast(*this\pFunction, @uri)
EndIf
CoTaskMemFree_(*uri)
EndIf
EndIf
EndIf
;EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.i WebViewSetContentLoadingEventHandler(WebView, *EventHandler)
Protected Result.i
Protected Controller.ICoreWebView2Controller, Core.ICoreWebView2
Protected *ContentLoadingEventHandler.ICoreWebView2ContentLoadingEventHandler_Structure
Protected Token.q
If GadgetType(WebView) = #PB_GadgetType_WebView And *EventHandler <> #Null
Controller = GetGadgetAttribute(WebView, #PB_WebView_ICoreController)
If Controller
If Controller\get_CoreWebView2(@Core) = #S_OK
If Core
If FindMapElement(ContentLoadingEventHandler(), Str(WebView))
If ContentLoadingEventHandler()\Token
Core\remove_ContentLoading(ContentLoadingEventHandler()\Token)
EndIf
DeleteMapElement(ContentLoadingEventHandler())
EndIf
*ContentLoadingEventHandler = AddMapElement(ContentLoadingEventHandler(), Str(WebView))
If *ContentLoadingEventHandler
*ContentLoadingEventHandler\pVtbl = *ContentLoadingEventHandler + OffsetOf(IUnknownBase_Structure\pQueryInterface)
*ContentLoadingEventHandler\pQueryInterface = @ICoreWebView2ContentLoadingEventHandler_QueryInterface()
*ContentLoadingEventHandler\pAddRef = @ICoreWebView2ContentLoadingEventHandler_AddRef()
*ContentLoadingEventHandler\pRelease = @ICoreWebView2ContentLoadingEventHandler_Release()
*ContentLoadingEventHandler\pInvoke = @ICoreWebView2ContentLoadingEventHandler_Invoke()
*ContentLoadingEventHandler\pFunction = *EventHandler
If Core\add_ContentLoading(*ContentLoadingEventHandler, @*ContentLoadingEventHandler\Token) = #S_OK
;Debug *ContentLoadingEventHandler\Token
Result = #True
Else
DeleteMapElement(ContentLoadingEventHandler())
EndIf
EndIf
Core\Release()
EndIf
EndIf
EndIf
EndIf
ProcedureReturn Result
EndProcedure
Global NewMap SourceChangedEventHandler.ICoreWebView2SourceChangedEventHandler_Structure()
Procedure.l ICoreWebView2SourceChangedEventHandler_QueryInterface(*this.IUnknownBase_Structure, *riid.IID, *ppvObject.Integer)
If *ppvObject And *riid
If CompareMemory(*riid, ?IID_IUnknown, SizeOf(IID))
*this\lRefCount + 1
*ppvObject\i = *this
Else
*ppvObject\i = 0
ProcedureReturn #E_NOINTERFACE
EndIf
Else
ProcedureReturn #E_POINTER
EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.l ICoreWebView2SourceChangedEventHandler_AddRef(*this.IUnknownBase_Structure)
*this\lRefCount + 1
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l ICoreWebView2SourceChangedEventHandler_Release(*this.IUnknownBase_Structure)
*this\lRefCount - 1
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l ICoreWebView2SourceChangedEventHandler_Invoke(*this.ICoreWebView2SourceChangedEventHandler_Structure, *sender.ICoreWebView2, *args.ICoreWebView2SourceChangedEventArgs)
Protected isNewDoc, *uri, uri.s
If *args And *args\get_IsNewDocument(@isNewDoc) = #S_OK And isNewDoc
If *sender
If *sender\get_Source(@*uri) = #S_OK
If *uri
uri = PeekS(*uri)
If *this\pFunction
CallFunctionFast(*this\pFunction, @uri)
EndIf
CoTaskMemFree_(*uri)
EndIf
EndIf
EndIf
EndIf
Debug isNewDoc
EndProcedure
Procedure.i WebViewSetSourceChangedEventHandler(WebView, *EventHandler)
Protected Result.i
Protected Controller.ICoreWebView2Controller, Core.ICoreWebView2
Protected *SourceChangedEventHandler.ICoreWebView2SourceChangedEventHandler_Structure
Protected Token.q
If GadgetType(WebView) = #PB_GadgetType_WebView And *EventHandler <> #Null
Controller = GetGadgetAttribute(WebView, #PB_WebView_ICoreController)
If Controller
If Controller\get_CoreWebView2(@Core) = #S_OK
If Core
If FindMapElement(SourceChangedEventHandler(), Str(WebView))
If SourceChangedEventHandler()\Token
Core\remove_SourceChanged(SourceChangedEventHandler()\Token)
EndIf
DeleteMapElement(SourceChangedEventHandler())
EndIf
*SourceChangedEventHandler = AddMapElement(SourceChangedEventHandler(), Str(WebView))
If *SourceChangedEventHandler
*SourceChangedEventHandler\pVtbl = *SourceChangedEventHandler + OffsetOf(IUnknownBase_Structure\pQueryInterface)
*SourceChangedEventHandler\pQueryInterface = @ICoreWebView2SourceChangedEventHandler_QueryInterface()
*SourceChangedEventHandler\pAddRef = @ICoreWebView2SourceChangedEventHandler_AddRef()
*SourceChangedEventHandler\pRelease = @ICoreWebView2SourceChangedEventHandler_Release()
*SourceChangedEventHandler\pInvoke = @ICoreWebView2SourceChangedEventHandler_Invoke()
*SourceChangedEventHandler\pFunction = *EventHandler
If Core\add_SourceChanged(*SourceChangedEventHandler, @*SourceChangedEventHandler\Token) = #S_OK
;Debug *SourceChangedEventHandler\Token
Result = #True
Else
DeleteMapElement(SourceChangedEventHandler())
EndIf
EndIf
Core\Release()
EndIf
EndIf
EndIf
EndIf
ProcedureReturn Result
EndProcedure
;----------------------------------------------------------------------------------------
Global WebView2_Busy.b, WebView2_SourceChanged.b
Procedure ContentLoading(uri.s)
;Debug "Loading: " + uri
WebView2_Busy = #True
EndProcedure
Procedure NaviComplete(uri.s)
;Debug "Loaded: " + uri
WebView2_Busy = #False
EndProcedure
Procedure ContentSourceChanged(uri.s)
Debug "source change: " + uri
WebView2_SourceChanged = #True
EndProcedure
Procedure ContentSourceEqual(uri.s)
Debug "source equal: " + uri
WebView2_SourceChanged = #False
EndProcedure
OpenWindow(0, 0, 0, 1000, 900, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
StringGadget(0, 0, 0, 400, 30, "https://www.w3schools.com/xml/tryit.asp?filename=tryxml_parsertest2")
ButtonGadget(1, 410, 0, 50, 30, "Go")
WebViewGadget(2, 0, 35, 1000, 900)
; WebViewSetContentLoadingEventHandler(2, @ContentLoading())
; WebViewSetNavigateCompleteEventHandler(2, @NaviComplete())
WebViewSetSourceChangedEventHandler(2, @ContentSourceChanged())
SetGadgetText(2, "https://www.w3schools.com/xml/tryit.asp?filename=tryxml_parsertest2")
AddWindowTimer(0, 1, 100)
Repeat
Event = WaitWindowEvent()
If Event = #PB_Event_Timer
If EventTimer() = 1
If WebView2_Busy
;Debug "WebView is Busy"
EndIf
If WebView2_SourceChanged
Debug "source changed!!!"
WebView2_SourceChanged = #False
Else
Debug "source equal!"
EndIf
EndIf
EndIf
If Event = #PB_Event_Gadget
If EventGadget() = 1
SetGadgetText(2, Trim(GetGadgetText(0)))
EndIf
EndIf
Until Event = #PB_Event_CloseWindow
PB 6.21 beta, PureVision User
Re: Any idea for #PB_Web_Busy with WebViewGadget? or other WebPageLoaded procedure?
This method will not work for the site “www.openstreetmap.org”, you will need to get the information through MutationObserver or use the API provided by that site.
Code: Select all
;----------------------------------------------------------------------------------------
; https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/navigation-events
DataSection
IID_IUnknown:
Data.l $00000000
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46
EndDataSection
Structure IUnknownBase_Structure
*pVtbl
*pQueryInterface
*pAddRef
*pRelease
*pInvoke
lRefCount.l
Token.q
EndStructure
Structure ICoreWebView2NavigationCompletedEventHandler_Structure Extends IUnknownBase_Structure
*pFunction
EndStructure
Structure ICoreWebView2ContentLoadingEventHandler_Structure Extends IUnknownBase_Structure
*pFunction
EndStructure
Global NewMap NavigationCompletedEventHandler.ICoreWebView2NavigationCompletedEventHandler_Structure()
Procedure.l ICoreWebView2NavigationCompletedEventHandler_QueryInterface(*this.IUnknownBase_Structure, *riid.IID, *ppvObject.Integer)
If *ppvObject And *riid
If CompareMemory(*riid, ?IID_IUnknown, SizeOf(IID))
*this\lRefCount + 1
*ppvObject\i = *this
Else
*ppvObject\i = 0
ProcedureReturn #E_NOINTERFACE
EndIf
Else
ProcedureReturn #E_POINTER
EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.l ICoreWebView2NavigationCompletedEventHandler_AddRef(*this.IUnknownBase_Structure)
*this\lRefCount + 1
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l ICoreWebView2NavigationCompletedEventHandler_Release(*this.IUnknownBase_Structure)
*this\lRefCount - 1
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l ICoreWebView2NavigationCompletedEventHandler_Invoke(*this.ICoreWebView2NavigationCompletedEventHandler_Structure, *sender.ICoreWebView2, *args.ICoreWebView2NavigationCompletedEventArgs)
Protected isSuccess, *uri, uri.s
If *args And *args\get_IsSuccess(@isSuccess) = #S_OK And isSuccess
If *sender
If *sender\get_Source(@*uri) = #S_OK
If *uri
uri = PeekS(*uri)
If *this\pFunction
CallFunctionFast(*this\pFunction, @uri)
EndIf
CoTaskMemFree_(*uri)
EndIf
EndIf
EndIf
EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.i WebViewSetNavigateCompleteEventHandler(WebView, *EventHandler)
Protected Result.i
Protected Controller.ICoreWebView2Controller, Core.ICoreWebView2
Protected *NavigationCompletedEventHandler.ICoreWebView2NavigationCompletedEventHandler_Structure
Protected Token.q
If GadgetType(WebView) = #PB_GadgetType_WebView And *EventHandler <> #Null
Controller = GetGadgetAttribute(WebView, #PB_WebView_ICoreController)
If Controller
If Controller\get_CoreWebView2(@Core) = #S_OK And Core <> #Null
If FindMapElement(NavigationCompletedEventHandler(), Str(WebView))
If NavigationCompletedEventHandler()\Token
Core\remove_NavigationCompleted(NavigationCompletedEventHandler()\Token)
EndIf
DeleteMapElement(NavigationCompletedEventHandler())
EndIf
*NavigationCompletedEventHandler = AddMapElement(NavigationCompletedEventHandler(), Str(WebView))
If *NavigationCompletedEventHandler
*NavigationCompletedEventHandler\pVtbl = *NavigationCompletedEventHandler + OffsetOf(IUnknownBase_Structure\pQueryInterface)
*NavigationCompletedEventHandler\pQueryInterface = @ICoreWebView2NavigationCompletedEventHandler_QueryInterface()
*NavigationCompletedEventHandler\pAddRef = @ICoreWebView2NavigationCompletedEventHandler_AddRef()
*NavigationCompletedEventHandler\pRelease = @ICoreWebView2NavigationCompletedEventHandler_Release()
*NavigationCompletedEventHandler\pInvoke = @ICoreWebView2NavigationCompletedEventHandler_Invoke()
*NavigationCompletedEventHandler\pFunction = *EventHandler
If Core\add_NavigationCompleted(*NavigationCompletedEventHandler, @*NavigationCompletedEventHandler\Token) = #S_OK
Result = #True
Else
DeleteMapElement(NavigationCompletedEventHandler())
EndIf
EndIf
EndIf
Core\Release()
EndIf
EndIf
ProcedureReturn Result
EndProcedure
Global NewMap ContentLoadingEventHandler.ICoreWebView2ContentLoadingEventHandler_Structure()
Procedure.l ICoreWebView2ContentLoadingEventHandler_QueryInterface(*this.IUnknownBase_Structure, *riid.IID, *ppvObject.Integer)
If *ppvObject And *riid
If CompareMemory(*riid, ?IID_IUnknown, SizeOf(IID))
*this\lRefCount + 1
*ppvObject\i = *this
Else
*ppvObject\i = 0
ProcedureReturn #E_NOINTERFACE
EndIf
Else
ProcedureReturn #E_POINTER
EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.l ICoreWebView2ContentLoadingEventHandler_AddRef(*this.IUnknownBase_Structure)
*this\lRefCount + 1
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l ICoreWebView2ContentLoadingEventHandler_Release(*this.IUnknownBase_Structure)
*this\lRefCount - 1
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l ICoreWebView2ContentLoadingEventHandler_Invoke(*this.ICoreWebView2ContentLoadingEventHandler_Structure, *sender.ICoreWebView2, *args.ICoreWebView2ContentLoadingEventArgs)
Protected isSuccess, *uri, uri.s
;If *args And *args\get_IsSuccess(@isSuccess) = #S_OK And isSuccess
If *sender
If *sender\get_Source(@*uri) = #S_OK
If *uri
uri = PeekS(*uri)
If *this\pFunction
CallFunctionFast(*this\pFunction, @uri)
EndIf
CoTaskMemFree_(*uri)
EndIf
EndIf
EndIf
;EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.i WebViewSetContentLoadingEventHandler(WebView, *EventHandler)
Protected Result.i
Protected Controller.ICoreWebView2Controller, Core.ICoreWebView2
Protected *ContentLoadingEventHandler.ICoreWebView2ContentLoadingEventHandler_Structure
Protected Token.q
If GadgetType(WebView) = #PB_GadgetType_WebView And *EventHandler <> #Null
Controller = GetGadgetAttribute(WebView, #PB_WebView_ICoreController)
If Controller
If Controller\get_CoreWebView2(@Core) = #S_OK
If Core
If FindMapElement(ContentLoadingEventHandler(), Str(WebView))
If ContentLoadingEventHandler()\Token
Core\remove_ContentLoading(ContentLoadingEventHandler()\Token)
EndIf
DeleteMapElement(ContentLoadingEventHandler())
EndIf
*ContentLoadingEventHandler = AddMapElement(ContentLoadingEventHandler(), Str(WebView))
If *ContentLoadingEventHandler
*ContentLoadingEventHandler\pVtbl = *ContentLoadingEventHandler + OffsetOf(IUnknownBase_Structure\pQueryInterface)
*ContentLoadingEventHandler\pQueryInterface = @ICoreWebView2ContentLoadingEventHandler_QueryInterface()
*ContentLoadingEventHandler\pAddRef = @ICoreWebView2ContentLoadingEventHandler_AddRef()
*ContentLoadingEventHandler\pRelease = @ICoreWebView2ContentLoadingEventHandler_Release()
*ContentLoadingEventHandler\pInvoke = @ICoreWebView2ContentLoadingEventHandler_Invoke()
*ContentLoadingEventHandler\pFunction = *EventHandler
If Core\add_ContentLoading(*ContentLoadingEventHandler, @*ContentLoadingEventHandler\Token) = #S_OK
;Debug *ContentLoadingEventHandler\Token
Result = #True
Else
DeleteMapElement(ContentLoadingEventHandler())
EndIf
EndIf
Core\Release()
EndIf
EndIf
EndIf
EndIf
ProcedureReturn Result
EndProcedure
;----------------------------------------------------------------------------------------
Global WebView2_Busy.i
Procedure ContentLoading(uri.s)
Debug "Loading: " + uri
WebView2_Busy = #True
EndProcedure
Procedure NaviComplete(uri.s)
; https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
; Protected js$ = "function callback(mutationList, observer) {" +
; " mutationList.forEach((mutation) => {" +
; " switch (mutation.type) {" +
; ~" case \"attributes\":" +
; ;" window.WV_Changed(1, mutation.attributeName, mutation.target.tagName, mutation.target.innerHTML );" +
; " window.WV_Changed(1, mutation.attributeName, mutation.target.tagName);" +
; " break;" +
; ~" case \"childList\":" +
; " window.WV_Changed(2);" +
; " break;" +
; ~" case \"characterData\":" +
; " window.WV_Changed(3);" +
; " break;" +
; " }" +
; " });" +
; "};" +
; "const observer = new MutationObserver(callback);" +
; "observer.observe(document.documentElement, { attributes: true, childList: true, subtree: true, characterData: true } );"
Protected js$ = ~"document.documentElement.addEventListener(\"change\", (event) => {" +
" window.WV_Changed(0);" +
"});"
Debug "Loaded: " + uri
WebView2_Busy = #False
WebViewExecuteScript(2, js$)
EndProcedure
Procedure WV_Changed(JsonParameters$)
Debug #PB_Compiler_Procedure + " " + JsonParameters$
;ProcedureReturn
EndProcedure
OpenWindow(0, 0, 0, 1000, 900, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
StringGadget(0, 0, 0, 400, 30, "https://www.openstreetmap.org")
ButtonGadget(1, 410, 0, 50, 30, "Go")
WebViewGadget(2, 0, 35, 1000, 900)
; WebViewSetContentLoadingEventHandler(2, @ContentLoading())
WebViewSetNavigateCompleteEventHandler(2, @NaviComplete())
BindWebViewCallback(2, "WV_Changed", @WV_Changed())
SetGadgetText(2, "https://www.w3schools.com/xml/tryit.asp?filename=tryxml_parsertest2")
; AddWindowTimer(0, 1, 100)
Repeat
Event = WaitWindowEvent()
; If Event = #PB_Event_Timer
; If EventTimer() = 1
; If WebView2_Busy
; Debug "WebView is Busy"
; EndIf
; EndIf
; EndIf
If Event = #PB_Event_Gadget
If EventGadget() = 1
SetGadgetText(2, Trim(GetGadgetText(0)))
EndIf
EndIf
Until Event = #PB_Event_CloseWindow
Re: Any idea for #PB_Web_Busy with WebViewGadget? or other WebPageLoaded procedure?
Thank you! I think I already solved it with MutationObserver some minutes agobreeze4me wrote: Thu Feb 06, 2025 1:01 pm This method will not work for the site “www.openstreetmap.org”, you will need to get the information through MutationObserver or use the API provided by that site.Code: Select all
...

https://www.purebasic.fr/english/viewtopic.php?t=86218
PB 6.21 beta, PureVision User