如何将用户数据传递给回调函数

问题描述 投票:7回答:2

我正在使用NativeCall接口;有一个接受回调的C函数,定义如下:

typedef void (* ExifContentForeachEntryFunc) (ExifEntry *, void *user_data);
void exif_content_foreach_entry (ExifContent *content, ExifContentForeachEntryFunc func, void *user_data);

我的第一次采取是:

sub exif_content_foreach_entry(ExifContent $exifcontent, &func (ExifEntry $entry, Buf $data), Buf $user_data) is native(LIB) is export { * }

但是在调用时,此函数会生成错误:

Internal error: unhandled dyncall callback argument type
  in method CALL-ME at /opt/rakudo-pkg/share/perl6/sources/24DD121B5B4774C04A7084827BFAD92199756E03 (NativeCall) line 588

如果我忽略user_data参数,一切正常,所以声明的其余部分都没问题:我只是没有将任何额外的数据传递给回调函数。

在其他情况下,我使用Buf将一块(可能的)二进制数据传递给C函数并且它工作;这里的区别是回调函数。知道如何解决这个问题吗?

(使用perl6 2018.03)

c callback perl6 nativecall
2个回答
4
投票

我不知道如何将Buf作为用户数据传递,因为Buf不是本机类型。但你可以使用例如CStruct代替:

class UserData is repr('CStruct') {
    has int32 $.dummy;
}

然后宣言将是:

sub exif_content_foreach_entry(
    ExifContent $exifcontent, 
    &func (ExifEntry $entry, UserData $data),
    UserData $user_data) is native(LIB) is export { * }

并且可以声明和定义回调,例如:

sub my-callback (ExifEntry $entry, UserData $data) {
    say "In callback";
    say "Value of data: ", $data.dummy;
}

编辑:

下面是一个解决方法,使用闭包将类似Buf的Perl 6类型(即非本机类型)传递给回调。例如:

my $buf = Buf.new( 1, 2, 3);
my $callback = my sub (ExifEntry $entry, UserData $data) {
    my-callback( $entry, $buf);
}

然后像这样声明真正的回调my-callback

sub my-callback (ExifEntry $entry, Buf $data) {
    say "In callback";
    say "Value of data: ", $data;
}

并调用库函数如下:

exif_content_foreach_entry( $content, &$callback, $data );

3
投票

我意识到这是一个老问题,你很可能很久以前就已经实现了解决方法,但是为了抓住类似问题的其他人,我现在就发布我的答案。

我不得不为不同的NativeCall库接口多次这样做,所以我决定把它打包成一个NativeHelpers::Callback模块。

它提供了一些简单的方法来将perl对象与CPointer相关联,并且可以在回调函数中轻松查找它。

这都是未经测试的,但这样的事情应该适用于您的情况:

use NativeHelpers::Callback :cb;                                                

class ExifEntry is repr('CPointer') { ... }                                     

sub exif_content_foreach_entry(ExifContent $exifcontent,                        
    &func (ExifEntry $entry, int64), int64) is native(LIB) is export { * }      

class MyPerlObject {                                                            
    has $.entry;                                                                
    has Buf $.buf;                                                              
    ...                                                                         
}                                                                               

sub MyCallBack(ExifEntry $entry, int64 $id) {                                   
    my MyPerlObject $object = cb.lookup($id);
    ... do stuff with $object ...                                   
}                                                                               

my ExifEntry $entry = ...;                                                      

my MyPerlObject $object = MyPerlObject.new(:$entry, buf => ...);                
cb.store($object, $entry);                                                      
exif_content_foreach_entry($exifcontent, &MyCallBack, cb.id($entry));           
© www.soinside.com 2019 - 2024. All rights reserved.