On Mon, 5 Mar 2001, Garrett Goebel wrote:

> It now works better. Well, the callback to the perl function when works
> once. The first time called, it gets valid arguments. The second time
> called, it looks like it is getting the stash followed by valid arguments.

Whenever you call Perl from C, it's a good idea to refresh yourself on the
basics. I still go back to the perlembed manpage whenever I need to call
Perl functions from C.

See below for specific comments.

> Any idea what's going wrong? Assumably something I'm failing to do.
>
> use Inline C => DATA => LIBS => '-luser32';
>
> Enum_Child_Windows(sub { print "foo(@_)\n" });
>
> __END__
> __C__
> #include <windows.h>
>
> static SV* coderef;
> void set_coderef(SV* cref) {
>   coderef = cref;
> }
>
> BOOL FAR PASCAL Enum_Child_Proc (HWND hWnd, LPARAM Param) {
>   Inline_Stack_Vars;
>   I32 flags = 0;
>   Inline_Stack_Reset;
>   Inline_Stack_Push(newSViv(hWnd));
>   Inline_Stack_Push(newSViv(Param));
>   Inline_Stack_Done;
>   call_sv(coderef, flags);
>
>   return 1;
> }

There's the problem. You call a Perl function without cleaning up the
stack afterwards. When Perl calls a function, it pushes a bunch of
information on the Stack (similar to C). If you don't clean it up, it will
stay on the stack, ruining the state of the interpreter.

Here's a similar example from the perlembed manpage:

----8<----
static void
PerlPower(int a, int b)
{
  dSP;                            /* initialize stack pointer      */
  ENTER;                          /* everything created after here */
  SAVETMPS;                       /* ...is a temporary variable.   */
  PUSHMARK(SP);                   /* remember the stack pointer    */
  XPUSHs(sv_2mortal(newSViv(a))); /* push the base onto the stack  */
  XPUSHs(sv_2mortal(newSViv(b))); /* push the exponent onto stack  */
  PUTBACK;                      /* make local stack pointer global */
  perl_call_pv("expo", G_SCALAR); /* call the function             */
  SPAGAIN;                        /* refresh stack pointer         */
                                /* pop the return value from stack */
  printf ("%d to the %dth power is %d.\n", a, b, POPi);
  PUTBACK;
  FREETMPS;                       /* free that return value        */
  LEAVE;                       /* ...and the XPUSHed "mortal" args.*/
}
----8<----

Notice the junk after the perl_call_sv().

Here's a handy phrase book for those unfamiliar with the XS macros:
dSP             Inline_Stack_Vars
ENTER
SAVETMPS
PUSHMARK(SP)
XPUSHs          Inline_Stack_Push
PUTBACK         Inline_Stack_Done
SPAGAIN         Inline_Stack_Reset
FREETMPS
LEAVE

As you can see, Inline is not yet mature enough to handle all those extra
XS macros. In your case, I would add these lines to your code and see if
everything starts working:

----8<----
   Inline_Stack_Done;
   call_sv(coderef, flags);
-
+  Inline_Stack_Reset;
+  Inline_Stack_Done;
   return 1;
----8<----

If it does, great. If not, replace your Inline_* macros one-by-one with
the corresponding XS macros from the example. Then send Brian a patch :)

Later,
Neil

-- 
Vote for Your Favorite Perl & Python Programming
Accomplishments in the first Active Awards!

>> http://www.ActiveState.com/Awards <<

Reply via email to