tags:

views:

177

answers:

3

I have a Windows DLL that I want to call from Perl. The prototype for the exported function is:

int __stdcall func(const char*, int, int, int, double, double, void**);

The last parameter returns a pointer to an object that is allocated in the function.

The perl code –

my $dll_path = "../stage/test_dll.dll";

my $dll_func = new Win32::API($dll_path,
                'func',
                'PIIIDDP', 'I');

my $data = "test something here";
my $pResult = 0;

my $rc = $ dll_func ->Call($data, 0, 0, 9, 0.6, 0.3, $pResult);

An error message popped up saying that the memory can’t be written. Maybe I can’t use P to represent void**? I read through all the documentation and could not locate a single example that uses void** parameter. Help!

A: 

Take a look at how swig would do it. Maybe you will find your answer there.

Donato Azevedo
+2  A: 

The variable associated with a P parameter must be a pre-allocated string variable, not an integer. Try something like:

my $pResult = "\0" x 8;   # Just in case we're 64-bit

my $rc = $ dll_func ->Call($data, 0, 0, 9, 0.6, 0.3, $pResult);

$pResult will then contain the pointer to the object. You'll probably need to use unpack to extract it.

You don't say what you need to do with the object. If you need to pass it to other DLL functions as a void*, you'll probably need to unpack it as a long and use N instead of P in the parameter list.

cjm
A: 

This answer might be off base, but the Inline::C module offers a pretty good interface into user libraries, and within Perl and C you can come up with all kinds of workarounds to passing data through a void** pointer.

use Inline C => DATA => LIBS => '-L../stage -ltest_dll';

my $data = "test something here";
my $rc = func_wrapper($data, 0, 0, 9, 0.6, 0.3);
my $p = get_pointer();
printf "func() set a pointer value of 0x%x\n", $p;    

__END__
__C__

#include <stdio.h>

int func(const char *, int, int, int, double, double, void **);    
void* pointer_value;

long get_pointer()
{
    return (long) pointer_value;
}

/*
 * Wraps func() in test_dll library.
 */
int func_wrapper(const char *s, int i1, int i2, int i3, double d1, double d2)
{
    void *p = (void *) "some pointer";
    int rval = func(s, i1, i2, i3, d1, d2, &p);

    /* func() may have changed  p  as a side effect */
    /* for demonstation, save it to a long value that can be retrieved with
       the  get_pointer()  function. There are other ways to pass the pointer
       data into Perl. */
    pointer_value = p;
    printf("The pointer value from func() is %p\n", p);
    return rval;
}

If Inline::C looks interesting to you, the Inline::C-Cookbook page on CPAN is also indispensable.

mobrule