WebViewGadget WebMessageReceived callback

Share your advanced PureBasic knowledge/code with the community.
infratec
Always Here
Always Here
Posts: 7616
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

WebViewGadget WebMessageReceived callback

Post by infratec »

Windows only.

Save it as WebViewWebMessageReceivedCallback.pbi

Code: Select all

;
; https://www.purebasic.fr/english/viewtopic.php?p=629641
;

CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf

CompilerIf Not Defined(IID_IUnknown, #PB_Label)
  DataSection
    IID_IUnknown:
    Data.l $00000000
    Data.w $0000, $0000
    Data.b $C0, $00, $00, $00, $00, $00, $00, $46
  EndDataSection
CompilerEndIf

CompilerIf Not Defined(IUnknownBase_Structure, #PB_Structure)
  Structure IUnknownBase_Structure
    *pVtable
    lRefCount.l
    *pQueryInterface
    *pAddRef
    *pRelease
  EndStructure
CompilerEndIf


Prototype.i WebViewWebMessageReceived_Prototype(Message$)

Structure ICoreWebView2WebMessageReceivedEventHandler_Structure Extends IUnknownBase_Structure
  *pInvoke
  Token.q
  *pCallback.WebViewWebMessageReceived_Prototype
EndStructure


Global NewMap WebViewWebMessageReceivedEventHandlerMap.ICoreWebView2WebMessageReceivedEventHandler_Structure()




Procedure.l ICoreWebView2WebMessageReceivedEventHandler_QueryInterface(*this.ICoreWebView2WebMessageReceivedEventHandler_Structure, *riid.IID, *ppvObject.Integer)
  
  Protected Result.l
  
  
  Debug "WebView  WebMessageReceived QueryInterface"
  
  Result = #S_OK
  
  If *ppvObject And *riid
    If CompareMemory(*riid, ?IID_IUnknown, SizeOf(IID))
      *this\lRefCount + 1
      *ppvObject\i = *this
    Else
      *ppvObject\i = 0
      Result = #E_NOINTERFACE
    EndIf
  Else
    Result = #E_POINTER
  EndIf
  
  ProcedureReturn Result
  
EndProcedure




Procedure.l ICoreWebView2WebMessageReceivedEventHandler_AddRef(*this.ICoreWebView2WebMessageReceivedEventHandler_Structure)
  
  Debug "WebView WebMessageReceived AddRef"
  
  *this\lRefCount + 1
  
  ProcedureReturn *this\lRefCount
  
EndProcedure




Procedure.l ICoreWebView2WebMessageReceivedEventHandler_Release(*this.ICoreWebView2WebMessageReceivedEventHandler_Structure)
  
  Debug "WebView WebMessageReceived Release"
  
  *this\lRefCount - 1
  
  ProcedureReturn *this\lRefCount
  
EndProcedure




Procedure.l ICoreWebView2WebMessageReceivedEventHandler_Invoke(*this.ICoreWebView2WebMessageReceivedEventHandler_Structure, *sender.ICoreWebView2, *args.ICoreWebView2WebMessageReceivedEventArgs)
  
  Protected *ptr, Result.i, Message$
  
  
  Debug "WebView WebMessageReceived Invoke"
  
  Result = #S_OK
  *args\get_webMessageAsJson(@*ptr)
  If *ptr
    Message$ = PeekS(*ptr)
    Result = *this\pCallback(Message$)
    CoTaskMemFree_(*ptr)
  EndIf
  
  ProcedureReturn Result
  
EndProcedure




Procedure WebViewRemoveWebMessageReceivedCallback(WebView.i, Core.ICoreWebView2)
  
  If FindMapElement(WebViewWebMessageReceivedEventHandlerMap(), Str(WebView))
    
    If WebViewWebMessageReceivedEventHandlerMap()\Token
      If Core
        Core\remove_WebMessageReceived(WebViewWebMessageReceivedEventHandlerMap()\Token)
      EndIf
    EndIf
    
    DeleteMapElement(WebViewWebMessageReceivedEventHandlerMap())
  EndIf
  
EndProcedure




; CompilerIf Not Defined(ICoreWebView2Settings, #PB_Interface)
;   
;   DataSection
;     IID_ICoreWebView2Settings:
;     Data.l $E562E4F0
;     Data.w $D7FA, $43AC
;     Data.b $8D, $71, $C0, $51, $50, $49, $9F, $0
;   EndDataSection
;   
;   Interface ICoreWebView2Settings Extends IUnknown
;     get_IsScriptEnabled(IsScriptEnabled.i)
;     put_IsScriptEnabled(IsScriptEnabled.l)
;     get_IsWebMessageEnabled(IsWebMessageEnabled.i)
;     put_IsWebMessageEnabled(IsWebMessageEnabled.l)
;     get_AreDefaultScriptDialogsEnabled(AreDefaultScriptDialogsEnabled.i)
;     put_AreDefaultScriptDialogsEnabled(AreDefaultScriptDialogsEnabled.l)
;     get_IsStatusBarEnabled(IsStatusBarEnabled.i)
;     put_IsStatusBarEnabled(IsStatusBarEnabled.l)
;     get_AreDevToolsEnabled(AreDevToolsEnabled.i)
;     put_AreDevToolsEnabled(AreDevToolsEnabled.l)
;     get_AreDefaultContextMenusEnabled(enabled.i)
;     put_AreDefaultContextMenusEnabled(enabled.l)
;     get_AreHostObjectsAllowed(allowed.i)
;     put_AreHostObjectsAllowed(allowed.l)
;     get_IsZoomControlEnabled(enabled.i)
;     put_IsZoomControlEnabled(enabled.l)
;     get_IsBuiltInErrorPageEnabled(enabled.i)
;     put_IsBuiltInErrorPageEnabled(enabled.l)
;   EndInterface
; CompilerEndIf




Procedure.i WebViewAddWebMessageReceivedCallback(WebView, *Callback.WebViewWebMessageReceived_Prototype)
  
  Protected Result.i
  Protected Controller.ICoreWebView2Controller, Core.ICoreWebView2
  Protected *EventHandler.ICoreWebView2WebMessageReceivedEventHandler_Structure
  ;Protected Settings.ICoreWebview2Settings
  
  
  If GadgetType(WebView) = #PB_GadgetType_WebView And *Callback <> #Null
    
    Controller = GetGadgetAttribute(WebView, #PB_WebView_ICoreController)
    If Controller
      
      If Controller\get_CoreWebView2(@Core) = #S_OK And Core <> #Null
        
        WebViewRemoveWebMessageReceivedCallback(WebView, Core)
        
;         Core\get_Settings(@Settings)
;         
;         If Settings\get_IsWebMessageEnabled(@Result) = #S_OK
;           If Result
;             Debug "WebMessageEnabled"
;           Else
;             If Settings\put_IsWebMessageEnabled(#True) = #S_OK
;               Debug "Ok"
;             Else
;               Debug "NoK"
;             EndIf
;           EndIf
;         EndIf
        
        *EventHandler = AddMapElement(WebViewWebMessageReceivedEventHandlerMap(), Str(WebView))
        If *EventHandler
          *EventHandler\pVtable = *EventHandler + OffsetOf(IUnknownBase_Structure\pQueryInterface)
          *EventHandler\pQueryInterface = @ICoreWebView2WebMessageReceivedEventHandler_QueryInterface()
          *EventHandler\pAddRef = @ICoreWebView2WebMessageReceivedEventHandler_AddRef()
          *EventHandler\pRelease = @ICoreWebView2WebMessageReceivedEventHandler_Release()
          *EventHandler\pInvoke = @ICoreWebView2WebMessageReceivedEventHandler_Invoke()
          *EventHandler\Token = 0
          *EventHandler\pCallback = *Callback
          
          Result = Core\add_WebMessageReceived(*EventHandler, @*EventHandler\Token)
          If Result = #S_OK
            ;Debug "Token: " + Str(*EventHandler\Token)
            Result = #True
          Else
            WebViewRemoveWebMessageReceivedCallback(WebView, Core)
            Result = #False
          EndIf
          
        EndIf
        
        Core\Release()
      EndIf
    EndIf
  EndIf
  
  ProcedureReturn Result
  
EndProcedure




CompilerIf #PB_Compiler_IsMainFile
  
  
  Procedure.i WebViewWebMessageReceived(Message$)
    
    Debug Message$
    
    ProcedureReturn #S_OK
    
  EndProcedure
  
  
  
  Define Event.i
  
  
  OpenWindow(0, 100, 100, 400, 100, "Hello", #PB_Window_SystemMenu)
  
  WebViewGadget(0, 0, 0, 400, 100)
  SetGadgetItemText(0, #PB_WebView_HtmlCode,
                    ~"<!DOCTYPE html>\n" + 
                    ~"<html lang=\"en\">\n" +
                    ~" <head>" +
                    ~"  <title>WebMessage</title>" +
                    ~" </head>" +
                    ~" <body>" +
                    ~"  After 3 seconds a message will be posted" +
                    ~" </body>" +
                    ~"</html>")
  
  
  WebViewAddWebMessageReceivedCallback(0, @WebViewWebMessageReceived())
  
  AddWindowTimer(0, 1, 3000)
  
  Repeat 
    Event = WaitWindowEvent()
    If Event = #PB_Event_Timer
      If EventTimer() = 1
        RemoveWindowTimer(0, 1)
        WebViewExecuteScript(0, "window.chrome.webview.postMessage('Hello PureBasic');")
      EndIf
    EndIf
  Until Event = #PB_Event_CloseWindow
  
CompilerEndIf
Last edited by infratec on Fri Oct 25, 2024 4:09 pm, edited 2 times in total.
User avatar
Kiffi
Addict
Addict
Posts: 1500
Joined: Tue Mar 02, 2004 1:20 pm
Location: Amphibios 9

Re: WebViewGadget WebMessageReceived callback

Post by Kiffi »

Very cool! Thanks Image
Hygge
Quin
Addict
Addict
Posts: 1133
Joined: Thu Mar 31, 2022 7:03 pm
Location: Colorado, United States
Contact:

Re: WebViewGadget WebMessageReceived callback

Post by Quin »

Nice work as always! :)
infratec
Always Here
Always Here
Posts: 7616
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: WebViewGadget WebMessageReceived callback

Post by infratec »

Updated the code above.

Forgot a CoTaskMemFree_(*ptr)
And changed the Parameter of the callback to string.
User avatar
Zapman
Enthusiast
Enthusiast
Posts: 205
Joined: Tue Jan 07, 2020 7:27 pm

Re: WebViewGadget WebMessageReceived callback

Post by Zapman »

Very nice! Thanks a lot!
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: WebViewGadget WebMessageReceived callback

Post by Kwai chang caine »

Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
dige
Addict
Addict
Posts: 1405
Joined: Wed Apr 30, 2003 8:15 am
Location: Germany
Contact:

Re: WebViewGadget WebMessageReceived callback

Post by dige »

Hello Bernd, thank you very much for the code. Can you please say something about the possibilities?

I'm thinking of an interactive map, if I move a marker by drag and drop etc., can I then get the position?

How does your code differ from the BindWebViewCallback()?
"Daddy, I'll run faster, then it is not so far..."
infratec
Always Here
Always Here
Posts: 7616
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: WebViewGadget WebMessageReceived callback

Post by infratec »

I extended the code of the BindWebViewCallback() example from the PB help:

Code: Select all

Html$ =  ~"<button id=\"displayInfo\">Display Info</button>\n"+
         ~"<script>\n"+
         ~"  const displayInfoElement=document.getElementById(\"displayInfo\");\n"+
         ~"  document.addEventListener(\"DOMContentLoaded\", () => {\n"+
         ~"    displayInfoElement.addEventListener(\"click\", () => {\n"+
         ~"      window.displayInfo(1000, 2000).then(result => {\n"+
         ~"        displayInfoElement.textContent = result.sum;\n"+
         ~"      });\n"+
         ~"    });\n"+
         ~"  });\n"+
         ~"</script>";


 Procedure IncrementJS(JsonParameters$)
    
    Dim Parameters(0)
    
    ParseJSON(0, JsonParameters$)
    ExtractJSONArray(JSONValue(0), Parameters())
    
    Debug "Nb Parameters: " + ArraySize(Parameters())
    
    Debug "Parameter 1: " + Parameters(0)
    Debug "Parameter 2: " + Parameters(1)
    
    ProcedureReturn UTF8(~"{ \"sum\": "+Str(Parameters(0) + Parameters(1))+ "}")
  EndProcedure


Procedure.i WebViewWebMessageReceived(Message$)
  
  Debug Message$
  
  ProcedureReturn #S_OK
  
EndProcedure


OpenWindow(0, 100, 100, 400, 400, "Hello", #PB_Window_SystemMenu)

WebViewGadget(0, 0, 0, 400, 400)
SetGadgetItemText(0, #PB_WebView_HtmlCode, Html$)

BindWebViewCallback(0, "postMessage", @WebViewWebMessageReceived())
BindWebViewCallback(0, "displayInfo", @IncrementJS())


AddWindowTimer(0, 1, 3000)

Repeat 
  Event = WaitWindowEvent()
  If Event = #PB_Event_Timer
    If EventTimer() = 1
      RemoveWindowTimer(0, 1)
      WebViewExecuteScript(0, "window.chrome.webview.postMessage('Hello PureBasic');")
      Debug "postMessage sent"
    EndIf
  EndIf
  
Until Event = #PB_Event_CloseWindow
It is not possible to use BindWebViewCallback() for postMessage().

It is only one more possibility to communicate between the web page and PB.
What you do with these possibilities depends on your JavaScript skills.
dige
Addict
Addict
Posts: 1405
Joined: Wed Apr 30, 2003 8:15 am
Location: Germany
Contact:

Re: WebViewGadget WebMessageReceived callback

Post by dige »

Thx for the information.

When I click on Display Info, the program crashes with an unhandled exception (Windows PB 6.12 x64)
"Daddy, I'll run faster, then it is not so far..."
infratec
Always Here
Always Here
Posts: 7616
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: WebViewGadget WebMessageReceived callback

Post by infratec »

Hm... works with firefox on my win10 PC with PB 6.12 x86
And also with PB 6.12 x64
dige
Addict
Addict
Posts: 1405
Joined: Wed Apr 30, 2003 8:15 am
Location: Germany
Contact:

Re: WebViewGadget WebMessageReceived callback

Post by dige »

Firefox?

If I run the code, a Window with webview gadget opens and there is the Click me button, who crashes the runtime, after clicking.
"Daddy, I'll run faster, then it is not so far..."
infratec
Always Here
Always Here
Posts: 7616
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: WebViewGadget WebMessageReceived callback

Post by infratec »

Ups ...

of course you are right. firefox was in the background :oops:

But still, it works here in x86 and x64 without crash.
Post Reply