Disable Ctrl+P (Print) on WebBrowser control - delphi

i use webbrowser in my delphi application . how can i disable Ctrl+P to prevent print ?

Look at the code below :
var
mClass : Array[0..1024] of Char;
begin
if (GetClassName(Msg.hwnd, mClass, 1024) > 0) then
begin
if (StrIComp(#mClass, 'Internet Explorer_Server') = 0) then
begin
if Msg.message = WM_KEYDOWN then
Handled := (Msg.wParam = Ord('P')) and (GetKeyState(VK_CONTROL) <> 0);
end
end;
end;
To prevent messages sent to a TWebBrowser control , we can get the class name of message receiver and then compare the class name with "Internet Explorer_Server" that is the IE Server Calss Name , if class-names where equal then you can make sure that the message sent to WebBrowser Control , now you can Handle Message arrived ...
In the code above we do this to Handle Ctrl+P Shortcut , but you can use this idea for more like disabling Context Menu or ...
Notice that when a page loaded in the WebBrowser , messages will post to IE Server not to TWebBrowser Handle ...
First Put a TApplicationEvents on the Form , next Copy/Paste code from here to it`s OnMessage Event ...
Good Luck ...

I used EmbeddedWB and my problem solved via this tiny code :
procedure TForm1.EmbeddedWb1KeyDown(Sender: TObject; var Key: Word; ScanCode: Word;
Shift: TShiftState);
begin
Key := 0;
end;

This is an old thread, but I wanted to update with the method I found to work. This builds on the helpful post by #Mahmood_N.
Notice that I first wrote the code to get the class name, and compared that to 'Shell Embedding', which is what showed up for TWebBrowser messages (see here: https://support.microsoft.com/en-us/kb/244310). But my application will include more than one TWebBrowser, so I modified it to be better, by getting the window handle directly, and use that for comparison with the handle of the window message.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, AppEvnts, StdCtrls, OleCtrls, SHDocVw, ActiveX;
type
TForm1 = class(TForm)
WebBrowser: TWebBrowser;
ApplicationEvents1: TApplicationEvents;
procedure FormCreate(Sender: TObject);
procedure ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
private
{ Private declarations }
WBHandle : THandle;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function GetStrClassName(Handle: THandle): String;
var
Buffer: array[0..MAX_PATH] of Char;
begin
Windows.GetClassName(Handle, #Buffer, MAX_PATH);
Result := String(Buffer);
end;
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
var
ClassName : string;
begin
ClassName := GetStrClassName(Msg.hwnd);
//if Pos('Shell Embedding', ClassName) > 0 then begin
if Msg.hwnd = WBHandle then begin
if Msg.message = WM_KEYDOWN then begin
Handled := (Msg.wParam = Ord('P')) and (GetKeyState(VK_CONTROL) <> 0);
end;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var Win : IOLEWindow;
WinHandle : HWND;
begin
WBHandle := 0;
if WebBrowser.ControlInterface.QueryInterface(IOleWindow, Win) = 0 then begin
if Win.GetWindow(WinHandle) = 0 then begin
WBHandle := WinHandle;
end;
end;
end;

Related

Unable to a print in Windows 10 when Delphi / QuickReport is within a DLL

Delphi 7 / QuickReport 5.02.2
We've used similar code for several years but have run into an issue recently now that we're migrating workstations to Windows 10. Previously, we were using Windows 7 and all was fine. Maybe there's something I'm missing or doing wrong?
Here's a simple test project I put together to test this. When the report is within a DLL every call to Printer.GetPrinter fails in Windows 10. Though, if the report is on a form within the main application it works fine.
Below is the code, and a zipped up folder for anyone that's interested. There is the dependency on QuickReport though, which can't be helped. Thanks for looking.
https://1drv.ms/u/s!AsbtokV75aocsXM6MQZcrvwpHKcg
DLL Project.
library test_dll;
uses
SysUtils,
Classes,
Forms,
report in 'report.pas' {report_test};
{$R *.res}
function Report_Print(PrinterName: Widestring): Integer; export;
var
Receipt: Treport_test;
begin
try
Receipt := Treport_test.Create(nil);
try
Receipt.Print(PrinterName);
Receipt.Close;
finally
Receipt.Free;
end;
except
Application.HandleException(Application.Mainform);
end;
Result := 1;
end;
exports
Report_Print;
begin
end.
Report Unit
unit report;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, QRCtrls, QuickRpt, ExtCtrls, Printers, QRpCtrls, QRPrntr;
type
Treport_test = class(TForm)
QuickRep1: TQuickRep;
DetailBand1: TQRBand;
TitleBand1: TQRBand;
QRLabel1: TQRLabel;
SummaryBand1: TQRBand;
QRLabel2: TQRLabel;
QRLabel3: TQRLabel;
private
{ Private declarations }
public
{ Public declarations }
procedure Print(const PrinterName: string);
end;
var
report_test: Treport_test;
procedure SetupPrinter(QuickRep: TQuickRep; const PrinterName: string);
function SelectPrinter(QuickRep: TQuickRep; const PrinterName: string): boolean;
implementation
var
DLL_QRPrinter: TQRPrinter;
{$R *.dfm}
function SelectPrinter(QuickRep: TQuickRep; const PrinterName: string): boolean;
var
i: integer;
compareLength: integer;
windowsPrinterName: string;
selectedPrinter: Integer;
defaultPrinterAvailable: Boolean;
begin
defaultPrinterAvailable := True;
try // an exception will occur if there is no default printer
i := Printer.printerIndex;
if i > 0 then ; // this line is here so Delphi does not generate a hint
except
defaultPrinterAvailable := False;
end;
compareLength := Length(PrinterName);
if (not Assigned(QuickRep.QRPrinter)) then
begin
QuickRep.QRPrinter := DLL_QRPrinter;
end;
// Look for the printer.
selectedPrinter := -1;
// Attempt #1: first try to find an exact match
for i := 0 to QuickRep.QRPrinter.Printers.Count - 1 do
begin
windowsPrinterName := Copy(QuickRep.QRPrinter.Printers.Strings[i], 1, compareLength);
if (UpperCase(windowsPrinterName) = UpperCase(PrinterName)) then
begin
selectedPrinter := i;
Break;
end;
end;
// Attempt #2: if no exact matches, look for the closest
if (selectedPrinter < 0) then
for i := 0 to QuickRep.QRPrinter.Printers.Count - 1 do
begin
windowsPrinterName := Copy(QuickRep.QRPrinter.Printers.Strings[i], 1, compareLength);
if (Pos(UpperCase(PrinterName), UpperCase(QuickRep.QRPrinter.Printers.Strings[i])) > 0) then
begin
selectedPrinter := i;
Break;
end;
end;
// Attempt #3: if no exact matches, and nothing close, use default printer
if (selectedPrinter < 0) and (defaultPrinterAvailable) then
selectedPrinter := QuickRep.Printer.printerIndex;
Result := False;
if (selectedPrinter > -1) then
begin
QuickRep.PrinterSettings.PrinterIndex := selectedPrinter;
Result := True;
end;
end;
procedure SetupPrinter(QuickRep: TQuickRep; const PrinterName: string);
begin
//check if we have the default printer instead of the selected printer
SelectPrinter(QuickRep, PrinterName);
QuickRep.Page.Units := Inches;
QuickRep.Page.Length := 11;
end;
procedure Treport_test.Print(const PrinterName: string);
begin
SetupPrinter(QuickRep1, PrinterName);
QuickRep1.Print;
end;
initialization
DLL_QRPrinter := TQRPrinter.Create(nil);
finalization
DLL_QRPrinter.Free;
DLL_QRPrinter := nil;
end.
Test Application
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Main Form
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, QRPrntr,
Dialogs, StdCtrls, QuickRpt, QRCtrls, ExtCtrls, Printers, QRPCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
type
TPrintReport = function(PrinterName: Widestring): Integer;
var
Form1: TForm1;
procedure PrintReport(const PrinterName: string);
implementation
var
DLLHandle: THandle = 0;
POS: TPrintReport = nil;
{$R *.dfm}
procedure PrintReport(const PrinterName: string);
begin
try
POS(PrinterName);
except on e: Exception do
ShowMessage(e.Message);
end;
end;
procedure LoadDLL;
var
DLLName: string;
DLLRoutine: PChar;
begin
DLLName := 'test_dll.dll';
DLLRoutine := 'Report_Print';
if not (FileExists(DLLName)) then
raise Exception.CreateFmt('The DLL "%s" is missing. Build the DLL project and try again.', [DLLName]);
Application.ProcessMessages;
DLLHandle := LoadLibrary(PChar(DLLName));
Application.ProcessMessages;
if (DLLHandle = 0) then
raise Exception.CreateFmt('Error: %s, while attempting to load DLL %s.', [IntToStr(GetLastError), DLLName]);
POS := GetProcAddress(DLLHandle, DLLRoutine);
if (#POS = nil) then
raise Exception.CreateFmt('Error: %s, while attempting get address to %s in DLL %s.', [IntToStr(GetLastError), DLLRoutine, DLLName]);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
LoadDLL;
ShowMessage('dll loaded');
PrintReport('MyPrinter');
FreeLibrary(DLLHandle);
end;
end.
Snippet from QuickReport
procedure TPrinterSettings.ApplySettings;
var
Cancel : boolean;
begin
FPrinter.GetPrinter(FDevice, FDriver, FPort, DeviceMode);
DevMode := GlobalLock(DeviceMode);
begin
SetField(dm_paperlength);
...
DeviceMode is 0, so SetField throws an access violation. See below.
Access violation at address 036BFBA7 in module 'test_dll.dll'. Write of address 00000028.
Try comment out those 2 lines for GetPrinter and for DevMode
procedure TPrinterSettings.ApplySettings;
var
Cancel : boolean;
begin
// FPrinter.GetPrinter(FDevice, FDriver, FPort, DeviceMode);
// DevMode := GlobalLock(DeviceMode);
begin
SetField(dm_paperlength);
...
end
uses ComObj, ActiveX, StdVcl;
if Printer.Printers.Count>0 then
begin
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
FWbemObject := FWMIService.Get(Format('Win32_Printer.DeviceID="%s"',[Printer.Printers.Strings[0]]));
if not VarIsClear(FWbemObject) then
FWbemObject.SetDefaultPrinter();
end;
new solution
Windows 10 have not default printer with this code u can set the default printer

How can I drag & drop a file from the shell? [duplicate]

This question already has answers here:
Cross-application drag-and-drop in Delphi
(2 answers)
Closed 8 years ago.
I am trying to drag and drop a video file (like .avi) from desktop But ı can not take it to the my program.But when ı try to drag and drop inside my program it works fine.For ex: I have an edittext and a listbox inside my pro and ı can move text that inside edittext to listbox.I could not get what is the difference ??
I take the video using openDialog.But ı wanna change it with drag and drop.
procedure TForm1.Button1Click(Sender: TObject);
begin
if OpenDialog1.Execute then
begin
MediaPlayer1.DeviceType:=dtAutoSelect;
MediaPlayer1.FileName := OpenDialog1.FileName;
Label1.Caption := ExtractFileExt(MediaPlayer1.FileName);
MediaPlayer1.Open;
MediaPlayer1.Display:=Self;
MediaPlayer1.DisplayRect := Rect(panel1.Left,panel1.Top,panel1.Width,panel1.Height);
panel1.Visible:=false;
MediaPlayer1.Play;
end;
end;
Here is a simple demo how to drag&drop files from Windows Explorer into a ListBox (for Delphi XE):
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
ListBox1: TListBox;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
protected
procedure WMDropFiles(var Msg: TMessage); message WM_DROPFILES;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses ShellAPI;
procedure TForm1.FormCreate(Sender: TObject);
begin
DragAcceptFiles(Handle, True);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
DragAcceptFiles(Handle, False);
end;
procedure TForm1.WMDropFiles(var Msg: TMessage);
var
hDrop: THandle;
FileCount: Integer;
NameLen: Integer;
I: Integer;
S: string;
begin
hDrop:= Msg.wParam;
FileCount:= DragQueryFile (hDrop , $FFFFFFFF, nil, 0);
for I:= 0 to FileCount - 1 do begin
NameLen:= DragQueryFile(hDrop, I, nil, 0) + 1;
SetLength(S, NameLen);
DragQueryFile(hDrop, I, Pointer(S), NameLen);
Listbox1.Items.Add (S);
end;
DragFinish(hDrop);
end;
end.
You can also use DropMaster from Raize software.
You can catch the WM_DROPFILES message.
First, set that your form will "accept" files from dragging in the FormCreate procedure:
DragAcceptFiles(Self.Handle, True);
After, declare the procedure in the desired form class:
procedure WMDropFiles(var Msg: TMessage); message WM_DROPFILES;
Finally, fill the procedure body as follows:
procedure TForm1.WMDropFiles(var Msg: TMessage);
begin
// do your job with the help of DragQueryFile function
DragFinish(Msg.WParam);
end
Alternatively, check out "The Drag and Drop Component Suite for Delphi" by Anders Melander. It works as-is with 32-bit and with some tweaking can be made to work with 64-bit as well (read the blog - it has been upgraded by 3rd parties).

Building HTTP Server Application

I have a project which does financial reports and I want to let user to be able to get this reports through the internet
I tried using TIdHTTPServer which is an Indy component to make my application to work as an HTTP Server and to let it to be able
receive request -> process the request -> send back the result of the request process
using a special port.
now my problem is that I'm getting a lot of Access Violation errors and random exceptions
it looks like about threads problem or I don't know because if I process the same request without using the TIdHTTPServer I don't get any problem
i'm using the OnCommandGet Event to process the request and send the result back to user inside the context stream.
what I need is a demonstration on how to use it with TADODataSet and TADOConnection
for example I need the user to be able to send a request and the TIdHTTPServer takes the request (for example call a stored procedure using to ADODataSet and take the result as XML file and send it back to the user)
please help....thank you.
one possibility how a Server could work ...
unit Unit3;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,IDContext, IdBaseComponent, IdComponent, IdCustomTCPServer, IdTCPServer, StdCtrls, DB, ADODB;
type
TForm3 = class(TForm)
IdTCPServer1: TIdTCPServer;
Memo1: TMemo;
Button1: TButton;
DummyConnection: TADOConnection;
procedure Button1Click(Sender: TObject);
procedure IdTCPServer1Execute(AContext: TIdContext);
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
var
Form3: TForm3;
implementation
uses ComObj,AdoInt,ActiveX;
{$R *.dfm}
function SendStream(AContext: TIdContext; AStream: TStream): Boolean;
begin
Result := False;
try
AContext.Connection.IOHandler.Write(AStream.Size); // sending length of Stream first
AContext.Connection.IOHandler.WriteBufferOpen;
AContext.Connection.IOHandler.Write(AStream, AStream.Size);
AContext.Connection.IOHandler.WriteBufferFlush;
finally
AContext.Connection.IOHandler.WriteBufferClose;
end;
Result := True;
end;
procedure TForm3.Button1Click(Sender: TObject);
begin
IdTCPServer1.Active := true;
end;
{ Clientside function
Function RecordsetFromXMLStream(Stream:TStream): _Recordset;
var
RS: Variant;
begin
RS := CreateOleObject('ADODB.Recordset');
RS.Open(TStreamAdapter.Create(Stream) as IUnknown);
Result := IUnknown(RS) as _Recordset;
end;
}
Procedure RecordsetToXMLStream(const Recordset: _Recordset;Stream:TStream);
var
RS: Variant;
begin
if Recordset = nil then Exit;
RS := CreateOleObject('ADODB.Recordset');
RS := Recordset;
RS.Save(TStreamAdapter.Create(stream) as IUnknown, adPersistXML);
Stream.Position := 0;
end;
Procedure GetQueryStream(Const s,ConStr:String;ms:TMemoryStream);
var
AC:TAdoConnection;
ads:TAdodataset;
begin
AC:=TAdoConnection.Create(nil);
try
ads:=TAdodataset.Create(nil);
try
ads.Connection := AC;
AC.ConnectionString := ConStr;
ads.CommandText := s;
ads.Open;
RecordsetToXMLStream(ads.Recordset,ms);
finally
ads.Free
end;
finally
AC.Free
end;
end;
procedure TForm3.IdTCPServer1Execute(AContext: TIdContext);
var
cmd:String;
ms:TMemoryStream;
begin
CoInitialize(nil);
AContext.Connection.IOHandler.Readln(cmd);
ms:=TMemoryStream.Create;
try
GetQueryStream('Select * from Adressen',DummyConnection.ConnectionString,ms);
ms.Position := 0;
SendStream(AContext,ms);
AContext.Connection.Socket.CloseGracefully;
finally
ms.Free;
CoUninitialize;
end;
end;
end.

Delphi VirtualKey to WideString/UNICODE using TNT controls on non-unicode Delphi 7

I am using this code to convert a virtual key to WideString:
function VKeytoWideString (Key : Word) : WideString;
var
WBuff : array [0..255] of WideChar;
KeyboardState : TKeyboardState;
UResult : Integer;
begin
Result := '';
GetKeyBoardState (KeyboardState);
ZeroMemory(#WBuff[0], SizeOf(WBuff));
UResult := ToUnicode(key, MapVirtualKey(key, 0), KeyboardState, WBuff, Length(WBuff), 0);
if UResult > 0 then
SetString(Result, WBuff, UResult)
else if UResult = -1 then
Result := WBuff;
end;
It works fine on my PC, but on a Chinese PC I get this:
It converts the Chinese chars to Hanyu Pinyin. I think the function actually returns the raw input of the keyboard and not what the user actually wants to type in.
How should I handle this?
As per the comments, here is an example of how you can avoid the problem by handling KeyPress events instead of manually converting KeyDown events. The TNT controls don't provide a WideChar KeyPress event, but it's fairly easy to add. Ideally, you should not put the extensions to TTntMemo and TTntForm in derived classes as I've done here, but instead modify the TNT source code.
The form contains two TTntMemo controls. Pressing keys in the first will log the events in the second.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, TntForms, StdCtrls, TntStdCtrls;
type
TKeyPressWEvent = procedure(Sender: TObject; var Key: WideChar) of object;
TTntMemo = class(TntStdCtrls.TTntMemo)
private
FOnKeyPressW: TKeyPressWEvent;
procedure WMChar(var Msg: TWMChar); message WM_CHAR;
protected
function DoKeyPressW(var Message: TWMKey): Boolean;
procedure KeyPressW(var Key: WideChar);
published
property OnKeyPressW: TKeyPressWEvent read FOnKeyPressW write FOnKeyPressW;
end;
TTntForm = class(TntForms.TTntForm)
private
FOnKeyPressW: TKeyPressWEvent;
procedure WMChar(var Msg: TWMChar); message WM_CHAR;
protected
function DoKeyPressW(var Message: TWMKey): Boolean;
procedure KeyPressW(var Key: WideChar);
published
property OnKeyPressW: TKeyPressWEvent read FOnKeyPressW write FOnKeyPressW;
end;
TForm1 = class(TTntForm)
TntMemo1: TTntMemo;
TntMemo2: TTntMemo;
procedure FormCreate(Sender: TObject);
procedure FormKeyPressW(Sender: TObject; var Key: WideChar);
procedure TntMemo1KeyPressW(Sender: TObject; var Key: WideChar);
end;
var
Form1: TForm1;
implementation
uses
TntControls;
{$R *.dfm}
type
TWinControlAccess = class(TWinControl);
TTntFormAccess = class(TTntForm);
function TntControl_DoKeyPressW(Self: TWinControl; var Message: TWMKey;
KeyPressW: Pointer): Boolean;
type
TKeyPressWProc = procedure(Self: TWinControl; var Key: WideChar);
var
Form: TCustomForm;
Ch: WideChar;
begin
Result := True;
Form := GetParentForm(Self);
if (Form <> nil) and (Form <> Self) and Form.KeyPreview then
begin
if (Form is TTntForm) and TTntFormAccess(Form).DoKeyPressW(Message) then Exit;
if TWinControlAccess(Form).DoKeyPress(Message) then Exit;
end;
if not (csNoStdEvents in Self.ControlStyle) then
begin
Ch := GetWideCharFromWMCharMsg(Message);
TKeyPressWProc(KeyPressW)(Self, Ch);
SetWideCharForWMCharMsg(Message, Ch);
if Ch = #0 then Exit;
end;
Result := False;
end;
{ TTntMemo }
function TTntMemo.DoKeyPressW(var Message: TWMKey): Boolean;
begin
Result := TntControl_DoKeyPressW(Self, Message, #TTntMemo.KeyPressW);
end;
procedure TTntMemo.KeyPressW(var Key: WideChar);
begin
if Assigned(FOnKeyPressW) then FOnKeyPressW(Self, Key);
end;
procedure TTntMemo.WMChar(var Msg: TWMChar);
begin
if not DoKeyPressW(Msg) then inherited;
end;
{ TTntForm }
function TTntForm.DoKeyPressW(var Message: TWMKey): Boolean;
begin
Result := TntControl_DoKeyPressW(Self, Message, #TTntForm.KeyPressW);
end;
procedure TTntForm.KeyPressW(var Key: WideChar);
begin
if Assigned(FOnKeyPressW) then FOnKeyPressW(Self, Key);
end;
procedure TTntForm.WMChar(var Msg: TWMChar);
begin
if not DoKeyPressW(Msg) then inherited;
end;
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
Self.OnKeyPressW := FormKeyPressW;
TntMemo1.OnKeyPressW := TntMemo1KeyPressW;
end;
procedure TForm1.FormKeyPressW(Sender: TObject; var Key: WideChar);
begin
TntMemo2.Lines.Add(WideString('FormKeyPress: ') + Key);
end;
procedure TForm1.TntMemo1KeyPressW(Sender: TObject; var Key: WideChar);
begin
TntMemo2.Lines.Add(WideString('TntMemo1KeyPress: ') + Key);
end;
end.
I haven’t got much experience with typing Chinese either, but I suspect this is the IME (Input Method Editor) kicking in. That’s what allows Chinese users to type in pinyin, which will then be translated into ideographic characters (otherwise, you’d need a keyboard with some 1000+ keys...)
The Virtual Keycodes are directly related to the keyboard, and so will, of necessity, only correspond to the entered keys. So your function works fine: it converts a VKEY code to a WideChar. To do what you want, you’ll have to write a second function, which would convert pinyin to characters.
If you want to do this specifically for Chinese, I’ll bet there’s functions for doing this out there. If you want to make it more generic, and independent of locale and language, then perhaps it’s possible to interface with the IME for the relevant TMemo, but if so, I haven’t got a clue. My best guess would be to search MSDN for IME.
But, to echo hvd’s comment: what do you want to accomplish here?
Wouldn’t it be easier to just copy the text of the TMemo?

How to get the url from Chrome using delphi

How can I get the url from a running instance of Chrome using Delphi?
I'm trying to do a Delphi application that gets the url of the active tab of the browser (IE, Mozilla, etc.). I'm using this code that works for IE:
procedure TForm1.GetCurrentURL (var URL, Title : string);
var
DDEClient : TDDEClientConv;
s : string;
begin
s := '';
try
DDEClient := TDDEClientConv.Create(self);
with DDEClient do
begin
if SetLink('IExplore','WWW_GetWindowInfo') then
s := RequestData('0xFFFFFFFF,sURL,sTitle')
else
if SetLink('Netscape','WWW_GetWindowInfo') then
s := RequestData('0xFFFFFFFF,sURL,sTitle')
else
if SetLink('Mosaic','WWW_GetWindowInfo') then
s := RequestData('0xFFFFFFFF,sURL,sTitle')
else
if SetLink('Netscp6','WWW_GetWindowInfo') then
s := RequestData('0xFFFFFFFF,sURL,sTitle')
else
if SetLink('Mozilla','WWW_GetWindowInfo') then
s := RequestData('0xFFFFFFFF,sURL,sTitle')
else
if SetLink('Firefox','WWW_GetWindowInfo') then
s := RequestData('0xFFFFFFFF,sURL,sTitle');
end;
if s <> '' then
begin
delete(s,1,1);
URL := copy(s,1,pos('","',s)-1);
delete(s,1,pos('","',s)+2);
Title := copy(s,1,pos('"',s) - 1);
end;
exit;
except
MessageDlg('URL attempt failed!',mtError,[mbOK],0);
end;
end;
But this code doesn't work with Chrome.
Thanks.
Here is how I have done it before for retrieving the URL from the active tab. You could probably extend this to include all of Chrome's tabs.
One other note, as you can see this grabs the first handle to chrome.exe that it finds. To have this accommodate multiple instances of Chrome running, you would need to adjust this to get a handle to each Chrome instance.
I put this together pretty quick, so don't consider this "production" quality. Just create a new vcl application and drop a TMemo and a TButton on the form and assign the Button1Click to TButton's OnClick event.
unit main;
interface
uses
Windows,
Messages,
SysUtils,
Classes,
Controls,
Forms,
StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
function GetActivePageUrlFromChrome(Handle: HWnd; Param: LParam): Bool; stdcall;
var
Form1 : TForm1;
implementation
{$R *.dfm}
function GetActivePageUrlFromChrome(Handle: HWnd; Param: LParam): Bool; stdcall;
var
List: TStrings;
hWndChrome, hWndChromeChild: HWND;
Buffer : array[0..255] of Char;
begin
List := TStrings(Param);
//get the window caption
SendMessage(Handle, WM_GETTEXT, Length(Buffer), integer(#Buffer[0]));
//look for the chrome window with "Buffer" caption
hWndChrome := FindWindow('Chrome_WidgetWin_0', Buffer);
if hWndChrome <> 0 then
begin
hWndChromeChild := FindWindowEx(hWndChrome, 0, 'Chrome_AutocompleteEditView', nil);
if hWndChromeChild <> 0 then
begin
SendMessage(hWndChromeChild, WM_GETTEXT, Length(Buffer), integer(#Buffer));
List.Add(Buffer);
end;
end;
Result := True;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
slChromeUrl : TStringList;
begin
slChromeUrl := TStringList.Create;
try
EnumWindows(GetActivePageUrlFromChrome, LParam(slChromeUrl));
Memo1.Lines.AddStrings(slChromeUrl);
finally
FreeAndNil(slChromeUrl);
end;
end;
end.
Error:
try
EnumWindows(GetActivePageUrlFromChrome, LParam(slChromeUrl));
Memo1.Lines.AddStrings(slChromeUrl);
Works:
try
EnumWindows(#GetActivePageUrlFromChrome, LParam(slChromeUrl));
Memo1.Lines.AddStrings(slChromeUrl);
Apparently there's an issue open to request DDE support by chrome/chromium, keep a look-out there if a future version would provide it:
http://code.google.com/p/chromium/issues/detail?id=70184

Resources