I have ZipForge for Delphi XE2 & Delphi XE2.
I try to test any invalid zip archives (e.g. not fully downloaded) like in their demo:
procedure TfmMain.bnStartClick(Sender: TObject);
begin
with Archiver do
begin
FileName := 'c:\2.zip';
OpenArchive;
try
TestFiles('*.*');
except
MessageDlg('Errors occurred in the archive file', mtError, [mbOk], 0);
end;
CloseArchive;
end;
end;
But my exception doesn't fire; ZipForge's dialog fires instead of mine.
I tried Abbrevia Component but it even can't recognize if an archive is invalid...
Please help me to make my exception working (not ZipForge's one) or suggest me a better component for zip files with a test feature. Thanks!
Be aware that you can modify ZIP files, e.g. by truncating them somewhat, the ZIP file will still be valid. With my test file, I removed the final 5000 bytes and it was reported as valid. I extracted it successfully using my ZIP program. Of course the extracted contents were incorrect and not the original contents. Perhaps this is what was happening for you. Maybe your attempts to corrupt your ZIP file were not in fact making it into an invalid ZIP file.
Delphi XE2 comes with a built in ZIP component that worked well in my simple test and successfully detected an invalid file, once I had truncated the file enough to make it truly corrupt.
I used the IsValid method to check validity. Here is my very simple test program.
program ZipTest;
{$APPTYPE CONSOLE}
uses
System.SysUtils, System.Zip;
procedure Main;
const
ZipArchive = 'C:\desktop\test.zip';
var
ZipFile: TZipFile;
FileName: string;
begin
ZipFile := TZipFile.Create;
try
if ZipFile.IsValid(ZipArchive) then begin
ZipFile.Open(ZipArchive, zmRead);
for FileName in ZipFile.FileNames do begin
Writeln(FileName);
end;
end else begin
Writeln(ZipArchive + ' not valid');
end;
finally
ZipFile.Free;
end;
end;
begin
try
Main;
Readln;
except
on E: Exception do begin
Writeln(E.ClassName, ': ', E.Message);
end;
end;
end.
If you have an invalid ZIP file, it is most likely that the call to OpenArchive will fail. As long as your execption handling doesn't cover that case, you will get the result you describe.
Update: The suggested way to catch exceptions during TestFiles or any other method is to connect an OnProcessFileFailure event handler.
Related
I have a program that calls a DLL stored in the same folder that the program is stored in. When I run the calling code, either from the IDE or the program directly, it finds the DLL and gives no errors. But, when the client runs the program, it gives the error "Unable To Load DllSendOrder2018.dll". This behavior just started. On old versions of the code, it loads with no errors (other than another problem I need to fix).
procedure TFrmMain.BtnSendOrderClick(Sender: TObject);
var
SendOrders : procedure; stdcall;
begin
DLLHandleSend := LoadLibrary('DllSendOrder2018.dll');
if DLLHandleSend <> 0 then
begin
#SendOrders := GetProcAddress(DLLHandleSend,'SendOrders');
try
SendOrders;
except
on E: Exception do
ShowMessage(E.Message);
end;
FreeLibrary(DLLHandleSend);
end
else
MessageDlg('Unable To Load DllSendOrder2018.dll',mtError,[mbOk],0);
FldLookup.SetFocus;
end;
Is there a better place to put the DLL?
I am trying to use the (Windows) clipboard in a Delphi console program, but when I try to compile I get the message
"[dcc32 Fatal Error] Clipboard_Project.dpr(6): F2613 Unit 'Clpbrd' not found."
The code looks like this:
program Clipboard_Project;
{$R *.res}
uses
System.SysUtils, Clpbrd;
var
s: String;
begin
try
s := Clipboard.AsText;
writeln(s);
readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
I can imagine that it's something simple and obvious, but I can't find it! Any help would be appreciated!
for correction of this question, it should be used in the uses clause Vcl.ClipBrd correctly and not Clpbrd as incorrectly typed.
I have a url of a website. It looks something like this: http://www.example.com/downloads/file/4789/download?
I would like to save the file to my system, but I do not know how to get the file name of the download triggered by the URL in my example. Some files are pdf others are doc and rtf etc.
If someone can please point me in a direction of the filename problem and also what components to use, I would really appreciate it.
to get the filename from a url you can retrieve the HEAD information and check Content Disposition header field. For this task you can use the TIdHTTP indy component. if the Content Disposition doesn't have the file name you can try parsing the url.
Try this sample .
{$APPTYPE CONSOLE}
{$R *.res}
uses
IdURI,
IdHttp,
SysUtils;
function GetRemoteFileName (const URI: string) : string;
var
LHttp: TIdHTTP;
begin
LHttp := TIdHTTP.Create(nil);
try
LHttp.Head(URI);
Result:= LHTTP.Response.RawHeaders.Params['Content-Disposition', 'filename'];
if Result = '' then
with TIdURI.Create(URI) do
try
Result := Document;
finally
Free;
end;
finally
LHttp.Free;
end;
end;
begin
try
Writeln(GetRemoteFileName('http://dl.dropbox.com/u/12733424/Blog/Delphi%20Wmi%20Code%20Creator/Setup_WmiDelphiCodeCreator.exe'));
Writeln(GetRemoteFileName('http://studiostyl.es/settings/downloadScheme/1305'));
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
If I would like to save a IXMLDOMDocument3 in runtime to a file on my harddrive, what is the syntax for that?
E.g. like IXMLDOMDocument3.save('c:\test.xml')
Or is it even possible?
Best regards!
the sample code below demonstrates how to load and save IXMLDomDocument3 XML at runtime. It uses msxml header file from Delphi-2010. IXMLDomDocument3 inherits from IXMLDomDocument and has Save method (as you wrote in your question). If method parameter is a string, then it specifies file name (it creates or replaces target file).
program Project3;
{$APPTYPE CONSOLE}
uses SysUtils, msxml, comObj, activex;
procedure LoadAndSaveXML(LoadFile, SaveFile : string);
var xml : IXMLDOMDocument3;
tn : IXMLDOMElement;
begin
xml := CreateComObject(CLASS_DOMDocument60) as IXMLDOMDocument3;
xml.load(LoadFile);
xml.save(SaveFile);
end;
begin
try
CoInitialize(nil);
try
LoadAndSaveXML('D:\in.xml', 'D:\out.xml');
finally
CoUninitialize();
end;
except
on E: Exception do begin
Writeln(E.ClassName, ': ', E.Message);
readln;
end;
end;
end.
Are there any zip components with such features? I need to download a zip archive from the Internet to a stream, then to open the archive from the stream and then to extract files to another stream.
E.g. ZipForge can open an archive from a stream ZipForge.OpenArchive(MyStream, false);
but how to extract to another one...?
procedure ExtractToStream(FileName: WideString; Stream: TStream);
Description
Use ExtractToStream to decompress data stored in the file inside the
archive to a TStream descendant object like TFileStream, TMemoryStream
or TBlobStream.
The FileName parameter specifies file name being extracted.
And what use of the OpenArchive(MyStream, false) method if extraction isn't supported...
The zip file component that is built into XE2 will do this.
There is an overloaded Open method that receives a TStream as its input parameters.
To extract individual files you can call an overloaded Read method passing the name of the file that you wish to extract. The extracted file is returned as a new instance of TStream. You can that use CopyFrom on that instance to transfer the extracted file to your stream.
var
ZipFile: TZipFile;
DownloadedStream, DecompressionStream, MyStream: TStream;
LocalHeader: TZipHeader;
...
ZipFile := TZipFile.Create;
try
ZipFile.Open(DownloadedStream, zmRead);
ZipFile.Read('myzippedfile', DecompressionStream, LocalHeader);
try
MyStream.CopyFrom(DecompressionStream, DecompressionStream.Size);
finally
DecompressionStream.Free;
end;
finally
ZipFile.Free;
end;
Note that I've not tested this code, I've just written it based on the source code for TZipFile and the documentation contained in that source code. There may be a few wrinkles in this but if the code behaves as advertised it meets your needs perfectly.
OK, now I tested it because I was curious. Here's the program that shows that this all works as advertised:
program ZipTest;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.Classes,
System.Zip;
procedure ExtractToFile(
const ZipFileName: string;
const ZippedFileIndex: Integer;
const ExtractedFileName: string
);
var
ZipFile: TZipFile;
DownloadedStream, DecompressionStream, OutputStream: TStream;
LocalHeader: TZipHeader;
begin
DownloadedStream := TFileStream.Create(ZipFileName, fmOpenRead);
try
ZipFile := TZipFile.Create;
try
ZipFile.Open(DownloadedStream, zmRead);
ZipFile.Read(ZippedFileIndex, DecompressionStream, LocalHeader);
try
OutputStream := TFileStream.Create(ExtractedFileName, fmCreate);
try
OutputStream.CopyFrom(DecompressionStream, DecompressionStream.Size);
finally
OutputStream.Free;
end;
finally
DecompressionStream.Free;
end;
finally
ZipFile.Free;
end;
finally
DownloadedStream.Free;
end;
end;
begin
try
ExtractToFile('C:\desktop\test.zip', 0, 'C:\desktop\out.txt');
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Note that I extracted by index rather than file name since that was more convenient for me. And I used file streams rather than memory streams which I imagine you would use. However, since the TZipFile methods work with TStream I'm sure that the code will work with streams of any form.
This is the latest in a series of questions about ZIP files. I know that you are using XE2 and I wonder why you seem reluctant to use the built in ZIP class that XE2 provides. I've not seen anything to indicate that it will not fulfil your requirements. In fact, it is precisely this ability to work directly with streams that makes me feel it has sufficient generality for any application.