2016-02-06 2 views
6

Ho il seguente Struct:NativeCall struct che contiene Pointer

typedef struct _info{ 
    DWORD myInfo; 
    BYTE *pInfo; 
    LPWSTR ExtData; 

} Info; 

Ho rappresentato questo struct usando NativeCall così:

class Info is repr('CStruct') { 
    has int32 $.myInfo; 
    has Pointer[int8] $.pInfo ; 
    has Pointer[int16] $.ExtData; 
} 

questa rappresentazione va bene? Come posso accedere e impostare i dati puntati da $.pInfo?

risposta

3

La rappresentazione sembra ok per me ... Dato questo ha inventato C libreria: (si prega di non prendere sul mio C pippo - proprio accanto al punto)

#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 

typedef unsigned long int DWORD; 
typedef unsigned char BYTE; 
typedef char * LPWSTR; 

typedef struct _info{ 
    DWORD myInfo; 
    BYTE *pInfo; 
    LPWSTR ExtData; 
} Info; 


Info* create_info(); 
void display_info(); 
void double_info(Info*); 

Info* 
create_info() { 
    DWORD init_myinfo = 2016; 
    BYTE init_pinfo  = 37; 
    char init_ExtData[] = "Hello World"; 

    Info *new_info = malloc(sizeof(Info)); 
    if (new_info == NULL) { 
     printf("Memory alloc failed\n"); 
     exit(1); 
    } 

    new_info->myInfo = init_myinfo; 

    BYTE *pinfo = malloc(sizeof(BYTE)); 
    *pinfo = init_pinfo; 
    new_info->pInfo = pinfo; 

    char *ext_data = malloc(sizeof(init_ExtData)); 
    strcpy(ext_data, init_ExtData); 
    new_info->ExtData = ext_data; 

    return new_info; 
} 

void 
display_info(Info *inf) { 
    printf("myInfo: %lu\n", inf->myInfo); 
    printf("pInfo: %i\n", *inf->pInfo); 
    printf("ExtData: %s\n", inf->ExtData); 
} 

void 
double_info(Info *inf) { 

    inf->myInfo *= 2; 

    if (*(inf->pInfo) < 128) 
     *(inf->pInfo) *= 2; 

    int extdata_len = strlen(inf->ExtData); 
    char *tmp_extdata = malloc(extdata_len * 2 + 2); 
    strncpy(tmp_extdata, inf->ExtData, extdata_len); 
    tmp_extdata[extdata_len] = '+'; 
    strcpy(&tmp_extdata[extdata_len+1], inf->ExtData); 
    inf->ExtData = tmp_extdata; 
} 

allora la vostra definizione perl6 struct usando NativeCall più o meno funziona:

#!/usr/bin/env perl6 
use NativeCall; 

class Info is repr('CStruct') { 
    has int32   $.myInfo; 
    has Pointer[int8] $.pInfo ; 
    has Pointer[Str] $.ExtData; 

    method Str { 
     qq:to/END HERE/; 
     myInfo: $!myInfo 
     pInfo: { $!pInfo.deref } 
     ExtData: { $!ExtData.deref } 
     END HERE 
    } 
} 

our sub create_info() returns Info is native('pinfo') { * } 
our sub display_info(Info) is native('pinfo') { * } 
our sub double_info(Info is rw) is native('pinfo') { * } 

my Info $inf = create_info(); 
say 'Displaying $inf after calling create_info()'; 
display_info $inf; 

double_info $inf; 
say 'Displaying $inf after calling double_info()'; 
display_info $inf; 

say 'Displaying $inf by calling attribute methods on Perl6 object'; 
say "myInfo: $inf.myInfo()"; 
say "pInfo: $inf.pInfo.deref()"; 
say "ExtData: $inf.ExtData.deref()"; 

say 'Displaying $inf by stringifying Perl6 object'; 
say "$inf"; 
exit 0; 

Una corsa di questo produce;

Displaying $inf after calling create_info() 
myInfo: 2016 
pInfo: 37 
ExtData: Hello World 
Displaying $inf after calling double_info() 
myInfo: 4032 
pInfo: 74 
ExtData: Hello World+Hello World 
Displaying $inf by calling attribute methods on Perl6 object 
myInfo: 4032 
pInfo: 74 
ExtData: Hello World+Hello World 
Displaying $inf by stringifying Perl6 object 
myInfo: 4032 
pInfo: 74 
ExtData: Hello World+Hello World 

In alternativa, è possibile nascondere una quantità maggiore di "colla" all'interno della classe perl6;

#!/usr/bin/env perl6 
use NativeCall; 

class Info is repr('CStruct') { 
    has int32   $.myInfo is rw ; 
    has Pointer[int8] $!pInfo ; 
    has Pointer[Str] $!ExtData ; 

    my sub create_info() returns Info is native('pinfo') { * } 
    my sub display_info(Info)   is native('pinfo') { * } 
    my sub double_info(Info is rw) is native('pinfo') { * } 

    method new  { create_info()  } 
    method display { display_info(self) } 
    method double { double_info(self) } 

    method pInfo { $!pInfo.deref  } 
    method ExtData { $!ExtData.deref } 

    method Str { 
     qq:to/END HERE/; 
     myInfo: { self.myInfo } 
     pInfo: { self.pInfo } 
     ExtData: { self.ExtData } 
     END HERE 
    } 
} 

my Info $inf .= new; 
say 'Displaying $inf after calling .new'; 
$inf.display ; 

$inf.double ; 
say 'Displaying $inf after calling .double'; 
$inf.display ; 

say 'Displaying $inf by calling attribute methods on Perl6 object'; 
say "myInfo: $inf.myInfo()"; 
say "pInfo: $inf.pInfo()"; 
say "ExtData: $inf.ExtData()"; 

$inf.myInfo = 12046 ; 
say 'Displaying $inf by stringifying Perl6 object'; 
say "$inf"; 
exit 0; 

... un aspetto molto più pulito. Similmente produce;

Displaying $inf after calling .new 
myInfo: 2016 
pInfo: 37 
ExtData: Hello World 
Displaying $inf after calling .double 
myInfo: 4032 
pInfo: 74 
ExtData: Hello World+Hello World 
Displaying $inf by calling attribute methods on Perl6 object 
myInfo: 4032 
pInfo: 74 
ExtData: Hello World+Hello World 
Displaying $inf by stringifying Perl6 object 
myInfo: 12046 
pInfo: 74 
ExtData: Hello World+Hello World 

Note:

(1) Si chiama il metodo .deref() su attributi di tipo puntatore per ottenere i dati reali da indicavano.

(2) La NativeCall documentation deve essere letto più di una volta ;-)

(3) Non importa quello che ho provato, non ho potuto modificare i dati che vengono riferiti tramite puntatori - ho continuato a ottenere "Can' t modificare i dati immutabili ".

(4) YMMV