TChromium how to block middle mouse click on the links? - delphi

How to block middle mouse click on the links in TChromium?
I want to handle this middle mouse click by my own to open it in new tab, so i need to block this middle mouse click in TChromium, and then hook middle mouse, and then open selected link in new tab.
I have this default function:
function TCustomRenderProcessHandler.OnBeforeNavigation(const browser: ICefBrowser;
const frame: ICefFrame; const request: ICefRequest;
navigationType: TCefNavigationType; isRedirect: Boolean): Boolean;
begin
Result:=False;
end;
But exactly it gives nothing.
TNX

I did it by some another way.
#TLama, thanks for fast working Hook Function.
So, how i did it:
//#HOOK PROC
function MouseProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var
HookStruct: TMouseHookStruct;
begin
HookStruct := PMouseHookStruct(lParam)^;
if (nCode >= 0) then
begin
case wParam of
WM_MBUTTONDOWN:
Begin
MiddleDown := True;
LeftMouse := False;
End;
WM_LBUTTONDOWN:
Begin
MiddleDown := False;
LeftMouse := True;
End;
WM_RBUTTONDOWN:
Begin
MiddleDown := False;
LeftMouse := False;
End;
end;
end;
Result := CallNextHookEx(0, nCode, wParam, lParam);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
If(MiddleDown) then
Begin
MiddleDown:=False;
If(SelectedItem<>'') Then
Form1.AddNewTab(SelectedItem,SelectedItem,'');
End
Else If(LeftMouse) then
Begin
LeftMouse:=False;
If(SelectedItem<>'') Then
FBrowsers[Current_FBrowser_Index].Load(SelectedItem);
End;
end;
function TCustomRenderProcessHandler.OnBeforeNavigation(const browser: ICefBrowser;
const frame: ICefFrame; const request: ICefRequest;
navigationType: TCefNavigationType; isRedirect: Boolean): Boolean;
begin
if navigationType = NAVIGATION_LINK_CLICKED then
begin
Result := True;
end
else
Result := False;
end;
So, thats how it works in my DCEF3 :)
Thanks to all for help!!!

Related

How to detect that Taskbar Thumbnail Preview is being drawn when DWMWA_HAS_ICONIC_BITMAP is set

How to detect that Taskbar Thumbnail Preview is being drawn (because user is moving mouse over taskbar button) or is currently appearing on screen?
Why the code below does not make log entries when WM_DWMSENDICONICTHUMBNAIL msg should be arriving to form?
procedure TStartInfoForm.FormCreate(Sender: TObject);
begin
SetWindowAttribute(DWMWA_HAS_ICONIC_BITMAP);
end;
function TStartInfoForm.SetWindowAttribute(dwAttr: DWORD): HRESULT;
var
Attr: function(hwnd: hwnd; dwAttribute: DWORD; pvAttribute: Pointer;
cbAttribute: DWORD): HRESULT; stdcall;
hndDLLHandle : THandle;
EnableAttribute : DWORD;
begin
EnableAttribute := DWORD(true);
try
hndDLLHandle := loadLibrary('dwmapi.dll');
if hndDLLHandle <> 0 then
begin
Attr := getProcAddress(hndDLLHandle, 'DwmSetWindowAttribute');
if addr(Attr) <> nil then
Result := Attr(Handle, dwAttr, #EnableAttribute, SizeOf(EnableAttribute));
end;
finally
freeLibrary(hndDLLHandle);
end;
end;
procedure TStartInfoForm.WndProc(var Msg : TMessage);
begin
DebugNote(0,'wndproc '+inttohex(msg.Msg,3)+' w '+inttohex(Msg.wparam,3)+' l '+inttohex(Msg.lparam,3));
case Msg.Msg of
WM_DWMSENDICONICTHUMBNAIL :
begin
DebugNote(0,' iconiclive');
end;
WM_DWMSENDICONICLIVEPREVIEWBITMAP:
begin
DebugNote(0,' iconiclive2 ');
end;
WM_WINDOWPOSCHANGING:
begin
// MessageBeep(1);
end ;
WM_WINDOWPOSCHANGED:
begin
// MessageBeep(1);
end
end;
inherited;// call this for default behaveour
end;

How to minimize to the tray on FMX

I am creating a launcher for the apps of my work. I want that when I minimize the app, he goes to the tray. I manage to create the icon with a button (the click call the proc), but I don't know what events I need to call the proc, there is no event like Onminized and the event OnHide does not affect. I see some posts about using a Hook ( i am not pretty sure whats is), I try it, but I got an error:
[dcc32 Error] UMain.pas(129): E2036 Variable required.
This point here:
procedure TfrmMain.FormCreate(Sender: TObject);
begin
SetWindowsHookEx(WH_CALLWNDPROC, #WndProc, 0, GetCurrentThreadId);
end;
More specific to #wndProc, i try to remove the # and I got [dcc32 Error] UMain.pas(129): E2009 Incompatible types: 'regular procedure and method pointer'
Type...
function WndProc(Code: integer; WParam, LParam: LongInt): LRESULT; stdcall;
var
WndProcHook: THandle;
const
WM_TRAYICON =WM_USER+1;
------------------------------------------------------
procedure TfrmMain.FormCreate(Sender: TObject);
begin
SetWindowsHookEx(WH_CALLWNDPROC, #WndProc, 0, GetCurrentThreadId);
....
end;
function TfrmMain.WndProc(Code: integer; WParam, LParam: LongInt): LRESULT; stdcall;
var
msg: TCWPRetStruct;
begin;
if (Code >= HC_ACTION) and (LParam > 0) then begin
msg := PCWPRetStruct(LParam)^;
if (msg.Message = WM_SIZE) and (msg.WParam = SIZE_MINIMIZED) then begin
criaIcone;
end;
end;
result := CallNextHookEx(WndProcHook, Code, WParam, LParam)
end;
//
procedure TfrmMain.CriaIcone;
var
NotifyIconData: TNotifyIconData;
begin
with NotifyIconData do
begin
cbSize := SizeOf;
Wnd := AllocateHWnd(WMTrayIcon);
uID := 0;
uCallbackMessage:= WM_TRAYICON;
uFlags := NIF_ICON or NIF_TIP or NIF_MESSAGE;
hIcon := GetClassLong(FmxHandleToHWND(self.Handle),GCL_HICONSM);
szTip := 'Teste TrayIcon';
end;
Shell_NotifyIcon(NIM_ADD, #NotifyIconData);
end;
The problem is like the #RemyLebeau said. I am pretty new on Delphi ( 3 months)
Here is the code, I used a lot of code of this post : FMX - Trayicon message handling
The code that works:
type
....
procedure FormCreate(Sender: TObject);
procedure DestroyIcone;
const
WM_ICONTRAY = WM_USER + 1;
private
{ Private declarations }
create : integer;
TrayWnd: HWND;
TrayIconData: TNotifyIconData;
TrayIconAdded: Boolean;
procedure TrayWndProc(var Message: TMessage);
implementation
procedure TfrmMain.FormCreate(Sender: TObject);
begin
TrayWnd := AllocateHWnd(TRayWndProc); // Alocate the wndProc
with TrayIconData do
begin // Instaciate
cbSize := SizeOf;
Wnd := TrayWnd;
uID := 1;
uFlags := NIF_MESSAGE + NIF_ICON + NIF_TIP;
uCallbackMessage := WM_ICONTRAY;
hIcon := GetClassLong(FmxHandleToHWND(self.Handle), GCL_HICONSM);
StrPCopy(szTip, 'testapp');
end;
//creating the icon
if not TrayIconAdded then
TrayIconAdded := Shell_NotifyIcon(NIM_ADD, #TrayIconData) ;
procedure TfrmMain.TrayWndProc(var Message: TMessage);
begin
if Message.MSG = WM_ICONTRAY then
begin
case Message.LParam of
WM_LBUTTONDOWN:
begin
frmMain.Show;//If u use some frmMain.hide
SetForegroundWindow(FmxHandleToHWND(frmMAin.Handle));
if TrayIconAdded then
begin
//Shell_NotifyIcon(NIM_DELETE, #TrayIconData);
TrayIconAdded := false;
ShowAppOnTaskbar(frmMain);
end;
end;
WM_RBUTTONDOWN: ShowMessage('RolePlay , but can be a PopUpMenu');
end;
end
else
Message.Result := DefWindowProc(TrayWnd, Message.Msg, Message.WParam, Message.LParam);
end;

TWebbrowser / TEmbeddedWb : hide all messageboxes

I have an application that uses TEmbeddedWb to automate data scrapping tasks.
Some web-sites show messages / popup boxes when my app navigates to it, and these makes the process slower.
I want to block any messagebox that TWebbrowser could show.
I'm already setting the 'silent' property to true, and also setting the onshowmessage method as follow, but still the messageboxes are show. Any hints ?
function TForm1.webShowMessage(Sender: TObject; HWND: Cardinal; lpstrText,
lpstrCaption: PWideChar; dwType: Integer; lpstrHelpFile: PWideChar; dwHelpContext: Integer;
var plResult: Integer): HRESULT;
begin
plresult := S_OK;
end;
I could achieve these task by making some changes on TEmbeddedWb source, specifically on the functionbelow :
procedure TEmbeddedWB.HandleDialogBoxes(var AMsg: Messages.TMessage);
Here is the change :
DlgClss := GetWinClass(PopHandle);
WinClss := GetWinClass(Windows.GetParent(PopHandle));
DlgCaption := GetWinText(PopHandle);
if (DlgClss = 'Internet Explorer_TridentDlgFrame') or ((DlgClss = '#32770'))
// comment here to make all windows be evaluated
{and (WinClss <> 'TApplication') and
(FindControl(Windows.GetParent(PopHandle)) = nil))}
then
begin
if (WinClss = 'TApplication') or (FindControl(Windows.GetParent(PopHandle)) <> nil) then
begin
if pos('web browser',lowercase(DlgCaption)) = 0 then
exit;
end;
I just add this code Result := S_OK; on ShowMessage Event and no more popup message:
function TForm1.webShowMessage(Sender: TObject; HWND: Cardinal; lpstrText,
lpstrCaption: PWideChar; dwType: Integer; lpstrHelpFile: PWideChar; dwHelpContext: Integer;
var plResult: Integer): HRESULT;
begin
Result := S_OK;
end;

Delphi XE2: Loading .EXE icon into MenuItem at run-time

At run-time, I want to load and show the main icon of a specific .EXE file in a specific MenuItem. When this is not possible for this specific .EXE file (e.g. due to access restrictions or similar), then the MenuItem icon should be set to a specific icon in a specific ImageList (e.g. MyMenuItem.ImageIndex := 7). How can this be done?
I think the simplest solution is to use ExtractIconEx. Here's a very simple example:
type
PHICON = ^HICON;
function ExtractIconEx(lpszFile: LPCWSTR; nIconIndex: Integer;
phiconLarge, phiconSmall: PHICON; nIcons: UINT): UINT; stdcall; external 'shell32.dll' name 'ExtractIconExW';
function GetSmallIconFromExecutableFile(const FileName: string): TIcon;
var
Icon: HICON;
ExtractedIconCount: UINT;
begin
Result := nil;
try
ExtractedIconCount := ExtractIconEx(
PChar(FileName),
0,
nil,
#Icon,
1
);
Win32Check(ExtractedIconCount=1);
Result := TIcon.Create;
Result.Handle := Icon;
except
Result.Free;
raise;
end;
end;
The icon associated with an executable file is the first one in the module. So you can extract it like this:
function EnumResNameProc(hModule: HMODULE; lpszType: LPCTSTR; lpszName: LPTSTR; lParam: LONG_PTR): BOOL; stdcall;
begin
HICON(Pointer(lParam)^) := LoadImage(
hModule,
lpszName,
IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
0
);
Result := False;
end;
function GetFirstSmallIcon(hmod: HMODULE): HICON;
begin
Result := 0;
EnumResourceNames(hmod, RT_GROUP_ICON, #EnumResNameProc, NativeInt(#Result));
end;
function GetSmallIconFromExecutableFile(const FileName: string): TIcon;
const
LOAD_LIBRARY_AS_IMAGE_RESOURCE = $00000020;
var
hmod: HMODULE;
Icon: HICON;
begin
Result := nil;
try
hmod := LoadLibraryEx(PChar(FileName), 0, LOAD_LIBRARY_AS_IMAGE_RESOURCE or LOAD_LIBRARY_AS_DATAFILE);
Win32Check(hmod<>0);
try
Icon := GetFirstSmallIcon(hmod);
if Icon<>0 then begin
Result := TIcon.Create;
Result.Handle := Icon;
end;
finally
FreeLibrary(hmod);
end;
except
Result.Free;
raise;
end;
end;

Enumerating DOM nodes in TChromium

I am trying to enumerate DOM nodes using the following code (under XE2).
I have borrowed most of this from answers given here in SO, but for some reason it's not doing anything.
IOW, ProcessDOM() is not ever getting called.
And, I am at my wits end.
Could someone show me what I am doing wrong here.
Thanks in advance.
procedure ProcessNode(ANode: ICefDomNode);
var
Node1: ICefDomNode;
begin
if Assigned(ANode) then begin
Node1 := ANode.FirstChild;
while Assigned(Node1) do begin
{Do stuff with node}
ProcessNode(Node1);
Node1 := Node1.NextSibling;
end;
end;
end;
procedure ProcessDOM(const ADocument: ICefDomDocument);
begin
ProcessNode(ADocument.Body);
end;
procedure TMainForm.Chrome1LoadEnd(Sender: TObject; const ABrowser: ICefABrowser; const AFrame: ICefAFrame; AStatus: Integer);
begin
if Assigned(AFrame) then AFrame.VisitDomProc(ProcessDOM);
end;
I had the same problem and I used the demo guiclient it comes with dcef3. With the following it works.
type TCustomRenderProcessHandler = class(TCefRenderProcessHandlerOwn)
protected
function OnProcessMessageReceived(const browser: ICefBrowser; sourceProcess: TCefProcessId; const message: ICefProcessMessage): Boolean; override;
end;
Chromium1.browser.SendProcessMessage(PID_RENDERER, TCefProcessMessageRef.New('visitdom'));
function TCustomRenderProcessHandler.OnProcessMessageReceived(browser: ICefBrowser; sourceProcess: TCefProcessId; message: ICefProcessMessage): Boolean;
begin
if (message.Name = 'visitdom') then begin
browser.MainFrame.VisitDomProc(
procedure(const doc: ICefDomDocument)
begin
ProcessNode(Doc.Body);
end);
Result := True;
end;
end;
initialization
CefRenderProcessHandler := TCustomRenderProcessHandler.Create;
You need to add a procedure to the handler.
procedure ProcessNode(ANode: ICefDomNode);
Read this: 1
As this blog point out, The main difficulty when accessing a rendered page's DOM is that you can only do so in the same process as the associated renderer for that page.
You can't access dom from browser thread, you have to do it in renderer thread.
First, Forward a message (like visitdom) from browser process to rendering process
procedure TMainForm.crmLoadEnd(Sender: TObject; const browser: ICefBrowser;
const frame: ICefFrame; httpStatusCode: Integer);
var
msg : ICefProcessMessage;
begin
if IsMain(browser, frame) then
FLoading := False;
msg := TCefProcessMessageRef.New('visitdom');
browser.SendProcessMessage(PID_RENDERER, msg);
end;
Second, create a TCustomRenderProcessHandler to handle the message, send the result back to the browser processs.
function TCustomRenderProcessHandler.OnProcessMessageReceived(
const browser: ICefBrowser; sourceProcess: TCefProcessId;
const message: ICefProcessMessage): Boolean;
begin
Result := False;
if (message.Name = 'visitdom') then
begin
browser.MainFrame.VisitDomProc(
procedure(const doc: ICefDomDocument)
function ProcessNode(ANode: ICefDomNode) : String;
var
Node: ICefDomNode;
begin
Result := 'Not Found';
if Assigned(ANode) then
begin
Node := ANode.FirstChild;
while Assigned(Node) do
begin
if Node.ElementTagName='DIV' then
begin
if Node.GetElementAttribute('class')='tv-panels' then
begin
Result := 'Found';
Exit;
end;
end;
ProcessNode(Node);
Node := Node.NextSibling;
end;
end;
end;
var msg : ICefProcessMessage;
begin
msg := TCefProcessMessageRef.New('visitdom');
msg.ArgumentList.SetString(0, processNode(doc.Body));
browser.SendProcessMessage(PID_BROWSER, msg);
end);
Result := True;
end;
end;
Third, On browser process, create an handler to process the messenage sent back from render process.
procedure TMainForm.crmProcessMessageReceived(Sender: TObject;
const browser: ICefBrowser; sourceProcess: TCefProcessId;
const message: ICefProcessMessage; out Result: Boolean);
begin
Result := False;
if (message.Name = 'visitdom') then
begin
StatusBar.SimpleText := message.ArgumentList.GetString(0);
Result := True;
end;
end;
Be careful, while debuging, placing a breakpoint in rendering process never work. It will never reached there.

Resources