Hi Sam-
  
At 2005-10-14, 00:05:10 you wrote:
>Hi
>
>Is there a way to call exported methods from a DLL without using win32::API.
>
>Has anyone tried calling an exported function from C DLL in a Perl Program 
>using XS.
>
[snipped]

YES!

First, your error is caused because you need an 'export' library from the dll 
you
are trying to access. If you have one. whip in into your module tree's root and
change Makefile.PL to use it ( library line ), and your make should work. 
WARNING:
'make clean' deletes *.lib, so you have to modify the clean routne ( see 
Make::Maker
docs ).

But there is s dynamic way to call dll's ( that's why they are called 
DynamicLinkLibraies :) ).
In your XS code, you can use the old 'LoadLibrary' and 'GetProcAddress' Win32 
functions.
( be sure your dll is in your current directory or in the PATH for this to 
work. )

I'm sorry, but the easiest way to show this is to post a working example ( 
rather long ) -
please bare with me! This is the XS file for a Windows Parallel Port driver. 
The dll it uses
is ppdrv.dll which has two functions:

void  _stdcall pp_out( int port_addr, int data );
int _stdcall pp_in ( int port_addr );

Here is the XS which accesses them:

#define PERL_NO_GET_CONTEXT     /* we want efficiency */
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include "ppport.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

static void ppdrv_init_dll( pTHX_ U32* pp_in_addr, U32* pp_out_addr )
{
  HMODULE h;
  int ( _stdcall *pp_in )( int  );
  void  ( _stdcall *pp_out )( int, int );

  h = LoadLibrary( "ppdrv.dll" );
  if( h == NULL )
    Perl_croak(aTHX_ "Unable to find 'ppdrv.dll'" );
  pp_in = ( int ( _stdcall * )( int  ) )GetProcAddress( h, "pp_in" );
  if( pp_in == NULL )
    Perl_croak(aTHX_ "Unable to find 'pp_in' in 'ppdrv.dll'" );
  pp_out =
    ( void ( _stdcall * )( int, int ) )GetProcAddress( h, "pp_out" );
  if( pp_out == NULL )
    Perl_croak(aTHX_ "Unable to find 'pp_out' in 'ppdrv.dll'" );
  *pp_in_addr = ( U32 ) pp_in;
  *pp_out_addr = ( U32 ) pp_out;
}

static int ppdrv_read( pTHX_ U32 func_addr, int base, int offset )
{
  int ( _stdcall *pp_in )( int  ) =
    ( int ( _stdcall * )( int  ) )func_addr;
  return pp_in( base + offset );
}

static void ppdrv_write( pTHX_ U32 func_addr, int base, int offset, int val )
{
  void  ( _stdcall *pp_out )( int, int ) =
    ( void ( _stdcall * )( int, int ) )func_addr;
  pp_out( base + offset, val );
}

MODULE = Device::ParallelPort::drv::win32_ppdrv         PACKAGE = 
Device::ParallelPort::drv::win32_ppdrv                

PROTOTYPES: ENABLE

void
ppdrv_init_dll()
        PREINIT:
                U32     pp_in_addr;
                U32     pp_out_addr;
        PPCODE:
                ppdrv_init_dll( aTHX_ &pp_in_addr, &pp_out_addr );
                EXTEND( SP, 2 );
                PUSHs( sv_2mortal( newSVuv( pp_in_addr ) ) );
                PUSHs( sv_2mortal( newSVuv( pp_out_addr ) ) );

int
ppdrv_read( pp_in_addr, base, offset )
        INPUT:
                U32     pp_in_addr
                int     base
                int     offset
        CODE:
                RETVAL = ppdrv_read( aTHX_ pp_in_addr, base, offset );
        OUTPUT:
                RETVAL

void
ppdrv_write( pp_out_addr, base, offset, val )
        INPUT:
                U32     pp_out_addr
                int     base
                int     offset
                int     val
        CODE:
                ppdrv_write( aTHX_ pp_out_addr, base, offset, val );

The perl code in the .pm module gets the two functions addresses
during initialization as follows:

    my( $in, $out ) = ppdrv_init_dll();
    $this->{FUNCADDR} = { IN => $in, OUT => $out, };

Later the functions be called with:

    ppdrv_write( $this->{FUNCADDR}{OUT}, $this->{DATA}{BASE}, $byte, $val );

and

    ppdrv_read( $this->{FUNCADDR}{IN}, $this->{DATA}{BASE}, $byte );

If you want the complete module to copy/study/etc., let me know and I will
send it to you off-list.
                        
Aloha => Beau;
[EMAIL PROTECTED]
2005-10-14



-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
<http://learn.perl.org/> <http://learn.perl.org/first-response>


Reply via email to