Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Problems with a DLL in ooRexx 4.0.0 under Windows XP

21 views
Skip to first unread message

Jeremy Nicoll - news posts

unread,
Nov 2, 2009, 1:50:52 PM11/2/09
to
ooRexx 4.0.0, Windows XP Pro SP3

I'm trying to get a rexx exec to use a function from a DLL. It's not
working how I expected it to, but I don't know where the problem lies.


The DLL is something called aamd532.dll, and it implements an MD5 digest on
a file. I found the following example of its use in VB (which I've never
used either):

Public Declare Sub MDFile Lib "aamd532.dll" (ByVal f As String,
ByVal r As String)

- which I presume means the function in the DLL expects to be given the
address of two strings, one containing a filename and the other enough space
for a (16-byte, represented as 32 hex digits?) md5 digest.

I've seen that used in turn as:

Public Function MD5File(f As String) As String
Dim r As String * 32
r = Space(32)
MDFile f, r
MD5File = r
End Function


So, in my rexx exec I did this:

md5dllnm = "MDFile" /* function name as defined inside DLL */
md5dllrx = "rxMD5" /* name I'll use for it in this rexx exec */
md5dllpt = "C:\Program Files\~A-folder\AutoPatcher\bin\aamd532.dll"

findadll = rxfuncadd(md5dllrx,md5dllpt,md5dllnm)
say "funcadd rc="findadll "(0=ok, 1=err)"


That shows a rc of 0 each time I run it, so I suppose it worked. I then
tried querying 4 function names, three of which I expected the exec not to
be able to find. In particular I was trying to show that the function name
that rexx would now recognise was the 'rx' one rather than the 'nm' value:

q.1 = "rxwibble"
q.2 = md5dllrx /* hopefully this one will work */
q.3 = md5dllnm
q.4 = "rxwobble"
q.0 = 4

do qq = 1 to q.0
qqthname = q.qq
queryfnm = rxfuncquery(qqthname)
say " rxfuncquery for name:" right(qqthname,12) "was:" queryfnm
end

which produces:

rxfuncquery for name: rxwibble was: 1
rxfuncquery for name: rxMD5 was: 0
rxfuncquery for name: MDFile was: 1
rxfuncquery for name: rxwobble was: 1

which I think means I have managed ok to define "rxMD5" as a function as far
as rexx is concerned.


Learning one step at a time, I thought I'd next try to drop the four
functions (or at least one function and three irrelevant names), in which I
expected to get one success and three failures, but that didn't happen, so I
followed this by 4 more queries to see if the drops had done anything:

do qq = 1 to q.0
qqthname = q.qq
dropfunc = rxfuncdrop(qqthname)
say " rxfuncdrop for name:" right(qqthname,12) "was:" dropfunc
end
say

do qq = 1 to q.0
qqthname = q.qq
queryfnm = rxfuncquery(qqthname)
say " rxfuncquery for name:" right(qqthname,12) "was:" queryfnm
end
say

which produces:

rxfuncdrop for name: rxwibble was: 1
rxfuncdrop for name: rxMD5 was: 1
rxfuncdrop for name: MDFile was: 1
rxfuncdrop for name: rxwobble was: 1

rxfuncquery for name: rxwibble was: 1
rxfuncquery for name: rxMD5 was: 0
rxfuncquery for name: MDFile was: 1
rxfuncquery for name: rxwobble was: 1

Does this mean that none of the rxfuncdrop calls worked?


After that I thought I'd have a go at calling the loaded function anyway.
So I tried an exec with the rxfuncadd (as above), then the four queries,
then:

testfile = "C:\TESTFILE.PY" /* this file does exist */
digest = copies(" ",40)
say "digest sz=" length(digest) /* make sure there's space for reply */

call "rxMD5" testfile,digest
say " fn result:" digest

This dumps. I don't know if I'm trying the call the wrong way, or failing
to pass parameters correctly, or what.


All hints gratefully accepted!

--
Jeremy C B Nicoll - my opinions are my own.

Email sent to my from-address will be deleted. Instead, please reply
to newsre...@wingsandbeaks.org.uk replacing "nnn" by "284".

Swifty

unread,
Nov 3, 2009, 6:08:02 AM11/3/09
to
Jeremy Nicoll - news posts wrote:
> The DLL is something called aamd532.dll, and it implements an MD5 digest on
> a file. I found the following example of its use in VB (which I've never
> used either):
>
> Public Declare Sub MDFile Lib "aamd532.dll" (ByVal f As String,
> ByVal r As String)
>
> - which I presume means the function in the DLL expects to be given the
> address of two strings, one containing a filename and the other enough space
> for a (16-byte, represented as 32 hex digits?) md5 digest.

The problem is, what format would those strings be when passed from VB
to the DLL? My guess would be a null-terminated sequence of 1-byte
characters, but that's all it is, a wild guess.

It's then easy enough to tack an '00'x on the ends or your arguments,
but does REXX pass strings to DLL's as nothing but the supplied string?
I'd be surprised if nothing is passed to define the length of the string.

I had a similar problem trying to call an obscure Lotus Notes OLE
function. It expected one of its parameters to be encoded in some
obscure format. I managed to get my string into the required format, but
never to the point where Notes would accept it.

--
Steve Swift
http://www.swiftys.org.uk/swifty.html
http://www.ringers.org.uk

Mark Hessling

unread,
Nov 3, 2009, 6:52:51 AM11/3/09
to
On Mon, 02 Nov 2009 18:50:52 +0000, Jeremy Nicoll - news posts wrote:

> ooRexx 4.0.0, Windows XP Pro SP3
>
> I'm trying to get a rexx exec to use a function from a DLL. It's not
> working how I expected it to, but I don't know where the problem lies.
>
>
> The DLL is something called aamd532.dll, and it implements an MD5 digest
> on a file. I found the following example of its use in VB (which I've
> never used either):
>
> Public Declare Sub MDFile Lib "aamd532.dll" (ByVal f As String,
> ByVal r As String)
>
> - which I presume means the function in the DLL expects to be given the
> address of two strings, one containing a filename and the other enough
> space for a (16-byte, represented as 32 hex digits?) md5 digest.
>

[snip]
>
> All hints gratefully accepted!

You can't simply call rxfuncadd() on any DLL. rxfuncadd() expects to load
a DLL consisting of Rexx external function packages. The DLL in question
is very likely NOT a Rexx external function package.
To load this DLL you would need to use something like the General Call
Interface (GCI) that is provided with Regina.
Otherwise you would need to write a Rexx function package that provides
an interface into the specified DLL.

Cheers, Mark

Jeremy Nicoll - news posts

unread,
Nov 3, 2009, 11:07:25 AM11/3/09
to
Mark Hessling <ma...@rexx.org> wrote:

> You can't simply call rxfuncadd() on any DLL. rxfuncadd() expects to load
> a DLL consisting of Rexx external function packages.

Ah. AH. Rats!

I used to use Rexx on MVS quite often for writing test harnesses for
assembler programs; whereas in the past the harnesses also needed to be in
assembler, being able to build parm lists in rexx and invoke things via eg
address attachmvs/attachpgm etc was extremely useful. Of course in those
situations we knew exactly what the called routine expected to see, whereas
in this case I have no idea what the DLL needs to be given.

> To load this DLL you would need to use something like the General Call
> Interface (GCI) that is provided with Regina.

Is that something that's integrated with Regina, or is it a standalone thing
that can also be used with ooRexx?


> Otherwise you would need to write a Rexx function package that provides
> an interface into the specified DLL.

No chance of that... Maybe I should just stick to using a CLI MD5 utility
and call that, with redirected output or something.

DO you have any thoughts on the rxfuncadd 'working', at least in that
rxfuncquery returned 0 in one case, but rxfuncdrop not working? Even if
the add only worked in the sense that a function name & the address of its
definition got added to a lookup table, surely the drop should have been
able to discard that info?

Jeremy Nicoll - news posts

unread,
Nov 3, 2009, 11:15:52 AM11/3/09
to
Swifty <steve....@gmail.com> wrote:

> The problem is, what format would those strings be when passed from VB
> to the DLL? My guess would be a null-terminated sequence of 1-byte
> characters, but that's all it is, a wild guess.

Actually I did try the null yesterday (thinking that that, which AFAIK is a
C-ism, might be needed), except for some reason I only put it on the end of
the string that was going to be written to...

I just tried again on both strings. It doesn't work.

Thanks for the idea.

Rick McGuire

unread,
Nov 3, 2009, 1:17:14 PM11/3/09
to
Jeremy Nicoll - news posts wrote:
> Mark Hessling <ma...@rexx.org> wrote:
>
>> You can't simply call rxfuncadd() on any DLL. rxfuncadd() expects to load
>> a DLL consisting of Rexx external function packages.
>
> Ah. AH. Rats!
>
> I used to use Rexx on MVS quite often for writing test harnesses for
> assembler programs; whereas in the past the harnesses also needed to be in
> assembler, being able to build parm lists in rexx and invoke things via eg
> address attachmvs/attachpgm etc was extremely useful. Of course in those
> situations we knew exactly what the called routine expected to see, whereas
> in this case I have no idea what the DLL needs to be given.
>
>
>
>> To load this DLL you would need to use something like the General Call
>> Interface (GCI) that is provided with Regina.
>
> Is that something that's integrated with Regina, or is it a standalone thing
> that can also be used with ooRexx?
>
>
>> Otherwise you would need to write a Rexx function package that provides
>> an interface into the specified DLL.
>
> No chance of that... Maybe I should just stick to using a CLI MD5 utility
> and call that, with redirected output or something.
>
>
>
> DO you have any thoughts on the rxfuncadd 'working', at least in that
> rxfuncquery returned 0 in one case, but rxfuncdrop not working? Even if
> the add only worked in the sense that a function name & the address of its
> definition got added to a lookup table, surely the drop should have been
> able to discard that info?

This sounds like it might be a bug in drop...I suggest opening a bug
report.

Rick

bwcherry

unread,
Nov 3, 2009, 3:36:39 PM11/3/09
to

If you decide to go with GCI, you might want to look at this
presentation on "The Generic Call Interface (GCI)":
http://rexxla.org/events/2004/abstracts.html

I can confirm it works on ooRexx 3.2.
--
Brandon Cherry

rony

unread,
Nov 3, 2009, 5:23:53 PM11/3/09
to
Jeremy:

having read the threads, there is nothing I could add to it, however, if you wished to solve your
problem at hand with ooRexx 4.0, which seems to be to use a MD5 digest algorithm on a file, then
what I can add is a possible solution. The solution would be independent of Windows and hence should
work on other platforms as well.

Rather than going for a particular Rexx function package, you could do something else: take
advantage of Java that is probably installed on your machine. The "Java runtime environment (JRE)"
is a powerful and huge set of functions available on all modern operating system platforms.

Using BSF4[oo]Rexx you become able to touch and use all of this Java functionality. Because Java is
openplatform, the Rexx solution is open platform as well. As you are using ooRexx 4.0, I would
strongly suggest to use "BSF4ooRexx" (note the two "oo" in the name) as this version takes advantage
of the new APIs in ooRexx 4.0.

You can download the current (stable!) beta version of BSF4ooRexx from
<http://wi.wu.ac.at/rgf/rexx/bsf4oorexx/current/> and install it in one or two minutes (just read
the "readmeBSF4ooRexx.txt"): unzip the installation archive, switch into the "bsf4oorexx" directory,
run "rexx setupBSF.rex" and after that run the generated batch file "installBSF4.cmd". From now on,
when you start a new session (open a new commandline window) you would be able from Rexx to use
Java. Just require the ooRexx package "BSF.CLS".

After that, you would need to google existing Java solutions, e.g. for MD5 MessageDigest nutshells,
study them, look-up the Java documentation via the WWW and transcribe the solution to Rexx.

For the following possible solution, I googled and stumbled over the following URLs:

- <http://www.twmacinta.com/myjava/fast_md5.php>,
- <http://www.java2s.com/Tutorial/Java/0180__File/UseFileChannelandByteBuffertoCopyFile.htm> <--
this one helped a lot!
- <http://java.sun.com/javase/6/docs/technotes/guides/security/StandardNames.html#MessageDigest>

Here is a little ooRexx program that would do what you are seeking: the public routine
"getMessageDigestForFile" expects a file name and an optional MessageDigest algorithm name,
defaulting to "MD5". It will return a Java byte array containing the calculated digest.

The main program will take a filename, invoke the routine "getMessageDigestForFile" and turn the
returned Java byte array into a hexadecimal string with the help of Rexx.

I ran that program on a 150 MB file and it executed in a very favorable time!

Just extract the following program to test:

------------------- cut here -------------------
parse arg inputFile /* get filename */

if inputFile="" then /* no filename given, abort */
do
inputFile="test_oha_dackl.txt"
say "inputFile missing, aborting..."
exit -1
end

say "inputFile ="pp(inputFile)
/* call public routine to calculate the MessageDigest, returns a Java byte array */
md=getMessageDigestForFile(inputFile, "MD5")

md5tail="*"inputFile~changeStr("\", "\\") /* escape MD5 tail (file name) */

/* turn Java byte array into a Java string, which will be returned as a string,
that then is turned into hexadecimal representation and lowercased */
say .bsf~new("java.lang.String", md)~toString~c2x~lower md5tail


::requires BSF.CLS /* get Java support */

::routine getMessageDigestForFile public /* calculate and return MessageDigest value */
use arg fileName, mdType="MD5"

/* create a channel to read from file */
fis=.bsf~new("java.io.FileInputStream", fileName) /* create an FileInputStream for file */
fc =fis~getChannel /* get the java.nio.channels.FileChannel for the FileInputStream */

/* create a ByteBuffer to be used with the FileChannel for reading */
kb=1024*1024 -- 1 MB, fast, o.k.
buffer=bsf.loadClass("java.nio.ByteBuffer")~allocate(kb) -- allocate a buffer of the given size

/* get the MessageDigester using the "mdType" algorithm */
digester=bsf.loadClass("java.security.MessageDigest")~getInstance(mdType)

loop forever
read=fc~read(buffer) /* read from file channel into buffer */
if read<1 then leave /* -1 if EOF */
digester~update(buffer~flip) /* calculate digest */
buffer~clear
end

return digester~digest /* return final digest */
------------------- cut here -------------------

This solution should run unchanged on Linux and/or MacOSX.

HTH,

---rony


Jeremy Nicoll - news posts wrote:

ML

unread,
Nov 5, 2009, 2:45:31 PM11/5/09
to

> I'm trying to get a rexx exec to use a function from a DLL.

Then obtain a rather simple example, like the old VXTECH01.ZIP, and use
some language one actually masters? Your problems really have nothing
to do with Rexx if you're not able to port (not *.C) or use (*.C) those
rather basic examples. Try e.g. comp.lang.c instead and don't downgrade
to the latest forever-broken-ooRexx.

---

Jeremy Nicoll - news posts

unread,
Nov 8, 2009, 8:40:32 PM11/8/09
to
Rick McGuire <objec...@gmail.com> wrote:

> This sounds like it might be a bug in drop...I suggest opening a bug
> report.

I've done so.

0 new messages