Another post on something that happened last week, this time it’s about a Java based Application again.
This particular application wanted to download three DLL’s from the Webserver to the Java bin directory.
This presents us with several issues on a multi user server such as a Citrix of Terminal Server:
- The user does not have write permissions in this directory
- If we we give the user write permissions here what happens when the DLL's are in use by another user?
Then I monitored with Process Monitor if the Application wrote some kind of check file but at first I didn’t find anything.
So I decided to use the CorrectFilePaths shim to redirect the DLL’s to the user’s homedirectory (see Using the CorrectFilePaths shim to redirect an ini file to a writable location for an explanation).
This worked nicely, I started the Application and saw the files being downloaded to the user’s homedirectory.
Side note: this downloading took a much too long time because it downloads byte by byte, #crappy!
I tested a few things in the application according to the instructions and everything seemed to work fine. Then I closed the Application and finally the Browser.
And then an error message came, indicating that the Application couldn’t a write a file called webutil.properties into the Java Home directory.
I then redirected this file as well and checked the content and it’s an ini alike file:
#WebUtil Properties File
#Mon Jan 10 11:03:38 CET 2011
syslib.d2kwut60.dll=1.0
syslib.jnisharedstubs.dll=1.0
syslib.jacob.dll=1.0I then removed the CorrectFilePaths shim and place the webutil.properties file in the Java Directory and the DLL’s in the bin directory.
Now everything worked well but of course the challenge is how to package this.
The easiest approach is to have the installer copy the files but what happens if a webutil.properties file is already present?
I think it’s risky to blindly write this file so I wanted to an installer that does the following:
- Dynamically determine Java Folder
- Create the webutil.properties file if it doesn't exist
- Add's the DLL entries to the file
- Does not overwrite existing entries
- Does not write the lines if they already exist
- On Uninstall remove the DLL files
- On Uninstall remove the lines from the webutil.properties file
Below my Setup.iss script, I think the script parts contains enough comments to explain the code. But if you have any questions please leave a comment.
If you want to use the script, combine the setup and code part to one .iss file and compile it.
The setup part:
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{04C0BBA1-22AC-4927-9E42-0DA8A5C1ECB5}
AppName=Centric Key 2 Financien Java Components
AppVersion=1.0
;AppVerName=Centric Key 2 Financien Java Components 1.0
AppPublisher=Remko Weijnen
CreateAppDir=no
OutputBaseFilename=setup
OutputDir=..\
Compression=lzma
SolidCompression=yes
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Files]
Source: ".\SourceFiles\d2kwut60.dll"; DestDir: "{code:GetJavaBin}"; Flags: ignoreversion;
Source: ".\SourceFiles\jacob.dll"; DestDir: "{code:GetJavaBin}"; Flags: ignoreversion
Source: ".\SourceFiles\jnisharedstubs.dll"; DestDir: "{code:GetJavaBin}"; Flags: ignoreversion
; NOTE: Don't use "Flags: ignoreversion" on any shared system filesAnd the script part:
const
JavaKey = 'SOFTWARE\JavaSoft\Java Runtime Environment';
function GetJavaDir(const s: String): String;
var
CurrentVersion: String;
begin
// Get Java Version
if RegQueryStringValue(HKEY_LOCAL_MACHINE, JavaKey, 'CurrentVersion', CurrentVersion) then
begin
// Get JavaHome Path
if RegQueryStringValue(HKEY_LOCAL_MACHINE, JavaKey + '\' + CurrentVersion, 'JavaHome', Result) then
begin
// Add subdir that was given as parameter
if s <> '' then
begin
Result := Result + '\' + s;
end;
end;
end;
if Result = '' then
RaiseException('Unable to determine Java Version!');
end;
// When using {code:SomeFunction} the function needs to have (const s: String)
function GetJavaBin(const s: String): String;
begin
Result := GetJavaDir('bin');
end;
procedure PostInstallProc;
var
WebUtilProps: String;
sl: TStringList;
begin
// Assemble Complete Path
WebUtilProps := GetJavaDir('') + '\webutil.properties';
sl := TStringList.Create;
try
// We don't want duplicates!
sl.Duplicates := dupIgnore;
sl.Sorted := True;
// Load existing file
try
sl.LoadFromFile(WebUtilProps);
except
// Ignore if the file doesn't exist
end;
// Add Entries (or overwrite)
sl.Add('#WebUtil Properties File');
sl.Add('syslib.d2kwut60.dll=1.0');
sl.Add('syslib.jnisharedstubs.dll=1.0');
sl.Add('syslib.jacob.dll=1.0');
// And save it
sl.SaveToFile(WebUtilProps);
finally
sl.Free;
end;
end;
procedure DeleteString(const sl: TStringList; const s: String);
var
i: Integer;
begin
i := sl.IndexOf(s);
if i > -1 then
begin
sl.Delete(i);
end;
end;
procedure PostUnInstallProc;
var
WebUtilProps: String;
sl: TStringList;
begin
// Assemble Complete Path
WebUtilProps := GetJavaDir('') + '\webutil.properties';
sl := TStringList.Create;
try
// We don't want duplicates!
sl.Duplicates := dupIgnore;
sl.Sorted := True;
// Load existing file
try
sl.LoadFromFile(WebUtilProps);
DeleteString(sl, 'syslib.d2kwut60.dll=1.0');
DeleteString(sl, 'syslib.jnisharedstubs.dll=1.0');
DeleteString(sl, 'syslib.jacob.dll=1.0');
// And save it
sl.SaveToFile(WebUtilProps);
except
// Ignore if the file doesn't exist
end;
finally
sl.Free;
end;
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
case CurStep of
ssPostInstall: PostInstallProc;
end;
end;
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
case CurUninstallStep of
usPostUninstall: PostUnInstallProc;
end;
end;