将结构数组传递给 Perl 6 NativeCall 函数
Passing an array of structures to a Perl 6 NativeCall function
我正在尝试使用 NativeCall 与某些 C 函数进行交互。
我有一个简单的 C 结构和一个需要它们数组的函数。
struct foo {
int x;
char *s;
};
struct foo foo_array[3];
foo_array[0].x = 12;
foo_array[0].s = "foo";
foo_array[1].x = 27;
foo_array[1].s = "bar";
foo_array[2].x = -1;
void somefunc(foo_array);
我尝试了很多方法,但似乎不太正确。
class foo is repr('CStruct') {
has int32 $.x;
has Str $.s
};
sub somefunc(CArray[foo]) is native { * }
my @foo-array := CArray[foo].new;
@foo-array[0] = ???
@foo-array[1] = ???
@foo-array[2] = ???
somefunc(@foo-array);
如何正确创建 class foo 的对象并设置它们的值,
以及如何制作适合传递的数组?
据我所知,没有内置的方法可以做到这一点。但是,有足够的绳子吊死自己 建立一个解决方法:
role StructArray[Mu:U \T where .REPR eq 'CStruct'] does Positional[T] {
has $.bytes;
has $.elems;
method new(UInt \n) {
self.bless(bytes => buf8.allocate(n * nativesizeof T), elems => n);
}
method AT-POS(UInt \i where ^$!elems) {
nativecast(T, Pointer.new(nativecast(Pointer, $!bytes) + i * nativesizeof T));
}
method pointer {
nativecast(Pointer[T], $!bytes);
}
}
这应该允许以下工作:
my @foo-array := StructArray[foo].new(10); # 'array' with 10 elements
@foo-array[0].x = 42;
通过将 @foo-array.pointer
传递给 Pointer[foo]
类型的参数,可以与 C 函数进行交互。由于结构也是通过指针传递的,因此您也可以将 @foo-array[0]
传递给类型为 foo
的参数以获得相同的效果。
以下代码显示如何将指向字节的指针和指向 wchar 的指针传递给 windows api 函数。
我还没有遇到需要传入结构数组的情况,但我不明白为什么同样的技术不适用。最重要的是:您必须确保为数据分配内存!
use NativeCall;
constant UINT := uint32;
constant BOOL := uint32;
constant BYTE := uint8;
constant WCHAR := uint16;
constant int := int32;
constant LPWTSTR := CArray[WCHAR];
constant PBYTE := CArray[BYTE];
my $virtual-keycode = 0xBC; # comma
sub SetConsoleCP(UINT) is native('Kernel32') returns BOOL { * };
sub SetConsoleOutputCP(UINT) is native('Kernel32') returns BOOL { * };
# winapi: int ToUnicode( UINT wVirtKey, UINT wScanCode, const PBYTE lpKeyState, LPWSTR pwszBuff, int cchBuff, UINT wFlags );
sub ToUnicode(UINT, UINT, PBYTE is rw, LPWTSTR is rw, int32, UINT) is native("User32") returns int32 { * };
my @kbs := CArray[BYTE].new(0 xx 256);
my @buf := CArray[WCHAR].new(0 xx 2);
say "Can't set Codepage" unless SetConsoleCP(65001) && SetConsoleOutputCP(65001);
say "Got Unicode" ~ @buf[0] ~ " -> " ~ @buf[0].chr
if ToUnicode( $virtual-keycode, 0, @kbs, @buf, 2 ,0);
我正在尝试使用 NativeCall 与某些 C 函数进行交互。
我有一个简单的 C 结构和一个需要它们数组的函数。
struct foo {
int x;
char *s;
};
struct foo foo_array[3];
foo_array[0].x = 12;
foo_array[0].s = "foo";
foo_array[1].x = 27;
foo_array[1].s = "bar";
foo_array[2].x = -1;
void somefunc(foo_array);
我尝试了很多方法,但似乎不太正确。
class foo is repr('CStruct') {
has int32 $.x;
has Str $.s
};
sub somefunc(CArray[foo]) is native { * }
my @foo-array := CArray[foo].new;
@foo-array[0] = ???
@foo-array[1] = ???
@foo-array[2] = ???
somefunc(@foo-array);
如何正确创建 class foo 的对象并设置它们的值, 以及如何制作适合传递的数组?
据我所知,没有内置的方法可以做到这一点。但是,有足够的绳子吊死自己 建立一个解决方法:
role StructArray[Mu:U \T where .REPR eq 'CStruct'] does Positional[T] {
has $.bytes;
has $.elems;
method new(UInt \n) {
self.bless(bytes => buf8.allocate(n * nativesizeof T), elems => n);
}
method AT-POS(UInt \i where ^$!elems) {
nativecast(T, Pointer.new(nativecast(Pointer, $!bytes) + i * nativesizeof T));
}
method pointer {
nativecast(Pointer[T], $!bytes);
}
}
这应该允许以下工作:
my @foo-array := StructArray[foo].new(10); # 'array' with 10 elements
@foo-array[0].x = 42;
通过将 @foo-array.pointer
传递给 Pointer[foo]
类型的参数,可以与 C 函数进行交互。由于结构也是通过指针传递的,因此您也可以将 @foo-array[0]
传递给类型为 foo
的参数以获得相同的效果。
以下代码显示如何将指向字节的指针和指向 wchar 的指针传递给 windows api 函数。
我还没有遇到需要传入结构数组的情况,但我不明白为什么同样的技术不适用。最重要的是:您必须确保为数据分配内存!
use NativeCall;
constant UINT := uint32;
constant BOOL := uint32;
constant BYTE := uint8;
constant WCHAR := uint16;
constant int := int32;
constant LPWTSTR := CArray[WCHAR];
constant PBYTE := CArray[BYTE];
my $virtual-keycode = 0xBC; # comma
sub SetConsoleCP(UINT) is native('Kernel32') returns BOOL { * };
sub SetConsoleOutputCP(UINT) is native('Kernel32') returns BOOL { * };
# winapi: int ToUnicode( UINT wVirtKey, UINT wScanCode, const PBYTE lpKeyState, LPWSTR pwszBuff, int cchBuff, UINT wFlags );
sub ToUnicode(UINT, UINT, PBYTE is rw, LPWTSTR is rw, int32, UINT) is native("User32") returns int32 { * };
my @kbs := CArray[BYTE].new(0 xx 256);
my @buf := CArray[WCHAR].new(0 xx 2);
say "Can't set Codepage" unless SetConsoleCP(65001) && SetConsoleOutputCP(65001);
say "Got Unicode" ~ @buf[0] ~ " -> " ~ @buf[0].chr
if ToUnicode( $virtual-keycode, 0, @kbs, @buf, 2 ,0);