Diese Seite mit anderen teilen ...

Informationen zum Thema:
Forum:
WinDev Forum
Beiträge im Thema:
23
Erster Beitrag:
vor 4 Jahren, 8 Monaten
Letzter Beitrag:
vor 4 Jahren, 8 Monaten
Beteiligte Autoren:
JP, Pragma Tix, Fabrice Harari, Stefan Bentvelsen

Using API to access ZLIB

Startbeitrag von JP am 02.04.2013 11:06

Hello All,

Using WinDev 17.

I am trying to access the uncompress() function in the popular ZLIB.DLL library.


1) I need to un-compress data being sent to me using this library. I have looked through the help and found the API description variable. I have setup this up as below:


gZLIB_Uncompress..DLLName = "ZLIB.DLL"
gZLIB_Uncompress..FunctionName = "uncompress"
gZLIB_Uncompress..Parameter[1]..Type = apiString // Output string
gZLIB_Uncompress..Parameter[2]..Type = apiInt_8 // Output string length
gZLIB_Uncompress..Parameter[3]..Type = apiString // Input string
gZLIB_Uncompress..Parameter[4]..Type = apiInt_8 // Input string length
gZLIB_Uncompress..ReturnType = apiInt_4



2) The function requires being passed an input compressed string, the length of this string, a pre-created output string, and the length of the output string. The first 3 parameters are meant to be passed by reference, the fourth one by value. The result is an integer with a 0 or positive value being success. A negative number is a failure. I am trying to call this uncompress() function using this code

sInput_string is string = sResponse_Data
nInput_String_Length is int = Length( sResponse_Data )
sOutput_String is string = Complete( Charact(0) , 1024*1024 )
nOutput_String_Length is int = Length( sOutput_String )

gZLIB_Uncompress( sOutput_String , nOutput_String_Length , sInput_string , nInput_String_Length )



I always get a failure and no other errors occurring from WinDev. The compressed string is not uncompressed and the output string remains unchanged from its initial value.

Can anyone provide any suggestion or help?

TIA

Antworten:

Hi JP,

may be you have to use unsigned ints instead of signed ints ?

von Stefan Bentvelsen - am 02.04.2013 12:31
Hi Stefan,

I have found some more info: I was trying this using a 64 bit WinDev application. When I try it using a 32bit application I get an actual error message from WinDev. The error says:

Runtime error caused by 'uncompress' function of zlib.dll DLL.

Error code: 2805
Level: fatal error (EL_FATAL)

Dump of the error of 'wd170vm.dll' module (17.0.287.3).
Identifier of detailed information (.err): 2805
Debugging information:

Détails techniques :

Module : zlib.dll
Adresse de base : 62E80000
Erreur système : Access violation (GPF)
EIP = 62E8DAD7
OS : Windows 8 (6.2.9200)
Registres :

EIP = 62E8DAD7 EBP = 0018E744
EAX = 03809034 EBX = 00000000
ECX = FFFFFFFF EDX = 03809034
ESI = 0018E6F4 EDI = 00100000

Pile des appels :

[zlib.dll (62E80000)] 62E8DAB0 : uncompress() + 39 bytes

Fonction (0,90)
Additional Information:
EIT_PILEWL :
Click BTN_NoName1 (WIN_TBO_WS_RT_Client.BTN_NoName1), line 25
EIT_DATEHEURE : 02/04/2013 14:21:50

Help

Check parameters:
- whether the parameter type is correct
- whether null values are supported
- whether previous callDLL32 are correct.
- if the problem persists, contact the DLL author.


von JP - am 02.04.2013 13:23
Hi JP

First, you should read in DETAILS the help file about the API function (ans associated pages), as there are many guidelines that are very useful...

In general, I would say that most of the time tyou don't use a string but the ADDRESS of a string for an api call (ie &MyStringName)... Furthermore, you do not use windev strings but ASCIIZ string (which are more compatible with external apis)

All that (and much more) is clearly described in the help, so I advise that you take the time to understand the details of the API function before tryint to use it

Best regards

von Fabrice Harari - am 02.04.2013 14:03
So some further feedback. I now have this code and using API() as a testing method::

sInput_String is string = sCompressed_Data
nInput_String_Length is int = Length( sCompressed_Data )
sOutput_String is string = Complete( Charact(0) , 1024*1024 )
nOutput_String_Length is int = Length( sOutput_String )

API( "zlib.dll", "uncompress", &sOutput_String , &nOutput_String_Length , &sInput_String , (nInput_String_Length) )

Trace( ErrorInfo(errFullDetails) )


The first 3 parameters must be passed by reference (their address) and the last one by value. Using this I get a zero return value from the API() function and the following errorinfo():

WL call:
Process of 'Click BTN_NoName1' (WIN_TBO_WS_RT_Client.BTN_NoName1), line 25, thread 0
'API' function, syntax 0
What happened?
203 returned by GetLastError()
Error code: 0
Level: non-fatal error (EL_ONRETURN)
System error code: 203
System error message:
The system could not find the environment option that was entered.
Dump of the error of 'wd170vm.dll' module (17.0.287.3).
Debugging information:
Fonction (0,90)
Additional Information:
EIT_XINFO :
EIT_PILEWL :
Click BTN_NoName1 (WIN_TEST.BTN_NoName1), line 25
EIT_DATEHEURE : 02/04/2013 14:57:27


Any suggestions?

von JP - am 02.04.2013 14:04
Thanks Fabrice, I have been reading all morning; API(), API Description, LoadDLL(), CallDLL(), FreeDLL(), etc. :) I just am not getting much further. I have changed to using the & to pass the address of the variables. I am not familiar with using ASCIIZ strings. I guess after spending a 3+ hours trying to solve it myself the next step is to ask a few questions on a forum. Possibly someone else has already solved it, or a similar problem, and so time can possibly be saved! Thanks for the feedback.

von JP - am 02.04.2013 14:36
Hi,
would be nice to have the C function.. so here just a guess.
Beside AsciiZ strings will most probably not work .. 64 K limit..


inString is buffer = fLoadBuffer("C:\Temp\MyFile.gz")
outString is buffer
inLen is int on 8 = length(inString)
outLen is int on 8
inAdr is system int = &inString
outAdr is system int = &outString
res is int
res = API( "ZLIB", "uncompress", outAdr, &outLen, inAdr, inLen)
Transfer( outAdr, inAdr, outLen )


Well, no guarantee that this snippet works.. as said having the C function signature will help.

#pragma

von Pragma Tix - am 02.04.2013 16:27
Pragma, thanks very much for trying :)

I have run your code but had to make a small adjustment to avoid ZLIB giving errors regarding stream (code -2) and buffers (code -5). Basicaly ZLIB needs the calling program to pre-create a string variable (or buffer?) into which it will write uncompressed contents. So your code is now:


inString is buffer = fLoadBuffer( "C:\temp\compressed_data.txt" )
outString is buffer = complete( charact(0) , 1024*1024 ) // Pre-create the target buffer

inLen is int on 8 = Length(inString)
outLen is int on 8 = Length(outString)

inAdr is system int = &inString
outAdr is system int = &outString

res is int
res = API( "ZLIB", "uncompress", outAdr, &outLen, inAdr, inLen)

Transfer( outAdr, inAdr, outLen )


This returns a zero code from te API() call which indicates no error BUT the string is not decompresed. ErrorInfo() returns this:

WL call:
Process of 'Click BTN_NoName1' (WIN_TBO_WS_RT_Client.BTN_NoName1), line 23, thread 0
'API' function, syntax 0

What happened?
203 returned by GetLastError()

Error code: 0
Level: non-fatal error (EL_ONRETURN)

System error code: 203
System error message:
The system could not find the environment option that was entered.

Dump of the error of 'wd170vm.dll' module (17.0.287.3).
Debugging information:
Fonction (0,90)
Additional Information:
EIT_XINFO :
EIT_PILEWL :
Click BTN_NoName1 (WIN_TBO_WS_RT_Client.BTN_NoName1), line 23
EIT_DATEHEURE : 02/04/2013 17:45:58


I am not sure what the above error means and cannot find any reference in the help file.

Just for completeness, the ZLIB documentation including C source code is here: http://www.zlib.net/

Thanks again! Really eager to find a solution.

von JP - am 02.04.2013 16:52
ok,
then drop the transfer statement .. instead use
b is buffer = outString [[1 to outlen]]
to remove trailing nulls.

I am pretty sure that you DO NOT have to set outLen.. as you pass this parameter by refrence. ZLIB.DLL will set this value.

What is the value of outlen ? should be smaller than inLen ;)

#pragma

von Pragma Tix - am 02.04.2013 17:00
Hi Pragma,

I made the change as suggested. We have some succcess :)

The variable b is the encrypted text - so that is not quite right. But... the length of outlen is 11037 bytes which I can confirm is the correct length of the decompressed contents !

So we are almost there!

UPDATE: Sorry it is not the encrypted text in variable b but some chinese style characters, not the ASCII plain text that was originally compressed.

von JP - am 02.04.2013 17:15
Hi JP that's strange .. try this ..
( Frankly, the pre-allocation makes no sense to me.)


inString is buffer = fLoadBuffer( "C:\temp\compressed_data.txt" )
outString is buffer = complete( charact(0) , 1024*1024 ) // Pre-create the target buffer
// OR
outString is buffer on 1024 * 1024

inLen is int on 8 = Length(inString)
outLen is int on 8


res is int
res = API( "ZLIB", "uncompress", &outString, &outLen, &inString, inLen)

b is buffer = outString [[1 to outlen]]



von Pragma Tix - am 02.04.2013 17:29
Hi Pragma,

One has to specify the length of the outString (which I have added below with comment //***). Then the fucntion runs, returns code 0 (no error), sets the correct outLen = 11037, but the contents of b are scrambled using a strange chracter set (not the compressed content) e.g.

outlen = 11037
b = 㘶ㄹ〴㌴ⰸ听卂听䝉剂乁卄〬㨹...... and more like this
b len = 11037

inString is Buffer = fLoadBuffer( "c:\temp\compressed_data.txt" )
outString is Buffer = Complete( Charact(0) , 1024*1024 ) // Pre-create the target buffer

inLen is int on 8 = Length(inString)
outLen is int on 8 = Length(outString) //*****

res is int
res = API( "ZLIB", "uncompress", &outString, &outLen, &inString, inLen)

b is Buffer = outString [[1 TO outLen]]
Trace( "outlen = " , outLen )
Trace( "b = ", b )
Trace( "b len = " , Length(b) )


von JP - am 02.04.2013 17:38
replace buffer with string and let me know :


// now string : fLoadString etc...
inString is string = fLoadString( "C:\temp\compressed_data.txt" )
outString is string = complete( charact(0) , 1024*1024 ) // Pre-create the target buffer

inLen is int on 8 = Length(inString)
outLen is int on 8


res is int
res = API( "ZLIB", "uncompress", &outString, &outLen, &inString, inLen)

s is string = outString [[1 to outlen]]




von Pragma Tix - am 02.04.2013 17:41
Quote
Pragma Tix
replace buffer with string and let me know :


// now string : fLoadString etc...
inString is string = fLoadString( "C:\temp\compressed_data.txt" )
outString is string = complete( charact(0) , 1024*1024 ) // Pre-create the target buffer


It is exactly the same - correct return length but contents is wrong character set or just wrong content. Frustrating to be this close - lol !

von JP - am 02.04.2013 17:44
last idea ( sure we have a adress problem)

Because I am clueless .. last desperate idea...

res = API( "ZLIB", "uncompress", outString, &outLen, inString, inLen)

von Pragma Tix - am 02.04.2013 17:47
Quote
Pragma Tix
last idea ( sure we have a adress problem)

Because I am clueless .. last desperate idea...

res = API( "ZLIB", "uncompress", outString, &outLen, inString, inLen)


Sadly the same result. Correct length but the contents are wrong.... :(

von JP - am 02.04.2013 17:53
inString is buffer = fLoadBuffer( "C:\temp\compressed_data.txt" )
outString is buffer = complete( charact(0) , 1024*1024 ) // Pre-create the target buffer
// OR
outString is buffer on 1024 * 1024

inLen is int on 8 = Length(inString)
outLen is int on 8


res is int
res = API( "ZLIB", "uncompress", &outString, &outLen, &inString, inLen)

b is buffer
transfer(&b, &outstring, outlen)
trace(b)


That's it from my side.. will have a look at the C API IF i have the chance/time.

von Pragma Tix - am 02.04.2013 17:56
Quote
Pragma Tix
That's it from my side.. will have a look at the C API IF i have the chance/time.


Thanks Pragma - same result .... Thanks for all your help :) What a mystery!

von JP - am 02.04.2013 18:05
Pragma - success :)

We cannot use buffer type variables for inString or outString. Here is the code that works using simple strings and fLoadText():


inString is string = fLoadText( "c:\temp\compressed_data.txt" )
outString is string = Complete( Charact(0) , 1024*1024 ) // Pre-create the target string - cater for max possible size required

inLen is int on 8 = Length(inString)
outLen is int on 8 = Length(outString)

res is int
res = API( "ZLIB", "uncompress", &outString, &outLen, &inString, inLen)

Trace( "Uncompressed = " , outString )



Thanks for all your help. Really appreciate your time and effort.

von JP - am 02.04.2013 18:16
Thats exactly the code I gave you before ...
http://27130.foren.mysnip.de/read.php?27131,152593,152649#msg-152649

:cheers:

#pragma

von Pragma Tix - am 02.04.2013 18:26
Hi

if you are getting a result but it seems "strange", it may just be that you did not declare your string as ANSI (so by default is unicode).. Try to specify ANSI and see if it works better

Best regards

von Fabrice Harari - am 03.04.2013 12:49
Hi again

I finally found it...
I new I did use that function along time ago... So here is some code that was made in windev 5.5 (yep, that long ago) and migrated... With clearly an older version of zlib... Hope this helps



iRes is int
//Code WinDev 5.5 remplacé par la migration :
//lDest is long int
lDest is int
//Code WinDev 5.5 remplacé par la migration :
//lDestLen is long int
lDestLen is int
//Code WinDev 5.5 remplacé par la migration :
//lSource is long int
lSource is int
//Code WinDev 5.5 remplacé par la migration :
//lSourceLen is long int
lSourceLen is int

sString is string=par_sString
lSource =&sString
lSourceLen =Length(sString)
sResult is fixed string on 64000
lDest = &sResult
lDestLen = 64000
//int uncompress (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
iRes=CallDLL32(:sLibname,"uncompress",&sResult, &lDestLen, &sString, lSourceLen)
//trace(iRes, lDestLen, sProc)

sRes is string=Left(sResult, lDestLen)
IF sRes [ [ 1 ] ] =Charact(0) THEN sRes=""
RESULT sRes





Best regards

von Fabrice Harari - am 03.04.2013 13:01
Pragma, yes I guess with the test/debug cycle and the need to edit some of the lines (e.g. fLoadString() needed to be fLoadText() and the output string needed to be pre-created) I guess some confusion and coding errors crept in - "the fog of war" - lol!

Working fine now and I have converted to using API Description so that the DLL only has to be loaded once for the duration of the programs execution. Makes it faster on repeat calls.


// Setup the ZLIB Compress function

gZLIB_Compress is API Description

gZLIB_Compress..DLLName = "ZLIB.DLL"
gZLIB_Compress..FunctionName = "compress2"
gZLIB_Compress..Parameter[1]..Type = apiInt_4 // Address of Output string
gZLIB_Compress..Parameter[2]..Type = apiInt_4 // Output string length
gZLIB_Compress..Parameter[3]..Type = apiInt_4 // Address of Input string
gZLIB_Compress..Parameter[4]..Type = apiInt_4 // Input string length
gZLIB_Compress..Parameter[5]..Type = apiInt_4 // Compression level
gZLIB_Compress..ReturnType = apiInt_4

// Setup the ZLIB Uncompress function

gZLIB_Uncompress is API Description

gZLIB_Uncompress..DLLName = "ZLIB.DLL"
gZLIB_Uncompress..FunctionName = "uncompress"
gZLIB_Uncompress..Parameter[1]..Type = apiInt_4 // Address of Output string
gZLIB_Uncompress..Parameter[2]..Type = apiInt_4 // Output string length
gZLIB_Uncompress..Parameter[3]..Type = apiInt_4 // Address of Input string
gZLIB_Uncompress..Parameter[4]..Type = apiInt_4 // Input string length
gZLIB_Uncompress..ReturnType = apiInt_4



Thanks and cheers!

von JP - am 03.04.2013 13:10
Zur Information:
MySnip.de hat keinen Einfluss auf die Inhalte der Beiträge. Bitte kontaktieren Sie den Administrator des Forums bei Problemen oder Löschforderungen über die Kontaktseite.
Falls die Kontaktaufnahme mit dem Administrator des Forums fehlschlägt, kontaktieren Sie uns bitte über die in unserem Impressum angegebenen Daten.