From 161b2e31871c2edff208e3c307dc41f590612560 Mon Sep 17 00:00:00 2001 From: salvadordf Date: Wed, 7 Feb 2024 12:32:52 +0100 Subject: [PATCH] Added the JSExtensionSubProcess demo --- .../JSExtensionSubProcess/00-DeleteDCUs.bat | 18 + .../JSExtensionSubProcess/JSExtension.dpr | 40 + .../JSExtensionSubProcess/JSExtension.dproj | 1180 +++++++++++++++++ .../JSExtensionSubProcessGroup.groupproj | 48 + .../JSExtensionSubProcess/JSExtension_sp.dpr | 18 + .../JSExtension_sp.dproj | 1121 ++++++++++++++++ .../JSExtensionSubProcess/uJSExtension.dfm | 97 ++ .../JSExtensionSubProcess/uJSExtension.pas | 477 +++++++ .../JSExtensionSubProcess/uJSExtension_sp.pas | 197 +++ .../uSimpleTextViewer.dfm | 27 + .../uSimpleTextViewer.pas | 33 + .../uTestExtensionHandler.pas | 75 ++ .../JSExtensionSubProcess/00-Delete.bat | 2 + .../JSExtensionSubProcess/JSExtension.lpi | 100 ++ .../JSExtensionSubProcess/JSExtension.lpr | 32 + .../JSExtensionSubProcess/JSExtension_sp.lpi | 92 ++ .../JSExtensionSubProcess/JSExtension_sp.lpr | 20 + .../JSExtensionSubProcess/uJSExtension.lfm | 86 ++ .../JSExtensionSubProcess/uJSExtension.pas | 496 +++++++ .../uSimpleTextViewer.lfm | 27 + .../uSimpleTextViewer.pas | 33 + .../uTestExtensionHandler.pas | 77 ++ .../JSExtensionSubProcess/ujsextension_sp.pas | 202 +++ update_CEF4Delphi.json | 2 +- 24 files changed, 4499 insertions(+), 1 deletion(-) create mode 100644 demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/00-DeleteDCUs.bat create mode 100644 demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/JSExtension.dpr create mode 100644 demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/JSExtension.dproj create mode 100644 demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/JSExtensionSubProcessGroup.groupproj create mode 100644 demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/JSExtension_sp.dpr create mode 100644 demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/JSExtension_sp.dproj create mode 100644 demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uJSExtension.dfm create mode 100644 demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uJSExtension.pas create mode 100644 demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uJSExtension_sp.pas create mode 100644 demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uSimpleTextViewer.dfm create mode 100644 demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uSimpleTextViewer.pas create mode 100644 demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uTestExtensionHandler.pas create mode 100644 demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/00-Delete.bat create mode 100644 demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/JSExtension.lpi create mode 100644 demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/JSExtension.lpr create mode 100644 demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/JSExtension_sp.lpi create mode 100644 demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/JSExtension_sp.lpr create mode 100644 demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/uJSExtension.lfm create mode 100644 demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/uJSExtension.pas create mode 100644 demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/uSimpleTextViewer.lfm create mode 100644 demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/uSimpleTextViewer.pas create mode 100644 demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/uTestExtensionHandler.pas create mode 100644 demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/ujsextension_sp.pas diff --git a/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/00-DeleteDCUs.bat b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/00-DeleteDCUs.bat new file mode 100644 index 00000000..a9a84095 --- /dev/null +++ b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/00-DeleteDCUs.bat @@ -0,0 +1,18 @@ +del /s /q *.dcu +del /s /q *.exe +del /s /q *.res +del /s /q *.rsm +del /s /q *.log +del /s /q *.dsk +del /s /q *.identcache +del /s /q *.stat +del /s /q *.local +del /s /q *.~* +rmdir Win32\Debug +rmdir Win32\Release +rmdir Win32 +rmdir Win64\Debug +rmdir Win64\Release +rmdir Win64 +rmdir __history +rmdir __recovery diff --git a/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/JSExtension.dpr b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/JSExtension.dpr new file mode 100644 index 00000000..4ba77570 --- /dev/null +++ b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/JSExtension.dpr @@ -0,0 +1,40 @@ +program JSExtension; + +{$I ..\..\..\..\source\cef.inc} + +uses + {$IFDEF DELPHI16_UP} + Vcl.Forms, + {$ELSE} + Forms, + {$ENDIF } + uCEFApplication, + uJSExtension in 'uJSExtension.pas' {JSExtensionFrm}, + uSimpleTextViewer in 'uSimpleTextViewer.pas' {SimpleTextViewerFrm}; + +{$R *.res} + +const + IMAGE_FILE_LARGE_ADDRESS_AWARE = $0020; + +// CEF needs to set the LARGEADDRESSAWARE ($20) flag which allows 32-bit processes to use up to 3GB of RAM. +{$IFDEF WIN32}{$SetPEFlags IMAGE_FILE_LARGE_ADDRESS_AWARE}{$ENDIF} + +begin + // GlobalCEFApp creation and initialization moved to a different unit to fix the memory leak described in the bug #89 + // https://github.com/salvadordf/CEF4Delphi/issues/89 + CreateGlobalCEFApp; + + if GlobalCEFApp.StartMainProcess then + begin + Application.Initialize; + {$IFDEF DELPHI11_UP} + Application.MainFormOnTaskbar := True; + {$ENDIF} + Application.CreateForm(TJSExtensionFrm, JSExtensionFrm); + Application.CreateForm(TSimpleTextViewerFrm, SimpleTextViewerFrm); + Application.Run; + end; + + DestroyGlobalCEFApp; +end. diff --git a/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/JSExtension.dproj b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/JSExtension.dproj new file mode 100644 index 00000000..fa4e4719 --- /dev/null +++ b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/JSExtension.dproj @@ -0,0 +1,1180 @@ + + + {7AA32B92-A408-42CB-A571-383721053FFA} + 20.1 + VCL + JSExtension.dpr + True + Debug + Win32 + 3 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + + + true + Base + true + + + true + Cfg_3 + true + true + + + true + Cfg_3 + true + true + + + 3082 + $(BDS)\bin\delphi_PROJECTICON.ico + JSExtension + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + .\$(Platform)\$(Config) + false + false + false + false + false + ..\..\..\..\bin + ..\..\..\..\source;$(DCC_UnitSearchPath) + + + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;vclactnband;frxe23;vclFireDAC;emsclientfiredac;DataSnapFireDAC;svnui;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;svn;Intraweb;DBXOracleDriver;inetdb;CEF4Delphi;FmxTeeUI;FireDACIBDriver;fmx;fmxdae;vclib;FireDACDBXDriver;dbexpress;IndyProtocols230;vclx;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;frxTee23;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;vcl;DBXSybaseASEDriver;FireDACDb2Driver;GR32_DSGN_RSXE5;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;TeeDB;FireDAC;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;FMXTee;soaprtl;DbxCommonDriver;ibxpress;Tee;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;GR32_RSXE5;bindcomp;appanalytics;DBXInformixDriver;bindcompvcl;frxDB23;TeeUI;IndyCore230;vclribbon;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;IndySystem230;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;frx23;fmxase;$(DCC_UsePackage) + 1033 + $(BDS)\bin\default_app.manifest + CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName) + true + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + + + DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;DataSnapFireDAC;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;Intraweb;DBXOracleDriver;inetdb;FmxTeeUI;FireDACIBDriver;fmx;fmxdae;vclib;FireDACDBXDriver;dbexpress;IndyProtocols230;vclx;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;vcl;DBXSybaseASEDriver;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;TeeDB;FireDAC;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;FMXTee;soaprtl;DbxCommonDriver;ibxpress;Tee;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;bindcompvcl;TeeUI;IndyCore230;vclribbon;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;IndySystem230;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;fmxase;$(DCC_UsePackage) + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + Debug + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + $(BDS)\bin\default_app.manifest + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + true + 1033 + true + false + Debug + CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName) + PerMonitor + + + true + PerMonitorV2 + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + true + Debug + PerMonitor + + + true + PerMonitorV2 + + + DEBUG;INTFLOG;$(DCC_Define) + + + true + true + true + true + 3 + true + true + true + 1033 + CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName) + Debug + + + true + PerMonitorV2 + + + + MainSource + + +
JSExtensionFrm
+
+ +
SimpleTextViewerFrm
+
+ + Base + + + Cfg_1 + Base + + + Cfg_2 + Base + + + Cfg_3 + Base + +
+ + Delphi.Personality.12 + Application + + + + JSExtension.dpr + + + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + + + JSExtension.exe + true + + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + classes + 64 + + + classes + 64 + + + + + res\xml + 1 + + + res\xml + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\armeabi + 1 + + + library\lib\armeabi + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\mips + 1 + + + library\lib\mips + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-anydpi-v21 + 1 + + + res\drawable-anydpi-v21 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-v21 + 1 + + + res\values-v21 + 1 + + + + + res\values-v31 + 1 + + + res\values-v31 + 1 + + + + + res\drawable-anydpi-v26 + 1 + + + res\drawable-anydpi-v26 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-anydpi-v33 + 1 + + + res\drawable-anydpi-v33 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-night-v21 + 1 + + + res\values-night-v21 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-ldpi + 1 + + + res\drawable-ldpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-small + 1 + + + res\drawable-small + 1 + + + + + res\drawable-normal + 1 + + + res\drawable-normal + 1 + + + + + res\drawable-large + 1 + + + res\drawable-large + 1 + + + + + res\drawable-xlarge + 1 + + + res\drawable-xlarge + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\drawable-anydpi-v24 + 1 + + + res\drawable-anydpi-v24 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-night-anydpi-v21 + 1 + + + res\drawable-night-anydpi-v21 + 1 + + + + + res\drawable-anydpi-v31 + 1 + + + res\drawable-anydpi-v31 + 1 + + + + + res\drawable-night-anydpi-v31 + 1 + + + res\drawable-night-anydpi-v31 + 1 + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + Contents\MacOS + 1 + .framework + + + Contents\MacOS + 1 + .framework + + + Contents\MacOS + 1 + .framework + + + 0 + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .dll;.bpl + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .bpl + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + Contents\Resources\StartUp\ + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + ..\ + 1 + + + + + Contents + 1 + + + Contents + 1 + + + Contents + 1 + + + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + Contents\MacOS + 1 + + + Contents\MacOS + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).launchscreen + 64 + + + ..\$(PROJECTNAME).launchscreen + 64 + + + + + 1 + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + + + + + + + + + + + + + True + True + + + 12 + + + + +
diff --git a/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/JSExtensionSubProcessGroup.groupproj b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/JSExtensionSubProcessGroup.groupproj new file mode 100644 index 00000000..59dd20d0 --- /dev/null +++ b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/JSExtensionSubProcessGroup.groupproj @@ -0,0 +1,48 @@ + + + {898EF1FF-A3E5-45E8-9D69-68E86985BB25} + + + + + + + + + + + Default.Personality.12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/JSExtension_sp.dpr b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/JSExtension_sp.dpr new file mode 100644 index 00000000..23919852 --- /dev/null +++ b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/JSExtension_sp.dpr @@ -0,0 +1,18 @@ +program JSExtension_sp; + +uses + uCEFApplicationCore, + uTestExtensionHandler in 'uTestExtensionHandler.pas', + uJSExtension_sp in 'uJSExtension_sp.pas'; + +const + IMAGE_FILE_LARGE_ADDRESS_AWARE = $0020; + +// CEF needs to set the LARGEADDRESSAWARE ($20) flag which allows 32-bit processes to use up to 3GB of RAM. +{$IFDEF WIN32}{$SetPEFlags IMAGE_FILE_LARGE_ADDRESS_AWARE}{$ENDIF} + +begin + CreateGlobalCEFApp; + DestroyGlobalCEFApp; +end. + diff --git a/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/JSExtension_sp.dproj b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/JSExtension_sp.dproj new file mode 100644 index 00000000..b3011ab7 --- /dev/null +++ b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/JSExtension_sp.dproj @@ -0,0 +1,1121 @@ + + + {6ABCF641-08D0-4F35-9D13-2FBD18E5152A} + 20.1 + VCL + JSExtension_sp.dpr + True + Debug + Win32 + 3 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + 3082 + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + $(BDS)\bin\delphi_PROJECTICON.ico + JSExtension_sp + .\$(Platform)\$(Config) + false + false + false + false + false + ..\..\..\..\bin + ..\..\..\..\source;$(DCC_UnitSearchPath) + + + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + true + 1033 + CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName) + $(BDS)\bin\default_app.manifest + DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;vclactnband;frxe23;vclFireDAC;emsclientfiredac;DataSnapFireDAC;svnui;tethering;Componentes;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;svn;Intraweb;DBXOracleDriver;inetdb;Componentes_Int;CEF4Delphi;FmxTeeUI;FireDACIBDriver;fmx;fmxdae;vclib;FireDACDBXDriver;dbexpress;IndyProtocols230;vclx;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;frxTee23;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;vcl;DBXSybaseASEDriver;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;Componentes_UI;TeeDB;FireDAC;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;FMXTee;soaprtl;DbxCommonDriver;Componentes_Misc;ibxpress;Tee;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;Componentes_RTF;DBXInformixDriver;bindcompvcl;frxDB23;Componentes_vCard;TeeUI;IndyCore230;vclribbon;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;IndySystem230;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;frx23;fmxase;$(DCC_UsePackage) + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + + + DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;DataSnapFireDAC;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;Intraweb;DBXOracleDriver;inetdb;FmxTeeUI;FireDACIBDriver;fmx;fmxdae;vclib;FireDACDBXDriver;dbexpress;IndyProtocols230;vclx;dsnap;DataSnapCommon;emsclient;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonDriver;DataSnapClient;inet;bindcompdbx;vcl;DBXSybaseASEDriver;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;TeeDB;FireDAC;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;FMXTee;soaprtl;DbxCommonDriver;ibxpress;Tee;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;bindcompvcl;TeeUI;IndyCore230;vclribbon;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;IndySystem230;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;fmxase;$(DCC_UsePackage) + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + Debug + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + true + 1033 + true + false + CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName) + PerMonitor + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + true + Debug + true + 1033 + CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName) + PerMonitor + + + + MainSource + + + + + Base + + + Cfg_1 + Base + + + Cfg_2 + Base + + + + Delphi.Personality.12 + Application + + + + JSExtension_sp.dpr + + + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + + + JSExtension_sp.exe + true + + + + + JSExtension_sp.exe + true + + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + classes + 64 + + + classes + 64 + + + + + res\xml + 1 + + + res\xml + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\armeabi + 1 + + + library\lib\armeabi + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\mips + 1 + + + library\lib\mips + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-anydpi-v21 + 1 + + + res\drawable-anydpi-v21 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-v21 + 1 + + + res\values-v21 + 1 + + + + + res\values-v31 + 1 + + + res\values-v31 + 1 + + + + + res\drawable-anydpi-v26 + 1 + + + res\drawable-anydpi-v26 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-anydpi-v33 + 1 + + + res\drawable-anydpi-v33 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-night-v21 + 1 + + + res\values-night-v21 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-ldpi + 1 + + + res\drawable-ldpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-small + 1 + + + res\drawable-small + 1 + + + + + res\drawable-normal + 1 + + + res\drawable-normal + 1 + + + + + res\drawable-large + 1 + + + res\drawable-large + 1 + + + + + res\drawable-xlarge + 1 + + + res\drawable-xlarge + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\drawable-anydpi-v24 + 1 + + + res\drawable-anydpi-v24 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-night-anydpi-v21 + 1 + + + res\drawable-night-anydpi-v21 + 1 + + + + + res\drawable-anydpi-v31 + 1 + + + res\drawable-anydpi-v31 + 1 + + + + + res\drawable-night-anydpi-v31 + 1 + + + res\drawable-night-anydpi-v31 + 1 + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + Contents\MacOS + 1 + .framework + + + Contents\MacOS + 1 + .framework + + + Contents\MacOS + 1 + .framework + + + 0 + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .dll;.bpl + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .bpl + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + Contents\Resources\StartUp\ + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + ..\ + 1 + + + + + Contents + 1 + + + Contents + 1 + + + Contents + 1 + + + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + Contents\MacOS + 1 + + + Contents\MacOS + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).launchscreen + 64 + + + ..\$(PROJECTNAME).launchscreen + 64 + + + + + 1 + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + + + + + + + + + + + + + True + True + + + 12 + + + + + diff --git a/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uJSExtension.dfm b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uJSExtension.dfm new file mode 100644 index 00000000..4a66e6db --- /dev/null +++ b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uJSExtension.dfm @@ -0,0 +1,97 @@ +object JSExtensionFrm: TJSExtensionFrm + Left = 0 + Top = 0 + Caption = 'JSExtension' + ClientHeight = 589 + ClientWidth = 978 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + Position = poScreenCenter + OnCloseQuery = FormCloseQuery + OnCreate = FormCreate + OnShow = FormShow + TextHeight = 13 + object NavControlPnl: TPanel + Left = 0 + Top = 0 + Width = 978 + Height = 30 + Align = alTop + BevelOuter = bvNone + Enabled = False + Padding.Left = 5 + Padding.Top = 5 + Padding.Right = 5 + Padding.Bottom = 5 + TabOrder = 0 + ExplicitWidth = 974 + object Edit1: TEdit + Left = 5 + Top = 5 + Width = 937 + Height = 20 + Margins.Right = 5 + Align = alClient + TabOrder = 0 + Text = 'http://www.google.com' + ExplicitWidth = 933 + ExplicitHeight = 21 + end + object GoBtn: TButton + Left = 942 + Top = 5 + Width = 31 + Height = 20 + Margins.Left = 5 + Align = alRight + Caption = 'Go' + TabOrder = 1 + OnClick = GoBtnClick + ExplicitLeft = 938 + end + end + object StatusBar1: TStatusBar + Left = 0 + Top = 570 + Width = 978 + Height = 19 + Panels = < + item + Width = 50 + end> + ExplicitTop = 569 + ExplicitWidth = 974 + end + object CEFWindowParent1: TCEFWindowParent + Left = 0 + Top = 30 + Width = 978 + Height = 540 + Align = alClient + TabOrder = 2 + ExplicitWidth = 974 + ExplicitHeight = 539 + end + object Chromium1: TChromium + OnProcessMessageReceived = Chromium1ProcessMessageReceived + OnBeforeContextMenu = Chromium1BeforeContextMenu + OnContextMenuCommand = Chromium1ContextMenuCommand + OnBeforePopup = Chromium1BeforePopup + OnAfterCreated = Chromium1AfterCreated + OnBeforeClose = Chromium1BeforeClose + OnClose = Chromium1Close + Left = 32 + Top = 224 + end + object Timer1: TTimer + Enabled = False + Interval = 300 + OnTimer = Timer1Timer + Left = 32 + Top = 288 + end +end diff --git a/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uJSExtension.pas b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uJSExtension.pas new file mode 100644 index 00000000..376ce7c3 --- /dev/null +++ b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uJSExtension.pas @@ -0,0 +1,477 @@ +unit uJSExtension; + +{$I ..\..\..\..\source\cef.inc} + +interface + +uses + {$IFDEF DELPHI16_UP} + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.ComCtrls, + {$ELSE} + Windows, Messages, SysUtils, Variants, Classes, Graphics, + Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ComCtrls, + {$ENDIF} + uCEFChromium, uCEFWindowParent, uCEFInterfaces, uCEFApplication, uCEFTypes, uCEFConstants, + uCEFWinControl, uCEFChromiumCore; + +const + MINIBROWSER_SHOWTEXTVIEWER = WM_APP + $100; + + MINIBROWSER_CONTEXTMENU_SETJSEVENT = MENU_ID_USER_FIRST + 1; + MINIBROWSER_CONTEXTMENU_JSVISITDOM = MENU_ID_USER_FIRST + 2; + MINIBROWSER_CONTEXTMENU_SHOWDEVTOOLS = MENU_ID_USER_FIRST + 3; + MINIBROWSER_CONTEXTMENU_OFFLINE = MENU_ID_USER_FIRST + 4; + + MOUSEOVER_MESSAGE_NAME = 'mouseover'; + CUSTOMNAME_MESSAGE_NAME = 'customname'; + +type + TJSExtensionFrm = class(TForm) + NavControlPnl: TPanel; + Edit1: TEdit; + GoBtn: TButton; + StatusBar1: TStatusBar; + CEFWindowParent1: TCEFWindowParent; + Chromium1: TChromium; + Timer1: TTimer; + + procedure FormShow(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); + + procedure Timer1Timer(Sender: TObject); + procedure GoBtnClick(Sender: TObject); + + procedure Chromium1BeforeContextMenu(Sender: TObject; const browser: ICefBrowser; const frame: ICefFrame; const params: ICefContextMenuParams; const model: ICefMenuModel); + procedure Chromium1ProcessMessageReceived(Sender: TObject; const browser: ICefBrowser; const frame: ICefFrame; sourceProcess: TCefProcessId; const message: ICefProcessMessage; out Result: Boolean); + procedure Chromium1AfterCreated(Sender: TObject; const browser: ICefBrowser); + procedure Chromium1BeforePopup(Sender: TObject; const browser: ICefBrowser; const frame: ICefFrame; const targetUrl, targetFrameName: ustring; targetDisposition: TCefWindowOpenDisposition; userGesture: Boolean; const popupFeatures: TCefPopupFeatures; var windowInfo: TCefWindowInfo; var client: ICefClient; var settings: TCefBrowserSettings; var extra_info: ICefDictionaryValue; var noJavascriptAccess: Boolean; var Result: Boolean); + procedure Chromium1Close(Sender: TObject; const browser: ICefBrowser; var aAction : TCefCloseBrowserAction); + procedure Chromium1BeforeClose(Sender: TObject; const browser: ICefBrowser); + procedure Chromium1ContextMenuCommand(Sender: TObject; + const browser: ICefBrowser; const frame: ICefFrame; + const params: ICefContextMenuParams; commandId: Integer; + eventFlags: Cardinal; out Result: Boolean); + + protected + FText : string; + // Variables to control when can we destroy the form safely + FCanClose : boolean; // Set to True in TChromium.OnBeforeClose + FClosing : boolean; // Set to True in the CloseQuery event. + + FOffline : boolean; + + procedure BrowserCreatedMsg(var aMessage : TMessage); message CEF_AFTERCREATED; + procedure BrowserDestroyMsg(var aMessage : TMessage); message CEF_DESTROY; + procedure ShowTextViewerMsg(var aMessage : TMessage); message MINIBROWSER_SHOWTEXTVIEWER; + procedure WMMove(var aMessage : TWMMove); message WM_MOVE; + procedure WMMoving(var aMessage : TMessage); message WM_MOVING; + procedure WMEnterMenuLoop(var aMessage: TMessage); message WM_ENTERMENULOOP; + procedure WMExitMenuLoop(var aMessage: TMessage); message WM_EXITMENULOOP; + + function SwitchOfflineMode : integer; + end; + +var + JSExtensionFrm: TJSExtensionFrm; + +procedure CreateGlobalCEFApp; + +implementation + +{$R *.dfm} + +uses + uSimpleTextViewer, uCEFMiscFunctions, uTestExtensionHandler, uCEFDictionaryValue; + +// BASIC CONCEPTS +// ============== + +// Chromium uses several processes to carry out all the tasks needed to handle a web page : +// 1. The main application process is called "BROWSER PROCESS" and it runs the UI. +// 2. The layout and interpretation of HTML is done in the "RENDERER PROCESS". + +// Read this for more details about Chromium's architecture : +// http://www.chromium.org/developers/design-documents/multi-process-architecture + +// Each process is isolated from the rest and you need to use some kind of inter-process +// communication (IPC) to send information between them. This isolation and protection is +// guaranteed by the operating system and it's the main reason Chromium uses several processes. + +// In many cases, you need to use JavaScript or visit the DOM to return some results to Delphi. +// The DOM and JavaScript live in the RENDERER PROCESS, while the Delphi code of your application +// lives in the BROWSER PROCESS. + +// As commented before, the operating system isolates each process and this means that you +// can't access anything declared in one process like variables, fields, classes, controls, etc. +// from a different process. + +// However, CEF has several ways to send information between processes and you can also use your +// own inter-process communication methods. + +// If you need to execute some JavaScript code all you need is to call TChromium.ExecuteJavaScript +// from your application's code in the BROWSER PROCESS and CEF will take care of executing that +// code in the RENDERER PROCESS. + +// If you need to send a message to the RENDERER PROCESS from the BROWSER PROCESS you can use +// TChromium.SendProcessMessage. + +// To send messages to the BROWSER PROCESS from the RENDERER PROCESS you can use +// ICefFrame.SendProcessMessage + + +// -------------- TChromium.SendProcessMessage -------------- +// | | ------------------------------> | | +// | BROWSER | | RENDERER | +// | | | | +// | PROCESS | ICefFrame.SendProcessMessage | PROCESS | +// | | <------------------------------ | | +// -------------- -------------- + + +// To receive the messages sent from the RENDERER PROCESS you need to use the +// TChromium.OnProcessMessageReceived event. This event is executed in a CEF thread that belongs +// to the BROWSER PROCESS. + +// To receive the messages sent from the BROWSER PROCESS you need to use the +// TCefApplication.OnProcessMessageReceived event (GlobalCEFApp.OnProcessMessageReceived). +// This event is executed in a CEF thread that belongs to the RENDERER PROCESS. + + +// JAVASCRIPT EXTENSIONS +// ===================== + +// CEF exposes a large number of JS features for integration in client applications. +// You can use JS types, arrays, functions, extensions, objects, etc. + +// All of those features are described in detail here : +// https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md + +// One of the most interesting JS features available in CEF are the JavaScript extensions because they +// can be used to execute custom Delphi code from JavaScript. + +// If you put all you know so far together you can get any result or information in Delphi from +// JavaScript following these steps : +// 1. Use TChromium.ExecuteJavaScript to execute your custom JavaScript code. +// 2. That custom JavaScript code is executed in the RENDERER PROCESS and it can call functions in your +// custom JavaScript extension, which executes Delphi code. This Delphi code is also executed in +// the RENDERER PROCESS. +// 3. The Delphi code in the JavaScript extension can use ICefFrame.SendProcessMessage to send +// information back to the BROWSER PROCESS. +// 4. The BROWSER PROCESS receives the information in the TChromium.OnProcessMessageReceived event. + +// To create a JavaScript extension in CEF you have to create a new class that inherits from +// TCefv8HandlerOwn and it has to override the "execute" function. Open uTestExtensionHandler.pas +// to see an example and read this for more details about the "execute" parameters : +// https://magpcss.org/ceforum/apidocs3/projects/(default)/CefV8Handler.html + +// In order to use that extension, you must register it in the GlobalCEFApp.OnWebKitInitialized event +// as you can see in the GlobalCEFApp_OnWebKitInitialized procedure on this PAS unit. + +// You have to call the CefRegisterExtension function with 3 parameters : +// 1. name : The extension name. +// 2. code : Any valid JS code but in this case it includes 2 "native function" forward declarations. +// 3. Handler : An instance of your TCefv8HandlerOwn subclass. + +// Notice that the code used with the CefRegisterExtension function in this demo is declaring +// "myextension.mouseover" as a function that calls the "mouseover" native function, and the +// "myextension.sendresulttobrowser" function that calls the "sendresulttobrowser" native function. + +// The "execute" function in the custom TCefv8HandlerOwn subclass will compare the "name" parameter +// with the name of the of the native function used in the code that registered this extension. +// As you can see in this demo, TTestExtensionHandler.Execute compares the "name" parameter with +// "mouseover" and "sendresulttobrowser" to execute the code you want for each of those custom functions. + +// TTestExtensionHandler.Execute is executed in the RENDERER PROCESS and it uses a process message +// to send some results to he BROWSER PROCESS. +// It uses TCefv8ContextRef.Current.Browser.MainFrame to call the SendProcessMessage procedure for +// the main frame. + +// The message is a TCefProcessMessageRef instance and you can set the information you want to send using +// its ArgumentList property. + +// You can add several items to ArgumentList using different indexes in the SetString, SetInt, SetBool, +// SetBinary, etc. functions. +// There is a size limit in the binary parameters of only a few kilobytes. Compress the binary data, use +// alternative IPC methods or use a database protected by a mutex if necessary. + +// For more information about this, read the following pages : +// https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md#markdown-header-functions-and-extensions +// https://bitbucket.org/chromiumembedded/cef/src/b6b033a52bb3f7059d169a4c8389966c8fe2531b/include/capi/cef_v8_capi.h#lines-924 + + +// TESTING THIS DEMO : +// =================== +// 1. Run the demo and wait until google.com is loaded +// 2. Right-click and select the "Set the mouseover event" menu option. +// 3. Move the mouse pointer over the web page and see the HTML elements in the status bar. + +// When you select the "Set the mouseover event" menu option, the +// TChromium.OnContextMenuCommand event is triggered and it adds an event listener to the +// document's body. That listener calls one of the functions available in the registered +// extension called "myextension.mouseover". + +// The TTestExtensionHandler.Execute function in the extension is executed and it +// uses TCefv8ContextRef.Current.Browser.MainFrame.SendProcessMessage(PID_BROWSER, msg) +// to send a process message with the results to the browser process. + +// That message is received in the TChromium.OnProcessMessageReceived event and it shows +// the information in the status bar. + +// If you have to debug the code executed by the extension you will need to use the +// debugging methods described in +// https://www.briskbard.com/index.php?lang=en&pageid=cef + + +// DESTRUCTION STEPS +// ================= +// 1. FormCloseQuery sets CanClose to FALSE calls TChromium.CloseBrowser which triggers +// the TChromium.OnClose event. +// 2. TChromium.OnClose sends a CEFBROWSER_DESTROY message to destroy CEFWindowParent1 +// in the main thread, which triggers the TChromium.OnBeforeClose event. +// 3. TChromium.OnBeforeClose sets FCanClose := True and sends WM_CLOSE to the form. + + +procedure CreateGlobalCEFApp; +begin + GlobalCEFApp := TCefApplication.Create; + GlobalCEFApp.BrowserSubprocessPath := 'JSExtension_sp.exe'; + {$IFDEF DEBUG} + GlobalCEFApp.LogFile := 'debug.log'; + GlobalCEFApp.LogSeverity := LOGSEVERITY_INFO; + {$ENDIF} +end; + +procedure TJSExtensionFrm.GoBtnClick(Sender: TObject); +begin + Chromium1.LoadURL(Edit1.Text); +end; + +procedure TJSExtensionFrm.Chromium1AfterCreated(Sender: TObject; const browser: ICefBrowser); +begin + PostMessage(Handle, CEF_AFTERCREATED, 0, 0); +end; + +procedure TJSExtensionFrm.Chromium1BeforeClose(Sender: TObject; const browser: ICefBrowser); +begin + FCanClose := True; + PostMessage(Handle, WM_CLOSE, 0, 0); +end; + +procedure TJSExtensionFrm.Chromium1BeforeContextMenu(Sender: TObject; + const browser: ICefBrowser; const frame: ICefFrame; + const params: ICefContextMenuParams; const model: ICefMenuModel); +begin + // Adding some custom context menu entries + model.AddSeparator; + model.AddItem(MINIBROWSER_CONTEXTMENU_SETJSEVENT, 'Set mouseover event'); + model.AddItem(MINIBROWSER_CONTEXTMENU_JSVISITDOM, 'Visit DOM in JavaScript'); + model.AddItem(MINIBROWSER_CONTEXTMENU_SHOWDEVTOOLS, 'Show DevTools'); + model.AddCheckItem(MINIBROWSER_CONTEXTMENU_OFFLINE, 'Offline'); + model.SetChecked(MINIBROWSER_CONTEXTMENU_OFFLINE, FOffline); +end; + +procedure TJSExtensionFrm.Chromium1BeforePopup(Sender: TObject; + const browser: ICefBrowser; const frame: ICefFrame; const targetUrl, + targetFrameName: ustring; targetDisposition: TCefWindowOpenDisposition; + userGesture: Boolean; const popupFeatures: TCefPopupFeatures; + var windowInfo: TCefWindowInfo; var client: ICefClient; + var settings: TCefBrowserSettings; var extra_info: ICefDictionaryValue; var noJavascriptAccess: Boolean; + var Result: Boolean); +begin + // For simplicity, this demo blocks all popup windows and new tabs + Result := (targetDisposition in [CEF_WOD_NEW_FOREGROUND_TAB, CEF_WOD_NEW_BACKGROUND_TAB, CEF_WOD_NEW_POPUP, CEF_WOD_NEW_WINDOW]); +end; + +procedure TJSExtensionFrm.Chromium1Close(Sender: TObject; + const browser: ICefBrowser; var aAction : TCefCloseBrowserAction); +begin + PostMessage(Handle, CEF_DESTROY, 0, 0); + aAction := cbaDelay; +end; + +procedure TJSExtensionFrm.Chromium1ContextMenuCommand(Sender: TObject; + const browser: ICefBrowser; const frame: ICefFrame; + const params: ICefContextMenuParams; commandId: Integer; + eventFlags: Cardinal; out Result: Boolean); +var + TempPoint : TPoint; + TempJSCode : string; +begin + Result := False; + + // Here is the code executed for each custom context menu entry + + case commandId of + MINIBROWSER_CONTEXTMENU_SETJSEVENT : + if (frame <> nil) and frame.IsValid then + begin + TempJSCode := 'document.body.addEventListener("mouseover", function(evt){'+ + 'function getpath(n){'+ + 'var ret = "<" + n.nodeName + ">";'+ + 'if (n.parentNode){return getpath(n.parentNode) + ret} else '+ + 'return ret'+ + '};'+ + 'myextension.mouseover(getpath(evt.target))}'+ + ')'; + + frame.ExecuteJavaScript(TempJSCode, 'about:blank', 0); + end; + + MINIBROWSER_CONTEXTMENU_JSVISITDOM : + if (frame <> nil) and frame.IsValid then + begin + TempJSCode := 'var testhtml = document.body.innerHTML; ' + + 'myextension.sendresulttobrowser(testhtml, ' + quotedstr(CUSTOMNAME_MESSAGE_NAME) + ');'; + + frame.ExecuteJavaScript(TempJSCode, 'about:blank', 0); + end; + + MINIBROWSER_CONTEXTMENU_SHOWDEVTOOLS : + begin + TempPoint.x := params.XCoord; + TempPoint.y := params.YCoord; + Chromium1.ShowDevTools(TempPoint, nil); + end; + + MINIBROWSER_CONTEXTMENU_OFFLINE : + SwitchOfflineMode; + end; +end; + +// This is a simple example to set the "offline" mode in the DevTools using the TChromium methods directly. +function TJSExtensionFrm.SwitchOfflineMode : integer; +var + TempParams : ICefDictionaryValue; +begin + try + FOffline := not(FOffline); + + TempParams := TCefDictionaryValueRef.New; + TempParams.SetBool('offline', FOffline); + TempParams.SetDouble('latency', 0); + TempParams.SetDouble('downloadThroughput', 0); + TempParams.SetDouble('uploadThroughput', 0); + + Result := Chromium1.ExecuteDevToolsMethod(0, 'Network.emulateNetworkConditions', TempParams); + finally + TempParams := nil; + end; +end; + +procedure TJSExtensionFrm.Chromium1ProcessMessageReceived(Sender: TObject; + const browser: ICefBrowser; const frame: ICefFrame; sourceProcess: TCefProcessId; + const message: ICefProcessMessage; out Result: Boolean); +begin + Result := False; + + if (message = nil) or (message.ArgumentList = nil) then exit; + + // This function receives the messages with the JavaScript results + + // Many of these events are received in different threads and the VCL + // doesn't like to create and destroy components in different threads. + + // It's safer to store the results and send a message to the main thread to show them. + + // The message names are defined in the extension or in JS code. + + if (message.Name = MOUSEOVER_MESSAGE_NAME) then + begin + StatusBar1.Panels[0].Text := message.ArgumentList.GetString(0); // this doesn't create/destroy components + Result := True; + end + else + if (message.Name = CUSTOMNAME_MESSAGE_NAME) then + begin + FText := message.ArgumentList.GetString(0); + PostMessage(Handle, MINIBROWSER_SHOWTEXTVIEWER, 0, 0); + Result := True; + end; +end; + +procedure TJSExtensionFrm.FormCloseQuery(Sender: TObject; + var CanClose: Boolean); +begin + CanClose := FCanClose; + + if not(FClosing) then + begin + FClosing := True; + Visible := False; + Chromium1.CloseBrowser(True); + end; +end; + +procedure TJSExtensionFrm.FormCreate(Sender: TObject); +begin + FCanClose := False; + FClosing := False; +end; + +procedure TJSExtensionFrm.FormShow(Sender: TObject); +begin + StatusBar1.Panels[0].Text := 'Initializing browser. Please wait...'; + + // GlobalCEFApp.GlobalContextInitialized has to be TRUE before creating any browser + // If it's not initialized yet, we use a simple timer to create the browser later. + if not(Chromium1.CreateBrowser(CEFWindowParent1, '')) then Timer1.Enabled := True; +end; + +procedure TJSExtensionFrm.WMMove(var aMessage : TWMMove); +begin + inherited; + + if (Chromium1 <> nil) then Chromium1.NotifyMoveOrResizeStarted; +end; + +procedure TJSExtensionFrm.WMMoving(var aMessage : TMessage); +begin + inherited; + + if (Chromium1 <> nil) then Chromium1.NotifyMoveOrResizeStarted; +end; + +procedure TJSExtensionFrm.WMEnterMenuLoop(var aMessage: TMessage); +begin + inherited; + + if (aMessage.wParam = 0) and (GlobalCEFApp <> nil) then GlobalCEFApp.OsmodalLoop := True; +end; + +procedure TJSExtensionFrm.WMExitMenuLoop(var aMessage: TMessage); +begin + inherited; + + if (aMessage.wParam = 0) and (GlobalCEFApp <> nil) then GlobalCEFApp.OsmodalLoop := False; +end; + +procedure TJSExtensionFrm.ShowTextViewerMsg(var aMessage : TMessage); +begin + // This form will show the HTML received from JavaScript + SimpleTextViewerFrm.Memo1.Lines.Text := FText; + SimpleTextViewerFrm.ShowModal; +end; + +procedure TJSExtensionFrm.Timer1Timer(Sender: TObject); +begin + Timer1.Enabled := False; + if not(Chromium1.CreateBrowser(CEFWindowParent1, '')) and not(Chromium1.Initialized) then + Timer1.Enabled := True; +end; + +procedure TJSExtensionFrm.BrowserCreatedMsg(var aMessage : TMessage); +begin + StatusBar1.Panels[0].Text := ''; + CEFWindowParent1.UpdateSize; + NavControlPnl.Enabled := True; + GoBtn.Click; +end; + +procedure TJSExtensionFrm.BrowserDestroyMsg(var aMessage : TMessage); +begin + CEFWindowParent1.Free; +end; + +end. diff --git a/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uJSExtension_sp.pas b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uJSExtension_sp.pas new file mode 100644 index 00000000..e065acbe --- /dev/null +++ b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uJSExtension_sp.pas @@ -0,0 +1,197 @@ +unit uJSExtension_sp; + +interface + +procedure CreateGlobalCEFApp; + +implementation + +uses + uCEFApplicationCore, uCEFConstants, uCEFv8Value, uCEFInterfaces, uCEFMiscFunctions, + uTestExtensionHandler; + +// BASIC CONCEPTS +// ============== + +// Chromium uses several processes to carry out all the tasks needed to handle a web page : +// 1. The main application process is called "BROWSER PROCESS" and it runs the UI. +// 2. The layout and interpretation of HTML is done in the "RENDERER PROCESS". + +// Read this for more details about Chromium's architecture : +// http://www.chromium.org/developers/design-documents/multi-process-architecture + +// Each process is isolated from the rest and you need to use some kind of inter-process +// communication (IPC) to send information between them. This isolation and protection is +// guaranteed by the operating system and it's the main reason Chromium uses several processes. + +// In many cases, you need to use JavaScript or visit the DOM to return some results to Delphi. +// The DOM and JavaScript live in the RENDERER PROCESS, while the Delphi code of your application +// lives in the BROWSER PROCESS. + +// As commented before, the operating system isolates each process and this means that you +// can't access anything declared in one process like variables, fields, classes, controls, etc. +// from a different process. + +// However, CEF has several ways to send information between processes and you can also use your +// own inter-process communication methods. + +// If you need to execute some JavaScript code all you need is to call TChromium.ExecuteJavaScript +// from your application's code in the BROWSER PROCESS and CEF will take care of executing that +// code in the RENDERER PROCESS. + +// If you need to send a message to the RENDERER PROCESS from the BROWSER PROCESS you can use +// TChromium.SendProcessMessage. + +// To send messages to the BROWSER PROCESS from the RENDERER PROCESS you can use +// ICefFrame.SendProcessMessage + + +// -------------- TChromium.SendProcessMessage -------------- +// | | ------------------------------> | | +// | BROWSER | | RENDERER | +// | | | | +// | PROCESS | ICefFrame.SendProcessMessage | PROCESS | +// | | <------------------------------ | | +// -------------- -------------- + + +// To receive the messages sent from the RENDERER PROCESS you need to use the +// TChromium.OnProcessMessageReceived event. This event is executed in a CEF thread that belongs +// to the BROWSER PROCESS. + +// To receive the messages sent from the BROWSER PROCESS you need to use the +// TCefApplication.OnProcessMessageReceived event (GlobalCEFApp.OnProcessMessageReceived). +// This event is executed in a CEF thread that belongs to the RENDERER PROCESS. + + +// JAVASCRIPT EXTENSIONS +// ===================== + +// CEF exposes a large number of JS features for integration in client applications. +// You can use JS types, arrays, functions, extensions, objects, etc. + +// All of those features are described in detail here : +// https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md + +// One of the most interesting JS features available in CEF are the JavaScript extensions because they +// can be used to execute custom Delphi code from JavaScript. + +// If you put all you know so far together you can get any result or information in Delphi from +// JavaScript following these steps : +// 1. Use TChromium.ExecuteJavaScript to execute your custom JavaScript code. +// 2. That custom JavaScript code is executed in the RENDERER PROCESS and it can call functions in your +// custom JavaScript extension, which executes Delphi code. This Delphi code is also executed in +// the RENDERER PROCESS. +// 3. The Delphi code in the JavaScript extension can use ICefFrame.SendProcessMessage to send +// information back to the BROWSER PROCESS. +// 4. The BROWSER PROCESS receives the information in the TChromium.OnProcessMessageReceived event. + +// To create a JavaScript extension in CEF you have to create a new class that inherits from +// TCefv8HandlerOwn and it has to override the "execute" function. Open uTestExtensionHandler.pas +// to see an example and read this for more details about the "execute" parameters : +// https://magpcss.org/ceforum/apidocs3/projects/(default)/CefV8Handler.html + +// In order to use that extension, you must register it in the GlobalCEFApp.OnWebKitInitialized event +// as you can see in the GlobalCEFApp_OnWebKitInitialized procedure on this PAS unit. + +// You have to call the CefRegisterExtension function with 3 parameters : +// 1. name : The extension name. +// 2. code : Any valid JS code but in this case it includes 2 "native function" forward declarations. +// 3. Handler : An instance of your TCefv8HandlerOwn subclass. + +// Notice that the code used with the CefRegisterExtension function in this demo is declaring +// "myextension.mouseover" as a function that calls the "mouseover" native function, and the +// "myextension.sendresulttobrowser" function that calls the "sendresulttobrowser" native function. + +// The "execute" function in the custom TCefv8HandlerOwn subclass will compare the "name" parameter +// with the name of the of the native function used in the code that registered this extension. +// As you can see in this demo, TTestExtensionHandler.Execute compares the "name" parameter with +// "mouseover" and "sendresulttobrowser" to execute the code you want for each of those custom functions. + +// TTestExtensionHandler.Execute is executed in the RENDERER PROCESS and it uses a process message +// to send some results to he BROWSER PROCESS. +// It uses TCefv8ContextRef.Current.Browser.MainFrame to call the SendProcessMessage procedure for +// the main frame. + +// The message is a TCefProcessMessageRef instance and you can set the information you want to send using +// its ArgumentList property. + +// You can add several items to ArgumentList using different indexes in the SetString, SetInt, SetBool, +// SetBinary, etc. functions. +// There is a size limit in the binary parameters of only a few kilobytes. Compress the binary data, use +// alternative IPC methods or use a database protected by a mutex if necessary. + +// For more information about this, read the following pages : +// https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md#markdown-header-functions-and-extensions +// https://bitbucket.org/chromiumembedded/cef/src/b6b033a52bb3f7059d169a4c8389966c8fe2531b/include/capi/cef_v8_capi.h#lines-924 + + +// TESTING THIS DEMO : +// =================== +// 1. Run the demo and wait until google.com is loaded +// 2. Right-click and select the "Set the mouseover event" menu option. +// 3. Move the mouse pointer over the web page and see the HTML elements in the status bar. + +// When you select the "Set the mouseover event" menu option, the +// TChromium.OnContextMenuCommand event is triggered and it adds an event listener to the +// document's body. That listener calls one of the functions available in the registered +// extension called "myextension.mouseover". + +// The TTestExtensionHandler.Execute function in the extension is executed and it +// uses TCefv8ContextRef.Current.Browser.MainFrame.SendProcessMessage(PID_BROWSER, msg) +// to send a process message with the results to the browser process. + +// That message is received in the TChromium.OnProcessMessageReceived event and it shows +// the information in the status bar. + +// If you have to debug the code executed by the extension you will need to use the +// debugging methods described in +// https://www.briskbard.com/index.php?lang=en&pageid=cef + +procedure GlobalCEFApp_OnWebKitInitialized; +var + TempExtensionCode : string; + TempHandler : ICefv8Handler; +begin + try + // This is a JS extension example with 2 functions and several parameters. + // Please, read the "JavaScript Integration" wiki page at + // https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md + + TempExtensionCode := 'var myextension;' + + 'if (!myextension)' + + ' myextension = {};' + + '(function() {' + + ' myextension.mouseover = function(a) {' + + ' native function mouseover();' + + ' mouseover(a);' + + ' };' + + ' myextension.sendresulttobrowser = function(b,c) {' + + ' native function sendresulttobrowser();' + + ' sendresulttobrowser(b,c);' + + ' };' + + '})();'; + + TempHandler := TTestExtensionHandler.Create; + + if CefRegisterExtension('myextension', TempExtensionCode, TempHandler) then + {$IFDEF DEBUG}CefDebugLog('JavaScript extension registered successfully!'){$ENDIF} + else + {$IFDEF DEBUG}CefDebugLog('There was an error registering the JavaScript extension!'){$ENDIF}; + finally + TempHandler := nil; + end; +end; + +procedure CreateGlobalCEFApp; +begin + GlobalCEFApp := TCefApplicationCore.Create; + GlobalCEFApp.OnWebKitInitialized := GlobalCEFApp_OnWebKitInitialized; + {$IFDEF DEBUG} + GlobalCEFApp.LogFile := 'debug.log'; + GlobalCEFApp.LogSeverity := LOGSEVERITY_INFO; + {$ENDIF} + GlobalCEFApp.StartSubProcess; +end; + +end. diff --git a/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uSimpleTextViewer.dfm b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uSimpleTextViewer.dfm new file mode 100644 index 00000000..71916e03 --- /dev/null +++ b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uSimpleTextViewer.dfm @@ -0,0 +1,27 @@ +object SimpleTextViewerFrm: TSimpleTextViewerFrm + Left = 0 + Top = 0 + BorderIcons = [biSystemMenu] + BorderStyle = bsSingle + Caption = 'Simple text viewer' + ClientHeight = 572 + ClientWidth = 694 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + Position = poScreenCenter + TextHeight = 13 + object Memo1: TMemo + Left = 0 + Top = 0 + Width = 694 + Height = 572 + Align = alClient + ReadOnly = True + ScrollBars = ssBoth + TabOrder = 0 + end +end diff --git a/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uSimpleTextViewer.pas b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uSimpleTextViewer.pas new file mode 100644 index 00000000..724d8b25 --- /dev/null +++ b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uSimpleTextViewer.pas @@ -0,0 +1,33 @@ +unit uSimpleTextViewer; + +{$I ..\..\..\..\source\cef.inc} + +interface + +uses + {$IFDEF DELPHI16_UP} + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; + {$ELSE} + Windows, Messages, SysUtils, Variants, Classes, Graphics, + Controls, Forms, Dialogs, StdCtrls; + {$ENDIF} + + +type + TSimpleTextViewerFrm = class(TForm) + Memo1: TMemo; + private + { Private declarations } + public + { Public declarations } + end; + +var + SimpleTextViewerFrm: TSimpleTextViewerFrm; + +implementation + +{$R *.dfm} + +end. diff --git a/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uTestExtensionHandler.pas b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uTestExtensionHandler.pas new file mode 100644 index 00000000..e613e27f --- /dev/null +++ b/demos/Delphi_VCL/JavaScript/JSExtensionSubProcess/uTestExtensionHandler.pas @@ -0,0 +1,75 @@ +unit uTestExtensionHandler; + +{$I ..\..\..\..\source\cef.inc} + +interface + +uses + {$IFDEF DELPHI16_UP} + Winapi.Windows, + {$ELSE} + Windows, + {$ENDIF} + uCEFRenderProcessHandler, uCEFBrowserProcessHandler, uCEFInterfaces, uCEFProcessMessage, + uCEFv8Context, uCEFTypes, uCEFv8Handler; + +type + TTestExtensionHandler = class(TCefv8HandlerOwn) + protected + function Execute(const name: ustring; const object_: ICefv8Value; const arguments: TCefv8ValueArray; var retval: ICefv8Value; var exception: ustring): Boolean; override; + end; + +implementation + +uses + uCEFMiscFunctions, uCEFConstants, uJSExtension; + +function TTestExtensionHandler.Execute(const name : ustring; + const object_ : ICefv8Value; + const arguments : TCefv8ValueArray; + var retval : ICefv8Value; + var exception : ustring): Boolean; +var + TempMessage : ICefProcessMessage; + TempFrame : ICefFrame; +begin + Result := False; + + try + if (name = 'mouseover') then + begin + if (length(arguments) > 0) and arguments[0].IsString then + begin + TempMessage := TCefProcessMessageRef.New(MOUSEOVER_MESSAGE_NAME); + TempMessage.ArgumentList.SetString(0, arguments[0].GetStringValue); + + TempFrame := TCefv8ContextRef.Current.Browser.MainFrame; + + if (TempFrame <> nil) and TempFrame.IsValid then + TempFrame.SendProcessMessage(PID_BROWSER, TempMessage); + end; + + Result := True; + end + else + if (name = 'sendresulttobrowser') then + begin + if (length(arguments) > 1) and arguments[0].IsString and arguments[1].IsString then + begin + TempMessage := TCefProcessMessageRef.New(arguments[1].GetStringValue); + TempMessage.ArgumentList.SetString(0, arguments[0].GetStringValue); + + TempFrame := TCefv8ContextRef.Current.Browser.MainFrame; + + if (TempFrame <> nil) and TempFrame.IsValid then + TempFrame.SendProcessMessage(PID_BROWSER, TempMessage); + end; + + Result := True; + end; + finally + TempMessage := nil; + end; +end; + +end. diff --git a/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/00-Delete.bat b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/00-Delete.bat new file mode 100644 index 00000000..0b5ba5c8 --- /dev/null +++ b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/00-Delete.bat @@ -0,0 +1,2 @@ +rmdir /S /Q lib +rmdir /S /Q backup diff --git a/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/JSExtension.lpi b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/JSExtension.lpi new file mode 100644 index 00000000..d8b1ac60 --- /dev/null +++ b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/JSExtension.lpi @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + </General> + <BuildModes Count="1"> + <Item1 Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + <UseFileFilters Value="True"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + </RunParams> + <RequiredPackages Count="2"> + <Item1> + <PackageName Value="CEF4Delphi_Lazarus"/> + </Item1> + <Item2> + <PackageName Value="LCL"/> + </Item2> + </RequiredPackages> + <Units Count="3"> + <Unit0> + <Filename Value="JSExtension.lpr"/> + <IsPartOfProject Value="True"/> + </Unit0> + <Unit1> + <Filename Value="uJSExtension.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="JSExtensionFrm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit1> + <Unit2> + <Filename Value="uSimpleTextViewer.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="SimpleTextViewerFrm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit2> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="..\..\..\..\bin\JSExtension"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <SyntaxMode Value="Delphi"/> + </SyntaxOptions> + </Parsing> + <Linking> + <Debugging> + <DebugInfoType Value="dsDwarf2Set"/> + </Debugging> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + <Other> + <CustomOptions Value="-dBorland -dVer150 -dDelphi7 -dCompiler6_Up -dPUREPASCAL"/> + </Other> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/JSExtension.lpr b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/JSExtension.lpr new file mode 100644 index 00000000..941403ab --- /dev/null +++ b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/JSExtension.lpr @@ -0,0 +1,32 @@ +program JSExtension; + +{$MODE Delphi} + +{$I ..\..\..\..\source\cef.inc} + +uses + Forms, LCLIntf, LCLType, LMessages, Interfaces, + uCEFApplication, + uJSExtension in 'uJSExtension.pas' {JSExtensionFrm}, + uSimpleTextViewer in 'uSimpleTextViewer.pas' {SimpleTextViewerFrm}; + +{.$R *.res} + +// CEF3 needs to set the LARGEADDRESSAWARE flag which allows 32-bit processes to use up to 3GB of RAM. +{$SetPEFlags $20} + +begin + // GlobalCEFApp creation and initialization moved to a different unit to fix the memory leak described in the bug #89 + // https://github.com/salvadordf/CEF4Delphi/issues/89 + CreateGlobalCEFApp; + + if GlobalCEFApp.StartMainProcess then + begin + Application.Initialize; + Application.CreateForm(TJSExtensionFrm, JSExtensionFrm); + Application.CreateForm(TSimpleTextViewerFrm, SimpleTextViewerFrm); + Application.Run; + end; + + DestroyGlobalCEFApp; +end. diff --git a/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/JSExtension_sp.lpi b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/JSExtension_sp.lpi new file mode 100644 index 00000000..509ce0aa --- /dev/null +++ b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/JSExtension_sp.lpi @@ -0,0 +1,92 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <ProjectOptions> + <Version Value="12"/> + <PathDelim Value="\"/> + <General> + <Flags> + <MainUnitHasUsesSectionForAllUnits Value="False"/> + <MainUnitHasCreateFormStatements Value="False"/> + <MainUnitHasTitleStatement Value="False"/> + <MainUnitHasScaledStatement Value="False"/> + <CompatibilityMode Value="True"/> + </Flags> + <SessionStorage Value="InProjectDir"/> + <Title Value="JSExtension_sp"/> + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + </General> + <BuildModes Count="1"> + <Item1 Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + <UseFileFilters Value="True"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + </RunParams> + <RequiredPackages Count="2"> + <Item1> + <PackageName Value="CEF4Delphi_Lazarus"/> + </Item1> + <Item2> + <PackageName Value="LCL"/> + </Item2> + </RequiredPackages> + <Units Count="3"> + <Unit0> + <Filename Value="JSExtension_sp.lpr"/> + <IsPartOfProject Value="True"/> + </Unit0> + <Unit1> + <Filename Value="uTestExtensionHandler.pas"/> + <IsPartOfProject Value="True"/> + </Unit1> + <Unit2> + <Filename Value="ujsextension_sp.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="uJSExtension_sp"/> + </Unit2> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="..\..\..\..\bin\JSExtension_sp"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <SyntaxMode Value="Delphi"/> + </SyntaxOptions> + </Parsing> + <Linking> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + <Other> + <CustomOptions Value="-dBorland -dVer150 -dDelphi7 -dCompiler6_Up -dPUREPASCAL"/> + </Other> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/JSExtension_sp.lpr b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/JSExtension_sp.lpr new file mode 100644 index 00000000..f0049c8f --- /dev/null +++ b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/JSExtension_sp.lpr @@ -0,0 +1,20 @@ +program JSExtension_sp; + +{$MODE Delphi} + +uses + LCLIntf, LCLType, LMessages, Forms, Interfaces, + uCEFApplicationCore, uJSExtension_sp, uTestExtensionHandler; + +{$IFDEF WIN32} +// CEF needs to set the LARGEADDRESSAWARE ($20) flag which allows 32-bit processes to use up to 3GB of RAM. +const + IMAGE_FILE_LARGE_ADDRESS_AWARE = $0020; + {$SetPEFlags IMAGE_FILE_LARGE_ADDRESS_AWARE} +{$ENDIF} + +begin + CreateGlobalCEFApp; + DestroyGlobalCEFApp; +end. + diff --git a/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/uJSExtension.lfm b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/uJSExtension.lfm new file mode 100644 index 00000000..7a1233b3 --- /dev/null +++ b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/uJSExtension.lfm @@ -0,0 +1,86 @@ +object JSExtensionFrm: TJSExtensionFrm + Left = 483 + Height = 589 + Top = 152 + Width = 978 + Caption = 'JSExtension' + ClientHeight = 589 + ClientWidth = 978 + Color = clBtnFace + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + OnCloseQuery = FormCloseQuery + OnCreate = FormCreate + OnShow = FormShow + Position = poScreenCenter + LCLVersion = '3.0.0.3' + object NavControlPnl: TPanel + Left = 0 + Height = 21 + Top = 0 + Width = 978 + Align = alTop + BevelOuter = bvNone + ClientHeight = 21 + ClientWidth = 978 + Enabled = False + ParentBackground = False + TabOrder = 0 + object Edit1: TEdit + Left = 0 + Height = 21 + Top = 0 + Width = 947 + Align = alClient + TabOrder = 0 + Text = 'http://www.google.com' + end + object GoBtn: TButton + Left = 947 + Height = 21 + Top = 0 + Width = 31 + Align = alRight + Caption = 'Go' + TabOrder = 1 + OnClick = GoBtnClick + end + end + object CEFWindowParent1: TCEFWindowParent + Left = 0 + Height = 547 + Top = 21 + Width = 978 + Align = alClient + TabOrder = 1 + end + object StatusPnl: TPanel + Left = 0 + Height = 21 + Top = 568 + Width = 978 + Align = alBottom + BevelOuter = bvLowered + ParentBackground = False + TabOrder = 2 + end + object Chromium1: TChromium + OnProcessMessageReceived = Chromium1ProcessMessageReceived + OnBeforeContextMenu = Chromium1BeforeContextMenu + OnContextMenuCommand = Chromium1ContextMenuCommand + OnBeforePopup = Chromium1BeforePopup + OnAfterCreated = Chromium1AfterCreated + OnBeforeClose = Chromium1BeforeClose + OnClose = Chromium1Close + Left = 32 + Top = 224 + end + object Timer1: TTimer + Enabled = False + Interval = 300 + OnTimer = Timer1Timer + Left = 32 + Top = 288 + end +end diff --git a/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/uJSExtension.pas b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/uJSExtension.pas new file mode 100644 index 00000000..917af06c --- /dev/null +++ b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/uJSExtension.pas @@ -0,0 +1,496 @@ +unit uJSExtension; + +{$MODE Delphi} + +{$I ..\..\..\..\source\cef.inc} + +interface + +uses + {$IFDEF DELPHI16_UP} + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.ComCtrls, + {$ELSE} + LCLIntf, LCLType, LMessages, Messages, SysUtils, Variants, Classes, Graphics, + Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ComCtrls, + {$ENDIF} + uCEFChromium, uCEFWindowParent, uCEFInterfaces, uCEFApplication, uCEFTypes, uCEFConstants, + uCEFWinControl; + +const + MINIBROWSER_SHOWTEXTVIEWER = WM_APP + $100; + + MINIBROWSER_CONTEXTMENU_SETJSEVENT = MENU_ID_USER_FIRST + 1; + MINIBROWSER_CONTEXTMENU_JSVISITDOM = MENU_ID_USER_FIRST + 2; + MINIBROWSER_CONTEXTMENU_SHOWDEVTOOLS = MENU_ID_USER_FIRST + 3; + MINIBROWSER_CONTEXTMENU_OFFLINE = MENU_ID_USER_FIRST + 4; + + MOUSEOVER_MESSAGE_NAME = 'mouseover'; + CUSTOMNAME_MESSAGE_NAME = 'customname'; + +type + + { TJSExtensionFrm } + + TJSExtensionFrm = class(TForm) + NavControlPnl: TPanel; + Edit1: TEdit; + GoBtn: TButton; + CEFWindowParent1: TCEFWindowParent; + Chromium1: TChromium; + StatusPnl: TPanel; + Timer1: TTimer; + procedure FormShow(Sender: TObject); + procedure GoBtnClick(Sender: TObject); + procedure Chromium1BeforeContextMenu(Sender: TObject; + const browser: ICefBrowser; const frame: ICefFrame; + const params: ICefContextMenuParams; const model: ICefMenuModel); + procedure Chromium1ContextMenuCommand(Sender: TObject; + const browser: ICefBrowser; const frame: ICefFrame; + const params: ICefContextMenuParams; commandId: Integer; + eventFlags: Cardinal; out Result: Boolean); + procedure Chromium1ProcessMessageReceived(Sender: TObject; + const browser: ICefBrowser; const frame: ICefFrame; sourceProcess: TCefProcessId; + const message: ICefProcessMessage; out Result: Boolean); + procedure Chromium1AfterCreated(Sender: TObject; const browser: ICefBrowser); + procedure Timer1Timer(Sender: TObject); + procedure Chromium1BeforePopup(Sender: TObject; + const browser: ICefBrowser; const frame: ICefFrame; const targetUrl, + targetFrameName: ustring; + targetDisposition: TCefWindowOpenDisposition; userGesture: Boolean; + const popupFeatures: TCefPopupFeatures; var windowInfo: TCefWindowInfo; + var client: ICefClient; var settings: TCefBrowserSettings; + var extra_info: ICefDictionaryValue; + var noJavascriptAccess: Boolean; var Result: Boolean); + procedure FormCreate(Sender: TObject); + procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); + procedure Chromium1Close(Sender: TObject; const browser: ICefBrowser; + var aAction : TCefCloseBrowserAction); + procedure Chromium1BeforeClose(Sender: TObject; + const browser: ICefBrowser); + protected + FText : string; + // Variables to control when can we destroy the form safely + FCanClose : boolean; // Set to True in TChromium.OnBeforeClose + FClosing : boolean; // Set to True in the CloseQuery event. + + FOffline : boolean; + + procedure BrowserCreatedMsg(var aMessage : TMessage); message CEF_AFTERCREATED; + procedure BrowserDestroyMsg(var aMessage : TMessage); message CEF_DESTROY; + procedure ShowTextViewerMsg(var aMessage : TMessage); message MINIBROWSER_SHOWTEXTVIEWER; + procedure WMMove(var aMessage : TWMMove); message WM_MOVE; + procedure WMMoving(var aMessage : TMessage); message WM_MOVING; + procedure WMEnterMenuLoop(var aMessage: TMessage); message WM_ENTERMENULOOP; + procedure WMExitMenuLoop(var aMessage: TMessage); message WM_EXITMENULOOP; + + function SwitchOfflineMode : integer; + public + { Public declarations } + end; + +var + JSExtensionFrm: TJSExtensionFrm; + +procedure CreateGlobalCEFApp; + +implementation + +{$R *.lfm} + +uses + uSimpleTextViewer, uCEFMiscFunctions, uTestExtensionHandler, uCEFDictionaryValue; + +// BASIC CONCEPTS +// ============== + +// Chromium uses several processes to carry out all the tasks needed to handle a web page : +// 1. The main application process is called "BROWSER PROCESS" and it runs the UI. +// 2. The layout and interpretation of HTML is done in the "RENDERER PROCESS". + +// Read this for more details about Chromium's architecture : +// http://www.chromium.org/developers/design-documents/multi-process-architecture + +// Each process is isolated from the rest and you need to use some kind of inter-process +// communication (IPC) to send information between them. This isolation and protection is +// guaranteed by the operating system and it's the main reason Chromium uses several processes. + +// In many cases, you need to use JavaScript or visit the DOM to return some results to Pascal. +// The DOM and JavaScript live in the RENDERER PROCESS, while the Pascal code of your application +// lives in the BROWSER PROCESS. + +// As commented before, the operating system isolates each process and this means that you +// can't access anything declared in one process like variables, fields, classes, controls, etc. +// from a different process. + +// However, CEF has several ways to send information between processes and you can also use your +// own inter-process communication methods. + +// If you need to execute some JavaScript code all you need is to call TChromium.ExecuteJavaScript +// from your application's code in the BROWSER PROCESS and CEF will take care of executing that +// code in the RENDERER PROCESS. + +// If you need to send a message to the RENDERER PROCESS from the BROWSER PROCESS you can use +// TChromium.SendProcessMessage. + +// To send messages to the BROWSER PROCESS from the RENDERER PROCESS you can use +// ICefFrame.SendProcessMessage + + +// -------------- TChromium.SendProcessMessage -------------- +// | | ------------------------------> | | +// | BROWSER | | RENDERER | +// | | | | +// | PROCESS | ICefFrame.SendProcessMessage | PROCESS | +// | | <------------------------------ | | +// -------------- -------------- + + +// To receive the messages sent from the RENDERER PROCESS you need to use the +// TChromium.OnProcessMessageReceived event. This event is executed in a CEF thread that belongs +// to the BROWSER PROCESS. + +// To receive the messages sent from the BROWSER PROCESS you need to use the +// TCefApplication.OnProcessMessageReceived event (GlobalCEFApp.OnProcessMessageReceived). +// This event is executed in a CEF thread that belongs to the RENDERER PROCESS. + + +// JAVASCRIPT EXTENSIONS +// ===================== + +// CEF exposes a large number of JS features for integration in client applications. +// You can use JS types, arrays, functions, extensions, objects, etc. + +// All of those features are described in detail here : +// https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md + +// One of the most interesting JS features available in CEF are the JavaScript extensions because they +// can be used to execute custom Pascal code from JavaScript. + +// If you put all you know so far together you can get any result or information in Pascal from +// JavaScript following these steps : +// 1. Use TChromium.ExecuteJavaScript to execute your custom JavaScript code. +// 2. That custom JavaScript code is executed in the RENDERER PROCESS and it can call functions in your +// custom JavaScript extension, which executes Pascal code. This Pascal code is also executed in +// the RENDERER PROCESS. +// 3. The Pascal code in the JavaScript extension can use ICefFrame.SendProcessMessage to send +// information back to the BROWSER PROCESS. +// 4. The BROWSER PROCESS receives the information in the TChromium.OnProcessMessageReceived event. + +// To create a JavaScript extension in CEF you have to create a new class that inherits from +// TCefv8HandlerOwn and it has to override the "execute" function. Open uTestExtensionHandler.pas +// to see an example and read this for more details about the "execute" parameters : +// https://magpcss.org/ceforum/apidocs3/projects/(default)/CefV8Handler.html + +// In order to use that extension, you must register it in the GlobalCEFApp.OnWebKitInitialized event +// as you can see in the GlobalCEFApp_OnWebKitInitialized procedure on this PAS unit. + +// You have to call the CefRegisterExtension function with 3 parameters : +// 1. name : The extension name. +// 2. code : Any valid JS code but in this case it includes 2 "native function" forward declarations. +// 3. Handler : An instance of your TCefv8HandlerOwn subclass. + +// Notice that the code used with the CefRegisterExtension function in this demo is declaring +// "myextension.mouseover" as a function that calls the "mouseover" native function, and the +// "myextension.sendresulttobrowser" function that calls the "sendresulttobrowser" native function. + +// The "execute" function in the custom TCefv8HandlerOwn subclass will compare the "name" parameter +// with the name of the of the native function used in the code that registered this extension. +// As you can see in this demo, TTestExtensionHandler.Execute compares the "name" parameter with +// "mouseover" and "sendresulttobrowser" to execute the code you want for each of those custom functions. + +// TTestExtensionHandler.Execute is executed in the RENDERER PROCESS and it uses a process message +// to send some results to he BROWSER PROCESS. +// It uses TCefv8ContextRef.Current.Browser.MainFrame to call the SendProcessMessage procedure for +// the main frame. + +// The message is a TCefProcessMessageRef instance and you can set the information you want to send using +// its ArgumentList property. + +// You can add several items to ArgumentList using different indexes in the SetString, SetInt, SetBool, +// SetBinary, etc. functions. +// There is a size limit in the binary parameters of only a few kilobytes. Compress the binary data, use +// alternative IPC methods or use a database protected by a mutex if necessary. + +// For more information about this, read the following pages : +// https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md#markdown-header-functions-and-extensions +// https://bitbucket.org/chromiumembedded/cef/src/b6b033a52bb3f7059d169a4c8389966c8fe2531b/include/capi/cef_v8_capi.h#lines-924 + + +// TESTING THIS DEMO : +// =================== +// 1. Run the demo and wait until google.com is loaded +// 2. Right-click and select the "Set the mouseover event" menu option. +// 3. Move the mouse pointer over the web page and see the HTML elements in the status bar. + +// When you select the "Set the mouseover event" menu option, the +// TChromium.OnContextMenuCommand event is triggered and it adds an event listener to the +// document's body. That listener calls one of the functions available in the registered +// extension called "myextension.mouseover". + +// The TTestExtensionHandler.Execute function in the extension is executed and it +// uses TCefv8ContextRef.Current.Browser.MainFrame.SendProcessMessage(PID_BROWSER, msg) +// to send a process message with the results to the browser process. + +// That message is received in the TChromium.OnProcessMessageReceived event and it shows +// the information in the status bar. + +// If you have to debug the code executed by the extension you will need to use the +// debugging methods described in +// https://www.briskbard.com/index.php?lang=en&pageid=cef + + +// DESTRUCTION STEPS +// ================= +// 1. FormCloseQuery sets CanClose to FALSE calls TChromium.CloseBrowser which triggers +// the TChromium.OnClose event. +// 2. TChromium.OnClose sends a CEFBROWSER_DESTROY message to destroy CEFWindowParent1 +// in the main thread, which triggers the TChromium.OnBeforeClose event. +// 3. TChromium.OnBeforeClose sets FCanClose := True and sends WM_CLOSE to the form. + +procedure CreateGlobalCEFApp; +begin + GlobalCEFApp := TCefApplication.Create; + GlobalCEFApp.BrowserSubprocessPath := 'JSExtension_sp.exe'; + GlobalCEFApp.SetCurrentDir := True; + {$IFDEF DEBUG} + GlobalCEFApp.LogFile := 'debug.log'; + GlobalCEFApp.LogSeverity := LOGSEVERITY_INFO; + {$ENDIF} +end; + +procedure TJSExtensionFrm.GoBtnClick(Sender: TObject); +begin + Chromium1.LoadURL(Edit1.Text); +end; + +procedure TJSExtensionFrm.Chromium1AfterCreated(Sender: TObject; const browser: ICefBrowser); +begin + PostMessage(Handle, CEF_AFTERCREATED, 0, 0); +end; + +procedure TJSExtensionFrm.Chromium1BeforeClose(Sender: TObject; + const browser: ICefBrowser); +begin + FCanClose := True; + PostMessage(Handle, WM_CLOSE, 0, 0); +end; + +procedure TJSExtensionFrm.Chromium1BeforeContextMenu(Sender: TObject; + const browser: ICefBrowser; const frame: ICefFrame; + const params: ICefContextMenuParams; const model: ICefMenuModel); +begin + // Adding some custom context menu entries + model.AddSeparator; + model.AddItem(MINIBROWSER_CONTEXTMENU_SETJSEVENT, 'Set mouseover event'); + model.AddItem(MINIBROWSER_CONTEXTMENU_JSVISITDOM, 'Visit DOM in JavaScript'); + model.AddItem(MINIBROWSER_CONTEXTMENU_SHOWDEVTOOLS, 'Show DevTools'); + model.AddCheckItem(MINIBROWSER_CONTEXTMENU_OFFLINE, 'Offline'); + model.SetChecked(MINIBROWSER_CONTEXTMENU_OFFLINE, FOffline); +end; + +procedure TJSExtensionFrm.Chromium1BeforePopup(Sender: TObject; + const browser: ICefBrowser; const frame: ICefFrame; const targetUrl, + targetFrameName: ustring; targetDisposition: TCefWindowOpenDisposition; + userGesture: Boolean; const popupFeatures: TCefPopupFeatures; + var windowInfo: TCefWindowInfo; var client: ICefClient; + var settings: TCefBrowserSettings; + var extra_info: ICefDictionaryValue; + var noJavascriptAccess: Boolean; + var Result: Boolean); +begin + // For simplicity, this demo blocks all popup windows and new tabs + Result := (targetDisposition in [CEF_WOD_NEW_FOREGROUND_TAB, CEF_WOD_NEW_BACKGROUND_TAB, CEF_WOD_NEW_POPUP, CEF_WOD_NEW_WINDOW]); +end; + +procedure TJSExtensionFrm.Chromium1Close(Sender: TObject; + const browser: ICefBrowser; var aAction : TCefCloseBrowserAction); +begin + PostMessage(Handle, CEF_DESTROY, 0, 0); + aAction := cbaDelay; +end; + +procedure TJSExtensionFrm.Chromium1ContextMenuCommand(Sender: TObject; + const browser: ICefBrowser; const frame: ICefFrame; + const params: ICefContextMenuParams; commandId: Integer; + eventFlags: Cardinal; out Result: Boolean); +var + TempPoint : TPoint; + TempJSCode : string; +begin + Result := False; + + // Here is the code executed for each custom context menu entry + + case commandId of + MINIBROWSER_CONTEXTMENU_SETJSEVENT : + if (frame <> nil) and frame.IsValid then + begin + TempJSCode := 'document.body.addEventListener("mouseover", function(evt){'+ + 'function getpath(n){'+ + 'var ret = "<" + n.nodeName + ">";'+ + 'if (n.parentNode){return getpath(n.parentNode) + ret} else '+ + 'return ret'+ + '};'+ + 'myextension.mouseover(getpath(evt.target))}'+ + ')'; + + frame.ExecuteJavaScript(TempJSCode, 'about:blank', 0); + end; + + MINIBROWSER_CONTEXTMENU_JSVISITDOM : + if (frame <> nil) and frame.IsValid then + begin + TempJSCode := 'var testhtml = document.body.innerHTML; ' + + 'myextension.sendresulttobrowser(testhtml, ' + quotedstr(CUSTOMNAME_MESSAGE_NAME) + ');'; + + frame.ExecuteJavaScript(TempJSCode, 'about:blank', 0); + end; + + MINIBROWSER_CONTEXTMENU_SHOWDEVTOOLS : + begin + TempPoint.x := params.XCoord; + TempPoint.y := params.YCoord; + Chromium1.ShowDevTools(TempPoint, nil); + end; + + MINIBROWSER_CONTEXTMENU_OFFLINE : + SwitchOfflineMode; + end; +end; + +// This is a simple example to set the "offline" mode in the DevTools using the TChromium methods directly. +function TJSExtensionFrm.SwitchOfflineMode : integer; +var + TempParams : ICefDictionaryValue; +begin + try + FOffline := not(FOffline); + + TempParams := TCefDictionaryValueRef.New; + TempParams.SetBool('offline', FOffline); + TempParams.SetDouble('latency', 0); + TempParams.SetDouble('downloadThroughput', 0); + TempParams.SetDouble('uploadThroughput', 0); + + Result := Chromium1.ExecuteDevToolsMethod(0, 'Network.emulateNetworkConditions', TempParams); + finally + TempParams := nil; + end; +end; + +procedure TJSExtensionFrm.Chromium1ProcessMessageReceived(Sender: TObject; + const browser: ICefBrowser; const frame: ICefFrame; sourceProcess: TCefProcessId; + const message: ICefProcessMessage; out Result: Boolean); +begin + Result := False; + + if (message = nil) or (message.ArgumentList = nil) then exit; + + // This function receives the messages with the JavaScript results + + // Many of these events are received in different threads and the VCL + // doesn't like to create and destroy components in different threads. + + // It's safer to store the results and send a message to the main thread to show them. + + // The message names are defined in the extension or in JS code. + + if (message.Name = MOUSEOVER_MESSAGE_NAME) then + begin + StatusPnl.Caption := message.ArgumentList.GetString(0); // this doesn't create/destroy components + Result := True; + end + else + if (message.Name = CUSTOMNAME_MESSAGE_NAME) then + begin + FText := message.ArgumentList.GetString(0); + PostMessage(Handle, MINIBROWSER_SHOWTEXTVIEWER, 0, 0); + Result := True; + end; +end; + +procedure TJSExtensionFrm.FormCloseQuery(Sender: TObject; + var CanClose: Boolean); +begin + CanClose := FCanClose; + + if not(FClosing) then + begin + FClosing := True; + Visible := False; + Chromium1.CloseBrowser(True); + end; +end; + +procedure TJSExtensionFrm.FormCreate(Sender: TObject); +begin + FCanClose := False; + FClosing := False; +end; + +procedure TJSExtensionFrm.FormShow(Sender: TObject); +begin + StatusPnl.Caption := 'Initializing browser. Please wait...'; + + // GlobalCEFApp.GlobalContextInitialized has to be TRUE before creating any browser + // If it's not initialized yet, we use a simple timer to create the browser later. + if not(Chromium1.CreateBrowser(CEFWindowParent1, '')) then Timer1.Enabled := True; +end; + +procedure TJSExtensionFrm.WMMove(var aMessage : TWMMove); +begin + inherited; + + if (Chromium1 <> nil) then Chromium1.NotifyMoveOrResizeStarted; +end; + +procedure TJSExtensionFrm.WMMoving(var aMessage : TMessage); +begin + inherited; + + if (Chromium1 <> nil) then Chromium1.NotifyMoveOrResizeStarted; +end; + +procedure TJSExtensionFrm.WMEnterMenuLoop(var aMessage: TMessage); +begin + inherited; + + if (aMessage.wParam = 0) and (GlobalCEFApp <> nil) then GlobalCEFApp.OsmodalLoop := True; +end; + +procedure TJSExtensionFrm.WMExitMenuLoop(var aMessage: TMessage); +begin + inherited; + + if (aMessage.wParam = 0) and (GlobalCEFApp <> nil) then GlobalCEFApp.OsmodalLoop := False; +end; + +procedure TJSExtensionFrm.ShowTextViewerMsg(var aMessage : TMessage); +begin + // This form will show the HTML received from JavaScript + SimpleTextViewerFrm.Memo1.Lines.Text := FText; + SimpleTextViewerFrm.ShowModal; +end; + +procedure TJSExtensionFrm.Timer1Timer(Sender: TObject); +begin + Timer1.Enabled := False; + if not(Chromium1.CreateBrowser(CEFWindowParent1, '')) and not(Chromium1.Initialized) then + Timer1.Enabled := True; +end; + +procedure TJSExtensionFrm.BrowserCreatedMsg(var aMessage : TMessage); +begin + StatusPnl.Caption := ''; + CEFWindowParent1.UpdateSize; + NavControlPnl.Enabled := True; + GoBtn.Click; +end; + +procedure TJSExtensionFrm.BrowserDestroyMsg(var aMessage : TMessage); +begin + CEFWindowParent1.Free; +end; + +end. diff --git a/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/uSimpleTextViewer.lfm b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/uSimpleTextViewer.lfm new file mode 100644 index 00000000..54ab49b5 --- /dev/null +++ b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/uSimpleTextViewer.lfm @@ -0,0 +1,27 @@ +object SimpleTextViewerFrm: TSimpleTextViewerFrm + Left = 0 + Height = 572 + Top = 0 + Width = 694 + BorderIcons = [biSystemMenu] + BorderStyle = bsSingle + Caption = 'Simple text viewer' + ClientHeight = 572 + ClientWidth = 694 + Color = clBtnFace + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Position = poScreenCenter + LCLVersion = '2.0.1.0' + object Memo1: TMemo + Left = 0 + Height = 572 + Top = 0 + Width = 694 + Align = alClient + ReadOnly = True + ScrollBars = ssBoth + TabOrder = 0 + end +end diff --git a/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/uSimpleTextViewer.pas b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/uSimpleTextViewer.pas new file mode 100644 index 00000000..9db77fcb --- /dev/null +++ b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/uSimpleTextViewer.pas @@ -0,0 +1,33 @@ +unit uSimpleTextViewer; + +{$MODE Delphi} + +interface + +uses + {$IFDEF DELPHI16_UP} + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; + {$ELSE} + LCLIntf, LCLType, LMessages, Messages, SysUtils, Variants, Classes, Graphics, + Controls, Forms, Dialogs, StdCtrls; + {$ENDIF} + + +type + TSimpleTextViewerFrm = class(TForm) + Memo1: TMemo; + private + { Private declarations } + public + { Public declarations } + end; + +var + SimpleTextViewerFrm: TSimpleTextViewerFrm; + +implementation + +{$R *.lfm} + +end. diff --git a/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/uTestExtensionHandler.pas b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/uTestExtensionHandler.pas new file mode 100644 index 00000000..b17baead --- /dev/null +++ b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/uTestExtensionHandler.pas @@ -0,0 +1,77 @@ +unit uTestExtensionHandler; + +{$MODE Delphi} + +{$I ..\..\..\..\source\cef.inc} + +interface + +uses + {$IFDEF DELPHI16_UP} + Winapi.Windows, + {$ELSE} + LCLIntf, LCLType, LMessages, + {$ENDIF} + uCEFRenderProcessHandler, uCEFBrowserProcessHandler, uCEFInterfaces, uCEFProcessMessage, + uCEFv8Context, uCEFTypes, uCEFv8Handler; + +type + TTestExtensionHandler = class(TCefv8HandlerOwn) + protected + function Execute(const name: ustring; const obj: ICefv8Value; const arguments: TCefv8ValueArray; var retval: ICefv8Value; var exception: ustring): Boolean; override; + end; + +implementation + +uses + uCEFMiscFunctions, uCEFConstants, uJSExtension; + +function TTestExtensionHandler.Execute(const name : ustring; + const obj : ICefv8Value; + const arguments : TCefv8ValueArray; + var retval : ICefv8Value; + var exception : ustring): Boolean; +var + TempMessage : ICefProcessMessage; + TempFrame : ICefFrame; +begin + Result := False; + + try + if (name = 'mouseover') then + begin + if (length(arguments) > 0) and arguments[0].IsString then + begin + TempMessage := TCefProcessMessageRef.New(MOUSEOVER_MESSAGE_NAME); + TempMessage.ArgumentList.SetString(0, arguments[0].GetStringValue); + + TempFrame := TCefv8ContextRef.Current.Browser.MainFrame; + + if (TempFrame <> nil) and TempFrame.IsValid then + TempFrame.SendProcessMessage(PID_BROWSER, TempMessage); + end; + + Result := True; + end + else + if (name = 'sendresulttobrowser') then + begin + if (length(arguments) > 1) and arguments[0].IsString and arguments[1].IsString then + begin + TempMessage := TCefProcessMessageRef.New(arguments[1].GetStringValue); + TempMessage.ArgumentList.SetString(0, arguments[0].GetStringValue); + + TempFrame := TCefv8ContextRef.Current.Browser.MainFrame; + + if (TempFrame <> nil) and TempFrame.IsValid then + TempFrame.SendProcessMessage(PID_BROWSER, TempMessage); + end; + + Result := True; + end; + finally + TempMessage := nil; + end; +end; + +end. diff --git a/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/ujsextension_sp.pas b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/ujsextension_sp.pas new file mode 100644 index 00000000..4e0307cd --- /dev/null +++ b/demos/Lazarus_Windows/JavaScript/JSExtensionSubProcess/ujsextension_sp.pas @@ -0,0 +1,202 @@ +unit uJSExtension_sp; + +{$mode Delphi} + +interface + +procedure CreateGlobalCEFApp; + +implementation + +uses + uCEFApplicationCore, uCEFConstants, uCEFv8Value, uCEFInterfaces, uCEFMiscFunctions, + uTestExtensionHandler; + + +// BASIC CONCEPTS +// ============== + +// Chromium uses several processes to carry out all the tasks needed to handle a web page : +// 1. The main application process is called "BROWSER PROCESS" and it runs the UI. +// 2. The layout and interpretation of HTML is done in the "RENDERER PROCESS". + +// Read this for more details about Chromium's architecture : +// http://www.chromium.org/developers/design-documents/multi-process-architecture + +// Each process is isolated from the rest and you need to use some kind of inter-process +// communication (IPC) to send information between them. This isolation and protection is +// guaranteed by the operating system and it's the main reason Chromium uses several processes. + +// In many cases, you need to use JavaScript or visit the DOM to return some results to Delphi. +// The DOM and JavaScript live in the RENDERER PROCESS, while the Delphi code of your application +// lives in the BROWSER PROCESS. + +// As commented before, the operating system isolates each process and this means that you +// can't access anything declared in one process like variables, fields, classes, controls, etc. +// from a different process. + +// However, CEF has several ways to send information between processes and you can also use your +// own inter-process communication methods. + +// If you need to execute some JavaScript code all you need is to call TChromium.ExecuteJavaScript +// from your application's code in the BROWSER PROCESS and CEF will take care of executing that +// code in the RENDERER PROCESS. + +// If you need to send a message to the RENDERER PROCESS from the BROWSER PROCESS you can use +// TChromium.SendProcessMessage. + +// To send messages to the BROWSER PROCESS from the RENDERER PROCESS you can use +// ICefFrame.SendProcessMessage + + +// -------------- TChromium.SendProcessMessage -------------- +// | | ------------------------------> | | +// | BROWSER | | RENDERER | +// | | | | +// | PROCESS | ICefFrame.SendProcessMessage | PROCESS | +// | | <------------------------------ | | +// -------------- -------------- + + +// To receive the messages sent from the RENDERER PROCESS you need to use the +// TChromium.OnProcessMessageReceived event. This event is executed in a CEF thread that belongs +// to the BROWSER PROCESS. + +// To receive the messages sent from the BROWSER PROCESS you need to use the +// TCefApplication.OnProcessMessageReceived event (GlobalCEFApp.OnProcessMessageReceived). +// This event is executed in a CEF thread that belongs to the RENDERER PROCESS. + + +// JAVASCRIPT EXTENSIONS +// ===================== + +// CEF exposes a large number of JS features for integration in client applications. +// You can use JS types, arrays, functions, extensions, objects, etc. + +// All of those features are described in detail here : +// https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md + +// One of the most interesting JS features available in CEF are the JavaScript extensions because they +// can be used to execute custom Delphi code from JavaScript. + +// If you put all you know so far together you can get any result or information in Delphi from +// JavaScript following these steps : +// 1. Use TChromium.ExecuteJavaScript to execute your custom JavaScript code. +// 2. That custom JavaScript code is executed in the RENDERER PROCESS and it can call functions in your +// custom JavaScript extension, which executes Delphi code. This Delphi code is also executed in +// the RENDERER PROCESS. +// 3. The Delphi code in the JavaScript extension can use ICefFrame.SendProcessMessage to send +// information back to the BROWSER PROCESS. +// 4. The BROWSER PROCESS receives the information in the TChromium.OnProcessMessageReceived event. + +// To create a JavaScript extension in CEF you have to create a new class that inherits from +// TCefv8HandlerOwn and it has to override the "execute" function. Open uTestExtensionHandler.pas +// to see an example and read this for more details about the "execute" parameters : +// https://magpcss.org/ceforum/apidocs3/projects/(default)/CefV8Handler.html + +// In order to use that extension, you must register it in the GlobalCEFApp.OnWebKitInitialized event +// as you can see in the GlobalCEFApp_OnWebKitInitialized procedure on this PAS unit. + +// You have to call the CefRegisterExtension function with 3 parameters : +// 1. name : The extension name. +// 2. code : Any valid JS code but in this case it includes 2 "native function" forward declarations. +// 3. Handler : An instance of your TCefv8HandlerOwn subclass. + +// Notice that the code used with the CefRegisterExtension function in this demo is declaring +// "myextension.mouseover" as a function that calls the "mouseover" native function, and the +// "myextension.sendresulttobrowser" function that calls the "sendresulttobrowser" native function. + +// The "execute" function in the custom TCefv8HandlerOwn subclass will compare the "name" parameter +// with the name of the of the native function used in the code that registered this extension. +// As you can see in this demo, TTestExtensionHandler.Execute compares the "name" parameter with +// "mouseover" and "sendresulttobrowser" to execute the code you want for each of those custom functions. + +// TTestExtensionHandler.Execute is executed in the RENDERER PROCESS and it uses a process message +// to send some results to he BROWSER PROCESS. +// It uses TCefv8ContextRef.Current.Browser.MainFrame to call the SendProcessMessage procedure for +// the main frame. + +// The message is a TCefProcessMessageRef instance and you can set the information you want to send using +// its ArgumentList property. + +// You can add several items to ArgumentList using different indexes in the SetString, SetInt, SetBool, +// SetBinary, etc. functions. +// There is a size limit in the binary parameters of only a few kilobytes. Compress the binary data, use +// alternative IPC methods or use a database protected by a mutex if necessary. + +// For more information about this, read the following pages : +// https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md#markdown-header-functions-and-extensions +// https://bitbucket.org/chromiumembedded/cef/src/b6b033a52bb3f7059d169a4c8389966c8fe2531b/include/capi/cef_v8_capi.h#lines-924 + + +// TESTING THIS DEMO : +// =================== +// 1. Run the demo and wait until google.com is loaded +// 2. Right-click and select the "Set the mouseover event" menu option. +// 3. Move the mouse pointer over the web page and see the HTML elements in the status bar. + +// When you select the "Set the mouseover event" menu option, the +// TChromium.OnContextMenuCommand event is triggered and it adds an event listener to the +// document's body. That listener calls one of the functions available in the registered +// extension called "myextension.mouseover". + +// The TTestExtensionHandler.Execute function in the extension is executed and it +// uses TCefv8ContextRef.Current.Browser.MainFrame.SendProcessMessage(PID_BROWSER, msg) +// to send a process message with the results to the browser process. + +// That message is received in the TChromium.OnProcessMessageReceived event and it shows +// the information in the status bar. + +// If you have to debug the code executed by the extension you will need to use the +// debugging methods described in +// https://www.briskbard.com/index.php?lang=en&pageid=cef + +procedure GlobalCEFApp_OnWebKitInitialized; +var + TempExtensionCode : string; + TempHandler : ICefv8Handler; +begin + try + // This is a JS extension example with 2 functions and several parameters. + // Please, read the "JavaScript Integration" wiki page at + // https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md + + TempExtensionCode := 'var myextension;' + + 'if (!myextension)' + + ' myextension = {};' + + '(function() {' + + ' myextension.mouseover = function(a) {' + + ' native function mouseover();' + + ' mouseover(a);' + + ' };' + + ' myextension.sendresulttobrowser = function(b,c) {' + + ' native function sendresulttobrowser();' + + ' sendresulttobrowser(b,c);' + + ' };' + + '})();'; + + TempHandler := TTestExtensionHandler.Create; + + if CefRegisterExtension('myextension', TempExtensionCode, TempHandler) then + {$IFDEF DEBUG}CefDebugLog('JavaScript extension registered successfully!'){$ENDIF} + else + {$IFDEF DEBUG}CefDebugLog('There was an error registering the JavaScript extension!'){$ENDIF}; + finally + TempHandler := nil; + end; +end; + +procedure CreateGlobalCEFApp; +begin + GlobalCEFApp := TCefApplicationCore.Create; + GlobalCEFApp.OnWebKitInitialized := GlobalCEFApp_OnWebKitInitialized; + GlobalCEFApp.SetCurrentDir := True; + {$IFDEF DEBUG} + GlobalCEFApp.LogFile := 'debug.log'; + GlobalCEFApp.LogSeverity := LOGSEVERITY_INFO; + {$ENDIF} + GlobalCEFApp.StartSubProcess; +end; + +end. + diff --git a/update_CEF4Delphi.json b/update_CEF4Delphi.json index 787b0f9e..e65fddf4 100644 --- a/update_CEF4Delphi.json +++ b/update_CEF4Delphi.json @@ -2,7 +2,7 @@ "UpdateLazPackages" : [ { "ForceNotify" : true, - "InternalVersion" : 559, + "InternalVersion" : 560, "Name" : "cef4delphi_lazarus.lpk", "Version" : "121.3.4" }