Discussion:
Access a perl dll's function on Win32
(too old to reply)
Sisyphus
2008-09-03 13:23:56 UTC
Permalink
Hi,
This stems from http://www.perlmonks.org/index.pl?node_id=708569 .

Basically, if you have a perl dll (by which I mean, eg, the Digest::SHA dll)
and you want to directly access a function from within that dll using XS or
Inline::C, how do you do that ?

With most Windows dll's, you can just use LoadLibrary() to get a handle to
the dll, and then use GetProcAddress() to return the address of the function
you want to access.

For the first part, there's no problem - one can easily use LoadLibrary()
to return a handle to SHA.dll. It's the second part that presents the
problem. GetProcAddress() can only return the address of functions/variables
that are *exported* ... and most of the functions in SHA.dll (eg 'hashsize')
are *not* exported.

How, therefore, can I get at the 'hashsize' function from an Inline::C
script (or an XSub) on Win32 ?

Cheers,
Rob
Jan Dubois
2008-09-03 18:47:34 UTC
Permalink
Post by Sisyphus
This stems from http://www.perlmonks.org/index.pl?node_id=708569 .
Basically, if you have a perl dll (by which I mean, eg, the Digest::SHA dll)
and you want to directly access a function from within that dll using XS or
Inline::C, how do you do that ?
With most Windows dll's, you can just use LoadLibrary() to get a handle to
the dll, and then use GetProcAddress() to return the address of the function
you want to access.
For the first part, there's no problem - one can easily use LoadLibrary()
to return a handle to SHA.dll. It's the second part that presents the
problem. GetProcAddress() can only return the address of functions/variables
that are *exported* ... and most of the functions in SHA.dll (eg 'hashsize')
are *not* exported.
How, therefore, can I get at the 'hashsize' function from an Inline::C
script (or an XSub) on Win32 ?
As the thread on PerlMonks already states, you call it using
perl_call_pv() because the XS function already expects to be called
using Perl calling conventions:

count = perl_call_pv("Digest::SHA::hashsize", G_SCALAR|G_EVAL);

If you want to call a C-level function directly using GetProcAddress()
then you must make sure that the module explicitly exports that symbol.
I've done this in Win32::OLE for some functions that are explicitly used
by some applications hosting a Perl interpreter. Look at the Makefile.PL
to see how to do it on Win32:

http://search.cpan.org/src/JDB/Win32-OLE-0.1709/Makefile.PL

I cannot remember why I also had to add the MY::dlsyms() function;
ideally adding the FUNCLIST argument to WriteMakefile() should be
enough, but I guess it wasn't when I wrote that code (about 10 years
ago, but it still works with current Perl and EU::MM).

Cheers,
-Jan
Reini Urban
2008-09-03 18:50:45 UTC
Permalink
Post by Sisyphus
How, therefore, can I get at the 'hashsize' function from an Inline::C
script (or an XSub) on Win32 ?
To answer what Jan didn't say:
You will have no luck getting the address of not exported functions in dll's.

The dll's is mapped into the exe address space, and for all exported functions
the entry points (exe specific GetProcAddress) are calculated, for not exported
functions not.

You might have luck adding the offset manually from a known function
by checking its addresses via nm or objdump, but this is very fragile and
is only specific for this very build. (dumpbin on MSVC)
--
Reini Urban
http://phpwiki.org/ http://murbreak.at/
Sisyphus
2008-09-04 04:47:37 UTC
Permalink
----- Original Message -----
From: "Marvin Humphrey" <***@rectangular.com>
To: <perl-***@perl.org>
Cc: <module-***@perl.org>
Sent: Thursday, September 04, 2008 2:15 AM
Subject: Re: Access a perl dll's function on Win32
[reply cross-posted to Module::Build list; reply-to header set to
Basically, if you have a perl dll (by which I mean, eg, the Digest::SHA
dll) and you want to directly access a function from within that dll
using XS or Inline::C, how do you do that ?
The brute-force way is cram function addresses through Perl variables, as
suggested at <http://www.perlmonks.org/?node_id=691174> and described in
the Time::HiRes POD documentation at
<http://perldoc.perl.org/Time/HiRes.html#C-API
Yes - I've used that approach before (with the help of that very same
perlmonks thread) - though only in a proof-of-concept exercise (in which I
also did an XS Boot) and it works beautifully. In this particular instance,
however, I was thinking more of how to access the dll's functionality
*without* recompiling it to include the additional functions that would be
necessary for that approach to work. (Sorry - I should have made that
restriction clearer.)

I think that Jan's suggestion of doing a callback is probably the sane way
to go. I was thinking more in terms of accessing the dll in isolation (ie
without actually loading the module - which would rule out callbacks), but
in reality that's probably a silly condition to be imposing anyway.

I thought it might be fun to try out Reini's idea - and I've got an
Inline::C script all set to go to access a function in the Math::GMPf dll.
(That dll has a function that takes no args and returns an int - which keeps
things really simple for me.) Only problem is I couldn't find a way to get
any useful address information at all using nm, objdump or dumpbin. I was,
of course, able to get the address of _boot_Math__GMPf/boot_Math__GMPf using
GetProcAddress, but that's the only address I could get hold of. No matter
.... it was, after all, just something I was going to try out for the heck
of it ;-)

Thanks guys.

Cheers,
Rob

Loading...