In my installer I'm extracting files from archives that don't store time/date attributes, so when they're extracted the last modified date is set to the current date. I would like to set it to the last modified date of the archive file but I can't figure out how. I tried using pieces of the code from here and here but while it didn't give any errors, it didn't work for changing the time. Last modified date would need to be changed for * .* in a folder.
Also, where do I need to hook into to delete these files if the user cancels setup and it starts rolling back changes? I've got it taken care of in UninstallDelete but not if the user cancels setup.
EDIT: Disregard the second part, I actually figured it out shortly after I posted here. Added my own CleanUp() to DeinitializeSetup() with a check for the uninstaller registry key.
Here is the section of code I'm trying to add it to:
procedure VolExtract(VWorld: String);
var
ResultCode: Integer;
VPath: String;
begin
// Files are extracted to {app}\VWorld\One, {app}\VWorld\Two, etc.
VPath := ExpandConstant('{app}\' + VWorld);
WizardForm.FilenameLabel.Caption := DriveLetter + VWorld + '\one.vol';
if Exec(ExpandConstant('{tmp}\volextract.exe'), '"' + DriveLetter + VWorld + '\one.vol" "' + VPath + '"', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) and (ResultCode = 0) then
begin
// Yep, it executed successfully
WizardForm.FilenameLabel.Caption := DriveLetter + VWorld + '\two.vol';
if Exec(ExpandConstant('{tmp}\volextract.exe'), '"' + DriveLetter + VWorld + '\two.vol" "' + VPath + '"', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) and (ResultCode = 0) then
begin
// Next
WizardForm.FilenameLabel.Caption := DriveLetter + VWorld + '\three.vol';
if Exec(ExpandConstant('{tmp}\volextract.exe'), '"' + DriveLetter + VWorld + '\three.vol" "' + VPath + '"', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) and (ResultCode = 0) then
begin
// Next
WizardForm.FilenameLabel.Caption := DriveLetter + VWorld + '\four.vol';
Exec(ExpandConstant('{tmp}\volextract.exe'), '"' + DriveLetter + VWorld + '\four.vol" "' + VPath + '"', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
end;
end;
end;
if ResultCode <> 0 then
begin
// Handle Fail
CDFound := False;
MsgBox(CustomMessage('FileErr'), mbInformation, MB_OK);
WizardForm.Close;
end;
end;
To change the last modified time (let's call it LastWriteTime for now) for all files from a specified directory by the LastWriteTime of a certain file, use the following code after you have your files extracted. You can follow the commented version
of the previous version of this post, but note that I've had bugs there (mixed time parameters and unused file flag parameter), but the point remains.
Also note that this code is for ANSI version of InnoSetup. If you need to use this for Unicode version, you should define the CreateFile
function import as CreateFileW
instead of CreateFileA
or use the trick suggested by kobik
in this post
.
[code]
const
OPEN_EXISTING = 3;
FILE_SHARE_WRITE = 2;
GENERIC_WRITE = $40000000;
INVALID_HANDLE_VALUE = 4294967295;
function CreateFile(lpFileName: string; dwDesiredAccess, dwShareMode,
lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes: DWORD;
hTemplateFile: THandle): THandle;
external 'CreateFileA@kernel32.dll stdcall';
function CloseHandle(hObject: THandle): BOOL;
external 'CloseHandle@kernel32.dll stdcall';
function SetFileTime(hFile: THandle; const lpCreationTime, lpLastAccessTime,
lpLastWriteTime: TFileTime): BOOL;
external 'SetFileTime@kernel32.dll stdcall';
function FileSetTime(const AFileName: string; const ACreationTime,
ALastAccessTime, ALastWriteTime: TFileTime): Boolean;
var
FileHandle: THandle;
begin
Result := False;
FileHandle := CreateFile(AFileName, GENERIC_WRITE, FILE_SHARE_WRITE, 0,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if FileHandle <> INVALID_HANDLE_VALUE then
try
Result := SetFileTime(FileHandle, ACreationTime, ALastAccessTime,
ALastWriteTime);
finally
CloseHandle(FileHandle);
end;
end;
procedure ModifyLastWriteTime(const ASourceFile, ATargetFolder: string);
var
FindRec: TFindRec;
LastWriteTime: TFileTime;
begin
if FindFirst(ASourceFile, FindRec) then
begin
LastWriteTime := FindRec.LastWriteTime;
if FindFirst(ATargetFolder + '*.*', FindRec) then
try
repeat
if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY) = 0 then
FileSetTime(ATargetFolder + FindRec.Name, FindRec.CreationTime,
FindRec.LastAccessTime, LastWriteTime);
until
not FindNext(FindRec);
finally
FindClose(FindRec);
end;
end;
end;
And the usage. The first parameter of the ModifyLastWriteTime
procedure is the name of the source file from which the LastWriteTime is taken. The second parameter is the directory in what the files will get modified their LastWriteTime values by the source file (don't forget to have the trailing backslash in the target folder parameter):
ModifyLastWriteTime('c:\SourceFile.xxx', 'c:\TargetFolder\')
About the second question, you can delete the files which have been extracted in a procedure called
Procedure CancelButtonClick(CurPageID: Integer; Var Cancel, Confirm: Boolean);
Begin
End;
As explained in the chm, section Pascal Scripting: Event Functions
About the first question I would suggest you to use inno setup [files] section instead of extracting from an archive. You could probably extract this archive to a local folder (so from your side, before compiling, and add this local folder to the [files]. But I may misunderstand your imperative about the file modification date.