I want to open a local HTML file in the default browser.
For example: Default Browser is Mozilla Firefox.
The file to be opened: C:\\My Custom Path\\New Folde
i think this is better way:
function OpenHtmlFile(FileAdr :string):Boolean;
var
vTempFile :string;
vData :TStrings;
begin
Result:= False;
vTempFile:= GetTempFolder + '_tmphtmlrunfile.html';
vData:= TStringList.Create;
vData.Text:= '<html><head><meta http-equiv="refresh" content="0;URL=''file:///' + FileAdr + '''">';
try
try
vData.SaveToFile(vTempFile, TEncoding.UTF8);
finally
vData.Free;
end;
ShellExecute(Handle,
'open',
PChar(vTempFile),
nil,
nil,
SW_SHOWNORMAL);
Result:= True;
except
end;
end;
Here is my implementation that supports all common web browsers and Microsoft Edge (Windows Store App).
It refers to the issues with queries (?
) and fragments (#
) in the URI and the issue with file:///
protocol in combination with the Edge browser.
(I use it for HTML output of "Flare" software, that's why the "help" in the naming of variables)
// AHelpFileName := 'C:\temp\Default.htm';
// AHelpID := '123';
procedure TSomeClass.OpenHelp(const AHelpFileName, AHelpID: string);
var
URL: string;
BrowserPath, FileName, Parameters: PWideChar;
begin
URL := Format('file:///%s', [AHelpFileName]);
if AHelpID <> '' then
URL := Format('%s#cshid=%s', [URL, AHelpID])
URL := StringReplace(URL, '\', '/', [rfReplaceAll]);
URL := StringReplace(URL, ' ', '%20', [rfReplaceAll]);
BrowserPath := StrAlloc(MAX_PATH);
Parameters := nil;
if FindExecutable(PWideChar(AHelpFileName), nil, BrowserPath) > 32 then
begin
Parameters := PWideChar(URL);
if SameText(ExtractFileName(BrowserPath), 'LaunchWinApp.exe') then
// Default browser is a Windows Store App (and most likely it is Edge)
FileName := 'shell:AppsFolder\Microsoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge'
else
// IE, Chrome, Firefox, Opera, Vivaldi, ...
FileName := BrowserPath;
end
else
FileName := PWideChar(URL);
ShellExecute(0, nil, FileName, Parameters, nil, SW_SHOWNORMAL);
end;
ShellExecute/Ex()
won't work directly using "open"
verb with the anchor (#
) in the URL. even if you use file://
protocol the anchor will be omitted.
The best way is to get the path for the default browser, you can use FindExecutable, and then execute it and pass the URL as a parameter.
uses
ShellAPI;
procedure TForm1.Button1Click(Sender: TObject);
var
Res: HINST;
Buffer: array[0..MAX_PATH] of Char;
SEInfo: TShellExecuteInfo;
HtmlFile, Anchor: string;
begin
HtmlFile := 'd:\1 - Copy.html';
Anchor := '#123';
FillChar(Buffer, SizeOf(Buffer), 0);
Res := FindExecutable(PChar(HtmlFile), nil, Buffer);
if Res <= 32 then
raise Exception.Create(SysErrorMessage(Res));
FillChar(SEInfo, SizeOf(SEInfo), 0);
SEInfo.cbSize := SizeOf(SEInfo);
with SEInfo do
begin
lpFile := PChar(string(Buffer));
lpParameters := PChar(Format('"file:///%s"', [HtmlFile + Anchor]));
nShow := SW_SHOWNORMAL;
fMask := SEE_MASK_FLAG_NO_UI; // Do not display an error message box if an error occurs.
end;
if not ShellExecuteEx(@SEInfo) then
RaiseLastOSError;
end;
EDIT: Looks like the file:///
URI scheme is important in cases where the URL includes query string parameters (e.g file.html?param=foo#bar
) or else the ?
is escaped to %3F
(tested in Chrome)
One can also create a process launching CMD.EXE with the following parameters :
'/C start '+Url
Quick and dirty, but it should work OK
I ended up doing this. I get the default browser, and used the CreateProcess API to launch the browser with my custom URL. Notice, I add the 'file:///' in the beginning and also surround the string with double quotes.
function GetDefaultBrowser(): String;
var
ExecName: array[0..MAX_PATH] of Char;
FHandle: THandle;
MyPath: String;
begin
Result := '';
MyPath := small.GetTempPath;
FHandle := System.SysUtils.FileCreate(MyPath + 'AFile.htm');
if FHandle <> INVALID_HANDLE_VALUE then
begin
FillChar(ExecName, Length(ExecName), #0);
if FindExecutable('AFile.htm', PChar(MyPath), ExecName) > 32 then
Result := ExecName;
System.SysUtils.FileClose(FHandle);
System.SysUtils.DeleteFile(MyPath + 'AFile.htm');
end;
end;
procedure LaunchHTMLPage(NumberToAppend : string);
var
Start: TStartupInfo;
Process: TProcessInformation;
FileNameString, AppPathAndName, AppPathOnly: string;
begin
AppPathAndName := GetDefaultBrowser ;
//Break the AppPathAndName and get the path name to use later
//I am adding double quotes in the path name to escape the spaces and the '#'
FileNameString := AnsiQuotedStr('file:///' + Application.HelpFile + '#' + NumberToAppend, '"');
AppPathAndName := AppPathAndName + ' ' + FileNameString;
FillChar(Start, SizeOf(StartUpInfo), #0);
FillChar(Process, SizeOf(TProcessInformation), #0);
CreateProcess(nil, PChar(AppPathAndName), nil, nil, false, CREATE_NEW_PROCESS_GROUP + NORMAL_PRIORITY_CLASS, nil, PChar(AppPathOnly), StartUpInfo, ProcessInfo);
end;
Unfortunately you can't do it only with ShellExecute. But there is some hack.
For example you want to open url like this:
C:\Users\User\Desktop\Some sitename with spaces.htm with the anchor #myAnchor
To make ShellExecute open file:
vS := 'file:///C:\Users\User\Desktop\Some sitename with spaces.htm#MyAnchor';
ShellExecute(0, 'OPEN', PChar(vS), '', '', SW_SHOWNORMAL);
It's Important to use "file:///" in the beginning, but ShellExecute open this page without anchor.
To open with the anchor you can dynamically create html file with content like this:
<html>
<meta http-equiv=Refresh content="0; url=file:///C:\Users\User\Desktop\Some sitename with spaces.htm#MyAnchor">
<body></body>
</html>
And open this dynamic file with ShellExecute.
Hope it helps.