FFI-Platypus

 view release on metacpan or  search on metacpan

lib/FFI/Platypus.pm  view on Meta::CPAN

 0
 6

=head3 Discussion

Starting with the Platypus version 2 API, you can also pass an array reference
in to a pointer argument.

In C pointer and array arguments are often used somewhat interchangeably.  In
this example we have an C<array_sum> function that takes a zero terminated
array of integers and computes the sum.  If the pointer to the array is zero
(C<0>) then we return C<-1> to indicate an error.

This is the main advantage from Perl for using pointer argument rather than
an array one: the array argument will not let you pass in C<undef> / C<NULL>.

=head2 Sending Strings to GUI on Unix with libnotify

=head3 C API

L<Libnotify Reference Manual|https://developer-old.gnome.org/libnotify/unstable>

=head3 Perl Source

 use FFI::CheckLib;
 use FFI::Platypus 2.00;
 
 my $ffi = FFI::Platypus->new(
   api => 2,
   lib => find_lib_or_die(lib => 'notify'),
 );
 
 $ffi->attach( notify_init              => ['string']                                  );
 $ffi->attach( notify_uninit            => []                                          );
 $ffi->attach( notify_notification_new  => ['string', 'string', 'string']  => 'opaque' );
 $ffi->attach( notify_notification_show => ['opaque', 'opaque']                        );
 
 my $message = join "\n",
   "Hello from Platypus!",
   "Welcome to the fun",
   "world of FFI";
 
 notify_init('Platypus Hello');
 my $n = notify_notification_new('Platypus Hello World', $message, 'dialog-information');
 notify_notification_show($n, undef);
 notify_uninit();

=head3 Execute

 $ perl notify.pl

=for html <p>And this is what it will look like:</p>
<div style="display: flex">
<div style="margin: 3px; flex: 1 1 50%">
<img alt="Test" src="/examples//notify.png">
</div>
</div>

=head3 Discussion

The GNOME project provides an API to send notifications to its desktop environment.
Nothing here is particularly new: all of the types and techniques are ones that we
have seen before, except we are using a third party library, instead of using our
own C code or the standard C library functions.

When using a third party library you have to know the name or location of it, which
is not typically portable, so here we use L<FFI::CheckLib>'s
L<find_lib_or_die function|FFI::CheckLib/find_lib_or_die>.  If the library is not
found the script will die with a useful diagnostic.  L<FFI::CheckLib> has a number
of useful features and will integrate nicely with L<Alien::Build> based L<Alien>s.

=head2 The Win32 API with MessageBoxW

=head3 Win32 API

L<MessageBoxW function (winuser.h)|https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messageboxw>

=head3 Perl Source

 use utf8;
 use FFI::Platypus 2.00;
 
 my $ffi = FFI::Platypus->new(
   api  => 2,
   lib  => [undef],
 );
 
 # see FFI::Platypus::Lang::Win32
 $ffi->lang('Win32');
 
 # Send a Unicode string to the Windows API MessageBoxW function.
 use constant MB_OK                   => 0x00000000;
 use constant MB_DEFAULT_DESKTOP_ONLY => 0x00020000;
 $ffi->attach( [MessageBoxW => 'MessageBox'] => [ 'HWND', 'LPCWSTR', 'LPCWSTR', 'UINT'] => 'int' );
 MessageBox(undef, "I ❤️ Platypus", "Confession", MB_OK|MB_DEFAULT_DESKTOP_ONLY);

=head3 Execute

 $ perl win32_messagebox.pl

=for html <p>And this is what it will look like:</p>
<div style="display: flex">
<div style="margin: 3px; flex: 1 1 50%">
<img alt="Test" src="/examples/win32_messagebox.png">
</div>
</div>

=head3 Discussion

The API used by Microsoft Windows presents some unique
challenges.  On 32 bit systems a different ABI is used than what
is used by the standard C library.  It also provides a rats nest of
type aliases.  Finally if you want to talk Unicode to any of the
Windows API you will need to use C<UTF-16LE> instead of C<UTF-8>
which is native to Perl.  (The Win32 API refers to these as
C<LPWSTR> and C<LPCWSTR> types).  As much as possible the Win32
"language" plugin attempts to handle these challenges transparently.
For more details see L<FFI::Platypus::Lang::Win32>.

=head3 Discussion

The libnotify library is a desktop GUI notification system for the
GNOME Desktop environment. This script sends a notification event that
should show up as a balloon, for me it did so in the upper right hand
corner of my screen.

=head2 Structured Data Records (by pointer or by reference)

=head3 C API

L<cppreference - localtime|https://en.cppreference.com/w/c/chrono/localtime>

=head3 Perl Source

 use FFI::Platypus 2.00;
 use FFI::C;
 
 my $ffi = FFI::Platypus->new(
   api => 2,
   lib => [undef],
 );
 FFI::C->ffi($ffi);
 
 package Unix::TimeStruct {
 
   FFI::C->struct(tm => [
     tm_sec    => 'int',
     tm_min    => 'int',
     tm_hour   => 'int',
     tm_mday   => 'int',
     tm_mon    => 'int',
     tm_year   => 'int',
     tm_wday   => 'int',
     tm_yday   => 'int',
     tm_isdst  => 'int',
     tm_gmtoff => 'long',
     _tm_zone  => 'opaque',
   ]);
 
   # For now 'string' is unsupported by FFI::C, but we
   # can cast the time zone from an opaque pointer to
   # string.
   sub tm_zone {
     my $self = shift;
     $ffi->cast('opaque', 'string', $self->_tm_zone);
   }
 
   # attach the C localtime function
   $ffi->attach( localtime => ['time_t*'] => 'tm', sub {
     my($inner, $class, $time) = @_;
     $time = time unless defined $time;
     $inner->(\$time);
   });
 }
 
 # now we can actually use our Unix::TimeStruct class
 my $time = Unix::TimeStruct->localtime;
 printf "time is %d:%d:%d %s\n",
   $time->tm_hour,
   $time->tm_min,
   $time->tm_sec,
   $time->tm_zone;



( run in 1.911 second using v1.01-cache-2.11-cpan-14f38c9f855 )