Re: Access a perl dll's function on Win32

[email protected] (Marvin Humphrey)
Newsgroups perl.module.build,perl.xs
Message-ID <[email protected]>
[reply cross-posted to Module::Build list; reply-to header set to [email protected] 
]

On Sep 3, 2008, at 6:23 AM, Sisyphus wrote:

> 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 
 >.  The latest version of Lingua::Stem::Snowball (0.952) takes this  
route so that svn trunk for KinoSearch can access those addresses.  
(The API isn't public yet, but I can get away with private API access  
because I maintain both distros.)  The XS BOOT: section which does the  
exporting for L::S::Snowball is pasted below my sig.

The advantage of this technique is that it's highly portable.   The  
big disadvantage is that it doesn't scale.  You  also have to worry  
about C symbol conflicts and you have to use function pointers rather  
than real C functions.

> 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.

When the Windows DLL is linked, it has to be told what symbols should  
be exportable.  The process is analogous to exporting functions from  
Perl modules using Exporter:

   package Foo;
   use base qw( Exporter );
   BEGIN { our @EXPORT_OK = qw( do_stuff ); }

The problem is that the way you tell the linker to export symbols is  
platform-specific.  For MSVC, the interface is described at <http://msdn.microsoft.com/en-us/library/z4zxe9k8(VS.80).aspx 
 >:

   You can export functions from a DLL using two methods:

     * Create a module definition (.def) file and use the .def
       file when building the DLL. Use this approach if you want
       to export functions from your DLL by ordinal rather than
       by name.
     * Use the keyword __declspec(dllexport) in the function's  
definition.

The .def file is a text file that's analogous to the @EXPORT_OK  
array.  The format is described at <http://msdn.microsoft.com/en-us/library/d91k01sh(VS.80).aspx 
 >.

What might be nice is to be able to feed a list of C function names to  
ExtUtils::CBuilder or Module::Build (which would pass to CBuilder),  
and have CBuilder generate the .def file.  We'd then have covered  
symbol exporting both unixen (easy if cryptic: use Dynaloader rather  
than XSLoader and put C<sub dl_load_flags {0x01}> in your Perl module  
code) and MSVC.  That would cover most Perl installations out there.

Marvin Humphrey
Rectangular Research
http://www.rectangular.com/

=============================================================
In Snowball.xs:

BOOT:
{
     SV *sb_stemmer_list_sv   = newSViv(PTR2IV(sb_stemmer_list));
     SV *sb_stemmer_new_sv    = newSViv(PTR2IV(sb_stemmer_new));
     SV *sb_stemmer_delete_sv = newSViv(PTR2IV(sb_stemmer_delete));
     SV *sb_stemmer_stem_sv   = newSViv(PTR2IV(sb_stemmer_stem));
     SV *sb_stemmer_length_sv = newSViv(PTR2IV(sb_stemmer_length));
     hv_store(PL_modglobal, "Lingua::Stem::Snowball::sb_stemmer_list",  
39,
         sb_stemmer_list_sv, 0);
     hv_store(PL_modglobal, "Lingua::Stem::Snowball::sb_stemmer_new",  
38,
         sb_stemmer_new_sv, 0);
     hv_store(PL_modglobal,  
"Lingua::Stem::Snowball::sb_stemmer_delete", 41,
         sb_stemmer_delete_sv, 0);
     hv_store(PL_modglobal, "Lingua::Stem::Snowball::sb_stemmer_stem",  
39,
         sb_stemmer_stem_sv, 0);
     hv_store(PL_modglobal,  
"Lingua::Stem::Snowball::sb_stemmer_length", 41,
         sb_stemmer_length_sv, 0);
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.