FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin for Harbour/xHarbour Class TEdge v1
Posts: 139
Joined: Mon Oct 17, 2005 03:03 AM

Class TEdge v1

Posted: Fri Sep 11, 2026 01:02 AM

The enhanced version of TWebView2, offering more WebView2 features, is named TEdge.

TEdge.prg

#include "FiveWin.ch"

#define GWL_STYLE        -16

static aWebViews := {}

//----------------------------------------------------------------------------//

STATIC FUNCTION Edge_DefaultUserDataFolder()

   LOCAL cBase := GetEnv( "LOCALAPPDATA" )

   IF Empty( cBase )
      cBase := GetEnv( "TEMP" )
   ENDIF
   IF Empty( cBase )
      cBase := GetEnv( "TMP" )
   ENDIF
   IF Empty( cBase )
      cBase := "."
   ENDIF

RETURN hb_DirSepAdd( hb_DirSepToOS( cBase ) ) + "FWH_edge_UserData"

//----------------------------------------------------------------------------//

STATIC FUNCTION Edge_PrepareUserDataFolder( cUserDataFolder )

   LOCAL cDir := hb_DirSepToOS( AllTrim( hb_defaultValue( cUserDataFolder, "" ) ) )
   LOCAL cDef := Edge_DefaultUserDataFolder()

   IF Empty( cDir )
      hb_DirBuild( cDef )
      RETURN ""
   ENDIF

   IF hb_DirExists( cDir ) .OR. hb_DirBuild( cDir ) == .T.
      RETURN cDir
   ENDIF

   hb_DirBuild( cDef )
RETURN ""

//----------------------------------------------------------------------------//
// TEdge — FiveWin WebView2 class backed by COM cedge.c + edge.c (no .lib)
//----------------------------------------------------------------------------//

CLASS TEdge

   DATA   hWebView
   DATA   oWnd
   DATA   bOnBind
   DATA   bOnNavigationCompleted
   DATA   bOnEval
   DATA   bOnConsole
   DATA   bOnHistoryChanged
   DATA   bOnNavigationStarting
   DATA   bOnSourceChanged
   DATA   bOnDocumentTitleChanged
   DATA   bOnNewWindow
   DATA   bOnPermission
   DATA   bOnWebResource
   DATA   bOnHostObject
   DATA   bOnCapturePreview
   DATA   bOnPrintToPdf
   DATA   bOnClearBrowsingData
   DATA   bOnZoomFactorChanged
   DATA   bOnScriptDialog
   DATA   bOnProcessFailed
   DATA   bOnFullScreen
   DATA   bOnFrameNavStarting
   DATA   bOnFrameNavCompleted
   DATA   cUserDataFolder

   METHOD New( oWndParent, cUserDataFolder ) CONSTRUCTOR

   METHOD Navigate( cURL ) INLINE edge_Navigate( ::hWebView, cURL )
   METHOD NavigateEx( cUrl, cMethod, cHeaders, cBody ) ;
      INLINE edge_NavigateEx( ::hWebView, cUrl, cMethod, cHeaders, cBody )

   METHOD Center() INLINE ::oWnd:Center()

   METHOD SetHtml( cHtml ) INLINE edge_SetHtml( ::hWebView, cHTML )

   METHOD SetTitle( cText ) INLINE SetWindowText( ::oWnd:hWnd, cText )

   METHOD SetSize( nWidth, nHeight ) INLINE edge_SetSize( ::hWebView, nWidth, nHeight )

   METHOD SetUserAgent( cUserAgent ) INLINE edge_SetUserAgent( ::hWebView, cUserAgent )

   METHOD OpenDevToolsWindow( lOnOff ) INLINE edge_OpenDevToolsWindow( ::hWebView, lOnOff )

   METHOD Run() INLINE ::oWnd:Activate()

   METHOD SetParent( oWnd ) INLINE ( ::oWnd := oWnd, SetWindowLong( ::GetWindow(), GWL_STYLE, nOr( WS_CHILD, WS_VISIBLE ) ),;
         SetWindowPos( ::GetWindow(), 0, 0, 0, oWnd:nWidth, oWnd:nHeight, 4 ),;
      SetParent( ::GetWindow(), oWnd:hWnd ) )

   METHOD GetWindow() INLINE ::oWnd:hWnd

   METHOD Eval( cJavaScript ) INLINE edge_Eval( ::hWebView, cJavaScript )

   METHOD InjectJavascript( cScript )

   METHOD Terminate() INLINE ::End()

   METHOD Destroy() INLINE ::End()

   METHOD End()

   METHOD ShowDownloads( lOnOff ) INLINE edge_ShowDownloads( ::hWebView, lOnOff )

   // EnableConsole( lOn ) + DATA bOnConsole
   //   預設建議 .T.;CDP Runtime.consoleAPICalled → Eval( bOnConsole, cJson )
   //   .F. — 關閉攔截(bOnConsole 不再被叫)
   //   cJson 含 type=log|warn|error|info|clear(console.clear())
   //   勿在 bOnConsole 預設 MsgInfo(Bing 等站會洗版);狀態列/寫檔即可
   METHOD EnableConsole( lOnOff ) INLINE edge_EnableConsole( ::hWebView, lOnOff )

   // TEdgeBrowser-parity navigation / info
   METHOD GoBack() INLINE edge_GoBack( ::hWebView )
   METHOD GoForward() INLINE edge_GoForward( ::hWebView )
   METHOD Reload() INLINE edge_Reload( ::hWebView )
   METHOD Stop() INLINE edge_Stop( ::hWebView )
   METHOD CanGoBack() INLINE edge_CanGoBack( ::hWebView )
   METHOD CanGoForward() INLINE edge_CanGoForward( ::hWebView )
   METHOD GetSource() INLINE edge_GetSource( ::hWebView )
   METHOD GetDocumentTitle() INLINE edge_GetDocumentTitle( ::hWebView )
   METHOD CapturePreview( cPngPath ) INLINE edge_CapturePreview( ::hWebView, cPngPath )
   METHOD PrintToPdf( cPdfPath, lLandscape ) ;
      INLINE edge_PrintToPdf( ::hWebView, cPdfPath, lLandscape )
   METHOD AddWebResourceRequestedFilter( cUri, nContext ) ;
      INLINE edge_AddWebResourceRequestedFilter( ::hWebView, cUri, nContext )
   METHOD RemoveWebResourceRequestedFilter( cUri, nContext ) ;
      INLINE edge_RemoveWebResourceRequestedFilter( ::hWebView, cUri, nContext )
   METHOD AddHostObject( cName ) INLINE edge_AddHostObject( ::hWebView, cName )
   METHOD RemoveHostObject( cName ) INLINE edge_RemoveHostObject( ::hWebView, cName )
   METHOD Print() INLINE edge_Print( ::hWebView )

   METHOD SetZoomFactor( nZoom ) INLINE edge_SetZoomFactor( ::hWebView, nZoom )
   METHOD GetZoomFactor() INLINE edge_GetZoomFactor( ::hWebView )
   METHOD SetSizeRatio( nRatio ) INLINE edge_SetSizeRatio( ::hWebView, nRatio )
   METHOD GetSizeRatio() INLINE edge_GetSizeRatio( ::hWebView )
   METHOD GetBrowserVersion() INLINE edge_GetBrowserVersion()
   METHOD CloseWebView() INLINE edge_CloseWebView( ::hWebView )
   METHOD Reinitialize() INLINE edge_Reinitialize( ::hWebView )
   METHOD SetDefaultScriptDialogs( lOn ) INLINE edge_SetDefaultScriptDialogs( ::hWebView, lOn )

   // Clear browsing data (async → bOnClearBrowsingData)
   //   ClearSession()  — cookies + cache + DOM storage + history (SEO clean env)
   //   ClearBrowsingData(0) / ClearAllBrowsingData() — entire profile
   //   ClearBrowsingData(nKinds) — bitmask flags
   METHOD ClearSession() INLINE edge_ClearSession( ::hWebView )
   METHOD ClearAllBrowsingData() INLINE edge_ClearBrowsingData( ::hWebView, 0 )
   METHOD ClearBrowsingData( nKinds ) INLINE edge_ClearBrowsingData( ::hWebView, nKinds )

   // Right-click menu customization
   //   SetContextMenuExclude( "inspectElement,print" ) — hide named items
   //   SetContextMenuExclude( "" ) — show all defaults again
   //   SetDefaultContextMenus( .F. ) — disable entire context menu
   METHOD SetContextMenuExclude( cCsv ) INLINE edge_SetContextMenuExclude( ::hWebView, cCsv )
   METHOD SetDefaultContextMenus( lOn ) INLINE edge_SetDefaultContextMenus( ::hWebView, lOn )

   // License (shared edge.lib — one lib for all customers)
   //   ::SetSerial(cHex) or ::SetSerial("Name|email") → .T. if valid
   //   empty / TEDGE-OK → trial: first SetHtml/Navigate shows bilingual splash ~3s
   //                       (once per process; SetTimer, then real content)
   //   invalid serial →「惡意破壞者」MsgBox then ExitProcess
   //   ::LicenseOwner() → Name|email after successful SetSerial; else "" (About/debug)
   METHOD SetSerial( cSerial )
   METHOD LicenseOwner() INLINE edge_LicenseOwner()

ENDCLASS

//----------------------------------------------------------------------------//

METHOD SetSerial( cSerial ) CLASS TEdge

RETURN edge_SetSerial( cSerial )

//----------------------------------------------------------------------------//

// New( oWndParent, cUserDataFolder )
//   oWndParent      — parent window (NIL = create own window)
//   cUserDataFolder — WebView2 user data folder path; empty/NIL uses
//                     %LOCALAPPDATA%\FWH_edge_UserData
METHOD New( oWndParent, cUserDataFolder ) CLASS TEdge

   cUserDataFolder := Edge_PrepareUserDataFolder( cUserDataFolder )

   if ! Empty( oWndParent ) .and. ! Empty( oWndParent:hWnd )
      ::hWebView = edge_New( oWndParent:hWnd, cUserDataFolder )
      ::oWnd = oWndParent
   else
      DEFINE WINDOW ::oWnd TITLE "WebView" COLOR "N/B"
      ::hWebView = edge_New( ::oWnd:hWnd, cUserDataFolder )
      ::oWnd:bResized = { | nType, nWidth, nHeight | nType, ::SetSize( nWidth, nHeight ) }
   endif

   ::cUserDataFolder = cUserDataFolder

   ::bOnBind = { | cJson | MsgInfo( cJson ) }

   AAdd( aWebViews, Self )

return Self

//----------------------------------------------------------------------------//

METHOD End() CLASS TEdge

   local nAt

   if ! Empty( ::hWebView )
      edge_End( ::hWebView )
      ::hWebView := nil
   endif

   nAt := AScan( aWebViews, { | o | o == Self } )
   if nAt > 0
      ADel( aWebViews, nAt )
      ASize( aWebViews, Len( aWebViews ) - 1 )
   endif

return nil

//----------------------------------------------------------------------------//

METHOD InjectJavascript( cScript ) CLASS TEdge

   local cInjection

   cInjection := "var script = document.createElement('script');" + CRLF
   cInjection += "script.textContent = `" + CRLF

   cInjection += cScript + CRLF

   cInjection += "`;" + CRLF
   cInjection += "document.head.appendChild(script);"

   ::Eval( cInjection )

return nil

//----------------------------------------------------------------------------//

static function GetWebView( hWebView )

return aWebViews[ AScan( aWebViews, { | o | o:hWebView == hWebView } ) ]

//----------------------------------------------------------------------------//

function Edge_OnBind( cParams, hWebView ) // SendToFWH() has been called from javascript

   local oWebView := GetWebView( hWebView )
   local hJson

   if Empty( oWebView )
      return nil
   endif

   hb_jsonDecode( cParams, @hJson )

   if ! Empty( oWebView:bOnBind )
      if ValType( hJson ) == "H" .and. hb_HHasKey( hJson, "params" )
         Eval( oWebView:bOnBind, hJson[ "params" ], oWebView )
      else
         Eval( oWebView:bOnBind, cParams, oWebView )
      endif
   endif

return nil

//----------------------------------------------------------------------------//

function Edge_OnNavigationCompleted( cUrl, hWebView )

   local nAt := AScan( aWebViews, { | o | o:hWebView == hWebView } ), nResult

   if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnNavigationCompleted )
      nResult = Eval( aWebViews[ nAt ]:bOnNavigationCompleted, cUrl, hWebView )
   endif

return nResult

//----------------------------------------------------------------------------//

function Edge_OnEval( cJson, hWebView )

   local nAt := AScan( aWebViews, { | o | o:hWebView == hWebView } ), nResult

   if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnEval )
      nResult = Eval( aWebViews[ nAt ]:bOnEval, cJson, hWebView )
   endif

return nResult

//----------------------------------------------------------------------------//

// CDP Runtime.consoleAPICalled JSON, e.g.
//   {"type":"log","args":[{"type":"string","value":"hello"}], ...}
function Edge_OnConsole( cJson, hWebView )

   local nAt := AScan( aWebViews, { | o | o:hWebView == hWebView } ), nResult

   if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnConsole )
      nResult = Eval( aWebViews[ nAt ]:bOnConsole, cJson, hWebView )
   endif

return nResult

//----------------------------------------------------------------------------//

function Edge_OnHistoryChanged( lCanBack, lCanFwd, hWebView )

   local nAt := AScan( aWebViews, { | o | o:hWebView == hWebView } )

   if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnHistoryChanged )
      Eval( aWebViews[ nAt ]:bOnHistoryChanged, lCanBack, lCanFwd, hWebView )
   endif

return nil

//----------------------------------------------------------------------------//

// Return .T. to CANCEL navigation
function Edge_OnNavigationStarting( cUrl, hWebView )

   local nAt := AScan( aWebViews, { | o | o:hWebView == hWebView } ), lCancel := .F.

   if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnNavigationStarting )
      lCancel := Eval( aWebViews[ nAt ]:bOnNavigationStarting, cUrl, hWebView )
      if ValType( lCancel ) != "L"
         lCancel := .F.
      endif
   endif

return lCancel

//----------------------------------------------------------------------------//

function Edge_OnSourceChanged( cUrl, hWebView )

   local nAt := AScan( aWebViews, { | o | o:hWebView == hWebView } )

   if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnSourceChanged )
      Eval( aWebViews[ nAt ]:bOnSourceChanged, cUrl, hWebView )
   endif

return nil

//----------------------------------------------------------------------------//

function Edge_OnDocumentTitleChanged( cTitle, hWebView )

   local nAt := AScan( aWebViews, { | o | o:hWebView == hWebView } )

   if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnDocumentTitleChanged )
      Eval( aWebViews[ nAt ]:bOnDocumentTitleChanged, cTitle, hWebView )
   endif

return nil

//----------------------------------------------------------------------------//

// FWH parity: C side always Navigate same webview + Handled; callback is notify
function Edge_OnNewWindow( cUrl, hWebView )

   local nAt := AScan( aWebViews, { | o | o:hWebView == hWebView } ), lRet := .T.

   if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnNewWindow )
      lRet := Eval( aWebViews[ nAt ]:bOnNewWindow, cUrl, hWebView )
      if ValType( lRet ) != "L"
         lRet := .T.
      endif
   endif

return lRet

//----------------------------------------------------------------------------//

// Return 1=allow, 2=deny, else default (0)
function Edge_OnPermission( cUrl, nKind, hWebView )

   local nAt := AScan( aWebViews, { | o | o:hWebView == hWebView } ), nState := 0

   if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnPermission )
      nState := Eval( aWebViews[ nAt ]:bOnPermission, cUrl, nKind, hWebView )
      if ValType( nState ) != "N"
         nState := 0
      endif
   endif

return nState

//----------------------------------------------------------------------------//

function Edge_OnWebResource( cUrl, nContext, hWebView )

   local nAt := AScan( aWebViews, { | o | o:hWebView == hWebView } ), xRet

   if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnWebResource )
      xRet := Eval( aWebViews[ nAt ]:bOnWebResource, cUrl, nContext, hWebView )
      if ValType( xRet ) == "A"
         return xRet
      endif
   endif

return nil

//----------------------------------------------------------------------------//

function Edge_OnHostObject( cObjName, cMethod, cArg, hWebView )

   local nAt := AScan( aWebViews, { | o | o:hWebView == hWebView } ), cRet := ""

   if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnHostObject )
      cRet := Eval( aWebViews[ nAt ]:bOnHostObject, cObjName, cMethod, cArg, hWebView )
      if ValType( cRet ) != "C"
         cRet := ""
      endif
   endif

return cRet

//----------------------------------------------------------------------------//

function Edge_OnCapturePreview( lOk, cPath, hWebView )

   local nAt := AScan( aWebViews, { | o | o:hWebView == hWebView } )

   if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnCapturePreview )
      Eval( aWebViews[ nAt ]:bOnCapturePreview, lOk, cPath, hWebView )
   endif

return nil

//----------------------------------------------------------------------------//

function Edge_OnPrintToPdf( lOk, cPath, hWebView )

   local nAt := AScan( aWebViews, { | o | o:hWebView == hWebView } )

   if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnPrintToPdf )
      Eval( aWebViews[ nAt ]:bOnPrintToPdf, lOk, cPath, hWebView )
   endif

return nil

//----------------------------------------------------------------------------//

function Edge_OnClearBrowsingData( lOk, cWhat, hWebView )

   local nAt := AScan( aWebViews, { | o | o:hWebView == hWebView } )

   if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnClearBrowsingData )
      Eval( aWebViews[ nAt ]:bOnClearBrowsingData, lOk, cWhat, hWebView )
   endif

return nil

//----------------------------------------------------------------------------//

function Edge_OnZoomFactorChanged( nZoom, hWebView )

   local nAt := AScan( aWebViews, { | o | o:hWebView == hWebView } )

   if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnZoomFactorChanged )
      Eval( aWebViews[ nAt ]:bOnZoomFactorChanged, nZoom, hWebView )
   endif

return nil

//----------------------------------------------------------------------------//

// Return .T. = Accept, .F. = Cancel/suppress; NIL = leave default dialogs
// kind: 0=alert 1=confirm 2=prompt 3=beforeunload
function Edge_OnScriptDialog( cUri, nKind, cMsg, cDefault, hWebView )

   local nAt := AScan( aWebViews, { | o | o:hWebView == hWebView } ), xRet

   if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnScriptDialog )
      xRet := Eval( aWebViews[ nAt ]:bOnScriptDialog, cUri, nKind, cMsg, cDefault, hWebView )
      if ValType( xRet ) == "L"
         return xRet
      endif
      return .T.
   endif

return nil

//----------------------------------------------------------------------------//

function Edge_OnProcessFailed( nKind, hWebView )

   local nAt := AScan( aWebViews, { | o | o:hWebView == hWebView } )

   if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnProcessFailed )
      Eval( aWebViews[ nAt ]:bOnProcessFailed, nKind, hWebView )
   endif

return nil

//----------------------------------------------------------------------------//

function Edge_OnFullScreen( lFull, cUnused, hWebView )

   local nAt := AScan( aWebViews, { | o | o:hWebView == hWebView } )

   if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnFullScreen )
      Eval( aWebViews[ nAt ]:bOnFullScreen, lFull, hWebView )
   endif

return nil

//----------------------------------------------------------------------------//

// Return .T. to CANCEL frame navigation
function Edge_OnFrameNavStarting( cUrl, hWebView )

   local nAt := AScan( aWebViews, { | o | o:hWebView == hWebView } ), lCancel := .F.

   if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnFrameNavStarting )
      lCancel := Eval( aWebViews[ nAt ]:bOnFrameNavStarting, cUrl, hWebView )
      if ValType( lCancel ) != "L"
         lCancel := .F.
      endif
   endif

return lCancel

//----------------------------------------------------------------------------//

function Edge_OnFrameNavCompleted( cUrl, hWebView )

   local nAt := AScan( aWebViews, { | o | o:hWebView == hWebView } )

   if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnFrameNavCompleted )
      Eval( aWebViews[ nAt ]:bOnFrameNavCompleted, cUrl, hWebView )
   endif

return nil

//----------------------------------------------------------------------------//

function FW_WebView( cHtml, oWnd )

   local oWebView

   if oWnd != nil .and. oWnd:IsKindOf( "TWEBVIEW2" )
      if Empty( oWnd:oWnd:hWnd )
         oWnd:End()
         oWnd  := nil
      elseif Empty( oWnd:hWebView )
         oWnd  := oWnd:oWnd
      endif
   endif

   if oWnd == nil
      if WndMain() != nil .and. WndMain():ClassName() == "TMDIFRAME"
         DEFINE WINDOW oWnd MDICHILD OF WndMain()
         oWebView := TEdge():New( oWnd )
         WebViewSetSource( cHtml, oWebView, .t. )
         ACTIVATE WINDOW oWnd
         return oWebView
      else
         DEFINE DIALOG oWnd TRUEPIXEL
         oWnd:lModal := Empty( WndMain() )
         oWnd:bInit := <||
         oWebView := TEdge():New( oWnd )
         WebViewSetSource( cHtml, oWebView, .t. )
         return nil
         >
         ACTIVATE DIALOG oWnd CENTERED
         return oWebView
      endif
   elseif oWnd:IsKindOf( "TWEBVIEW2" )
      oWebView := oWnd
      WebViewSetSource( cHtml, oWebView )
      return oWebView
   endif

   oWebView := TEdge():New( oWnd )
   WebViewSetSource( cHtml, oWebView, .t. )

return oWebView

//----------------------------------------------------------------------------//

static function WebViewSetSource( cSrc, oWeb, lNew )

   local o, w, h, cTitle := "WEB VIEW"
   local lText

   if Empty( cSrc )
      return nil
   endif

   if !( lText := ( "<html>" $ Lower( Left( cSrc, 200 ) ) ) )
      if Len( cSrc ) < 300 .and. File( cSrc )
         cSrc    := TrueName( cSrc )
         cTitle   := cSrc
         if IsImageExt( cSrc )
            cSrc := ( o := TImageBase64():New( cSrc ) ):MakeText( .t., .t., .t., cSrc )
            w     := o:nImgWidth  + 60
            h     := o:nImgHeight + 90
            lText := .t.
         endif
      else
         cTitle   := cSrc
      endif
   endif

   WITH OBJECT oWeb
   if lText
      :SetHTML( cSrc )
   else
      :Navigate( cSrc )
   endif
   DEFAULT lNew := .f.
   if oWeb:oWnd:ClassName() == "TDIALOG"
      :SetTitle( cTitle )
      DEFAULT w := ScreenWidth() * 0.8
      DEFAULT h := ScreenHeight() * 0.8
      :SetSize( w, h )
      :oWnd:SetSize( w, h )
      :center()
      if !lNew
         :oWnd:GoTop()
      endif
   endif
   END

   if lNew
      SetWebWndValid( oWeb )
   endif

return nil

static function SetWebWndValid( oWeb )

   local oWnd     := oWeb:oWnd
   local bValid   := { || oWeb:End(), .t. }

   if oWnd:IsKindOf( "TCONTROL" )
      oWnd  := oWnd:oWnd
   endif

   if oWnd:IsKindOf( "TMDICHILD" )
      oWnd:bPostEnd  := bValid
   else
      oWnd:bValid    := bValid
   endif

return nil

edge.c

/*
 * edge.c - Harbour HB_FUNC entry points for the TEdge package.
 * The COM engine and callable bodies live in cedge.c / edge.lib.
 */

#include "edge.h"

HB_FUNC( EDGE_NEW )
{
   edge_hb_edge_new();
}

HB_FUNC( EDGE_NAVIGATE )
{
   edge_hb_edge_navigate();
}

HB_FUNC( EDGE_SETHTML )
{
   edge_hb_edge_sethtml();
}

HB_FUNC( EDGE_EVAL )
{
   edge_hb_edge_eval();
}

HB_FUNC( EDGE_SETSIZE )
{
   edge_hb_edge_setsize();
}

HB_FUNC( EDGE_SETUSERAGENT )
{
   edge_hb_edge_setuseragent();
}

HB_FUNC( EDGE_OPENDEVTOOLSWINDOW )
{
   edge_hb_edge_opendevtoolswindow();
}

HB_FUNC( EDGE_SHOWDOWNLOADS )
{
   edge_hb_edge_showdownloads();
}

HB_FUNC( EDGE_ENABLECONSOLE )
{
   edge_hb_edge_enableconsole();
}

HB_FUNC( EDGE_GOBACK )
{
   edge_hb_edge_goback();
}

HB_FUNC( EDGE_GOFORWARD )
{
   edge_hb_edge_goforward();
}

HB_FUNC( EDGE_RELOAD )
{
   edge_hb_edge_reload();
}

HB_FUNC( EDGE_STOP )
{
   edge_hb_edge_stop();
}

HB_FUNC( EDGE_CANGOBACK )
{
   edge_hb_edge_cangoback();
}

HB_FUNC( EDGE_CANGOFORWARD )
{
   edge_hb_edge_cangoforward();
}

HB_FUNC( EDGE_GETSOURCE )
{
   edge_hb_edge_getsource();
}

HB_FUNC( EDGE_GETDOCUMENTTITLE )
{
   edge_hb_edge_getdocumenttitle();
}

HB_FUNC( EDGE_CAPTUREPREVIEW )
{
   edge_hb_edge_capturepreview();
}

HB_FUNC( EDGE_PRINTTOPDF )
{
   edge_hb_edge_printtopdf();
}

HB_FUNC( EDGE_PRINTTOPDFEX )
{
   edge_hb_edge_printtopdfex();
}

HB_FUNC( EDGE_ADDWEBRESOURCEREQUESTEDFILTER )
{
   edge_hb_edge_addwebresourcerequestedfilter();
}

HB_FUNC( EDGE_REMOVEWEBRESOURCEREQUESTEDFILTER )
{
   edge_hb_edge_removewebresourcerequestedfilter();
}

HB_FUNC( EDGE_ADDHOSTOBJECT )
{
   edge_hb_edge_addhostobject();
}

HB_FUNC( EDGE_REMOVEHOSTOBJECT )
{
   edge_hb_edge_removehostobject();
}

HB_FUNC( EDGE_PRINT )
{
   edge_hb_edge_print();
}

HB_FUNC( EDGE_CLEARBROWSINGDATA )
{
   edge_hb_edge_clearbrowsingdata();
}

HB_FUNC( EDGE_CLEARSESSION )
{
   edge_hb_edge_clearsession();
}

HB_FUNC( EDGE_SETCONTEXTMENUEXCLUDE )
{
   edge_hb_edge_setcontextmenuexclude();
}

HB_FUNC( EDGE_SETDEFAULTCONTEXTMENUS )
{
   edge_hb_edge_setdefaultcontextmenus();
}

HB_FUNC( EDGE_END )
{
   edge_hb_edge_end();
}

HB_FUNC( EDGE_SETZOOMFACTOR )
{
   edge_hb_edge_setzoomfactor();
}

HB_FUNC( EDGE_GETZOOMFACTOR )
{
   edge_hb_edge_getzoomfactor();
}

HB_FUNC( EDGE_SETSIZERATIO )
{
   edge_hb_edge_setsizeratio();
}

HB_FUNC( EDGE_GETSIZERATIO )
{
   edge_hb_edge_getsizeratio();
}

HB_FUNC( EDGE_NAVIGATEEX )
{
   edge_hb_edge_navigateex();
}

HB_FUNC( EDGE_GETBROWSERVERSION )
{
   edge_hb_edge_getbrowserversion();
}

HB_FUNC( EDGE_CLOSEWEBVIEW )
{
   edge_hb_edge_closewebview();
}

HB_FUNC( EDGE_REINITIALIZE )
{
   edge_hb_edge_reinitialize();
}

HB_FUNC( EDGE_SETDEFAULTSCRIPTDIALOGS )
{
   edge_hb_edge_setdefaultscriptdialogs();
}

HB_FUNC( EDGE_SETMARGINS )
{
   edge_hb_edge_setmargins();
}

HB_FUNC( EDGE_RESIZE )
{
   edge_hb_edge_resize();
}

HB_FUNC( EDGE_WV2_READY )
{
   edge_hb_edge_wv2_ready();
}

HB_FUNC( EDGE_WV2_CREATE )
{
   edge_hb_edge_wv2_create();
}

HB_FUNC( EDGE_WV2_NAVIGATE )
{
   edge_hb_edge_wv2_navigate();
}

HB_FUNC( EDGE_WV2_END )
{
   edge_hb_edge_wv2_end();
}

HB_FUNC( EDGE_URLENCODE )
{
   edge_hb_edge_urlencode();
}

HB_FUNC( EDGE_URLDECODE )
{
   edge_hb_edge_urldecode();
}

HB_FUNC( EDGE_SETSERIAL )
{
   /* TEdge:SetSerial / edge_SetSerial → cedge edge_hb_edge_setserial */
   edge_hb_edge_setserial();
}

HB_FUNC( EDGE_LICENSEOWNER )
{
   /* Forensic / about: who this edge.lib was built for */
   edge_hb_edge_licenseowner();
}

For more information, please refer to the following link: https://www4.zzz.com.tw/phpBB3/viewtopic.php?f=2&t=377

line ID: ssbbstw

WeChat ID: ssbbstw
Posts: 44508
Joined: Thu Oct 06, 2005 05:47 PM

Re: Class TEdge v1

Posted: Fri Sep 11, 2026 08:58 AM

Dear Wen,

We do appreciate your research and contribution (though it seems as a commercial and closed one).

You know that these days, using AI, we can ask it to enhance and extend Class TWebView2 functionality and provide the same functionality as you are offering. In our case it will be open and free for FWH users.

So if users are interested, we will include your announced features in FWH Class TWebView2.

Thank you for your understanding

regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 139
Joined: Mon Oct 17, 2005 03:03 AM

Re: Class TEdge v1

Posted: Fri Sep 11, 2026 10:24 AM

Dear Antonio,

Thank you for your feedback. I completely agree that AI is a fantastic tool for extending features, and having a free, open-source TWebView2 with these capabilities will be a great win for the FWH community!

My goal with TEdge was to provide a ready-to-use, battle-tested solution today. While AI can certainly generate API wrappers, implementing this via C89 raw COM without relying on the WebView2 SDK, and resolving specific edge cases like CJK IME input (compositionend) and memory management, required significant real-world testing.

I fully support the community having multiple choices. TEdge is simply an option for developers who need a packaged, highly optimized, and supported solution right now. I look forward to seeing how TWebView2 evolves!

Best regards, Wen.

line ID: ssbbstw

WeChat ID: ssbbstw
Posts: 44508
Joined: Thu Oct 06, 2005 05:47 PM

Re: Class TEdge v1

Posted: Sat Sep 12, 2026 04:28 AM

ES — Novedades de TWebView2 (FWH 26.09)
La clase TWebView2 crece de 10 a más de 40 funciones nativas, manteniendo la nomenclatura FWH (WebView2_*). Todo lo anterior sigue funcionando igual.
Navegación e info (nuevos métodos)

  • NavigateEx( cUrl, cMethod, cHeaders, cBody ) — GET/POST con cabeceras y cuerpo.
  • GoBack(), GoForward(), Reload(), Stop(), CanGoBack(), CanGoForward().
  • GetSource(), GetDocumentTitle(), GetBrowserVersion() (lee el Runtime instalado).
  • Print() (vía window.print()).
    Zoom y diálogos
  • SetZoomFactor() / GetZoomFactor() + evento bOnZoomFactorChanged.
  • SetDefaultScriptDialogs() + bOnScriptDialog (Aceptar con .T.).
    Ficheros: captura y PDF (asíncronos, con callback)
  • CapturePreview( cPng ) → bOnCapturePreview( lOk, cPath ).
  • PrintToPdf( cPdf, lLandscape ) → bOnPrintToPdf( lOk, cPath ).
    Red y privacidad
  • Add/RemoveWebResourceRequestedFilter() + bOnWebResource (devolver .T. bloquea con 403 vacío).
  • ClearSession() / ClearBrowsingData() (nivel JS) + bOnClearBrowsingData.
  • SetDefaultContextMenus() + SetContextMenuExclude().
    Eventos nuevos (todos bOn)
    bOnNavigationStarting (cancelable), bOnSourceChanged, bOnHistoryChanged, bOnDocumentTitleChanged, bOnNewWindow, bOnPermission (allow/deny), bOnFullScreen, bOnProcessFailed, bOnFrameNavStarting/Completed, bOnConsole (nuevo: EnableConsole() intercepta console.
    vía JS).
    Ciclo de vida y utilidades
  • CloseWebView(), Reinitialize(), SetSizeRatio()/GetSizeRatio().
  • End() ahora se da de baja del registro interno (antes fugaba).
  • Carpeta de datos por defecto %LOCALAPPDATA%\FWH_webview2_UserData (se crea sola).
  • Nuevo include/WebView2.ch con constantes (WV_CONTEXT, WV_DIALOG, WV_PERM, WV_FAIL).
  • Diagnóstico: Diag() (HResults + contadores) y Reregister().
  • Ejemplo nuevo samples/webview2/ con página pulse.html separada y modo AUTO desatendido.
    Límites conocidos: AddHostObject() sin implementar (requiere IDispatch); el filtrado fino del menú contextual y el borrado total del perfil exigen un SDK WebView2 más nuevo.
    EN — TWebView2 improvements (FWH 26.09)
    TWebView2 grows from 10 to 40+ natives, keeping FWH naming (WebView2_*). Fully backward compatible.
    Navigation & info (new): NavigateEx( cUrl, cMethod, cHeaders, cBody ); GoBack/GoForward/Reload/Stop; CanGoBack/CanGoForward; GetSource/GetDocumentTitle/GetBrowserVersion; Print().
    Zoom & dialogs: SetZoomFactor/GetZoomFactor + bOnZoomFactorChanged; SetDefaultScriptDialogs + bOnScriptDialog (.T. = Accept).
    Files (async + callback): CapturePreview( cPng ) → bOnCapturePreview; PrintToPdf( cPdf, lLandscape ) → bOnPrintToPdf.
    Network & privacy: Add/RemoveWebResourceRequestedFilter + bOnWebResource (.T. blocks with empty 403); ClearSession/ClearBrowsingData (JS level) + ack; SetDefaultContextMenus/SetContextMenuExclude.
    New events: cancelable bOnNavigationStarting, bOnSourceChanged/HistoryChanged/DocumentTitleChanged/NewWindow, bOnPermission (allow/deny), bOnFullScreen/ProcessFailed/FrameNavStarting/FrameNavCompleted, bOnConsole via EnableConsole().
    Lifecycle & utils: CloseWebView/Reinitialize/SetSizeRatio; fixed End() registry leak; default %LOCALAPPDATA%\FWH_webview2_UserData; new include/WebView2.ch; Diag()/Reregister() diagnostics; new samples/webview2/ demo (external pulse.html, unattended AUTO mode).
    Known limits: AddHostObject() unimplemented (needs IDispatch); per-item menu filtering and full-profile wipe need a newer WebView2 SDK.
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 44508
Joined: Thu Oct 06, 2005 05:47 PM

Re: Class TEdge v1

Posted: Sat Sep 12, 2026 04:30 AM

===========

September 2026

  • Enhanced: TWebView2 (source\classes\twebview2.prg, source\internal\twebview\cwebview.cpp,
    source\winapi\webview2.c, include\WebView2.ch) grows from 10 to 40+ natives.
    New methods: NavigateEx( cUrl, cMethod, cHeaders, cBody ) (native POST),
    GoBack/GoForward/Reload/Stop, CanGoBack/CanGoForward, GetSource,
    GetDocumentTitle, GetBrowserVersion, Print, SetZoomFactor/GetZoomFactor,
    SetDefaultScriptDialogs, SetDefaultContextMenus/SetContextMenuExclude,
    CapturePreview (async PNG) / PrintToPdf (async PDF), Add/RemoveWebResourceRequestedFilter
    (block with .T.), ClearSession/ClearBrowsingData, EnableConsole (console.* interception),
    CloseWebView, Reinitialize, SetSizeRatio, Diag/Reregister diagnostics.
    New bOn* events: NavigationStarting (cancelable), SourceChanged, HistoryChanged,
    DocumentTitleChanged, NewWindow, Permission (allow/deny), FullScreen, ProcessFailed,
    FrameNavStarting/Completed, Console. Fixed End() registry leak. Default user data
    folder %LOCALAPPDATA%\FWH_webview2_UserData. New sample samples\webview2\
    (external pulse.html, unattended AUTO mode). Fully backward compatible.
    Known limits: AddHostObject() needs IDispatch; per-item menu filtering and
    full-profile wipe need a newer WebView2 SDK.
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 139
Joined: Mon Oct 17, 2005 03:03 AM

Re: Class TEdge v1

Posted: Sat Sep 12, 2026 11:17 AM

If you ever need someone to test Chinese character support, feel free to count me in! I noticed that in the current TWebView2, if we run :Eval( jscode ) and the jscode contains Chinese characters, the execution fails.

line ID: ssbbstw

WeChat ID: ssbbstw
Posts: 139
Joined: Mon Oct 17, 2005 03:03 AM

Re: Class TEdge v1

Posted: Thu Sep 17, 2026 08:20 AM

Hello everyone,
I am giving away free lifetime license keys to forum members!
Please note that this giveaway is only valid for the next 30 days, and the offer will not be available after the deadline.
If you are interested, please send me an email with the following details:

Email :
Name :

Looking forward to hearing from you!
mailto: wen.ssbbs@gmail.com

line ID: ssbbstw

WeChat ID: ssbbstw

Continue the discussion