将结构数组传递给Perl 6 NativeCall函数

时间:2017-04-21 14:12:54

标签: perl6 nativecall

我正在尝试使用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);

如何正确创建类foo的对象并设置其值, 以及如何使它们的数组适合传递?

2 个答案:

答案 0 :(得分:1)

据我所知,没有内置的方法可以做到这一点。但是,有足够的绳索来自己挂起 构建一个变通方法

phpinfo()

这应该允许以下工作:

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类型的参数,可以与C函数进行交互。由于结构也通过指针传递,您也可以将Pointer[foo]传递给@foo-array[0]类型的参数,以获得相同的效果。

答案 1 :(得分:1)

以下代码显示如何将指向字节的指针和指向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);