How can I load an HTML string into a Firemonkey TWebBrowser? - delphi

I'm trying to use the Firemonkey TWebBrowser to load some HTML that is generated at runtime. The HTML is a Delphi string.
I've looked at some code from: http://delphi.about.com/cs/adptips2004/a/bltip0104_4.htm
procedure WBLoadHTML(WebBrowser: TWebBrowser; HTMLCode: string) ;
var
sl: TStringList;
ms: TMemoryStream;
begin
WebBrowser.Navigate('about:blank') ;
while WebBrowser.ReadyState < READYSTATE_INTERACTIVE do
Application.ProcessMessages;
if Assigned(WebBrowser.Document) then begin
sl := TStringList.Create;
try
ms := TMemoryStream.Create;
try
sl.Text := HTMLCode;
sl.SaveToStream(ms) ;
ms.Seek(0, 0) ;
(WebBrowser.Document as IPersistStreamInit).Load(TStreamAdapter.Create(ms)) ;
finally
ms.Free;
end;
finally
sl.Free;
end;
end;
end;
procedure TForm1.FormCreate(Sender: TObject) ;
var
sHTML : string;
begin
sHTML := 'GOTO' +
'<b>About Delphi Programming</b>';
WBLoadHTML(WebBrowser1,sHTML) ;
end;
but this appears to be designed for a VCL application which is incompatible with Firemonkey TWebBrowser.
How can I achieve the same thing as this code example but using the Firemonkey control?

Use WebBrowser LoadFromStrings Method.

You could implement this functionality in a DLL...detail and downloadable example here.
Another option is to consider this open-source TWebBrowserEx project. It actually will use the platform's normal web browser functionality. However, in the case of Windows it means that in your FMX project you will be using the VCL for the web browser support...which may or may not have unintended effects.
This class provide WebBrowser for All-Platform FireMonkey
Applications.
Platform => Component
Windows => IWebBrowser(IE)
OS X => WebView(Safari)
iOS => WebView
Android => WebView

Related

Opening a second presentation fails - Delphi XE2 + Windows 8

Need to an open an PowerPoint presentation. I am using the below statement.
Var
ppt: _Application;
pres: _Presentation;
try
ppt := GetActiveOleObject('PowerPoint.Application') as _Application;
except
ppt := CreateOleObject('PowerPoint.Application') as _Application ;
end;
ppt.Visible := msoTrue;
try
pres := ppt.Presentations.Open(FPOTX, msoFalse, msoTrue, msoTrue);
except
on e:exception do begin
printtofile('Error in call to ppt.Presentation.Open' + e.message);
end;
end;
It works fine whenever , CreateOleObject() in exception is called. (i.e., no presentation is already open).
But the above statement fails , if one presentation is already open. (i.e, ppt.Presentations.Open() is called after GetActiveOleObject() function).
Using Delphi XE2 , MS Office 2013 , Windows 8
This fails only in Windows 8 not in Windows 7.
Thanks in advance.
I don't know where the problem is, if it is your Delphi or Office or Windows version. But this code works no problem in Windows 8.1 x64, Delphi XE2 (32bit target), Office 2007. Unfortunately I do not have Office 2013 to test it.
I don't have any Type LIBs imported in my Delphi. So I tested it just using plain Variant types.
If PPT isn't opened, the code opens it. Otherwise it gets the OLE Object. Afterwards the desired Presentation is opened. Works as often as I tested it, no matter if PPT is closed or opened.
...
implementation
uses
ComObj, ActiveX;
const
msoFalse = TOleEnum(False);
msoTrue = TOleEnum(True);
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
ppt, pres: Variant;
begin
ppt := Unassigned;
pres := Unassigned;
try
ppt := GetActiveOleObject('PowerPoint.Application');
except
ppt := CreateOleObject('PowerPoint.Application');
end;
ppt.Visible := msoTrue;
try
pres := ppt.Presentations.Open('C:\Temp\Test.pptx', msoFalse, msoTrue, msoTrue);
except
on E:Exception do
ShowMessage('OOPS');
end;
end;
EDIT
I also tested it with an imported PowerPoint Type Lib. And your code works 1:1 here:
...
implementation
uses
ComObj, ActiveX, PowerPoint_TLB;
const
msoFalse = TOleEnum(False);
msoTrue = TOleEnum(True);
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
ppt: _Application;
pres: _Presentation;
begin
ppt := nil;
pres := nil;
try
ppt := GetActiveOleObject('PowerPoint.Application') as _Application;
except
ppt := CreateOleObject('PowerPoint.Application') as _Application;
end;
ppt.Visible := msoTrue;
try
pres := ppt.Presentations.Open('C:\Temp\Test.pptx', msoFalse, msoTrue, msoTrue);
except
on E:Exception do
ShowMessage('OOPS');
end;
end;
SOLUTION FOR OFFICE 2013
As you already found out: It seems to work with Office 2013 when changing the Title parameter of ppt.Presentations.Open to msoFalse ==> ppt.Presentations.Open(FPOTX, msoFalse, msoFalse, msoTrue)
This works for me absolutely without any issues. The problem faced was compatibility issue between the XXX.pot(office 1997-2003) and XXX.potx (office2014). Apart from that everthing was fine.

How to add persistence to the Delphi Docking example

Although I realise that in addition to the included Delphi docking demo there are other and better docking libraries available such as the Developer Express Library and the JVCL Docking Library, but for a specific demonstration project I am restricted to use only the Delphi built-in capability (despite some of the noted flaws).
My question relates to adding persistence to the docking state. I see from examining Controls.pas that TDockTree is the default dock manager and it has Stream I/O routines. Digging around on SO and in various forums though I cant see how anyone has called these routines. I've tried loading and saving to a file from the relevant Create and OnDrop events but I'm stabbing in the dark. I am happy saving and restoring form sizes and states but am struggling with the concepts of what I should be saving. Would any kind person give me a starting place?
I'm using Delphi XE3, so all (?) things are possible!
Many thanks.
I'm using Toolbar 2000 from J. Russels. It is providing panels, toolwindow's and toolbar's.
That one provides functions like TBRegSavePositions and TBRegSavePositions to store the user customization into registry.
Loading a "view" get's easily done by on code line:
TBRegLoadPositions(self, HKEY_CURRENT_USER, c_BaseUserRegKey);
in this case self is my form.
You can load and save your docking configuration with the LoadFromStream and SaveToStream methods by storing the data in a string.
Therefore, the following methods are required:
save the current docking configuration to a string
load the current docking configuration from a string
Here is some code to do this:
function GetDockString(const AManager: IDockManager): AnsiString;
var
LStream: TMemoryStream;
begin
LStream := TMemoryStream.Create();
try
AManager.SaveToStream(LStream);
SetLength(Result, 2 * LStream.Size);
BinToHex(LStream.Memory, PAnsiChar(Result), LStream.Size);
finally
FreeAndNil(LStream);
end;
end;
procedure ReadDockString(const ADockString: AnsiString; const AManager: IDockManager);
var
LStream: TMemoryStream;
begin
LStream := TMemoryStream.Create();
try
LStream.Size := Length(ADockString) div 2;
HexToBin(PAnsiChar(ADockString), LStream.Memory, LStream.Size);
LStream.Position := 0;
AManager.LoadFromStream(LStream);
finally
FreeAndNil(LStream);
end;
end;
I've used such methods in an application to create dockable windows, but the vcl provides only a very basic user experience. You can do something about it, but it is hard to test and debug - I already spent too much time to use and override TCustDockDragObject and TCaptionedTabDockTree, so I would recommend using a docking framework.
Here is a minimal example which creates two forms and reads a docking configuration.
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDblClick(Sender: TObject);
private
FPanel: TPanel;
end;
Implementation:
procedure TForm1.FormCreate(Sender: TObject);
var
LWindow: TForm;
const
LDockExample = '0000080000000000000000000000000000000000000000000000000100000000000000000B0000004368696C6457696E646F77FFFFFFFF';
begin
FPanel := TPanel.Create(Self);
FPanel.Align := alTop;
FPanel.Height := 300;
FPanel.DockSite := true;
FPanel.Parent := Self;
LWindow := TForm.CreateNew(Self);
LWindow.Name := 'ChildWindow';
LWindow.DragKind := dkDock;
LWindow.BoundsRect:=Rect(10, 10, 400, 400);
LWindow.Color := clGreen;
LWindow.Show;
ReadDockString(LDockExample, FPanel.DockManager);
end;
procedure TForm1.FormDblClick(Sender: TObject);
begin
ShowMessage(GetDockString(FPanel.DockManager));
end;

Delphi EXPERT ToolServices.getCurrentFile failing

What is a new way to get current file that is being worked on in Experts for Delphi XE
Previously in Delphi 5-7 we used ToolServices.getCurrentFile
Perhaps the deprecated units ToolIntf, ExptIntf etc. are no longer working. You can use IOTAModuleServices.CurrentModule instead. Here's a quick example:
function GetCurrentEditorFileName: string;
var
Module: IOTAModule;
Editor: IOTAEditor;
begin
Result := '';
Module := (BorlandIDEServices as IOTAModuleServices).CurrentModule;
if Assigned(Module) then
begin
Editor := Module.CurrentEditor;
if Assigned(Editor) then
Result := Editor.FileName;
end;
end;
An alternate method is to pass the "name of file in the editor" to your tool as a parameter. $EDNAME

Get richtext from a richedit in Delphi

Is there a way to get the RTF data from a richedit without using savetostream as in
strStream := TStringStream.Create('') ;
try
RichEdit.Lines.SaveToStream(strStream);
Text := strStream.DataString;
strStream.CleanupInstance;
finally
strStream.Free
Tim the only way to get the RTF data from an RichEdit control is using a Stream because the windows message (EM_STREAMOUT) wich retrieve the RTF Data require a EditStreamCallback structure, this is the way used by windows to transfer rtf data into or out of a richedit control.
So you can use your own sample code, or implement the call to the windows message EM_STREAMOUT.
function RichTextToStr(red : TRichEdit) : string;
var ss : TStringStream;
begin
ss := TStringStream.Create('');
try
red.Lines.SaveToStream(ss);
Result := ss.DataString;
finally
ss.Free;
end;
end;
procedure CopyRTF(redFrom,redTo : TRichEdit);
var s : TMemoryStream;
begin
s := TMemoryStream.Create;
try
redFrom.Lines.SaveToStream(s);
s.Position := 0;
redTo.Lines.LoadFromStream(s);
finally
s.Free;
end;
end;
I can attest deviation from the pattern results in frustration....

how to retrieve text from website text boxes

how can i retrieve text from a web sites text boxes in delphi for example suppose i type
''tiger'' in google's search box how do i retrieve text from that search box would wm_gettext or getwindowtext work?
i am using delphi 7
try this code.
Only works with internet explorer. tested in Windows Vista,IE8 y Delphi 2007.
Uses
SHDocVw,
mshtml;
procedure GetTextFromEditIExplorer(ListStr: TStringList);
var
ShellWindow : IShellWindows;
Web_Browser : IWebbrowser2;
reg_Shell_window : IDispatch;
Dummy : IHTMLDocument2;
ovElements : OleVariant;
Document : Variant;
WindowsCount : Integer;
ElementsCount : Integer;
FormsCount : Integer;
begin
ShellWindow := CoShellWindows.Create; //Provides access to the collection of open Shell windows
for WindowsCount := 0 to ShellWindow.Count do //iterate through number of windows in the Shell windows collection
begin
reg_Shell_window := ShellWindow.Item(WindowsCount); //Returns the registered Shell window for a specified index.
if reg_Shell_window = nil then Continue; //go to next reg window
reg_Shell_window.QueryInterface(iWebBrowser2, Web_Browser); // determines if an interface can be used with an object
if Web_Browser <> nil then
begin
Web_Browser.Document.QueryInterface(IHTMLDocument2, Dummy);
if Dummy <> nil then
begin
Web_Browser := ShellWindow.Item(WindowsCount) as IWebbrowser2;
Document := Web_Browser;
for FormsCount := 0 to Document.forms.Length - 1 do
begin
ovElements := Document.forms.Item(FormsCount).elements;
for ElementsCount := 0 to ovElements.Length - 1 do
begin
try
if (CompareText(ovElements.item(ElementsCount).tagName, 'INPUT') = 0) and (CompareText(ovElements.item(ElementsCount).type, 'text') = 0) then
ListStr.Add('Control Name ['+ovElements.item(ElementsCount).Name+']'+' Type -> '+ovElements.item(ElementsCount).Type+' -> Value ['+ovElements.item(ElementsCount).Value+']');
except
ListStr.Add('Error Reading element n° '+IntToStr(ElementsCount));
end;
end;
end;
end;
end;
end;
end;
procedure TForm1.btn1Click(Sender: TObject);
var
List : TStringList;
begin
List:=TStringList.Create;
GetTextFromEditIExplorer(List);
ShowMessage(List.Text);
end;
Edit :
Omar unfortunately there is no simple solution to your problem. This is because each browser uses a different interface to interact with the information.
Here are a couple of suggestions
Firefox uses XPCOM, you can research about that.
Try using DDE (dynamic data exchange).
You can use WatiN, is a .net library wich work with firefox and iexplorer. you can see this article to learn how interact with a .net Assembly in delphi win32.
Bye.
The simplest way would be by using a regular expression on the original HTML code from the page.

Resources