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>