Reputation: 8063
I have a frame which contains a TWebBrowser
component and is used by some of my applications and I need to disable the TWebBrowser
's default popup menu.
I found a solution which works at the application level, by using a TApplicationEvents
component and its OnMessage
event handler this way:
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
var Handled: Boolean);
begin
if (Msg.Message = WM_RBUTTONDOWN) or (Msg.Message = WM_RBUTTONDBLCLK) then
begin
if IsChild(WebBrowser1.Handle, Msg.hwnd) then
begin
Handled := True;
end;
end;
end;
I'm looking for a solution which works at the frame/TWebBrowser
's level, without requiring to add code at the application level.
I've tried assigning the TWebBrowser
's TPopupMenu
property, but it only works before loading the page on the WebBrowser.
I've tried assigning the TWebBrowser
's WindowProc
but after a page has been loaded in the WebBrowser, the code is no more executed.
private
FPrevBrowWindowProc : TWndMethod;
procedure BrowWindowProc(var AMessage: TMessage);
...
procedure TFrame1.BrowWindowProc(var AMessage: TMessage);
begin
if(AMessage.Msg = WM_RBUTTONDOWN) or (AMessage.Msg = WM_RBUTTONDBLCLK) then
Exit;
if(Assigned(FPrevBrowWindowProc))
then FPrevBrowWindowProc(AMessage);
end;
constructor TFrame1.Create(AOwner : TComponent);
begin
inherited;
FPrevBrowWindowProc := WebBrowser1.WindowProc;
VS_Brow.WindowProc := BrowWindowProc;
end;
Upvotes: 3
Views: 1259
Reputation: 335
Here is a solution when using IE. Maybe someone would have a solution for me how to do it with Edge TEdgeBrowser Popup menu!
The following unit from P D Johnson, http://www.delphidabbler.com/articles?article=22 is required for implementation. I do not know the new URL address, sorry.
{
This demo application accompanies the article
"How to call Delphi code from scripts running in a TWebBrowser" at
http://www.delphidabbler.com/articles?article=22.
This unit provides a do-nothing implementation of a web browser OLE container
object
This code is copyright (c) P D Johnson (www.delphidabbler.com), 2005-2006.
v1.0 of 2005/05/09 - original version named UBaseUIHandler.pas
v2.0 of 2006/02/11 - total rewrite based on unit of same name from article at
http://www.delphidabbler.com/articles?article=22
}
{$A8,B-,C+,D+,E-,F-,G+,H+,I+,J-,K-,L+,M-,N+,O+,P+,Q-,R-,S-,T-,U-,V+,W-,X+,Y+,Z1}
{$WARN UNSAFE_TYPE OFF}
unit UContainerBasis;
interface
uses
Winapi.Windows, Winapi.ActiveX, Winapi.Mshtmhst, SHDocVw;
type
TContainerBasis = class(TObject,
IUnknown, IOleClientSite, IDocHostUIHandler)
private
fHostedBrowser: TWebBrowser;
// Registration method
procedure SetBrowserOleClientSite(const Site: IOleClientSite);
protected
{ IUnknown }
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
{ IOleClientSite }
function SaveObject: HResult; stdcall;
function GetMoniker(dwAssign: Longint;
dwWhichMoniker: Longint;
out mk: IMoniker): HResult; stdcall;
function GetContainer(
out container: IOleContainer): HResult; stdcall;
function ShowObject: HResult; stdcall;
function OnShowWindow(fShow: BOOL): HResult; stdcall;
function RequestNewObjectLayout: HResult; stdcall;
{ IDocHostUIHandler }
function ShowContextMenu(const dwID: DWORD; const ppt: PPOINT;
const pcmdtReserved: IUnknown; const pdispReserved: IDispatch): HResult;
stdcall;
function GetHostInfo(var pInfo: TDocHostUIInfo): HResult; stdcall;
function ShowUI(const dwID: DWORD;
const pActiveObject: IOleInPlaceActiveObject;
const pCommandTarget: IOleCommandTarget; const pFrame: IOleInPlaceFrame;
const pDoc: IOleInPlaceUIWindow): HResult; stdcall;
function HideUI: HResult; stdcall;
function UpdateUI: HResult; stdcall;
function EnableModeless(const fEnable: BOOL): HResult; stdcall;
function OnDocWindowActivate(const fActivate: BOOL): HResult; stdcall;
function OnFrameWindowActivate(const fActivate: BOOL): HResult; stdcall;
function ResizeBorder(const prcBorder: PRECT;
const pUIWindow: IOleInPlaceUIWindow; const fFrameWindow: BOOL): HResult;
stdcall;
function TranslateAccelerator(const lpMsg: PMSG; const pguidCmdGroup: PGUID;
const nCmdID: DWORD): HResult; stdcall;
function GetOptionKeyPath(var pchKey: POLESTR; const dw: DWORD ): HResult;
stdcall;
function GetDropTarget(const pDropTarget: IDropTarget;
out ppDropTarget: IDropTarget): HResult; stdcall;
function GetExternal(out ppDispatch: IDispatch): HResult; stdcall;
function TranslateUrl(const dwTranslate: DWORD; const pchURLIn: POLESTR;
var ppchURLOut: POLESTR): HResult; stdcall;
function FilterDataObject(const pDO: IDataObject;
out ppDORet: IDataObject): HResult; stdcall;
public
constructor Create(const HostedBrowser: TWebBrowser);
destructor Destroy; override;
property HostedBrowser: TWebBrowser read fHostedBrowser;
end;
implementation
uses
System.SysUtils;
{ TNulWBContainer }
constructor TContainerBasis.Create(const HostedBrowser: TWebBrowser);
begin
Assert(Assigned(HostedBrowser));
inherited Create;
fHostedBrowser := HostedBrowser;
SetBrowserOleClientSite(Self as IOleClientSite);
end;
destructor TContainerBasis.Destroy;
begin
SetBrowserOleClientSite(nil);
inherited;
end;
function TContainerBasis.EnableModeless(const fEnable: BOOL): HResult;
begin
{ Return S_OK to indicate we handled (ignored) OK }
Result := S_OK;
end;
function TContainerBasis.FilterDataObject(const pDO: IDataObject;
out ppDORet: IDataObject): HResult;
begin
{ Return S_FALSE to show no data object supplied.
We *must* also set ppDORet to nil }
ppDORet := nil;
Result := S_FALSE;
end;
function TContainerBasis.GetContainer(
out container: IOleContainer): HResult;
{Returns a pointer to the container's IOleContainer
interface}
begin
{ We do not support IOleContainer.
However we *must* set container to nil }
container := nil;
Result := E_NOINTERFACE;
end;
function TContainerBasis.GetDropTarget(const pDropTarget: IDropTarget;
out ppDropTarget: IDropTarget): HResult;
begin
{ Return E_FAIL since no alternative drop target supplied.
We *must* also set ppDropTarget to nil }
ppDropTarget := nil;
Result := E_FAIL;
end;
function TContainerBasis.GetExternal(out ppDispatch: IDispatch): HResult;
begin
{ Return E_FAIL to indicate we failed to supply external object.
We *must* also set ppDispatch to nil }
ppDispatch := nil;
Result := E_FAIL;
end;
function TContainerBasis.GetHostInfo(var pInfo: TDocHostUIInfo): HResult;
begin
{ Return S_OK to indicate UI is OK without changes }
Result := S_OK;
end;
function TContainerBasis.GetMoniker(dwAssign, dwWhichMoniker: Integer;
out mk: IMoniker): HResult;
{Returns a moniker to an object's client site}
begin
{ We don't support monikers.
However we *must* set mk to nil }
mk := nil;
Result := E_NOTIMPL;
end;
function TContainerBasis.GetOptionKeyPath(var pchKey: POLESTR;
const dw: DWORD): HResult;
begin
{ Return E_FAIL to indicate we failed to override
default registry settings }
Result := E_FAIL;
end;
function TContainerBasis.HideUI: HResult;
begin
{ Return S_OK to indicate we handled (ignored) OK }
Result := S_OK;
end;
function TContainerBasis.OnDocWindowActivate(
const fActivate: BOOL): HResult;
begin
{ Return S_OK to indicate we handled (ignored) OK }
Result := S_OK;
end;
function TContainerBasis.OnFrameWindowActivate(
const fActivate: BOOL): HResult;
begin
{ Return S_OK to indicate we handled (ignored) OK }
Result := S_OK;
end;
function TContainerBasis.OnShowWindow(fShow: BOOL): HResult;
{Notifies a container when an embedded object's window
is about to become visible or invisible}
begin
{ Return S_OK to pretend we've responded to this }
Result := S_OK;
end;
function TContainerBasis.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
if GetInterface(IID, Obj) then
Result := S_OK
else
Result := E_NOINTERFACE;
end;
function TContainerBasis.RequestNewObjectLayout: HResult;
{Asks container to allocate more or less space for
displaying an embedded object}
begin
{ We don't support requests for a new layout }
Result := E_NOTIMPL;
end;
function TContainerBasis.ResizeBorder(const prcBorder: PRECT;
const pUIWindow: IOleInPlaceUIWindow; const fFrameWindow: BOOL): HResult;
begin
{ Return S_FALSE to indicate we did nothing in response }
Result := S_FALSE;
end;
function TContainerBasis.SaveObject: HResult;
{Saves the object associated with the client site}
begin
{ Return S_OK to pretend we've done this }
Result := S_OK;
end;
procedure TContainerBasis.SetBrowserOleClientSite(
const Site: IOleClientSite);
var
OleObj: IOleObject;
begin
Assert((Site = Self as IOleClientSite) or (Site = nil));
if not Supports(
fHostedBrowser.DefaultInterface, IOleObject, OleObj
) then
raise Exception.Create(
'Browser''s Default interface does not support IOleObject'
);
OleObj.SetClientSite(Site);
end;
function TContainerBasis.ShowContextMenu(const dwID: DWORD;
const ppt: PPOINT; const pcmdtReserved: IInterface;
const pdispReserved: IDispatch): HResult;
begin
{ Return S_FALSE to notify we didn't display a menu and to
let browser display its own menu }
Result := S_FALSE
end;
function TContainerBasis.ShowObject: HResult;
{Tells the container to position the object so it is
visible to the user}
begin
{ Return S_OK to pretend we've done this }
Result := S_OK;
end;
function TContainerBasis.ShowUI(const dwID: DWORD;
const pActiveObject: IOleInPlaceActiveObject;
const pCommandTarget: IOleCommandTarget; const pFrame: IOleInPlaceFrame;
const pDoc: IOleInPlaceUIWindow): HResult;
begin
{ Return S_OK to say we displayed own UI }
Result := S_OK;
end;
function TContainerBasis.TranslateAccelerator(const lpMsg: PMSG;
const pguidCmdGroup: PGUID; const nCmdID: DWORD): HResult;
begin
{ Return S_FALSE to indicate no accelerators are translated }
Result := S_FALSE;
end;
function TContainerBasis.TranslateUrl(const dwTranslate: DWORD;
const pchURLIn: POLESTR; var ppchURLOut: POLESTR): HResult;
begin
{ Return E_FAIL to indicate that no translations took place }
Result := E_FAIL;
end;
function TContainerBasis.UpdateUI: HResult;
begin
{ Return S_OK to indicate we handled (ignored) OK }
Result := S_OK;
end;
function TContainerBasis._AddRef: Integer;
begin
Result := -1;
end;
function TContainerBasis._Release: Integer;
begin
Result := -1;
end;
end.
And here is the actual program: UMain.pas
unit UMain;
interface
uses
Winapi.Windows, Winapi.Messages, Winapi.ActiveX, Winapi.Mshtmhst,
System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.OleCtrls, Vcl.Edge, SHDocVw,
Vcl.Menus, UContainerBasis, Vcl.StdCtrls;
const
HTML= '<!DOCTYPE html><html lang="de"><head><title>Hallo Welt</title><style type="text/css">' +
'.verlauf{font-size:27px;-webkit-background-clip: text;-webkit-text-fill-color: transparent;' +
'background-color: #ba254c;background-image: linear-gradient(to right,#ba254c 30%,#392ea4 70%);' +
'background-size: cover;background-position: center center;}</style>' +
'</head><body><b class="verlauf">Hallöchen - Welt!</b></body></html>';
type
TWBContainer = class(TContainerBasis, IDocHostUIHandler, IOleClientSite)
private
FbUserPopUp: boolean;
protected
function ShowContextMenu(const AiID: DWORD; const ApptPos: PPOINT;
const AptrCmdtReserved: IUnknown;
const AptrDispReserved: IDispatch): HResult; stdcall;
public
property bUserPopUp: Boolean read FbUserPopUp
write FbUserPopUp default False;
end;
TForm1 = class(TForm)
WebIE: TWebBrowser;
Splitter1: TSplitter;
WebEdge: TWebBrowser;
mnp: TPopupMenu;
Eins1: TMenuItem;
Zwei1: TMenuItem;
Drei1: TMenuItem;
Panel1: TPanel;
chkIE: TCheckBox;
chkEdge: TCheckBox;
procedure FormActivate(Sender: TObject);
procedure chkIEClick(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
FEdge : TEdgeBrowser;
FWbIe : TWBContainer;
FWbEdge: TWBContainer;
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
implementation
uses
System.Rtti;
{$R *.dfm}
function TWBContainer.ShowContextMenu(const AiID: DWORD; const ApptPos: PPOINT;
const AptrCmdtReserved: IUnknown;
const AptrDispReserved: IDispatch): HResult; stdcall;
begin
if bUserPopUp then
begin
Result := S_OK; // Ok. I do it myself.
if Assigned(HostedBrowser.PopupMenu) then
HostedBrowser.PopupMenu.Popup(ApptPos.X, ApptPos.Y); //Show own Popup
end
else
Result := S_FALSE; // Orign Popup. You do it
end;
procedure TForm1.chkIEClick(Sender: TObject);
begin
if Sender = chkIE then
FWbIe.bUserPopUp := chkIE.Checked
else
FWbEdge.bUserPopUp := chkEdge.Checked
end;
procedure TForm1.FormActivate(Sender: TObject);
var
doc: variant;
LcT: string;
rtC: TRttiContext;
rtT: TRttiType;
rtF: TRttiField;
begin
OnActivate := nil;
FWbIe := nil;
FWbEdge := nil;
Top := 50;
Height := 600;
Width := 600;
WebIE.Height := 270;
WebIE.PopupMenu := mnp;
FWbIe := TWBContainer.Create(WebIE);
FWbIe.bUserPopUp := chkIE.Checked;
WebIE.Navigate('about:blank');
doc := WebIE.Document;
doc.clear;
doc.write(HTML);
doc.close;
LcT := ExtractFilePath(ParamStr(0));
LcT := LcT + 'WebView2Loader.dll';
if not FileExists(LcT) then
raise Exception.Create('WebView2Loader.dll not found!');
WebEdge.PopupMenu := mnp;
try
FWbEdge := TWBContainer.Create(WebEdge);
FWbEdge.bUserPopUp := chkEdge.Checked;
chkEdge.Enabled := true;
except
on E: Exception do
ShowMessage(Format('Error %s; %s', [E.Message, E.ClassName]));
end;
//to trigger CreateWebView
WebEdge.Navigate('about:blank');
//doc := WebEdge.Document; //0 !!!
//WebEdge.Navigate(HTML);
//Exit;
//Psalm 130, 1
// Out of the depths I cry to you, Lord.
// https://www.youtube.com/watch?v=lm84E2At9Zk
rtc := TRttiContext.Create;
try
rtt := rtc.GetType(TWebBrowser);
rtF := rtt.GetField('FEdge');
FEdge := rtF.GetValue(WebEdge).AsObject as TEdgeBrowser;
finally
rtF.Free;
rtt.Free;
end;
while FEdge.BrowserControlState = TCustomEdgeBrowser.TBrowserControlState.Creating do
begin
Application.ProcessMessages;
end;
FEdge.NavigateToString(HTML);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FreeAndNil(FWbIe);
FreeAndNil(FWbEdge);
end;
end.
UMain.dfm:
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 289
ClientWidth = 554
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnActivate = FormActivate
OnDestroy = FormDestroy
PixelsPerInch = 96
TextHeight = 13
object Splitter1: TSplitter
Left = 0
Top = 185
Width = 554
Height = 3
Cursor = crVSplit
Align = alTop
ExplicitTop = 150
ExplicitWidth = 139
end
object Panel1: TPanel
Left = 0
Top = 0
Width = 554
Height = 35
Align = alTop
TabOrder = 2
object chkIE: TCheckBox
Left = 19
Top = 9
Width = 97
Height = 17
Caption = 'IE PopUp'
Checked = True
State = cbChecked
TabOrder = 0
OnClick = chkIEClick
end
object chkEdge: TCheckBox
Left = 114
Top = 10
Width = 97
Height = 17
Caption = 'Edge PopUp'
Enabled = False
TabOrder = 1
OnClick = chkIEClick
end
end
object WebIE: TWebBrowser
Left = 0
Top = 35
Width = 554
Height = 150
Align = alTop
PopupMenu = mnp
TabOrder = 0
ExplicitLeft = 144
ExplicitTop = 40
ExplicitWidth = 300
ControlData = {
4C00000042390000810F00000000000000000000000000000000000000000000
000000004C000000000000000000000001000000E0D057007335CF11AE690800
2B2E126209000000000000004C0000000114020000000000C000000000000046
8000000000000000000000000000000000000000000000000000000000000000
00000000000000000100000000000000000000000000000000000000}
end
object WebEdge: TWebBrowser
Left = 0
Top = 188
Width = 554
Height = 101
Align = alClient
PopupMenu = mnp
TabOrder = 1
SelectedEngine = EdgeOnly
ExplicitLeft = 168
ExplicitTop = 156
ExplicitWidth = 300
ExplicitHeight = 150
ControlData = {
4C00000042390000700A00000000000000000000000000000000000000000000
000000004C000000000000000000000001000000E0D057007335CF11AE690800
2B2E126209000000000000004C0000000114020000000000C000000000000046
8000000000000000000000000000000000000000000000000000000000000000
00000000000000000100000000000000000000000000000000000000}
end
object mnp: TPopupMenu
Left = 432
Top = 40
object Eins1: TMenuItem
Caption = 'Eins'
end
object Zwei1: TMenuItem
Caption = 'Zwei'
end
object Drei1: TMenuItem
Caption = 'Drei'
end
end
end
Upvotes: 1