What is the proper way to detect if the Lazarus IDE is installed in a system programmatically using Delphi?
For example to detect if Delphi 7 is installed I can check this key HKLM\Software\Borland\Delphi\7.0
.
I search for a similar key for Lazarus in the Windows registry but I don't found anything.
Lazarus store a file called environmentoptions.xml
by default in the <user name>\Local Settings\Application Data\lazarus
folder (in some scenarios this file can be located in other folder). This file contains all the info necessary to get the Lazarus IDE location as well the FPC (Free Pascal compiler) used by the IDE.
the environmentoptions.xml
file look like this
<?xml version="1.0"?>
<CONFIG>
<EnvironmentOptions>
<Version Value="106"/>
<LazarusDirectory Value="C:\lazarus\">
<History Count="1">
<Item1 Value="C:\lazarus\"/>
</History>
</LazarusDirectory>
<CompilerFilename Value="C:\lazarus\fpc\2.2.4\bin\i386-win32\fpc.exe">
<History Count="3">
<Item1 Value="C:\fpc\2.2.4\bin\i386-win32\fpc.exe"/>
<Item2 Value="C:\lazarus\fpc\2.2.4\bin\i386-win32\fpc.exe"/>
<Item3 Value="C:\lazarus\fpc\2.4.2\bin\i386-win32\fpc.exe"/>
</History>
</CompilerFilename>
<FPCSourceDirectory Value="c:\lazarus\fpc\2.2.4\source\">
<History Count="1">
<Item1 Value="c:\lazarus\fpc\2.2.4\source\"/>
</History>
</FPCSourceDirectory>
<MakeFilename Value="C:\lazarus\fpc\2.2.4\bin\i386-win32\make.exe">
<History Count="2">
<Item1 Value="C:\fpc\2.2.4\bin\i386-win32\make.exe"/>
<Item2 Value="C:\lazarus\fpc\2.2.4\bin\i386-win32\make.exe"/>
</History>
</MakeFilename>
<TestBuildDirectory Value="C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\">
<History Count="3">
<Item1 Value="C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\"/>
<Item2 Value="C:\temp\"/>
<Item3 Value="C:\windows\temp\"/>
</History>
</TestBuildDirectory>
<BackupProjectFiles AdditionalExtension="bak" MaxCounter="9"/>
<BackupOtherFiles AdditionalExtension="bak" MaxCounter="9"/>
<Debugger Class="TGDBMIDebugger" EventLogLineLimit="100"/>
<DebuggerFilename Value="c:\lazarus\mingw\bin\gdb.exe">
<History Count="4">
<Item1 Value="c:\lazarus\mingw\bin\gdb.exe"/>
<Item2 Value="/usr/bin/gdb"/>
<Item3 Value="/usr/local/bin/gdb"/>
<Item4 Value="/opt/fpc/gdb"/>
</History>
</DebuggerFilename>
<Recent>
<OpenFiles Max="10" Count="10">
</OpenFiles>
<ProjectFiles Max="5" Count="5">
</ProjectFiles>
<PackageFiles Max="10" Count="1">
<Item1 Value="C:\Librerias\Indy10\Lib\indylaz.lpk"/>
</PackageFiles>
</Recent>
<ExternalTools Count="0"/>
<CharcaseFileAction Value="Ask"/>
<CompilerMessagesFilename Value=""/>
</EnvironmentOptions>
<ObjectInspectorOptions ShowHints="False" InfoBoxHeight="50">
<Version Value="3"/>
<ComponentTree>
<Height Value="97"/>
</ComponentTree>
</ObjectInspectorOptions>
</CONFIG>
so the steps necessaries to determine if the Lazarus IDE is installed in a Windows system are
Determine the location of the <user name>\Local Settings\Application Data\lazarus
using the SHGetSpecialFolderLocation
function with the CSIDL_LOCAL_APPDATA
value.
Parse the file environmentoptions.xml
to locate the LazarusDirectory
Key under the EnvironmentOptions
root.
Now with the location of the Lazarus IDE you can check the existence of the lazarus.exe
file in that folder.
check this sample application which summarize all steps in this answer.
{$APPTYPE CONSOLE}
uses
ShlObj,
ComObj,
ActiveX,
Classes,
Windows,
Variants,
SysUtils;
function GetLocalAppDataFolder : string;
const
CSIDL_LOCAL_APPDATA = $001C;
var
ppMalloc : IMalloc;
ppidl : PItemIdList;
begin
ppidl := nil;
try
if SHGetMalloc(ppMalloc) = S_OK then
begin
SHGetSpecialFolderLocation(0, CSIDL_LOCAL_APPDATA, ppidl);
SetLength(Result, MAX_PATH);
if not SHGetPathFromIDList(ppidl, PChar(Result)) then
RaiseLastOSError;
SetLength(Result, lStrLen(PChar(Result)));
end;
finally
if ppidl <> nil then
ppMalloc.free(ppidl);
end;
end;
function GetLazarusLocalFolder : string;
begin
Result:=Format('%slazarus',[IncludeTrailingPathDelimiter(GetLocalAppDataFolder)]);
if not DirectoryExists(Result) then
Result:='';
end;
function FileToString(const FileName: TFileName): AnsiString;
var
Stream : TFileStream;
begin
Stream:=TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
try
SetLength(Result, Stream.Size);
Stream.Read(Pointer(Result)^, Stream.Size);
except
Result:='';
end;
finally
Stream.Free;
end;
end;
function GetLazarusFolder : string;
var
LocalFolder : TFileName;
FileName : TFileName;
XmlDoc : OleVariant;
Node : OleVariant;
begin
Result:='';
LocalFolder:=GetLazarusLocalFolder;
if LocalFolder<>'' then
begin
FileName:=IncludeTrailingPathDelimiter(LocalFolder)+'environmentoptions.xml';
if FileExists(FileName) then
begin
XmlDoc := CreateOleObject('Msxml2.DOMDocument.6.0');
try
XmlDoc.Async := False;
XmlDoc.LoadXML(FileToString(FileName));
XmlDoc.SetProperty('SelectionLanguage','XPath');
if (XmlDoc.parseError.errorCode <> 0) then
raise Exception.CreateFmt('Error in Xml Data %s',[XmlDoc.parseError]);
Node :=XmlDoc.selectSingleNode('//CONFIG/EnvironmentOptions/LazarusDirectory/@Value');
if not VarIsClear(Node) then
Result:=Node.text;
finally
XmlDoc:=Unassigned;
end;
end;
end;
end;
function IsLazarusInstalled : Boolean;
begin
Result:=FileExists(IncludeTrailingPathDelimiter(GetLazarusFolder)+'lazarus.exe');
end;
begin
try
CoInitialize(nil);
try
Writeln('Lazarus config Folder '+GetLazarusLocalFolder);
Writeln('Lazarus Install folder '+GetLazarusFolder);
Writeln('Is Lazarus Installed '+BoolToStr(IsLazarusInstalled,True));
Readln;
finally
CoUninitialize;
end;
except
on E:Exception do
begin
Writeln(E.Classname, ':', E.Message);
Readln;
end;
end;
end.