Code: Select all
;--------------------------------------
; https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/navigation-events
; code from zikitrake https://www.purebasic.fr/english/viewtopic.php?t=86218
CompilerIf Defined(IID_IUnknown, #PB_Label) = #False
DataSection
IID_IUnknown:
Data.l $00000000
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46
EndDataSection
CompilerEndIf
;- STRUCTURES
Structure IUnknownBase_Structure
*pVtbl
*pQueryInterface
*pAddRef
*pRelease
*pInvoke
lRefCount.l
Token.q
hEvent.i
EndStructure
Structure ICoreWebView2ExecuteScriptCompletedHandler_Structure Extends IUnknownBase_Structure
Result$
EndStructure
Structure ICoreWebView2NavigationCompletedEventHandler_Structure Extends IUnknownBase_Structure
*pFunction
EndStructure
Structure ICoreWebView2ContentLoadingEventHandler_Structure Extends IUnknownBase_Structure
*pFunction
EndStructure
Structure ICoreWebView2WebMessageReceivedEventHandler_Structure Extends IUnknownBase_Structure
*pFunction
EndStructure
;--------------------------------------
;- NavigationCompleted
Global NewMap MapNavigationCompletedEventHandler.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
;-zikichange
;*sender\add_WebMessageReceived = *sender\
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(MapNavigationCompletedEventHandler(), Str(WebView))
If MapNavigationCompletedEventHandler()\Token
Core\remove_NavigationCompleted(MapNavigationCompletedEventHandler()\Token)
EndIf
DeleteMapElement(MapNavigationCompletedEventHandler())
EndIf
*NavigationCompletedEventHandler = AddMapElement(MapNavigationCompletedEventHandler(), 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(MapNavigationCompletedEventHandler())
EndIf
EndIf
EndIf
Core\Release()
EndIf
EndIf
ProcedureReturn Result
EndProcedure
;- ContentLoading
Global NewMap MapContentLoadingEventHandler.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(MapContentLoadingEventHandler(), Str(WebView))
If MapContentLoadingEventHandler()\Token
Core\remove_ContentLoading(MapContentLoadingEventHandler()\Token)
EndIf
DeleteMapElement(MapContentLoadingEventHandler())
EndIf
*ContentLoadingEventHandler = AddMapElement(MapContentLoadingEventHandler(), 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(MapContentLoadingEventHandler())
EndIf
EndIf
Core\Release()
EndIf
EndIf
EndIf
EndIf
ProcedureReturn Result
EndProcedure
;- WebMessageReceived
Global NewMap MapMessageReceivedEventHandler.ICoreWebView2WebMessageReceivedEventHandler_Structure()
Procedure.l ICoreWebView2WebMessageReceivedEventHandler_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 ICoreWebView2WebMessageReceivedEventHandler_AddRef(*this.IUnknownBase_Structure)
*this\lRefCount + 1
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l ICoreWebView2WebMessageReceivedEventHandler_Release(*this.IUnknownBase_Structure)
*this\lRefCount - 1
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l ICoreWebView2WebMessageReceivedEventHandler_Invoke(*this.ICoreWebView2WebMessageReceivedEventHandler_Structure, *sender.ICoreWebView2, *args.ICoreWebView2WebMessageReceivedEventArgs)
Protected message, *uri, uri.s
Debug uri
If *args And *args\TryGetWebMessageAsString(@message) = #S_OK And message
If PeekS(message) = "PBWEB content changed!"
Debug PeekS(message)
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
EndIf
EndProcedure
Procedure.i WebViewSetWebMessageReceivedEventHandler(WebView, *EventHandler)
Protected Result.i = #False
Protected Controller.ICoreWebView2Controller, Core.ICoreWebView2
Protected *WebMessageReceivedEventHandler.ICoreWebView2WebMessageReceivedEventHandler_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(MapMessageReceivedEventHandler(), Str(WebView))
If MapMessageReceivedEventHandler()\Token
Core\remove_WebMessageReceived(MapMessageReceivedEventHandler()\Token)
EndIf
DeleteMapElement(MapMessageReceivedEventHandler())
EndIf
*WebMessageReceivedEventHandler = AddMapElement(MapMessageReceivedEventHandler(), Str(WebView))
If *WebMessageReceivedEventHandler
*WebMessageReceivedEventHandler\pVtbl = *WebMessageReceivedEventHandler + OffsetOf(IUnknownBase_Structure\pQueryInterface)
*WebMessageReceivedEventHandler\pQueryInterface = @ICoreWebView2WebMessageReceivedEventHandler_QueryInterface()
*WebMessageReceivedEventHandler\pAddRef = @ICoreWebView2WebMessageReceivedEventHandler_AddRef()
*WebMessageReceivedEventHandler\pRelease = @ICoreWebView2WebMessageReceivedEventHandler_Release()
*WebMessageReceivedEventHandler\pInvoke = @ICoreWebView2WebMessageReceivedEventHandler_Invoke()
*WebMessageReceivedEventHandler\pFunction = *EventHandler
If Core\add_WebMessageReceived(*WebMessageReceivedEventHandler, @*WebMessageReceivedEventHandler\Token) = #S_OK
;Debug *WebMessageReceivedEventHandler\Token
Result = #True
Else
DeleteMapElement(MapMessageReceivedEventHandler())
EndIf
EndIf
Core\Release()
EndIf
EndIf
EndIf
EndIf
ProcedureReturn Result
EndProcedure
;--------------------------------------
;- EXECUTESCRIPT WITH RESULTS RETURN
Procedure.l CoreWebView2ExecuteScriptCompletedHandler_Invoke(*this.ICoreWebView2ExecuteScriptCompletedHandler_Structure, errorCode.l, *returnObjectAsJson)
Protected sResult.s, iCount
;Debug "CoreWebView2ExecuteScriptCompletedHandler_Invoke"
If errorCode = #S_OK
If *returnObjectAsJson
*this\Result$ = PeekS(*returnObjectAsJson)
EndIf
EndIf
If *this\hEvent
SetEvent_(*this\hEvent)
EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.s WebViewExecuteScriptWithStringResult(WebView, JavaScript$)
Protected Result$
Protected Controller.ICoreWebView2Controller, Core.ICoreWebView2
Protected *ExecuteScriptCompletedHandler.ICoreWebView2ExecuteScriptCompletedHandler_Structure
Protected hEvent
If GadgetType(WebView) = #PB_GadgetType_WebView
Controller = GetGadgetAttribute(WebView, #PB_WebView_ICoreController)
If Controller
If Controller\get_CoreWebView2(@Core) = #S_OK And Core <> #Null
hEvent = CreateEvent_(0, 0, 0, 0)
If hEvent
*ExecuteScriptCompletedHandler = AllocateMemory(SizeOf(ICoreWebView2ExecuteScriptCompletedHandler_Structure))
If *ExecuteScriptCompletedHandler
*ExecuteScriptCompletedHandler\pVtbl = *ExecuteScriptCompletedHandler + OffsetOf(IUnknownBase_Structure\pQueryInterface)
*ExecuteScriptCompletedHandler\pQueryInterface = @ICoreWebView2NavigationCompletedEventHandler_QueryInterface()
*ExecuteScriptCompletedHandler\pAddRef = @ICoreWebView2NavigationCompletedEventHandler_AddRef()
*ExecuteScriptCompletedHandler\pRelease = @ICoreWebView2NavigationCompletedEventHandler_Release()
*ExecuteScriptCompletedHandler\pInvoke = @CoreWebView2ExecuteScriptCompletedHandler_Invoke()
*ExecuteScriptCompletedHandler\hEvent = hEvent
If Core\ExecuteScript(JavaScript$, *ExecuteScriptCompletedHandler) = #S_OK
While WaitForSingleObject_(hEvent, 0) <> #WAIT_OBJECT_0
WindowEvent()
Wend
Result$ = *ExecuteScriptCompletedHandler\Result$
EndIf
FreeMemory(*ExecuteScriptCompletedHandler)
EndIf
CloseHandle_(hEvent)
EndIf
Core\Release()
EndIf
EndIf
EndIf
ProcedureReturn Result$
EndProcedure
;--------------------------------------
#WebView_BusyTimer = 666
Global WebView2_Busy.b, WebView2_NaviComplete.b, WebView2_MessageChanged.b
Procedure ContentLoading(uri.s)
Debug "Loading: " + uri
WebView2_Busy = #True
EndProcedure
Procedure NaviComplete(uri.s)
Debug "Loaded: " + uri
WebView2_Busy = #False
WebView2_NaviComplete = #True
EndProcedure
Procedure ContentMessageChanged(uri.s)
Debug "message change: " + uri
WebView2_MessageChanged = #True
EndProcedure
Procedure MutationObserverSet(webView)
Protected javascript.s
javascript = "const observer = new MutationObserver((mutationsList) => {"
javascript + " for (let mutation of mutationsList) {"
javascript + " if (mutation.type === 'childList') {"
javascript + " console.log('A child node has been added or removed.');"
javascript + " } else if (mutation.type === 'attributes') {"
javascript + " console.log('The ' + mutation.attributeName + ' attribute was modified.');"
javascript + " }"
javascript + " }"
javascript + "});"
javascript + "observer.observe(document.body, { attributes: true, childList: true, subtree: true });"
javascript = "var observer = new MutationObserver(function(mutations) {"
javascript + " window.chrome.webview.postMessage('PBWEB content changed!');"
javascript + " });"
javascript + "observer.observe(document.body, { childList: true, subtree: true });"
Debug WebViewExecuteScriptWithStringResult(webView, javascript)
EndProcedure
;--------------------------------------
;- Creación de UI
Procedure resizeW()
ResizeGadget(0, #PB_Ignore, #PB_Ignore, WindowWidth(0), WindowHeight(0)-50)
EndProcedure
; ----
Define Zoom0$, Zoom$
OpenWindow(0, 100, 100, 800, 600, "Hello", #PB_Window_SystemMenu|#PB_Window_MinimizeGadget |#PB_Window_MaximizeGadget |#PB_Window_SizeGadget)
WebViewGadget(0, 0, 50, 800, 500, #PB_WebView_Debug)
SetGadgetText(0, "https:\\www.purebasic.com")
BindEvent(#PB_Event_SizeWindow,@resizeW())
ButtonGadget(1, 10, 10, 120, 25, "100%")
TrackBarGadget(2,130,10,600,30,10,400)
SetGadgetState(2, 100)
TextGadget(3,750,10,60,30,"100%")
WebViewSetContentLoadingEventHandler(0, @ContentLoading())
WebViewSetNavigateCompleteEventHandler(0, @NaviComplete())
AddWindowTimer(0, #WebView_BusyTimer, 100)
Repeat
Select WaitWindowEvent()
Case #PB_Event_Timer
If EventTimer() = #WebView_BusyTimer
If WebView2_NaviComplete
WebView2_NaviComplete = #False
MutationObserverSet(0)
WebViewSetWebMessageReceivedEventHandler(0, @ContentMessageChanged())
Debug "complete!"
zoom0$=Str(GetGadgetState(2))
zoom$=~"document.body.style.zoom=\""+zoom0$+~"%\""
WebViewExecuteScript(0, zoom$)
SetGadgetText(3,zoom0$)
EndIf
If WebView2_Busy
Debug "WebView is Busy"
EndIf
If WebView2_MessageChanged
Debug "Message Changed!"
WebView2_MessageChanged = #False
EndIf
EndIf
Case #PB_Event_Gadget
Select EventGadget()
Case 1
WebViewExecuteScript(0, ~"document.body.style.zoom=\"100%\"")
SetGadgetState(2, 100)
SetGadgetText(3,"100%")
Case 2
zoom0$=Str(GetGadgetState(2))
zoom$=~"document.body.style.zoom=\""+zoom0$+~"%\""
WebViewExecuteScript(0, zoom$)
SetGadgetText(3,zoom0$)
EndSelect
Case #PB_Event_CloseWindow
Break
EndSelect
ForEver