Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Delphi XE and Zip32.dll

Status
Not open for further replies.

Kenbla

Programmer
Oct 11, 2006
68
SE
Hello there, am I the only one that has problems with zip32.dll using Delphi XE?
I get a return code = 12 when I run my Delphi XE application program and try to compress a file which is to be sent via e-mail. It worked just fine in version 2006 and I haven't made any modifications at all.
The zip32.dll file I currently use is version 2.3 (from 1999!!).
Any assistance is greatly appreciated!
Regards
 
Unicode might be the issue. Try setting your application to use ansistrings instead of string (which are unicode compatible).
 
Hi DjangMan, and thanks for your response. How do you mean? Do I need to set the unicode in zip32.dll and if so how do I do it?
 
What he is trying to say is that since Delphi 2009, the Delphi string type is a Unicode string instead of an ANSI string. Try using AnsiString instead of string to pass string data to zip32.dll functions.
 
Thanks Prattaratt, I have tried to change the string variables that I use when communicating with zip32.dll to AnsiString but I still get the same result (return code 12).
This piece of code returns 12:
"iRC := ZpArchive(ZIPRec);"
and ZIPRec is defined as: ZIPRec : TZCL;
Any other ideas?
Regards,
Kenbla
 
I would be willing to bet that Delphi is still trying to pass the wrong type of string to zip32.dll. Try converting the AnsiStrings to a null terminated string. like so:

Code:
Procedure SomeProc()
VAR
  Str :AnsiString;
  PS:PChar;
Begin
  Str:= 'Test'
  PS:= PChar(Str);  // PS points to a Null term'd String.
End;
 
Hi and thanks for your help.
I have tried to use PAnsiChar in the only string that is used when communicating with zip32.dll, unfortunately I still get the same error message (return code 12).
The call to the procedure which produces the zip-file looks like this:
MakeZipFile(sFileName: String; oFileList: TStrings); //it requires a string as the first parameter
and the procedure itself looks like this:
Procedure TXXX.MakeZipFile(sFileName: String; oFileList: TStrings);
I have then typed the string to PAnsiChar whereever it is used as follows:
GetMem(ZIPRec.lpszZipFN, Length(PAnsiCharsFileName)) + 1);
ZIPRec.lpszZipFN := StrPCopy(ZIPRec.lpszZipFN, PAnsiChar(sFileName));
iRC := ZpArchive(ZIPRec); //Send the data to the dll
if iRC <> 0 then
begin
showmessage('Error code = ' + IntToStr(iRC)); //the return code is 12
halt;
end;
Am I doing something wrong? Well obviously I am! but I don't know what!
 
Your getmem may be incorrect

GetMem(ZIPRec.lpszZipFN, Length(PAnsiChars(FileName)) + 1);

should be

GetMem(ZIPRec.lpszZipFN, Length(sFileName) + 1);

However;

If the call to the DLL is going to fill this variable with a return string you would have to allocate memory for it (or have the DLL do it, and have the DLL free it), but since that's not the case, you should be able to get by with simply assigning the string to lpszZipFN.

ZIPRec.lpszZipFN := PANSIChar(sFileName);

Also, you don't include the code you have to assign the list of files to include in the zip file (ZIPRec.FNV), so you may also have an issue there. Can't tell without seeing it.
 
There are also other zip libraries that are free. The JCL has one, for example.
 
Hi again, the GetMem call is correct, it was just a "misprint" from me.
The rest of the code looks like this, please note that I have left out the declaration of variables and some other irrelevant code:
ZIPOptions := ZpGetOptions;
ZIPOptions.Date := nil;
ZIPOptions.szRootDir := nil;
ZIPOptions.szTempDir := nil;
ZIPOptions.fJunkDir := true;
ZIPOptions.fLevel := '9';
ZpSetOptions(ZIPOptions);
oFiles := TStringList.create;

for iIx := 0 To livUtkorg.Items.Count - 1 do
begin
oFiles.Add(livUtkorg.Items[iIx].SubItems[0] + livUtkorg.Items[iIx].Caption);
end;
sTimestamp := FormatDateTime('yyyymmddhhmmss', Date + Time); //Create a unique name for the zip-file
msTempName := 'ABC123_' + sTimestamp + '.zip';
MakeZipFile(msExportPath + msTempName, oFiles);

procedure TGEN990.MakeZipFile(sFileName: String; oFileList: TStrings);
SetDummyInitFunctions(ZUF); //Initialize the dll with dummy functions
ZIPRec.argc := oFileList.Count; //Number of files to zip
GetMem(ZIPRec.lpszZipFN, Length(sFileName) + 1); //Name of zip file - allocate room for null terminated string
ZIPRec.lpszZipFN := StrPCopy(ZIPRec.lpszZipFN, sFileName);
try
GetMem(ZIPRec.FNV, ZIPRec.argc * SizeOf(PChar)); //Dynamic array allocation
FNVStart := ZIPRec.FNV;
try
for iIx := 0 to ZIPRec.argc - 1 do //Copy the file names from FileList to ZipRec.FNV dynamic array
begin
GetMem(ZIPRec.FNV^[iIx], Length(oFileList[iIx]) + 1);
StrPCopy(ZIPRec.FNV^[iIx], oFileList[iIx]);
end;
try
iRC := ZpArchive(ZIPRec); //Send the data to the dll
if iRC <> 0 then
begin
showmessage('An error occurred, errorcode = ' + IntToStr(iRC)); //This is where I get errorcode 12
halt;
end;
finally
ZIPRec.FNV := FNVStart; //Release the memory for the file list
for iIx := (ZIPRec.argc - 1) downto 0 do
begin
FreeMem(ZIPRec.FNV^[iIx], Length(oFileList[iIx]) + 1);
end;
end;
finally
ZIPRec.FNV := FNVStart; //Release the memory for the ZipRec.FNV dynamic array
FreeMem(ZIPRec.FNV, ZIPRec.argc * SizeOf(PChar));
end;
finally
FreeMem(ZIPRec.lpszZipFN, Length(sFileName) + 1); //Release the memory for the FileName
end;

As I said it has worked for many years now using Delphi 2006 but not now using XE! I have also tried to use PAnsiChar around all string variables but unfortunately with the sama result.
Regards,
Kenbla
 
The oFileList is TStrings which will also be the unicode strings as well.
 
Thanks for your replies, I have now changed the oFileList but it still doesn't work (same return code 12) the GetMem for example looks like this now:
GetMem(ZIPRec.FNV^[iIx], Length(PAnsiChar(oFileList[iIx])) + 1);
and I have changed it in similar ways throughout the code.
Any other ideas?
Regards,
Kenbla
 
Have you converted these lines

GetMem(ZIPRec.FNV, ZIPRec.argc * SizeOf(PChar));

FreeMem(ZIPRec.FNV, ZIPRec.argc * SizeOf(PChar));

Should be SizeOf(PANSIChar)

SizeOf will be different for a PChar and a PANSIChar.
 
Thanks majlumbo, yes I have tried that and I get the same returncode (12) unfortunately!
 
something just occurresd to me: check to see if you have an archive already created with all the files already in it that you are trying to create. If nothing has changed inside of an archive/zipfile, it may be returning code 12 because there really is nothing to do. If the zip file does exist, try deleting and see what happens.
If that is not the case, then try this:

Set a breakpoint at the call to ZpArchive. Then open up a CPU debug window and locate the ZipRec variable in the data pane. Check to see if the filename and filelist strings have a 0 prepended to them. If so, that is the problem. ZpArchive is expecting a zero terminated string, and since the first char of the string is zero, it thinks you are not passing any parameters to it at all. convert your strings thus:

Next Question if the above is the case: Did you define the TZCL yourself, or is it provided already for you? Check the record definition; if the definitions for lpszZipFN and FNV are based on string (IE ^String and ^^String respectively or PChar and ^PChar), that is your problem. It needs to be changed to based of of PAnsiChar. As long as it tries to use anything that is derived from String type, it is going to be using Unicode, which is a 2 byte character size.

Your record type declaration should look something like this:
TCZ = record
ArgC : Integer;
ZipFName: PAnsiChar;
FileList: ^PAnsiChar;
end;

Next, the most efficient manner of converting UnicodeStrings (String) to AnsiStr is:

AStr := UString; // results in warning that you may lose data.

You will recieve a warning of possible data loss from the assignment, but that is because it will strip the extra byte from the 16 bit char to make it an 8 bit char. Once you do that, you can assign the PAnsiChar := @AStr[1]; and you have a null terminated string pointer. The other thing to consider is that the FNV field is a ponter to a pointer, so the assignment would be:
AFileListPtr := @AZipFileList[1];
ZipRec.FNV := @AFileListPtr;
 
Thanks for your reply Prattaratt!
1. The zipfile I try to create use timestamp as part of the filename som there can be no duplicates.
2. The filename and filelist does not have a 0 as part of the strings.
3. I did not write this code by myself, it was copied from the internet years ago
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top