如何将用户数据传递给回调函数
How to pass user data to a callback function
我正在研究 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)
我不确定如何将 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;
}
编辑:
这里有一个解决方法,可以使用闭包将 Perl 6 类型(如 Buf
(即不是本机类型)传递给回调。例如:
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 );
我知道这是一个老问题,您可能很久以前就实施了解决方法,但为了发现其他人有类似问题,我现在 post 我的回答。
我不得不为不同的 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));
我正在研究 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)
我不确定如何将 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;
}
编辑:
这里有一个解决方法,可以使用闭包将 Perl 6 类型(如 Buf
(即不是本机类型)传递给回调。例如:
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 );
我知道这是一个老问题,您可能很久以前就实施了解决方法,但为了发现其他人有类似问题,我现在 post 我的回答。
我不得不为不同的 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));