[prev in list] [next in list] [prev in thread] [next in thread] 

List:       perl-win32-users
Subject:    Re: Passing a reference to a perl function as an argument to an XS function
From:       "Aldo Calpini" <dada.list () alos ! it>
Date:       2002-03-27 11:53:43
[Download RAW message or body]

c. church wrote:
> I have a routine, say 'myFunc', that expects a pointer to another function
> (to be used as a callback) as a third argument.  I want to be able to
create
> this function in perl, and pass it as the third argument to 'myFunc'.  I
> understand that there are functions such as 'call_pv', 'call_sv', etc.,
but
> I'm not actually calling it here, the other function (which I didn't
write)
> is doing so.

here lies the problem. you *have to* use a function such as 'call_pv'. you
can't have C execute a CV* (eg. a perl sub to XS) directly. you *must* write
a C wrapper function that calls the perl sub.

> MyPkg.xs(52) : warning C4047: 'function' : 'unsigned long ' differs in
> levels of indirection from 'struct cv ** '
> MyPkg.xs(52) : warning C4024: 'myFunc' : different types for formal and
> actual parameter 3

exactly what said before: C is expecting a DWORD_PTR (unsigned long), which
is completely different from what you're passing to it (&subpass is a CV**).
even casting this won't help you very much :-)

the strategy to follow is outlined in perlcall.pod (try perldoc perlcall),
and can be summarized as:

- have a global (static) SV* variable outside of your functions like this:

  static SV* perl_callback = (SV*) NULL;

- in your XS function, memorize 'subpass' in the global variable:

  int
  Process(self,level,subpass)
   SV* self
   int level
   SV* subpass
  PREINIT:
   # ...
  CODE:
   # ...
   perl_callback = subpass;

- write a C function which should look like:

  int
  myCallback(int a, int b) // #### this should be the prototype of your
callback
  {
    int r;
    dSP;
    ENTER;
    SAVETMPS;
    PUSHMARK(sp);
    XPUSHs(sv_2mortal(newSViv(a)));
    XPUSHs(sv_2mortal(newSViv(b)));
    PUTBACK;
    call_sv(perl_callback, G_SCALAR);
    SPAGAIN;
    r = POPi;
    PUTBACK;
    FREETMPS;
    LEAVE;
    return r;
  }

  the template is standard enough, you just have to adjust the various
  XPUSHs(...) for the parameters your callback has, and eventually change
  POPi (the return value, an integer) with another POP macro (eg. POPn for a
  double, POPl for a long, etc.).

- then, in your XS function pass myCallback (the C function above) to the
  function that needs a callback:

  RETVAL =
myFunc(&thisHandle,level,(DWORD_PTR)myCallback,NULL,CALLBACK_FUNCTION);

- this way, C will call myCallback, which will fill perl's @_ with its
parameters
  and then call the SV* you've stored in perl_callback.

> Where have I gone wrong?  Please excuse my ignorance with XS and
datatypes,
> I'm not very familiar with C and the XS documentation is like Greek to me.

learn Greek then :-)


cheers,
Aldo

__END__
$_=q,just perl,,s, , another ,,s,$, hacker,,print;

_______________________________________________
Perl-Win32-Users mailing list
Perl-Win32-Users@listserv.ActiveState.com
To unsubscribe: http://listserv.ActiveState.com/mailman/mysubs
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic