I'm trying to zip some files using Delphi 2007 using the JEDI JCL. The problem is I can't figure out why I keep getting this error "Sevenzip: Failed to load 7z.dll"
My code is :
var
archiveclass: TJclDecompressArchiveClass;
archive: TJclDecompressArchive;
item: TJclCompressionItem;
s: String;
i: Integer;
begin
archiveclass := GetArchiveFormats.FindDecompressFormat(dir);
if not Assigned(archiveclass) then
raise Exception.Create('Could not determine the Format of ' + dir);
archive := archiveclass.Create(dir);
try
if not (archive is TJclSevenZipDecompressArchive) then
raise Exception.Create('This format is not handled by 7z.dll');
archive.ListFiles;
s := Format('test.zip Item Count: %d'#13#10#13#10, [archive.ItemCount]);
for i := 0 to archive.ItemCount - 1 do
begin
item := archive.Items[i];
case item.Kind of
ikFile:
s := s + IntToStr(i+1) + ': ' + item.PackedName + #13#10;
ikDirectory:
s := s + IntToStr(i+1) + ': ' + item.PackedName + '\'#13#10;//'
end;
end;
if archive.ItemCount > 0 then
begin
// archive.Items[0].Selected := true;
// archive.ExtractSelected('F:\temp\test');
archive.ExtractAll('F:\temp\test');
end;
ShowMessage(s);
finally
archive.Free;
end;
I have the 7z.dll in the same folder as the Delphi project. What Am I doing wrong? Also is there any other simple way to 7z a folder? I'm not looking for some complex tasks, just to create a zip from a folder.
The JCLCompression unit only wraps the 7z API inside JCLCompression classes. The 7z API itself resides in the SevenZip.pas unit (in the windows folder of the JCL source). This is where the 7z.dll is loaded (by the Load7Zip routine, when required).
You appear to be compiling the project with dynamic linking to that DLL, resulting in the DLL only being loaded when needed, rather than being loaded and linked with your EXE. The fact that the loading is failing and the error message you are seeing in the exception indicates some problem with finding or loading that DLL at runtime.
Things to check:
Ensure that the 7z.dll is in the same folder as your EXE (not the DPR source file, but the EXE at runtime)
Ensure that the 7z.dll you are using is 32-bit. Delphi 2007 produces 32-bit executables only, so even on a 64-bit OS you will still need the 32-bit version of 7z.dll for your Delphi application.
Related
In my Delphi (10.3 community edition) program, I try to use Indy with the OpenSSL library, but I receive an error
Could not load SSL library
My OpenSSL library is version 1.0.2u and I put the libeay32.dll and ssleay32.dll files in my program EXE directory, and in Windows\SYSWOW64 and Windows\System32.
I have installed the Embarcadero Delphi Patch RS1033_Indy_SSL_Patch.
After the exception, I call WhichFailedToLoad() and the result is
Failed to load libeay32.dll
This is a simple program that raises the exception:
url := 'https://www.google.it';
try
Web := TIdHTTP.Create(nil);
hIOHand := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
hIOHand.SSLOptions.SSLVersions := [sslvTLSv1,sslvTLSv1_1,sslvTLSv1_2,sslvSSLv23];
Web.IOHandler := hIOHand;
Web.Request.UserAgent := INET_USERAGENT; //Custom user agent string
Web.RedirectMaximum := INET_REDIRECT_MAX; //Maximum redirects
Web.HandleRedirects := INET_REDIRECT_MAX <> 0; //Handle redirects
Web.ReadTimeOut := INET_TIMEOUT_SECS * 1000; //Read timeout msec
try
Sito := Web.Get(Url);
Sito := DateToStr(Web.Response.LastModified) + Sito;
except
on e : exception do
stg := WhichFailedToLoad();
end;
finally
Web.Free;
end;
Can you help me to solve the problem?
I put the libeay32.dll and ssleay32.dll files in my program EXE directory
That is fine. That is the 1st place the OS will look for them.
and in Windows\SYSWOW64 and in Windows\System32
Don't do that! Non-system files do not belong there. ESPECIALLY if you are putting the same files in both folders, since Windows\SYSWOW64 is meant only for 32bit files and Windows\System32 is meant only for 64bit files.
Failed to load libeay32.dll
That means Windows could not load that DLL into memory at all. Probably because it couldn't find the dependent ssleay32.dll file, but more likely because you mixed up the 32bit and 64bit versions of the DLLs. If your app is compiled as a 32bit EXE, you must use the 32bit version of both DLLs. If your app is compiled as a 64bit EXE, you must use the 64bit version of both DLLs.
I have an application compiled for Compact Framework which I need to find the version number for using Delphi 2006. I am using the code below.
function VersionNumber(ExeFile: string): string;
var
Size: Longint;
Dummy: Cardinal;
Buffer: Pointer;
FileInfo: Pointer;
begin
Size := GetFileVersionInfoSize(PChar(ExeFile), Dummy);
GetMem(Buffer, Size);
if (GetFileVersionInfo(PChar(ExeFile), Dummy, Size, Buffer)) then begin
//VerQueryValue(Buffer, '\\', FileInfo, Dummy);
//with PVSFixedFileInfo(FileInfo)^ do
//Result := IntToStr(dwFileVersionMS div $10000) + '.' +
// IntToStr(dwFileVersionMS mod $10000) + '.' +
// IntToStr(dwFileVersionLS div $10000) + ' (' +
// IntToStr(dwFileVersionLS mod $10000) + ')';
end
else begin
Result := 'No version info available.';
end;
FreeMem(Buffer, Size);
end;
If I view the file details using Windows 7 I cannot see the version number there either, so it's not surprising that I cannot get it from Delphi.
Just on the off chance someone knows a way to get the version number it would be greatly appreciated.
UPDATE
This code was written more then a decade ago by an ex staff member. Up until now, it has worked fine, but has never been tried on an executable compiled for Compact Framework.
The GetFileVersionInfo function is returning false, so I am getting 'No version info available.' result.
CF does not put C/C++ FileVersionInfo into exe or DLL files. The AssemblyInfo is something different from the FileVersionInfo resource you are looking for with your code sample.
ctacke has a usefull post about this at http://blog.opennetcf.com/2014/01/03/howto-add-the-win32-file-version-to-your-net-compact-framework-assemblies/ which can be found via Version information missing from .NET assembly (Compact Framework 3.5/VS2008), what graymatter already posted.
I wanted to bring an old Delphi application (built in Borland Delphi 6) up to version 13 of Crystal reports. It had been brought up to version 10.2 before using the steps outlined in the do-it-yourself guide SAP has posted: http://scn.sap.com/docs/DOC-11048
I committed the same changes again, pointing from the 10.2 registry keys to the 13 registry keys and updating the version checks in the VCL. The VCL component now pulls CRPE32.dll successfully from the right location but then fails to find the related Dll files such as pvlocal-1-0.dll and local_fallback-4-0.dll. If I move all the Dlls to the same folder as the application they are found, but I don't know if I want to be packing all 16 dlls and a license file together with the application.
I've narrowed the issue to the LoadLibrary call in the following method. Unfortunately I can't find any information on how to resolve the issue and was hoping the community might know a way to fix it:
function TCrpeEngine.PELoadCrpeDll(const CrpeLocation: string) : Bool;
var
s1,s2 : string;
begin
Result := False;
s1 := Trim(CrpeLocation);
CRDEngine := LoadLibrary(PChar(s1));
{If an error occured, set the flag}
if (CRDEngine < HINSTANCE_ERROR) then
begin
CRDEngine := 0;
s2 := SysErrorMessage(GetLastError);
if Trim(s2) = '' then
s1 := CRD_ERROR_LOADING + Chr(10) + 'Windows Error Number: ' + IntToStr(GetLastError)
else
s1 := CRD_ERROR_LOADING + Chr(10) +
'Windows Error Number: ' + IntToStr(GetLastError) + ' - ' + Trim(s2);
CRDEngineError(s1);
end
else
Result := True;
end;
The problem is that the the CRPE32.dll is loaded but it does not know where the other DLLs
are located as they are not in the search path.
You have a few options.
You can call SetDLLDirectory with with the path that you are storing the DLLs in.
Add the directory where the files are located to the system path.
Add the files to a directory already in the search path.
Add the files to your working directory.
You can not use CR version 13 > with Delphi. CR V13 is .NET
I use CR V13 now w/Delphi XE2. You need to write .NET wrapper using C# or Delphi Prism and call It from Delphi.
Summary:
I am having trouble to get the JCL compression library to open any spanned archives.
It presents the error "(0000001) Incorrect Function" as defined in borlands 'windows.pas';
scenerios:
A single archive compressed using the JCL compression example.
-Will uncompress in both the JCL example and the 7zip gui.
A spanned archive over 7 files compressed using the JCL compression example.
-Will uncompress in only the 7zip gui. Fails to uncompress using JCL example.
A single archive compressed using the 7zip gui.
-Will uncompress in both the JCL example and the 7zip gui.
A spanned archive compressed over 7 files using the 7zip gui.
-Will uncompress in only the 7zip gui. Fails to uncompress using JCL
Extra information
The JCL compression demo is the one included with the JCL library.
JCL: 2.2.1.3970
7zip dll: 9.20.0.0 and 9.65.0.0
Example filename in spanned archive set: "Test Archive.7z.002"
Tried with both .tar and .7z compression
Different file sizes were used. 2048 bytes and 2048KB
Delphi 2009.
This is the code im using.
Its from the JCL compression demo.
Error occurs on line 'TJclDecompressArchive(FArchive).ListFiles'.
procedure TFormMain.ActionOpenROExecute(Sender: TObject);
var
ArchiveFileName, Password: string;
AFormat: TJclDecompressArchiveClass;
SplitArchive: Boolean;
begin
if OpenDialogArchiveRO.Execute then
begin
CloseArchive;
ArchiveFileName := OpenDialogArchiveRO.FileName;
SplitArchive := AnsiSameText(ExtractFileExt(ArchiveFileName), '.001');
if SplitArchive then
ArchiveFileName := ChangeFileExt(ArchiveFileName, '');
AFormat := GetArchiveFormats.FindDecompressFormat(ArchiveFileName);
if AFormat <> nil then
begin
if SplitArchive then
ArchiveFileName := ArchiveFileName + '.%.3d';
InputQuery('Archive password', 'Value', Password);
FArchive := AFormat.Create(ArchiveFileName, 0, SplitArchive);
FArchive.Password := Password;
FArchive.OnProgress := ArchiveProgress;
if FArchive is TJclDecompressArchive then
TJclDecompressArchive(FArchive).ListFiles
else
if FArchive is TJclUpdateArchive then
TJclUpdateArchive(FArchive).ListFiles;
ListView1.Items.BeginUpdate;
try
while ListView1.Items.Count < FArchive.ItemCount do
ListView1.Items.Add;
finally
ListView1.Items.EndUpdate;
end;
end
else
ShowMessage('not a supported format');
end;
end;
The JCL example does know about the files and does open them.
(zip format used in image. Same problem).
Prehaps someone has come across this before?.
Can anyone point me in the right direction please?.
Thank you for your time.
Scott M.
This bug exists in Project JEDI - Issue Tracker.
http://issuetracker.delphi-jedi.org/bug_view_advanced_page.php?bug_id=5137
Two possible work-around
Upgrade your JCL installation to latest daily build
Comment the following line in JclCompression.pas at procedure TJclSevenzipDecompressArchive.OpenArchive; and rebuild the packages.
// comment this line !
SevenzipCheck(InArchive.Open(AInStream, #MaxCheckStartPosition, OpenCallback));
Can I create Windows XP's Compressed (Zipped) Folder using Delphi?
If you are using Delphi X2, just use TZipFile from System.Zip:
To Zip a folder, use:
TZipFile.ZipDirectoryContents('ZipFile.zip', 'C:\Zip\this\right\now');
To Zip files, use:
Zip := TZipFile.Create;
try
Zip.Open('ZipFile.zip', zmWrite);
Zip.Add('FileToBeZipped.txt');
Zip.Add('ThisWillBeCompressedAgainForSureAndBecomeSmaller.zip');
finally
Zip.Free;
end
According to a thread in eggheadcafe, you can use CreateFile Function with FILE_FLAG_BACKUP_SEMANTICS to create a Compressed Folder.
For shell extensions route, take a look at Using Windows XP "Compressed Folder" shell extension to work with .zip files by Namespace Edanmo, which is written in VB.
I just found the similar question asked on C++. Take a look at Creating a ZIP file on Windows (XP/2003) in C/C++. I have a feeling the easiest route is buying ZipForge. See Zip a file in Delphi code sample.
Some time ago, I've tried all of the Delphi compression libraries that I could find, and eventually I ended up using KaZip by Kiril Antonov.
My requirements were:
Free;
Open source;
Native Delphi code;
No external dependencies (dll, exe). My most important requirement;
Small memory footprint;
Easy to use;
I use it mainly to turn .kml files into .kmz, and it does that amazingly fast.
Here's an example of how I use it:
uses
KaZip;
...
// replaces a .kml file with a .kmz file
procedure KmlToKmz(const aFileName: string);
var
FS: TFileStream;
KaZip:TKaZip;
KmzFileName:TFileName;
begin
KmzFileName := ChangeFileExt(aFileName, '.kmz');
KaZip := TKaZip.Create(nil);
try
// create an empty zipfile with .kmz extension:
FS := TFileStream.Create(KmzFileName, fmOpenReadWrite or FmCreate);
try
KaZip.CreateZip(FS);
finally
FS.Free;
end;
KaZip.Open(KmzFileName); // Open the new .kmz zipfile
KaZip.Entries.AddFile(aFileName); // add the .kml
KaZip.Close;
DeleteFile(aFileName); // delete the .kml
finally
KaZip.Free;
end;
end;
Take a look at this OpenSource SynZip unit. It's even faster for decompression than the default unit shipped with Delphi, and it will generate a smaller exe (crc tables are created at startup).
No external dll is needed. Works from Delphi 6 up to XE. No problem with Unicode version of Delphi. All in a single unit.
I just made some changes to handle Unicode file names inside Zip content, not only Win-Ansi charset but any Unicode chars. Feedback is welcome.
You could use TurboPower Abbrevia which is now open source.
A "zipped" folder in Windows is nothing more than a .ZIP file compressed using any standard zip library. Compressed folders are a different animal and require an NTFS disk format.
For the "Zip" file, I strongly suggest the Turbo Power Abbrevia, which is open source and works well. You might want to check this alternate site if your using Delphi 2009 as it might be a more recent copy.
If your wanting to use the compressed folders option, you will need to modify the directory flags on the directory handle. This will only impact NEW files added to that directory and will not automatically compress existing files. If you have an existing directory you are trying to compress, then rename each existing file, and load and save it back to the original name deleting the original file when complete with each one. Yozey had a good link to the MSDN documentation. Just remember that this only works with NTFS formatted disks, so you will need to add a check for that in your code.
You can use some command line version of any compressor like 7zip and do the task using ShellExecute, or you can use a free or comercial component like anyone of these.
I had used ZipMaster and it behaves very well for my purpose. I don't know what are your size, space and performance requirements.
Take a look at these:
File Compression
FSCTL_SET_COMPRESSION
The TZipFile.ZipDirectoryContents method did not work for me, so I created my own implementation using TZipFile.add(). I am posting it here if anyone needs it.
procedure CreateZipOfDirectory(directory: string);
var
zip: TZipFile;
Arr: tarray<string>;
str: string;
function GetAllFilesInDir(const Dir: string): tarray<string>;
var
Search: TSearchRec;
procedure addAll(arr: tarray<string>; parent: string);
var
tmp: string;
begin
for tmp in arr do
begin
setlength(result, length(result) + 1);
result[length(result) - 1] := IncludeTrailingBackslash(parent) + tmp;
end;
end;
begin
setlength(result, 0);
if FindFirst(IncludeTrailingBackslash(Dir) + '*.*', faAnyFile or faDirectory, Search) = 0 then
try
repeat
if (Search.Attr and faDirectory) = 0 then
begin
setlength(result, length(result) + 1);
result[length(result) - 1] := Search.Name;
end
else if (Search.Name <> '..') and (Search.Name <> '.') then
addAll(GetAllFilesInDir(IncludeTrailingBackslash(Dir) + Search.Name), Search.Name);
until FindNext(Search) <> 0;
finally
FindClose(Search);
end;
end;
begin
Zip := TZipFile.Create;
try
Zip.Open('Foo.zip', zmWrite);
arr := GetAllFilesInDir(directory); // The Delphi TZipFile.ZipDirectoryContents does not work properly, so let's create our own.
for str in arr do
zip.Add(directory + str, str); // Add the second parameter to make sure that the file structure is preserved.
finally
zip.Free;
end;
end;