Delphi: Unzipping Files using FlexCompress (3rd-Party-Component) - delphi

I am having trouble unzipping files using the Delphi 3rd Party component FlexCompress. Here is the Code, detailed explanation after the code:
MyZipReader := TFlexCompress.Create(myComponent);
MyZipReader.Name := 'MyReader';
MyZipReader.FileName := DataPath; //e.g. C:\Users\thisUser\AppData\Local\Temp\ThisTempFolder\ThisZip.zip
MyZipReader.OpenArchive(fmOpenRead);
MyZipReader.BaseDir := BasePath; //e.g. C:\Users\[...]\ThisTempFolder\UnzipHere\
MyZipReader.CreateDirs := TRUE;
MyZipReader.ExtractCorruptedFiles := TRUE;
MyZipReader.ExtractFiles := ('*.*');
MyZipReader.closeArchive;
All files will be extracted and placed accordingly, so that's OK.
BUT: All files are empty. No text no nothing.
I have no idea what I am doing wrong. If I extract an archive I packed with Flexcompress everything is OK but if I try this with an external archive this behaviour occurs. Is there some sort of switch I am missing? I would be grateful about every tip or idea! I also tried the options ReplaceReadOnly and overwriteMode. Did not help and I am out of Ideas. If anyone knows some sort of FlexCompress forum I would also appreciate a link, maybe I could find info there? Sadly componentAce does not seem to host something like this.
Edit(2021.12.14 - 1.17pm)
Extra information gathered in the process:
One should not set the ExtractCorruptedFiles property to TRUE. This will prevent the eventhandler from raising an exception within the extractFiles() procedure

Related

Can't use DeleteFile() unless running program as admin, even with full control privileges

Our program is something like this:
C:\Main
C:\Main\Utils
C:\Main\App.exe
For C:\Main and all subfolders, we have all privileges for Everyone set to allow Full Control.
In our code, we create a .bmp file:
BmpSt := TMemoryStream.Create;
BmpSt.SetSize(Length(dta));
BmpSt.WriteBuffer(dta[1],Length(dta));
BmpSt.Seek(0,soFromBeginning);
Bmp := '\Main\Util\' + FormatDateTime('YYYYMMDDHHNNSS',Now) + '.bmp';
BmpSt.SaveToFile(Bmp);
if not DeleteFile(Bmp) then begin
ShowMessage('No');
end;
If I don't run App.exe as an administrator, it will never delete the file. However, when I do run it as an administrator, it deletes the file just fine.
Privileges are set to Full Control for Everyone.
I know this might not exactly be a Delphi question since its heavily dealing with Windows UAC, but this code worked fine when our program was in Delphi 5, now we are building it in Delphi 10.
We are also getting similiar issues using a TPrinter object to insert the above .bmp onto a print page, but I'm confident that the issues with DeleteFile will solve those.
Right after using DeleteFile() you can use GetLastError() to get what went wrong and trigger an exception for it with CheckOSError(). Once you know why it is failing you can troubleshoot further.
if not deletefile(bmp) then begin
CheckOSError(GetLastError);
end;

No PDF output from ReportBuilder

I have a ReportBuilder report that preview's as expected.
I'm trying to save it to pdf with the following code taken from the documentation:
ppReport1.ShowPrintDialog := false;
ppReport1.DeviceType := dtPDF;
ppReport1.TextFileName := 'C:\temp\report.pdf';
ppReport1.Print;
I get a glimpse of an dialog on the screen, stating that it outputs a couple of pages to the given file, but the file is no where to be found on disk.
What have I missed?
So, Process Monitor showed me that the file was written, but then deleted.
After a lot of source code browsing, I found the cause of this.
There is a property under EmailSettings called DeleteFile. For some reason, it also effects printing to file.
Try checking this property:
ppReport1.AllowPrintToFile := True;
It works fine with me.
It's strange. I just use by this way:
ppReport1.AllowPrintToFile := True;
ppReport1.ShowPrintDialog := False;
ppReport1.DeviceType := 'PDF';
ppReport1.TextFileName := 'C:\temp\report.pdf';
ppReport1.Print;
(I'm using it on ReportBuilder v14.07)

UrlDownloadToFile doesn't work in Delphi XE2?

I'm trying to download a file from the internet with Delphi XE2, but Nothing happens.
Here's my code:
uses URLMon;
...
procedure TForm1.Button1Click(Sender: TObject);
Const
SourceFile = 'http://www.google.com/intl/de/images/home_title.gif';
DestFile = 'c:\download\home_title.gif';
begin
UrlDownloadToFile(nil, PChar(SourceFile), PChar(DestFile), 0, nil);
end;
So my problem is: When I click the button, the program doesn't download the file.
I tried to download to another directory, I tried to download other files but nothing.
I can't get it to work.
What Am I doing wrong?
Please Help Me!
Your code works fine. Most likely the problem is a local one. Perhaps a problem with your network connection. Or perhaps the directory 'c:\download' does not exist.
To investigate your local problem, you'll need to make a note of the value returned by the function UrlDownloadToFile. It's an HRESULT and S_OK indicates success. Other values indicate failure. Once you know what the error code is, you should be able to track down your problem.
Having said that, UrlDownloadToFile doesn't seem to do a good job of returning meaningful error codes. For example, if you make DestFile be a path with non-existant folders, then the function still returns S_OK.

Problem adding lots of strings to a TStringList

I have a problem adding strings to a TStringList. I've searched other posts but couldn't find an answer to this.
What I'm trying to do is to add a big amount of strings to a TStringList (more than 14000) but somewhere in the process I get an EAccessViolation. Here's the code I'm using:
procedure TForm1.FormCreate(Sender: TObject);
begin
List := TStringList.Create;
List.Duplicates := dupAccept;
end;
procedure TForm1.ButtonStartClick(Sender: TObject);
begin
List.Clear;
List.Add('125-AMPLE');
List.Add('TCUMSON');
List.Add('ATLV 4300');
List.Add('150T-15');
List.Add('TDL-08ZE');
List.Add('RT20L');
List.Add('SIN LINEA');
List.Add('TIARA');
List.Add('FL200ZK1');
List.Add('FL250ZK1');
List.Add('SIN LINEA');
List.Add('CENTAURO-70 S.P.');
List.Add('CORSADO');
{ This list continues to about 14000 strings...}
List.Add('VOSJOD 2');
List.Add('Z 125');
List.Add('ZUMY');
List.Add('NEW AGE 125');
List.Add('SIN LINEA');
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FreeAndNil(List);
end;
¿What's wrong with this code? The list contains duplicate strings so I set the Duplicates property to dupAccept. I was able to load the list using LoadFromFile, but I don't want to have a text file outside my application.
I hope you can help me!!! Please tell me if you need any further information.
Thank you very much. I really appreciate your help.
The suggestions for using an external file are on the mark here. However, your post indicates your desire for not having an external file. I would then suggest you link the file to the executable as a resource. You can easily do this following these steps:
Place all the strings into a text file called stringdata.txt (or whatever name you choose). Then create a .rc file of whatever name you choose and put the following into it (STRING_DATA can be any identifier you choose):
STRING_DATA RCDATA "stringdata.txt"
Create a .res file from the .rc:
BRCC32 <name of rc>.rc
Now reference this file from the source code. Place the following someplace in the unit:
{$R <name of res>.res}
Instead of loading from a file stream, load from a resource stream:
StringData := TResourceStream.Create(HInstance, 'STRING_DATA', RT_RCDATA);
try
List.LoadFromStream(StringData);
finally
StringData.Free;
end;
If you do command-line automated builds, I would suggest you keep the .rc file under source control and build the .res during the build process. This way you can also keep the stringdata.txt file under source control and any edits are automatically caught on the next build without having to explicitly build the .res file each time the .txt file changes.
What Delphi version are you using? Some older versions had a bug in the memory manager that can cause an access violation when trying to reallocate an array to a size that's too large.
Try adding FastMM4 to your project to replace the old memory manager and see if that helps.
Also, you're probably better off keeping the list in an external file. Yes, it's another file, but it also means that you can change the list without having to recompile the entire program. This also makes creating (and distributing!) updates easier.
Mason is probably right for the cause of the AV; this is quite a large array to grow.
On a side note, when doing such a long processing on a StringList, it's recommended to surround it by BeginUpdate/EndUpdate to avoid firing any update event.
Even if you don't have any now, they might be added later and you'll get problems.
Set list.capacity to the number of items you plan to add, immediately after you create the list. Alternatively, place the list in an RC file (named other than with the name of your project) and add it to your project. This gets compiled into your application, but does not involve executable code to create the list.
I would also worry about compiler integrity with a 14,000 line procedure. People have found other cases where going beyond anything reasonable breaks the compiler in various ways.
You may also want to try THashedStringList, could see a speed boost (although not in this function), although I'm not sure if the add method is a whole lot different.
try using the following instead of your code to add the strings to the StringList
var
Str: string;
begin
Str := '125-AMPLE' + #13#10;
Str := Str + 'TCUMSON' + #13#10;
Str := Str + 'ATLV 4300' + #13#10;
Str := Str + '150T-15' + #13#10;
................
List.Text := Str;
end;

Too many open files

I get an EInOutError with message 'Too many open files' when executing this code block repeatedly for some time from a number of client threads:
var InputFile : Text;
...
Assign (InputFile, FileName);
Reset (InputFile)
try
// do some stuff
finally
CloseFile (InputFile);
end;
The number of client threads is approximately 10, so only 10 files can be open at any time. Is there any possibility that Delphi refuses to close files right away? Can I ensure that it does? Or am I making a mistake here? This is the only place where I open files and the try..finally block should guarantee that opened files get closed, shouldn't it?
REEDIT: forget the edit
I can only advise you to use the more "modern" facilities for dealing with files. I don't know whether there is a limit of open files using the Windows API, but I just tested and could easily open 1000 streams in parallel:
procedure TForm1.Button1Click(Sender: TObject);
var
Strs: TList;
i: integer;
begin
Strs := TList.Create;
try
for i := 1 to 1000 do begin
Strs.Add(TFileStream.Create('D:\foo.txt', fmOpenRead or fmShareDenyWrite));
end;
finally
FreeObjectList(Strs);
end;
end;
I have never understood why people still use untyped files instead of TStream and its descendants in new code.
Edit: In your comment you write that you only want to read plain text files - if so just create a TStringList and use its LoadFromFile() method.
You aren't running this on an older Windows 9x based computer, are you? If so, you might be running into a DOS filehandle problem.
Delphi closes immidiately in the CloseFile. Your example code seems to be correct.
Try again without anything between try and finally.
There IS a thread safety issue here although I can't see how it could cause the problem.
The problem is Reset uses the global FileMode variable.
As for client threads--are you sure they aren't leaking away on broken connections or something?
Might be useful to put some debug output alongside the Reset and the Close so you can see how long each thread has the file open for.
Do you really need threads? It sounds like they are causing you problems. Your code would be easier to debug without them.
This code should work just fine. There are no known problems related to using files from threaded code (as far as I know). We use such idioms fairly regularly and everything works fine.
I would suggest adding some logging code (before Assign and CloseFile) to see if a) close is executed and b) you really have only 10 threads running. Maybe your thread terminating logic is faulty and CloseFile never executes.

Resources