frazap has asked for the wisdom of the Perl Monks concerning the following question:

I have the following files for a embryonic keyboard hook on windows

lib/Kbh.pm

package Kbh; our $VERSION = '0.01'; require XSLoader; XSLoader::load('Kbh', $VERSION); sub process_key { print "process_key in perl\n"; } 1;
Makefile.pl
use ExtUtils::MakeMaker; WriteMakefile ( NAME => 'Kbh', VERSION => '0.01', OBJECT => 'hook.o Kbh.o', );
hook.h
LRESULT CALLBACK HookCallback(int nCode, WPARAM wParam, LPARAM lParam) +; void processKey(); void register_hook(); void unregister_hook(); void MsgLoop();
hook.c
#include <windows.h> #include <WinAble.h> #include "stdio.h" #include "hook.h" HHOOK hook; LRESULT CALLBACK HookCallback( int nCode, WPARAM wParam, LPARAM lParam + ) { processKey(); return CallNextHookEx( hook, nCode, wParam, lParam ); } void processKey() { printf("processKey in C\n"); } void MsgLoop() { MSG message; while ( GetMessage( &message, NULL, 0, 0 ) ) { TranslateMessage(&message); DispatchMessage(&message); } } void register_hook() { HMODULE hMod = (HMODULE) GetModuleHandle(NULL); hook = SetWindowsHookEx( WH_KEYBOARD_LL, HookCallback, hMod, 0 ); } void unregister_hook() { UnhookWindowsHookEx(hook); }
and Kbh.xs
#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #include "hook.h" MODULE = Kbh PACKAGE = Kbh PROTOTYPES: DISABLE void MsgLoop() void register_hook() void unregister_hook() void processKey() INIT: int count; PPCODE: dSP; PUSHMARK(SP); count= call_pv("Kbh::process_key", G_DISCARD|G_NOARGS); if (count != 0) croak("Big trouble\n");
When I run
Perl Makefile.pl dmake

the things compile.

When I run runit.pl from the main directory(use ctrl+c to quit)

runit.pl
use lib qw(./lib ./blib/arch/auto/Kbh); use Kbh; Kbh::register_hook(); Kbh::MsgLoop; Kbh::unregister_hook();
I see that the hook is installed, I get two messages from processKey when I hit a key, but I don't have msg "process_key from perl"

What am I missing ?

Thanks

François

Replies are listed 'Best First'.
Re: perlcall for dummies
by RMGir (Prior) on Sep 22, 2017 at 18:05 UTC
    I haven't done anything with XS in years, so I may be missing something. But wouldn't the "C" processKey hide the "XS" processKey, depending on your link line order?

    I see you're printing a trace in your C processKey, and in the perl process_key.

    Have you tried adding a trace to the xs routine to make sure it's being invoked?


    Mike
      Good idea: and it's not called. The suggestion of beech get me in the right direction.
        That works, but I'm betting that just deleting
        void processKey() { printf("processKey in C\n"); }
        would have worked, too - then your XS 'processKey' would have been called instead of this one.

        Mike
Re: perlcall for dummies
by beech (Parson) on Sep 22, 2017 at 20:04 UTC

    Hi,

    I think you need to have that call_pv stuff inside HookCallback

      Yes, thanks and this code works: hook.c
      #include <windows.h> #include <WinAble.h> #include "stdio.h" #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #include "hook.h" HHOOK hook; LRESULT CALLBACK HookCallback( int nCode, WPARAM wParam, LPARAM lParam + ) { processKey(); return CallNextHookEx( hook, nCode, wParam, lParam ); } void processKey() { printf("processKey in C\n"); dSP; PUSHMARK(SP); int count= call_pv("Kbh::process_key", G_DISCARD|G_NOARGS); if (count != 0) croak("Big trouble\n"); } void MsgLoop() { MSG message; while ( GetMessage( &message, NULL, 0, 0 ) ) { TranslateMessage(&message); DispatchMessage(&message); } } void register_hook() { HMODULE hMod = (HMODULE) GetModuleHandle(NULL); hook = SetWindowsHookEx( WH_KEYBOARD_LL, HookCallback, hMod, 0 ); } void unregister_hook() { UnhookWindowsHookEx(hook); }
      Kbh.xs
      #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #include "hook.h" MODULE = Kbh PACKAGE = Kbh PROTOTYPES: DISABLE void MsgLoop() void register_hook() void unregister_hook()

      The tricky part for me was to put the header in hook.c files in the right order.

      François