Differenze tra le versioni di "Gestire con sicurezza le Strutture esterne"

Da Gambas-it.org - Wikipedia.
 
(32 versioni intermedie di uno stesso utente non sono mostrate)
Riga 1: Riga 1:
 
Talvolta nell'uso delle risorse appartenenti a librerie esterne ci si può imbattere in ''Strutture'' molto complesse, dichiarate nei relativi file ''header'' (.h), la trascrizione delle quali in Gambas può risultare assai difficile.
 
Talvolta nell'uso delle risorse appartenenti a librerie esterne ci si può imbattere in ''Strutture'' molto complesse, dichiarate nei relativi file ''header'' (.h), la trascrizione delle quali in Gambas può risultare assai difficile.
  
Per essere sicuri di non commettere errori, si può scegliere che alcune di queste ''Strutture'', e comunque quelle più ostiche, non vengano ''ricostruite'' e dichiarate nel codice del progetto Gambas, ma usate così come sono in una speciale libreria esterna dinamica condivisa (''.so'') <SPAN Style="text-decoration:underline">appositamente da noi realizzata</span>.
+
Per essere sicuri di non commettere errori, si può scegliere che alcune di queste ''Strutture'', e comunque quelle più ostiche, non vengano ''ricostruite'' e dichiarate nel codice del progetto Gambas, ma usate così come sono in una speciale libreria esterna condivisa (''.so'') <SPAN Style="text-decoration:underline">appositamente da noi realizzata</span>.
  
 
Più in particolare per ogni struttura che si intende usare, all'interno di tale apposita libreria condivisa (''.so'') vengono scritte in C alcune funzioni che verranno richiamate dall'applicativo Gambas principale.
 
Più in particolare per ogni struttura che si intende usare, all'interno di tale apposita libreria condivisa (''.so'') vengono scritte in C alcune funzioni che verranno richiamate dall'applicativo Gambas principale.
Riga 10: Riga 10:
  
  
==Conoscere la dimensione di una ''Struttura'' da utilizzare==
+
=Conoscere la dimensione di una ''Struttura'' da utilizzare=
Dunque, avremo una funzione C per ciascuna ''Struttura'' da utilizzare che ritorna la dimensione della ''Struttura'' medesima. In ordine al nome della ''Struttura'', da inserire nella predetta funzione C, si deve precisare che:
+
Per ciascuna ''Struttura'' esterna da utilizzare, qualora nel codice essa non venga creata ed istanziata da alcuna funzione esterna e debba essere passata ad altra funzione esterna, sarà necessario conoscere la sua dimensione. Si rende necessario ciò, perché si dovrà creare la variabile di tipo ''Puntatore'' a un'area di memoria riservata che andrà a sostituire la ''Struttura'' esterna, accogliendo quindi i dati che quella avrebbe normalmente ricevuto nei suoi membri.
 +
 
 +
Dunque, scriveremo nella libreria condivisa ''.so'' (da noi scritta in linguaggio C) una funzione per ciascuna ''Struttura'' da utilizzare. Ciascuna funzione ritornerà la dimensione della ''Struttura'' medesima.
 +
<BR>Bisogna ricordare che in ogni predetta funzione, da noi scritta, <SPAN Style="text-decoration:underline">dovrà essere specificato con il tag "#include" di C il file ''header''</span>, nel quale la ''Struttura'' esterna da emulare è dichiarata.
 +
 
 +
In ordine al nome della ''Struttura'', da inserire nella predetta funzione C, si deve precisare che:
 
====Caso in cui la ''Struttura'' è dichiarata nel file ''header'' con la parola chiave "''typedef''"====
 
====Caso in cui la ''Struttura'' è dichiarata nel file ''header'' con la parola chiave "''typedef''"====
In questo caso, se è dichiarata anche l'etichetta della ''Struttura'' ed il suo nome ''alias''
+
In questo caso:
 +
* se è dichiarata <SPAN Style="text-decoration:underline">anche</span> l'etichetta della ''Struttura'' ed il suo nome ''alias'':
 
  <FONT Color=#B22222>typedef</font> struct etichetta {
 
  <FONT Color=#B22222>typedef</font> struct etichetta {
 
  ...
 
  ...
Riga 19: Riga 25:
 
  ...
 
  ...
 
  } nome_alias;
 
  } nome_alias;
oppure se è dichiarato soltanto il nome ''alias'' della ''Struttura'':
+
allora come argomento della funzione ''sizeof()'' presente nel sorgente in C dell'apposita libreria condivisa, da noi creata, potrà essere indicata l'etichetta della ''Struttura'' preceduta dalla parola ''struct'':
 +
int nome_funzione() {
 +
    return sizeof(<FONT color=#B22222>struct</font> etichetta);
 +
  }
 +
Al riguardo mostriamo un esempio, nel quale si otterrà la dimensione della ''Struttura'' "typedef struct AVFormatContext", dichiarata nel file header "/usr/include/x86_64-linux-gnu/libavformat/avformat.h":
 +
<FONT Color=gray>' ''int dim_AVFormatContext()''
 +
' ''La funzione per ottenere la dimensione della Struttura "AVFormatContext":''</font>
 +
Private Extern dim_AVFormatContext() As Integer In "/tmp/libdim"
 +
 +
 +
Public Sub Main()
 +
 +
  Dim i As Integer
 +
 +
<FONT Color=gray>' ''Invoca la Procedura, nella quale si creerà la libreria condiva ".so" per conoscere la dimensione della Struttura "AVFormatContext":''</font>
 +
  Creaso()
 +
 +
<FONT Color=gray>' ''Invoca la funzione specifica, presente nella libreria condiva esterna, per conoscere la dimensione della Struttura "AVFormatContext":''</font>
 +
  i = dim_AVFormatContext()
 +
 +
  Print "La dimensione della Struttura 'AVFormatContext' è = "; i; " byte"
 +
 +
End
 +
 +
Private Procedure Creaso()
 +
 
 +
  File.Save("/tmp/libdim.c", "#include <libavformat/avformat.h>\n\n" &
 +
                            "int dim_AVFormatContext() {\n" &
 +
                            "  return <FONT Color=#B22222>sizeof('''struct''' AVFormatContext)</font>;\n}")
 +
 
 +
  Shell "gcc -o /tmp/libdim.so /tmp/libdim.c -shared" Wait
 +
 
 +
End
 +
Potrà però essere indicato il solo nome ''alias'' della ''Struttura'':
 +
int nome_funzione() {
 +
    return sizeof(nome_alias);
 +
}
 +
 
 +
 
 +
* Se, invece, è dichiarato <SPAN Style="text-decoration:underline">soltanto</span> il nome ''alias'' della ''Struttura'' dichiarata con "typedef":
 
  <FONT Color=#B22222>typedef</font> struct {
 
  <FONT Color=#B22222>typedef</font> struct {
 
  ...
 
  ...
Riga 25: Riga 70:
 
  ...
 
  ...
 
  } nome_alias;
 
  } nome_alias;
allora come argomento della funzione ''sizeof()'' in C andrà indicato soltanto il nome ''alias'' della ''Struttura'':
+
allora come argomento della funzione ''sizeof()'' presente nel sorgente in C dell'apposita libreria condivisa, da noi creata, andrà indicato soltanto il nome ''alias'' della ''Struttura'':
 
  int nome_funzione() {
 
  int nome_funzione() {
 
     return sizeof(nome_alias);
 
     return sizeof(nome_alias);
   }
+
}
 +
Al riguardo mostriamo un esempio, nel quale si otterrà la dimensione della ''Struttura'' "div_t", dichiarata nel file header "stdlib.h" e avente soltanto il proprio nome ''alias'':
 +
<FONT Color=gray>' ''int dim_divt()''
 +
' ''La funzione per ottenere la dimensione della Struttura "div_t":''</font>
 +
Private Extern dim_divt() As Integer In "/tmp/libdim"
 +
 +
 +
Public Sub Main()
 +
 +
  Dim i As Integer
 +
 +
<FONT Color=gray>' ''Invoca la Procedura, nella quale si creerà la libreria condiva ".so" per conoscere la dimensione della Struttura "div_t":''</font>
 +
  Creaso()
 +
 +
<FONT Color=gray>' ''Invoca la funzione specifica, presente nella libreria condiva esterna, per conoscere la dimensione della Struttura "div_t":''</font>
 +
  i = dim_divt()
 +
 +
  Print "La dimensione della Struttura 'div_t' è = "; i; " byte"
 +
 +
End
 +
 +
Private Procedure Creaso()
 +
 
 +
   File.Save("/tmp/libdim.c", "#include <stdlib.h>\n\n" &
 +
                            "int dim_divt() {\n" &
 +
                            "  return <FONT Color=#B22222>sizeof(div_t)</font>;\n}")
 +
 
 +
  Shell "gcc -o /tmp/libdim.so /tmp/libdim.c -shared" Wait
 +
 
 +
End
  
  
 
====Caso in cui la ''Struttura'' <SPAN style="text-decoration:underline">non</span> è dichiarata con la parola chiave "''typedef''"====
 
====Caso in cui la ''Struttura'' <SPAN style="text-decoration:underline">non</span> è dichiarata con la parola chiave "''typedef''"====
 
In questo caso:
 
In questo caso:
* se è presente soltanto l'etichetta della ''Struttura''
+
* se è presente <SPAN style="text-decoration:underline">soltanto</span> l'etichetta della ''Struttura''
 
  struct etichetta {
 
  struct etichetta {
 
  ...
 
  ...
Riga 39: Riga 113:
 
  ...
 
  ...
 
  };
 
  };
allora come argomento della funzione ''sizeof()'' in C andrà indicata l'etichetta della ''Struttura'' preceduta dalla parola ''struct'':
+
allora come argomento della funzione ''sizeof()'' presente nel sorgente in C dell'apposita libreria condivisa, da noi creata, andrà indicata l'etichetta della ''Struttura'' preceduta dalla parola ''struct'':
 
  int nome_funzione() {
 
  int nome_funzione() {
 
     return sizeof(<FONT color=#B22222>struct</font> etichetta);
 
     return sizeof(<FONT color=#B22222>struct</font> etichetta);
 
   }
 
   }
 +
Mostriamo un esempio, nel quale si otterrà la dimensione della ''Struttura'' "struct pollfd", dichiarata nel file header "/usr/include/asm-generic/poll.h":
 +
<FONT Color=gray>' ''int dim_pollfd()''
 +
' ''La funzione per ottenere la dimensione della Struttura "struct pollfd":''</font>
 +
Private Extern dim_pollfd() As Integer In "/tmp/libdim"
 +
 +
 +
Public Sub Main()
 +
 +
  Dim i As Integer
 +
 +
<FONT Color=gray>' ''Invoca la Procedura, nella quale si creerà la libreria condiva ".so" per conoscere la dimensione della Struttura "struct pollfd":''</font>
 +
  Creaso()
 +
 +
<FONT Color=gray>' ''Invoca la funzione specifica, presente nella libreria condiva esterna, per conoscere la dimensione della Struttura "struct pollfd":''</font>
 +
  i = dim_pollfd()
 +
 +
  Print "La dimensione della Struttura 'pollfd' è = "; i; " byte"
 +
 +
End
 +
 +
Private Procedure Creaso()
 +
 
 +
  File.Save("/tmp/libdim.c", "#include <asm-generic/poll.h>\n\n" &
 +
                            "int dim_pollfd() {\n" &
 +
                            "  return <FONT Color=#B22222>sizeof(struct pollfd)</font>;\n}")
 +
 
 +
  Shell "gcc -o /tmp/libdim.so /tmp/libdim.c -shared" Wait
 +
 
 +
End
  
* se è presente il solo nome ''alias'' della ''Struttura''
+
* se è presente il <SPAN style="text-decoration:underline">solo</span> nome ''alias'' della ''Struttura''
 
  struct {
 
  struct {
 
  ...
 
  ...
Riga 50: Riga 153:
 
  ...
 
  ...
 
  } nome_alias;
 
  } nome_alias;
allora come argomento della funzione ''sizeof()'' in C andrà indicato soltanto il nome ''alias'' della ''Struttura'':
+
allora come argomento della funzione ''sizeof()'' presente nel sorgente in C dell'apposita libreria condivisa, da noi creata, andrà indicato soltanto il nome ''alias'' della ''Struttura'':
 
  int nome_funzione() {
 
  int nome_funzione() {
 
     return sizeof(nome_alias);
 
     return sizeof(nome_alias);
 
   }
 
   }
  
* se sono presenti l'etichetta ed il nome ''alias'' della ''Struttura''
+
* se sono presenti <SPAN style="text-decoration:underline">l'etichetta ed il nome ''alias''</span> della ''Struttura''
 
  struct etichetta {
 
  struct etichetta {
 
  ...
 
  ...
Riga 61: Riga 164:
 
  ...
 
  ...
 
  } nome_alias;
 
  } nome_alias;
allora come argomento della funzione ''sizeof()'' in C andrà indicato soltanto il nome ''alias'' della ''Struttura'':
+
allora come argomento della funzione ''sizeof()'' presente nel sorgente in C dell'apposita libreria condivisa, da noi creata, potrà essere indicato soltanto il nome ''alias'' della ''Struttura'':
 
  int nome_funzione() {
 
  int nome_funzione() {
 
     return sizeof(nome_alias);
 
     return sizeof(nome_alias);
  }
+
}
 
 
 
Come già detto, se vi è una funzione della libreria esterna principale che inizializza nel codice Gambas la variabile di tipo ''Puntatore'', allora questa funzione C è inutile.
 
Come già detto, se vi è una funzione della libreria esterna principale che inizializza nel codice Gambas la variabile di tipo ''Puntatore'', allora questa funzione C è inutile.
  
  
Se deve essere conosciuta la dimensione di un membro che punta ad una sub-Struttura, va ovviamente posta come argomento della funzione ''sizeof()'' il nome della sub-Struttura:
+
===Conoscere la dimensione di una Struttura ''innestata'' o di un ''Puntatore'' ad una ''Struttura'' secondaria===
 +
Se deve essere conosciuta la dimensione di un membro che punta ad una Struttura ''innestata'' all'interno di una ''Struttura'' principale, ovvero del ''Puntatore'' ad una sub-Struttura innestata, va ovviamente posto  il nome della Struttura ''secondaria'' come argomento della funzione ''sizeof()'' presente nel sorgente in C dell'apposita libreria condivisa, da noi creata:
 
   int nome_funzione() {
 
   int nome_funzione() {
 
     return sizeof(nome_della_sub-Struttura);
 
     return sizeof(nome_della_sub-Struttura);
  }
+
}
 +
Ovviamente, se si tratta di un membro di tipo ''Puntatore'' ad una Struttura ''secondaria'', allora la dimensione del membro della Struttura "principale",sarà della consueta quantità di memoria occupata nel sistema in uso da una variabile di tipo ''Puntatore''. Se il membro punta ad una sub-Struttura ''innestata'', allora la dimensione del membro sarà pari alla quantità di memoria occupata dall'intera sub-Struttura ''innestata''.
  
  
==Leggere e scrivere nei membri delle ''Strutture''==
+
=Leggere e scrivere nei membri delle ''Strutture''=
Per leggere e scrivere nei membri che ci interessano di una ''Struttura'', si porrano nella nostra libreria ''ad hoc'' una serie di funzioni, alle quali come loro argomento si passerà una variabile di tipo ''Puntatore'', avendo avuto l'accortezza nel codice Gambas di dimensionare oppurtunamente ed adeguatamente (ossia riservare un'area di memoria <SPAN style= "text-decoration:underline">di dimensione identica</span> a quella della Struttura da gestire) tale ''Puntatore'' mediante la funzione ''Alloc()'' nella modalità vista nel precedente paragrafo "''Conoscere la dimensione di una Struttura da utilizzare''".
+
Per leggere e scrivere nei membri che ci interessano di una ''Struttura'', si porrano nella nostra libreria ''ad hoc'' una serie di funzioni, alle quali come loro argomento si passerà una variabile di tipo ''Puntatore'', avendo avuto l'accortezza nel codice Gambas di dimensionare oppurtunamente ed adeguatamente (ossia riservare un'area di memoria <SPAN style= "text-decoration:underline">di dimensione identica</span> a quella della Struttura da gestire) tale ''Puntatore'' mediante la funzione "Alloc()" nella modalità vista nel precedente paragrafo "''Conoscere la dimensione di una Struttura da utilizzare''".
 
<BR>Se, invece, vi è una funzione esterna della libreria esterna principale che inizializza (e quindi anche dimensionandola) nel codice Gambas la variabile di tipo ''Puntatore'' ad una ''Struttura'' in C, allora alla libreria ''ad hoc'' si passerà tale variabile ''Puntatore''.
 
<BR>Se, invece, vi è una funzione esterna della libreria esterna principale che inizializza (e quindi anche dimensionandola) nel codice Gambas la variabile di tipo ''Puntatore'' ad una ''Struttura'' in C, allora alla libreria ''ad hoc'' si passerà tale variabile ''Puntatore''.
  
Riga 83: Riga 187:
 
  void nome_funzione(nome_della_Struttura *p, int valore_da_scrivere) {
 
  void nome_funzione(nome_della_Struttura *p, int valore_da_scrivere) {
 
     p->nome_membro = valore_da_scrivere;
 
     p->nome_membro = valore_da_scrivere;
  }
+
}
  
  
Riga 90: Riga 194:
 
   int nome_funzione(nome_della_Struttura *p) {
 
   int nome_funzione(nome_della_Struttura *p) {
 
     return p->nome_membro;
 
     return p->nome_membro;
  }
+
}
 
Per ritornare il valore di un membro di una sub-Struttura vettoriale contenuta nella ''Struttura'' principale, si tiene conto dell'indice della sub-Struttura vettoriale prescelta:
 
Per ritornare il valore di un membro di una sub-Struttura vettoriale contenuta nella ''Struttura'' principale, si tiene conto dell'indice della sub-Struttura vettoriale prescelta:
 
  int nome_funzione(nome_della_Struttura *p) {
 
  int nome_funzione(nome_della_Struttura *p) {
 
     return p->nome_sub_Struttura_vettoriale[numero_indice].nome_membro;
 
     return p->nome_sub_Struttura_vettoriale[numero_indice].nome_membro;
  }
+
}
  
 
* oppure per ritornare una Stringa:
 
* oppure per ritornare una Stringa:
 
  char * nome_funzione(nome_della_Struttura *p) {
 
  char * nome_funzione(nome_della_Struttura *p) {
 
     return p->nome_membro;
 
     return p->nome_membro;
  }
+
}
  
 
* oppure per ritornare un puntatore ad una ''Struttura'' secondaria contenuta in un'altra ''Struttura'' principale:
 
* oppure per ritornare un puntatore ad una ''Struttura'' secondaria contenuta in un'altra ''Struttura'' principale:
 
  nome_Struttura_secondaria * nome_funzione(nome_della_Struttura_principale *p) {
 
  nome_Struttura_secondaria * nome_funzione(nome_della_Struttura_principale *p) {
 
     return &p->nome_membro_che_punta_alla_Struttura_secondaria;
 
     return &p->nome_membro_che_punta_alla_Struttura_secondaria;
  }
+
}
 
Anche in questo caso se la ''Struttura'' <SPAN style="text-decoration:underline">non</span> è dichiarata con la parola chiave "''typedef''", allora il nome della ''Struttura'' andrà preceduto dalla paola ''struct'', oppure ''union'' se si tratta di una ''Union'':
 
Anche in questo caso se la ''Struttura'' <SPAN style="text-decoration:underline">non</span> è dichiarata con la parola chiave "''typedef''", allora il nome della ''Struttura'' andrà preceduto dalla paola ''struct'', oppure ''union'' se si tratta di una ''Union'':
 
  union nome_della_union * nome_funzione(nome_della_Struttura_principale *p) {
 
  union nome_della_union * nome_funzione(nome_della_Struttura_principale *p) {
 
     return &p->nome_membro_che_punta_alla_Union;
 
     return &p->nome_membro_che_punta_alla_Union;
  }
+
}
  
  
Riga 118: Riga 222:
  
 
===Applicazione in ausilio===
 
===Applicazione in ausilio===
Per agevolare la redazione delle funzioni di lettura e scrittura dei membri della ''Struttura'' esterna da gestire con sicurezza, potremmo adottare - nel rispetto e compatibilmente con quanto sopra descritto - il seguente codice:
+
Potremo anche creare dall'applicazione principale Gambas la nostra apposita libreria esterna condivisa:
  '''Private''' Procedure Genera_Struttura()
+
  Private Procedure Genera_Struttura()
 
    
 
    
 
   Dim st As New String[][]
 
   Dim st As New String[][]
Riga 129: Riga 233:
 
  ' ''Nella seconda dimensione della matrice vengono inseriti gli identificatori di ciascun membro della Struttura in corrispondenza dei rispettivi tipi presenti negli elementi della prima dimensione.''
 
  ' ''Nella seconda dimensione della matrice vengono inseriti gli identificatori di ciascun membro della Struttura in corrispondenza dei rispettivi tipi presenti negli elementi della prima dimensione.''
 
  ' ''Riguardo al primo elemento di ciascuna delle due dimensioni bisognerà fare attenzione in particolare se nella Struttura è presente la parola chiave "typedef" e/o il nome alias.''</font>
 
  ' ''Riguardo al primo elemento di ciascuna delle due dimensioni bisognerà fare attenzione in particolare se nella Struttura è presente la parola chiave "typedef" e/o il nome alias.''</font>
  st.Add(["struct ", "char ", "short ", "int "])
+
  st.Add(["struct ", "char ", "short ", "int "])
  st.Add(["STRUTTURA ", "c", "s", "i"])
+
  st.Add(["STRUTTURA ", "c", "s", "i"])
 
    
 
    
 
  <FONT Color=gray>' ''Qui si inserisce la libreria esterna .h (il suo file "header"), nella quale è contenuta la Struttura da gestire con sicurezza:''</font>
 
  <FONT Color=gray>' ''Qui si inserisce la libreria esterna .h (il suo file "header"), nella quale è contenuta la Struttura da gestire con sicurezza:''</font>
  s = "#include <''libreria_esterna.h''>\n\n\n"
+
  s = "#include <''libreria_esterna.h''>\n\n\n"
 
    
 
    
 
  <FONT Color=gray>' ''Questa riga crea la funzione per ottenere la dimensione della Struttura da gestire con sicurezza:''</font>
 
  <FONT Color=gray>' ''Questa riga crea la funzione per ottenere la dimensione della Struttura da gestire con sicurezza:''</font>
  s &= "\nint Dim_" & st[1][0] & "() {\n  return sizeof(" & st[0][0] & st[1][0] & ");\n}"
+
  s &= "\nint Dim_" & st[1][0] & "() {\n  return sizeof(" & st[0][0] & st[1][0] & ");\n}"
 
   
 
   
 
  <FONT Color=gray>' ''Qui si creano le funzioni di lettura e di scrittura dei membri della Struttura da gestire con sicurezza:''</font>
 
  <FONT Color=gray>' ''Qui si creano le funzioni di lettura e di scrittura dei membri della Struttura da gestire con sicurezza:''</font>
  For b = 1 To st[0].Max
+
  For b = 1 To st[0].Max
    s &= String$(4, "\n") & st[0][b] & "Legge_" & st[1][b] & "(" & st[0][0] & st[1][0] & "* p) {" &
+
    s &= String$(4, "\n") & st[0][b] & "Legge_" & st[1][b] & "(" & st[0][0] & st[1][0] & "* p) {" &
          "\n  return p->" & st[1][b] & ";\n}"
+
        "\n  return p->" & st[1][b] & ";\n}"
    s &= "\n\nvoid Scrive_" & st[1][b] & "(" & st[0][0] & st[1][0] & "* p, " & st[0][b] & "v) {" &
+
    s &= "\n\nvoid Scrive_" & st[1][b] & "(" & st[0][0] & st[1][0] & "* p, " & st[0][b] & "v) {" &
          "\n  p->" & st[1][b] & " = v;\n}"
+
        "\n  p->" & st[1][b] & " = v;\n}"
  Next
+
  Next
 
    
 
    
  <FONT Color=gray>' ''Viene salvato il sorgente della Libreria dinamica .so ad hoc, da noi creata, per gestire con sicurezza la Struttura esterna:''</font>
+
  <FONT Color=gray>' ''Viene salvato il sorgente della Libreria condivisa ".so" ''ad hoc'', da noi creata, per gestire con sicurezza la Struttura esterna:''</font>
  File.Save("/tmp/Libadhoc.c", s)
+
  File.Save("/tmp/Libadhoc.c", s)
 
    
 
    
  <FONT Color=gray>' ''Viene infine generata la Libreria dinamica .so ad hoc, da noi creata:''</font>
+
  <FONT Color=gray>' ''Viene infine generata la Libreria condivisa ".so" ''ad hoc'', da noi creata:''</font>
  Shell "gcc -o /tmp/Libadhoc.so /tmp/membri.c -shared" Wait
+
  Shell "gcc -o /tmp/Libadhoc.so /tmp/membri.c -shared" Wait
 
    
 
    
  '''End'''
+
  End
  
  
 
+
=Gestione mediante l'uso del metodo ''GetExternSymbol()'' della Classe ''System'' di Gambas=
==Gestione mediante l'uso del metodo ''GetExternSymbol()'' della Classe ''System'' di Gambas==
 
 
Una seconda possibilità, per gestire le risorse della nostra libreria esterna .so ''ad hoc'' (creata per poter utilizzare con ''sicurezza'' le ''Strutture'' in C presenti in uno o più file ''header'' della libreria esterna principale), è quella offerta dal metodo ''.GetExternSymbol()'' della Classe ''System''.
 
Una seconda possibilità, per gestire le risorse della nostra libreria esterna .so ''ad hoc'' (creata per poter utilizzare con ''sicurezza'' le ''Strutture'' in C presenti in uno o più file ''header'' della libreria esterna principale), è quella offerta dal metodo ''.GetExternSymbol()'' della Classe ''System''.
  
Riga 163: Riga 266:
  
 
===Scrivere una funzione per ogni azione da esercitare su un membro===
 
===Scrivere una funzione per ogni azione da esercitare su un membro===
All'interno della libreria dinamica condivisa esterna, da noi creata, verrà scritta una o due funzioni (lettura e/o scrittura) da eseguire su un membro della ''Struttura'' esterna.
+
All'interno della libreria condivisa esterna, da noi creata, verrà scritta una o due funzioni (lettura e/o scrittura) da eseguire su un membro della ''Struttura'' esterna.
  
 
Vediamo un esempio pratico.
 
Vediamo un esempio pratico.
Riga 171: Riga 274:
 
     int i;
 
     int i;
 
  };
 
  };
 +
 +
struct STRUTTURA st;
 
e che intendiamo leggere e scrivere dati da/sul membro ''int i''.
 
e che intendiamo leggere e scrivere dati da/sul membro ''int i''.
  
Dunque la libreria dinamica condivisa esterna ''ad hoc'', che dovremo noi creare, sarà la seguente:
+
Dunque la libreria condivisa esterna ''ad hoc'', che dovremo noi creare, sarà la seguente:
  #include "''/percorso/del/file.h''"
+
  #include "<FONT Color=darkgreen>''/percorso/del/file.h''</font>"
 +
 
   
 
   
 
  void Scrivi(struct STRUTTURA *p, int val) {
 
  void Scrivi(struct STRUTTURA *p, int val) {
Riga 180: Riga 286:
 
       p->i = val;
 
       p->i = val;
 
  }
 
  }
 
 
   
 
   
 
  int Leggi(struct STRUTTURA *p) {
 
  int Leggi(struct STRUTTURA *p) {
Riga 188: Riga 293:
  
 
Il codice Gambas dell'applicazione sarà il seguente:
 
Il codice Gambas dell'applicazione sarà il seguente:
  Library "''/percorso/della/libreria/esterna/da/noi/creata''"
+
  Library "<FONT Color=darkgreen>''/percorso/della/libreria/esterna/da/noi/creata''</font>"
 
   
 
   
 
  Private Extern Scrivi(po As Pointer, i As Integer)
 
  Private Extern Scrivi(po As Pointer, i As Integer)
Riga 194: Riga 299:
 
   
 
   
 
   
 
   
  '''Public''' Sub Main()
+
  Public Sub Main()
 
   
 
   
 
   Dim p As Pointer
 
   Dim p As Pointer
 
    
 
    
  p = System.GetExternSymbol("''/percorso/della/libreria/esterna/da/noi/creata''", "''variabile_della_Struttura''")
+
  p = System.GetExternSymbol("<FONT Color=darkgreen>''/percorso/della/libreria/esterna/da/noi/creata''</font>", "<FONT Color=#B22222>st</font>")
 
    
 
    
  Scrivi(p, 99)
+
  Scrivi(p, 99)
 
    
 
    
  Print Leggi(p)
+
  Print Leggi(p)
 
   
 
   
  '''End'''
+
  End
  
  
  
 
===Puntare a variabili ''Globali'' che si riferiscono ai membri della ''Struttura'' esterna===
 
===Puntare a variabili ''Globali'' che si riferiscono ai membri della ''Struttura'' esterna===
Questa modalità prevede il puntamento ad alcuni ''simboli'' della nostra libreria esterna, diversi dalle funzioni, mediante il metodo ''System.GetExternSymbol()''.  
+
Questa modalità prevede il puntamento a variabili ''globali'', alle quali vengono assegnati direttamente i valori contenuti dai rispettivi membri della ''Struttura'' esterna da gestire, oppure per scrivervi.
  
 
La nostra speciale libreria esterna .so sarà sostanzialmente così impostata:
 
La nostra speciale libreria esterna .so sarà sostanzialmente così impostata:
Riga 247: Riga 352:
  
  
==Esempi pratici==
+
=Esempi pratici=
Circa quanto esposto nei precedenti paragrafi del presente argomento:
+
Mostriamo alcuni esempi pratici circa quanto esposto nei precedenti paragrafi della presente pagina.
<BR>- relativamente all'uso delle sole funzioni esterne mostriamo di seguito un codice semplicemente per conoscere la quantità di memoria occupata complessivamente da una ''Struttura'' (in questo esempio la Struttura "''XGCValues''" presente nel file header ''/X11/Xlib.h''):
+
 
 +
===Conoscere la quantità di memoria occupata complessivamente da una ''Struttura''===
 +
Mostriamo di seguito un codice semplicemente per conoscere la quantità di memoria occupata complessivamente da una ''Struttura'' (in questo esempio la ''Struttura'' da gestire sarà la Struttura "''XGCValues''" presente nel file header ''/X11/Xlib.h''):
 
  <FONT Color=gray>' ''Dichiariamo che la funzione esterna, che useremo, è presente nella libreria, da noi appositamente creata, "libadhoc.so":''</font>
 
  <FONT Color=gray>' ''Dichiariamo che la funzione esterna, che useremo, è presente nella libreria, da noi appositamente creata, "libadhoc.so":''</font>
 
  Library "/tmp/libadhoc"
 
  Library "/tmp/libadhoc"
 
   
 
   
  <FONT Color=gray>' ''Dichiariamo la funzione esterna presente nella libreria, da noi appositamente creata, "libadhoc.so":''</font>
+
  <FONT Color=gray>' ''Dichiariamo la funzione esterna presente nella libreria, da noi appositamente creata, "libadhoc.so":
 +
' ''int Dim_XGCValues()''</font>
 
  Private Extern Dim_XGCValues() As Integer
 
  Private Extern Dim_XGCValues() As Integer
 
   
 
   
 
   
 
   
  '''Public''' Sub Main()
+
  Public Sub Main()
 
   
 
   
 
   Dim i As Integer
 
   Dim i As Integer
 +
 
 +
<FONT Color=gray>' ''Invochiamo la sottoprocedura per generare la nostra apposita libreria condivisa "libadhoc.so":''</font>
 +
  CreaSo()
 +
 
 +
<FONT Color=gray>' ''Invochiamo la funzione esterna presente nella libreria condivisa "libadhoc.so", da noi appositamente creata, che ci dirà la quantità di memoria occupata dalla Struttura prescelta:''</font>
 +
  i = Dim_XGCValues()
 +
   
 +
<FONT Color=gray>' ''Mostriamo il risultato:''</font>
 +
  Print "La Struttura 'XGCValues()' occupa "; i; " byte."
 +
 +
End
 +
 +
 +
Private Procedure CreaSo()
 
    
 
    
 
  <FONT Color=gray>' ''Scriviamo il codice in C per creare l'apposita libreria condivisa:''</font>
 
  <FONT Color=gray>' ''Scriviamo il codice in C per creare l'apposita libreria condivisa:''</font>
  File.Save("/tmp/libadhoc.c", "#include <X11/Xlib.h>\n" &
+
  File.Save("/tmp/libadhoc.c", "#include <X11/Xlib.h>\n" &
            "\nint Dim_XGCValues() {\n" &
+
            "\nint Dim_XGCValues() {\n" &
            "  return sizeof(XGCValues);\n}")
+
            "  return sizeof(XGCValues);\n}")
 
                
 
                
 
  <FONT Color=gray>' ''Generiamo la nostra libreria condivisa "libadhoc.so":''</font>
 
  <FONT Color=gray>' ''Generiamo la nostra libreria condivisa "libadhoc.so":''</font>
  Shell "gcc -o /tmp/libadhoc.so /tmp/libadhoc.c -shared -lX11" Wait
+
  Shell "gcc -o /tmp/libadhoc.so /tmp/libadhoc.c -shared -lX11" Wait
 +
 
 +
End
 +
 
 +
===Leggere e scrivere dati nei membri di una ''Struttura''===
 +
In quest'altro esempio, oltre a conoscere la dimensione della ''Struttura'' esterna da gestire con ''sicurezza'' ed appartenente ovviamente ad una libreria esterna, provvederemo a scrivere e successivamente a leggere un dato da un membro della predetta ''Struttura'' esterna.
 +
 
 +
Ai fini didattici di questo esempio, generiamo la libreria esterna principale di cui dovremo utilizzare e gestire la ''Struttura''.
 +
<BR>Poniamo, dunque, il caso che il codice sorgente, scritto in C e posto in un file che chiameremo ''struttura.c'', della libreria esterna principale (quella appunto contenente la ''Struttura'' esterna da gestire con sicurezza) sia il seguente:
 +
#include "/tmp/struttura.h"
 +
 +
 +
int Struttura_init(struct STRUTTURA *st) {
 +
 +
<FONT Color=blue>/* Moltiplica per 10 il valore presente nel membro "c" della Struttura */</font>
 +
  st->c *= 10;
 +
 
 +
  return (0);
 +
}
 +
ed il suo file ''header'' (che chiameremo ''struttura.h'') sia il seguente:
 +
struct STRUTTURA {
 +
  char c;
 +
  short s;
 +
  int i;
 +
};
 +
Poniamo ad esempio entrambi i suddetti file nella cartella dei file temporanei ''/tmp'', e generiamo da terminale la libreria esterna principale con la seguente riga di comando:
 +
~ $ gcc -o /tmp/struttura.so /tmp/struttura.c -shared
 +
 
 +
 
 +
Fatto ciò preliminarmente, possiamo sperimentare l'esempio e verificarne gli effetti e risultati.
 +
 
 +
Nel codice del programma Gambas che deve utilizzare le risorse (ossia la funzione chiamata ''Struttura_init()'' e la ''Struttura'' chimata ''STRUTTURA'') presenti in questa libreria esterna, bisognerà utilizzare sia la funzione sia la ''Struttura''. Il codice Gambas prevede che, per gestire con ''sicurezza'' la ''Struttura'' della libreria esterna, sia necessario crea una nostra apposita libreria condivisa (che chiameremo ''libadhoc.c'' e che porremo nella cartella ''/tmp''), scritta in linguaggio C, mediante la quale:
 +
* viene letta la dimensione della ''Struttura'' chiamata ''STRUTTURA'';
 +
* viene ''scritto'' un valore al membro, chiamato "c" di tipo ''char'', della ''Struttura'' esterna denominata ''STRUTTURA'';
 +
* viene invocata la funzione ''Struttura_init()'', la quale moltiplicherà il valore, assegnato al membro "c" della ''Struttura'';
 +
* viene ''letto'' il valore finale contenuto dal membro "c" della ''Struttura'' chiamata ''STRUTTURA''.
 +
 
 +
Il codice del programma Gambas sarà il seguente:
 +
Library "/tmp/struttura"  <FONT Color=gray>' ''La libreria condivisa ".so" esterna principale''</font>
 +
 +
<FONT Color=gray>' ''int Struttura_init()''
 +
' ''Moltiplica il valore assegnato al membro "c" della Struttura per 10:''</font>
 +
Private Extern Struttura_init(po As Pointer) As Integer
 +
 +
 +
Library "/tmp/libadhoc"    <FONT Color=gray>' ''La nostra libreria condivisa ".so" esterna per gestire con "sicurezza" la Struttura presente nella libreria esterna principale''</font>
 +
 +
<FONT Color=gray>' ''int Dim_struttura()''
 +
' ''Legge la dimensione della "Struttura" esterna''</font>
 +
Private Extern Dim_struttura() As Integer
 +
 +
<FONT Color=gray>' ''void Scrive(struct STRUTTURA *p, int valore)''
 +
' ''Scrive un valore in un membro "Struttura" esterna''</font>
 +
Private Extern Scrive(po As Pointer, v As Integer)
 +
 +
<FONT Color=gray>' ''int Legge(struct STRUTTURA *p)''
 +
' ''Legge un valore da un membro "Struttura" esterna''</font>
 +
Private Extern Legge(po As Pointer) As Integer
 +
 +
 +
Public Sub Main()
 +
 +
  Dim p As Pointer
 +
  Dim i As Integer
 +
 
 +
<FONT Color=gray>' ''Crea la nostra libreria ".so" ad hoc che ci consente di gestire con sicurezza la Struttura presente nella libreria ".so" esterna principale:''</font>
 +
  CreaSo()
 +
   
 +
<FONT Color=gray>' ''Ottiene la dimensione in byte della Struttura da gestire e contenuta dalla libreria esterna principale:''</font>
 +
  i = <FONT Color=#B22222>Dim_struttura()</font>
 +
  If i = 0 then Error.Raise("Errore nella lettura della dimensione della Struttura esterna !")
 +
  Print i
 +
   
 +
<FONT Color=gray>' ''Alloca una quantità di memoria pari alla dimensione della Struttura esterna:''</font>
 +
  p = Alloc(SizeOf(gb.Byte), i)
 +
 
 +
<FONT Color=gray>' ''Scrive un valore nel membro, chiamato "c", della Struttura esterna:''</font>
 +
  <FONT Color=#B22222>Scrive(p, 4)</font>
 
      
 
      
  <FONT Color=gray>' ''Invochiamo la funzione esterna presente nella libreria condivisa "libadhoc.so", da noi appositamente creata'',
+
  <FONT Color=gray>' ''Invoca per utilizzare la funzione esterna presente nella libreria esterna principale, passandole il "Puntatore" all'area di memoria riservata:''</font>
  ' ''che ci dirà la quantità di memoria occupata dala Struttura prescelta:''</font>
+
  Struttura_init(p)
   i = Dim_XGCValues()
+
 
 +
  <FONT Color=gray>' ''Legge il valore finale contenuto nel membro, chiamato "c", della Struttura esterna:''</font>
 +
   i = <FONT Color=#B22222>Legge(p)</font>
 +
  Print "Valore finale del membro 'c' della Struttura esterna: "; i
 
      
 
      
  <FONT Color=gray>' ''Mostriamo il risultato:''</font>
+
  <FONT Color=gray>' ''Libera l'area di memoria precedentemente allocata e assicura che il Puntatore non punti ad un indirizzo rilevante:''</font>
   Print "La Struttura 'XGCValues' occupa "; i; " byte."
+
   Free(p)
 +
  p = 0
 +
 
 +
End
 +
 
   
 
   
  '''End'''
+
  Private Procedure CreaSo()
nonché rinviamo a:
+
 
* [[La_gestione_mediante_le_funzioni_esterne_del_API_di_Sox|questa pagina della WIKI]] per esempi sulla '''''lettura''''' di dati dai membri di una Struttura esterna in C;
+
  File.Save("/tmp/libadhoc.c", "#include \"/tmp/struttura.h\"" &
* [[Convertire_un_file_WAV_in_formato_AAC_con_le_funzioni_esterne_del_API_di_Faac|questa pagina della WIKI]] per esempi sulla '''''scrittura''''' di dati nei membri di una Struttura esterna in C.
+
            "\n\nint Dim_struttura() {" &
 +
            "\n  return sizeof(struct STRUTTURA);" &
 +
            "\n}" &
 +
            "\n\nvoid Scrive(struct STRUTTURA *p, int valore) {" &
 +
            "\n  p->c = valore;" &
 +
            "\n}" &
 +
            "\n\nint Legge(struct STRUTTURA *p) {" &
 +
            "\n  return p->c;" &
 +
            "\n}")
 +
 
 +
  Shell "gcc -o /tmp/libadhoc.so /tmp/libadhoc.c -shared" Wait
 +
 
 +
End
 +
 
  
 +
===Uso di apposito programma===
 +
Ai nostri scopi potremmo utilizzare un piccolo programma capace di creare l'apposita libreria condivisa, scritta in C, la quale sia atta a scrivere funzioni per ottenere la dimensione di una ''Struttura'' esterna e di leggere e scrivere valori in un membro di detta ''Struttura'' esterna.
  
- relativamente all'uso del metodo ''System.GetExternSymbol()'' mostriamo un esempio con la libreria ''Sox'':
+
Mostriamo un codice pratico, nel quale si prenderà come semplice esempio la ''Struttura'' esterna "''struct aiocb''" presente nel file header ''/usr/include/aio.h'':
  #include "sox.h"
+
  Library "/tmp/libadhoc"
 
   
 
   
 +
<FONT Color=gray>' ''int Dim_aiocb()''
 +
' ''Ottiene la dimensione della Struttura "aiocb".''</font>
 +
Private Extern Dim_aiocb() As Integer
 
   
 
   
  <FONT color=gray>// ''In questo esempio le Strutture da gestire, appartenenti alla libreria esterna principale, quella di "Sox",sono:''
+
  <FONT Color=gray>' ''void Scrive_aio_fildes(struct *aiocb)''
// ''-  sox_format_t      (Struttura principale)''
+
  ' ''Scrive un valore nel membro "aio_fildes".''</font>
  // ''-  sox_signalinfo_t  (Struttura secondaria, in quanto utilizzata come un membro della Struttura principale)''</font>
+
Private Extern Scrive_aio_fildes(po As Pointer, v As Integer)
 
   
 
   
  sox_signalinfo_t sp;      <FONT color=gray>// ''Questa Struttura secondaria viene dichiarata globale, poiché verrà richiamata (anche) interamente nella penultima linea della funzione''</font>
+
  <FONT Color=gray>' ''int Legge_aio_fildes(struct *aiocb)''
 +
' ''Legge il valore contenuto dal membro "aio_fildes".''</font>
 +
Private Extern Legge_aio_fildes(po As Pointer) As Integer
 
   
 
   
 +
<FONT Color=gray>' ''void Scrive_lio_opcode(struct *aiocb)''
 +
' ''Scrive un valore nel membro "aio_lio_opcode".''</font>
 +
Private Extern Scrive_aio_lio_opcode(po As Pointer, v As Integer)
 
   
 
   
  char * nome;              <FONT color=gray>// ''Queste sono le 4 variabili, alle quali saranno assegnati i valori dei vari membri''</font>
+
  <FONT Color=gray>' ''int Legge_lio_opcode(struct *aiocb)''
  int rate;                <FONT color=gray>// ''della Struttura da gestire, e che successivamente saranno lette''</font>
+
  ' ''Legge il valore contenuto dal membro "aio_lio_opcode".''</font>
  int channels;            <FONT color=gray>//</font>
+
  Private Extern Legge_aio_lio_opcode(po As Pointer) As Integer
int precision;            <FONT color=gray>//</font>
 
 
   
 
   
sox_uint64_t length;
 
 
   
 
   
 +
Public Sub Main()
 +
 
 +
  Dim i As Integer
 +
  Dim p As Pointer
 +
 
 +
  CreaSo("/usr/include/aio.h", "struct aiocb", ["aio_fildes", "aio_lio_opcode"], "/tmp/libadhoc")
 +
 
 +
  i = Dim_aiocb()
 +
  Print "La dimensione della Struttura è:    ", i; " byte"
 +
  p = Alloc(SizeOf(gb.Byte), i)
 +
 
 +
  Scrive_aio_fildes(p, 99)
 +
 
 +
  i = Legge_aio_fildes(p)
 +
  Print "Valore letto dal membro 'aio_fildes': ", i
 +
 
 +
  Scrive_aio_lio_opcode(p, 200)
 +
 
 +
  i = Legge_aio_lio_opcode(p)
 +
  Print "Valore letto dal membro 'aio_fildes': ", i
 +
 
 +
<FONT Color=gray>' ''Libera l'area di memoria precedentemente allocata e assicura che il Puntatore non punti ad un indirizzo rilevante:''</font>
 +
  Free(p)
 +
  p = 0
 +
 
 +
End
 
   
 
   
int sox_lettura(sox_format_t *p) {
 
 
   
 
   
  nome = p->filename;
+
Private Procedure CreaSo(Percorso_del_file_header As String, Nome_della_Struttura As String, Nome_dei_Membri As String[], libreria_adhoc As String)
 
    
 
    
   rate = p->signal.rate;          <FONT color=gray>// ''Vengono assegnati alle variabili globali i membri della Struttura "sox_signalinfo_t", a sua volta membro della Struttura principale "sox_format_t"''</font>
+
   Dim s As String
   channels = p->signal.channels;
+
   Dim b As Byte
  precision = p->signal.precision;
 
  length = p->signal.length;
 
 
    
 
    
   sp = p->signal;                 <FONT color=gray>// ''Viene assegnata alla variabile "sp" il membro della Struttura principale che è una variabile del tipo della Struttura secondaria "sox_signalinfo_t"''</font>
+
   s = "#include <" & Percorso_del_file_header & ">\n\n" &
    
+
      "int Dim_" & LTrim(Replace(Nome_della_Struttura, "struct", Null)) & "() {\n" &
   return (0);
+
      "  return sizeof(" & Nome_della_Struttura & ");\n}" &
+
      "\n\n\n"
  }
+
       
 +
  For b = 0 To Nome_dei_Membri.Max
 +
    s &= "void Scrive_" & Nome_dei_Membri[b] & "(" & Nome_della_Struttura & " *p, int valore) {\n" &
 +
    "  p->" & Nome_dei_Membri[b] & " = valore;\n}"
 +
    "\n\n\n" &
 +
    "int Legge_" & Nome_dei_Membri[b] & "(" & Nome_della_Struttura & " *p) {\n" &
 +
    "   return p->" & Nome_dei_Membri[b] & ";\n}"
 +
   Next
 +
       
 +
   File.Save(libreria_adhoc & ".c", s)
 +
 
 +
  Shell "gcc -o " &/ libreria_adhoc & ".so " &/ libreria_adhoc & ".c -shared" Wait
 +
 
 +
  End
  
  
 +
===Uso del metodo ''System.GetExternSymbol()''===
 +
Per l'uso del metodo "System.GetExternSymbol()" si rinvia alla preliminare e necessaria lettura della seguente pagina della wiki: [[Utilizzare_il_metodo_''System.GetExternSymbol()''_per_richiamare_funzioni_esterne_di_librerie_dinamiche|Utilizzare il metodo ''System.GetExternSymbol()'' per richiamare funzioni esterne di librerie dinamiche]], poiché si procederà in modo analogo a quanto ivi descritto, tenendo conto comunque anche di quanto descritto nei codici dei precedenti due paragrafi della presente pagina.
  
==Ottenere il ''Puntatore'' ad un membro di una ''Struttura'' esterna==
+
=Ottenere il ''Puntatore'' ad un membro di una ''Struttura'' esterna=
 
Mostriamo di seguito le modlità per ottenere il ''Puntatore'' ad un membro di una ''Struttura'' esterna, utile per una gestione successiva del medesimo.
 
Mostriamo di seguito le modlità per ottenere il ''Puntatore'' ad un membro di una ''Struttura'' esterna, utile per una gestione successiva del medesimo.
 
  
 
===Modalità conoscendo la dimensione di una ''Struttura'' da utilizzare===
 
===Modalità conoscendo la dimensione di una ''Struttura'' da utilizzare===
Riga 361: Riga 625:
 
   
 
   
 
   
 
   
  '''Public''' Sub Main()
+
  Public Sub Main()
 
   
 
   
  Dim p, puntatore_membro As Pointer
+
  Dim p, puntatore_membro As Pointer
  Dim st As Stream
+
  Dim st As Stream
 
   
 
   
 
   Shell "gcc -o /tmp/LibreriaEsempio.so " &/ Application.Path &/ "LibreriaEsempio.c -shared -fPIC" Wait
 
   Shell "gcc -o /tmp/LibreriaEsempio.so " &/ Application.Path &/ "LibreriaEsempio.c -shared -fPIC" Wait
 
    
 
    
   p = Alloc(Dim_Stru())
+
   p = Alloc(SizeOf(gb.Byte), Dim_Stru())
 
    
 
    
 
   puntatore_membro = Ottiene_PuntMembro(p)
 
   puntatore_membro = Ottiene_PuntMembro(p)
Riga 380: Riga 644:
 
   Print Legge_StruChar(p)
 
   Print Legge_StruChar(p)
 
   
 
   
 +
<FONT Color=gray>' ''Libera l'area di memoria precedentemente allocata e assicura che il Puntatore non punti ad un indirizzo rilevante:''</font>
 
   Free(p)
 
   Free(p)
 +
  p = 0
 
   
 
   
  '''End'''
+
  End
  
  
Riga 416: Riga 682:
 
   
 
   
 
   
 
   
  '''Public''' Sub Main()
+
  Public Sub Main()
 
   
 
   
 
   Dim p, puntatore_membro As Pointer
 
   Dim p, puntatore_membro As Pointer
 
   Dim st As Stream
 
   Dim st As Stream
 
   
 
   
  Shell "gcc -o /tmp/LibreriaEsempio.so " &/ Application.Path &/ "LibreriaEsempio.c -shared -fPIC" Wait
+
  Shell "gcc -o /tmp/LibreriaEsempio.so " &/ Application.Path &/ "LibreriaEsempio.c -shared -fPIC" Wait
 
    
 
    
  p = System.GetExternSymbol("/tmp/LibreriaEsempio", "stru")
+
  p = System.GetExternSymbol("/tmp/LibreriaEsempio", "stru")
 
    
 
    
  puntatore_membro = Ottiene_PuntMembro(p)
+
  puntatore_membro = Ottiene_PuntMembro(p)
 
   
 
   
 
  <FONT color=gray>' ''Scriviamo per verifica:''</font>
 
  <FONT color=gray>' ''Scriviamo per verifica:''</font>
  st = Memory puntatore_membro For Read Write
+
  st = Memory puntatore_membro For Read Write
    Write #st, 66 As Byte
+
  Write #st, 66 As Byte
  st.Close
+
  st.Close
 
   
 
   
 
  <FONT color=gray>' ''Leggiamo per verifica:''</font>
 
  <FONT color=gray>' ''Leggiamo per verifica:''</font>
  Print Legge_StruChar(p)
+
  Print Legge_StruChar(p)
 
   
 
   
  '''End'''
+
  End

Versione attuale delle 15:42, 7 giu 2024

Talvolta nell'uso delle risorse appartenenti a librerie esterne ci si può imbattere in Strutture molto complesse, dichiarate nei relativi file header (.h), la trascrizione delle quali in Gambas può risultare assai difficile.

Per essere sicuri di non commettere errori, si può scegliere che alcune di queste Strutture, e comunque quelle più ostiche, non vengano ricostruite e dichiarate nel codice del progetto Gambas, ma usate così come sono in una speciale libreria esterna condivisa (.so) appositamente da noi realizzata.

Più in particolare per ogni struttura che si intende usare, all'interno di tale apposita libreria condivisa (.so) vengono scritte in C alcune funzioni che verranno richiamate dall'applicativo Gambas principale.

Una di queste funzioni deve ritornare la dimensione in byte della Struttura, così da poterla allocarla con Gambas mediante la creazione di una variabile di tipo Puntatore. Questa incombenza può essere omessa se ad inizializzare la variabile di tipo Puntatore è una funzione della libreria esterna principale, di cui intendiamo sfruttare le risorse.

Le altre funzioni servono a leggere e scrivere dentro la Struttura. Ad ogni funzione, atta a leggere o scrivere nella Struttura, si passerà la relativa variabile di tipo Puntatore, creata in Gambas - come già detto - all'atto dell'allocazione, e l'eventuale valore da scrivere (se si deve scrivere in un membro della Struttura).


Conoscere la dimensione di una Struttura da utilizzare

Per ciascuna Struttura esterna da utilizzare, qualora nel codice essa non venga creata ed istanziata da alcuna funzione esterna e debba essere passata ad altra funzione esterna, sarà necessario conoscere la sua dimensione. Si rende necessario ciò, perché si dovrà creare la variabile di tipo Puntatore a un'area di memoria riservata che andrà a sostituire la Struttura esterna, accogliendo quindi i dati che quella avrebbe normalmente ricevuto nei suoi membri.

Dunque, scriveremo nella libreria condivisa .so (da noi scritta in linguaggio C) una funzione per ciascuna Struttura da utilizzare. Ciascuna funzione ritornerà la dimensione della Struttura medesima.
Bisogna ricordare che in ogni predetta funzione, da noi scritta, dovrà essere specificato con il tag "#include" di C il file header, nel quale la Struttura esterna da emulare è dichiarata.

In ordine al nome della Struttura, da inserire nella predetta funzione C, si deve precisare che:

Caso in cui la Struttura è dichiarata nel file header con la parola chiave "typedef"

In questo caso:

  • se è dichiarata anche l'etichetta della Struttura ed il suo nome alias:
typedef struct etichetta {
...
...
...
} nome_alias;

allora come argomento della funzione sizeof() presente nel sorgente in C dell'apposita libreria condivisa, da noi creata, potrà essere indicata l'etichetta della Struttura preceduta dalla parola struct:

int nome_funzione() {
   return sizeof(struct etichetta);
 }

Al riguardo mostriamo un esempio, nel quale si otterrà la dimensione della Struttura "typedef struct AVFormatContext", dichiarata nel file header "/usr/include/x86_64-linux-gnu/libavformat/avformat.h":

' int dim_AVFormatContext()
' La funzione per ottenere la dimensione della Struttura "AVFormatContext": 
Private Extern dim_AVFormatContext() As Integer In "/tmp/libdim"


Public Sub Main()

 Dim i As Integer

' Invoca la Procedura, nella quale si creerà la libreria condiva ".so" per conoscere la dimensione della Struttura "AVFormatContext": 
 Creaso()

' Invoca la funzione specifica, presente nella libreria condiva esterna, per conoscere la dimensione della Struttura "AVFormatContext":
 i = dim_AVFormatContext()

 Print "La dimensione della Struttura 'AVFormatContext' è = "; i; " byte"

End

Private Procedure Creaso()
 
 File.Save("/tmp/libdim.c", "#include <libavformat/avformat.h>\n\n" &
                            "int dim_AVFormatContext() {\n" &
                            "   return sizeof(struct AVFormatContext);\n}")
 
 Shell "gcc -o /tmp/libdim.so /tmp/libdim.c -shared" Wait
 
End

Potrà però essere indicato il solo nome alias della Struttura:

int nome_funzione() {
   return sizeof(nome_alias);
}


  • Se, invece, è dichiarato soltanto il nome alias della Struttura dichiarata con "typedef":
typedef struct {
...
...
...
} nome_alias;

allora come argomento della funzione sizeof() presente nel sorgente in C dell'apposita libreria condivisa, da noi creata, andrà indicato soltanto il nome alias della Struttura:

int nome_funzione() {
   return sizeof(nome_alias);
}

Al riguardo mostriamo un esempio, nel quale si otterrà la dimensione della Struttura "div_t", dichiarata nel file header "stdlib.h" e avente soltanto il proprio nome alias:

' int dim_divt()
' La funzione per ottenere la dimensione della Struttura "div_t": 
Private Extern dim_divt() As Integer In "/tmp/libdim"


Public Sub Main()

 Dim i As Integer

' Invoca la Procedura, nella quale si creerà la libreria condiva ".so" per conoscere la dimensione della Struttura "div_t": 
 Creaso()

' Invoca la funzione specifica, presente nella libreria condiva esterna, per conoscere la dimensione della Struttura "div_t":
 i = dim_divt()

 Print "La dimensione della Struttura 'div_t' è = "; i; " byte"

End

Private Procedure Creaso()
 
 File.Save("/tmp/libdim.c", "#include <stdlib.h>\n\n" &
                            "int dim_divt() {\n" &
                            "   return sizeof(div_t);\n}")
 
 Shell "gcc -o /tmp/libdim.so /tmp/libdim.c -shared" Wait
 
End


Caso in cui la Struttura non è dichiarata con la parola chiave "typedef"

In questo caso:

  • se è presente soltanto l'etichetta della Struttura
struct etichetta {
...
...
...
};

allora come argomento della funzione sizeof() presente nel sorgente in C dell'apposita libreria condivisa, da noi creata, andrà indicata l'etichetta della Struttura preceduta dalla parola struct:

int nome_funzione() {
   return sizeof(struct etichetta);
 }

Mostriamo un esempio, nel quale si otterrà la dimensione della Struttura "struct pollfd", dichiarata nel file header "/usr/include/asm-generic/poll.h":

' int dim_pollfd()
' La funzione per ottenere la dimensione della Struttura "struct pollfd": 
Private Extern dim_pollfd() As Integer In "/tmp/libdim"


Public Sub Main()

 Dim i As Integer

' Invoca la Procedura, nella quale si creerà la libreria condiva ".so" per conoscere la dimensione della Struttura "struct pollfd": 
 Creaso()

' Invoca la funzione specifica, presente nella libreria condiva esterna, per conoscere la dimensione della Struttura "struct pollfd":
 i = dim_pollfd()

 Print "La dimensione della Struttura 'pollfd' è = "; i; " byte"

End

Private Procedure Creaso()
 
 File.Save("/tmp/libdim.c", "#include <asm-generic/poll.h>\n\n" &
                            "int dim_pollfd() {\n" &
                            "   return sizeof(struct pollfd);\n}")
 
 Shell "gcc -o /tmp/libdim.so /tmp/libdim.c -shared" Wait
 
End
  • se è presente il solo nome alias della Struttura
struct {
...
...
...
} nome_alias;

allora come argomento della funzione sizeof() presente nel sorgente in C dell'apposita libreria condivisa, da noi creata, andrà indicato soltanto il nome alias della Struttura:

int nome_funzione() {
   return sizeof(nome_alias);
 }
  • se sono presenti l'etichetta ed il nome alias della Struttura
struct etichetta {
...
...
...
} nome_alias;

allora come argomento della funzione sizeof() presente nel sorgente in C dell'apposita libreria condivisa, da noi creata, potrà essere indicato soltanto il nome alias della Struttura:

int nome_funzione() {
   return sizeof(nome_alias);
}

Come già detto, se vi è una funzione della libreria esterna principale che inizializza nel codice Gambas la variabile di tipo Puntatore, allora questa funzione C è inutile.


Conoscere la dimensione di una Struttura innestata o di un Puntatore ad una Struttura secondaria

Se deve essere conosciuta la dimensione di un membro che punta ad una Struttura innestata all'interno di una Struttura principale, ovvero del Puntatore ad una sub-Struttura innestata, va ovviamente posto il nome della Struttura secondaria come argomento della funzione sizeof() presente nel sorgente in C dell'apposita libreria condivisa, da noi creata:

 int nome_funzione() {
   return sizeof(nome_della_sub-Struttura);
}

Ovviamente, se si tratta di un membro di tipo Puntatore ad una Struttura secondaria, allora la dimensione del membro della Struttura "principale",sarà della consueta quantità di memoria occupata nel sistema in uso da una variabile di tipo Puntatore. Se il membro punta ad una sub-Struttura innestata, allora la dimensione del membro sarà pari alla quantità di memoria occupata dall'intera sub-Struttura innestata.


Leggere e scrivere nei membri delle Strutture

Per leggere e scrivere nei membri che ci interessano di una Struttura, si porrano nella nostra libreria ad hoc una serie di funzioni, alle quali come loro argomento si passerà una variabile di tipo Puntatore, avendo avuto l'accortezza nel codice Gambas di dimensionare oppurtunamente ed adeguatamente (ossia riservare un'area di memoria di dimensione identica a quella della Struttura da gestire) tale Puntatore mediante la funzione "Alloc()" nella modalità vista nel precedente paragrafo "Conoscere la dimensione di una Struttura da utilizzare".
Se, invece, vi è una funzione esterna della libreria esterna principale che inizializza (e quindi anche dimensionandola) nel codice Gambas la variabile di tipo Puntatore ad una Struttura in C, allora alla libreria ad hoc si passerà tale variabile Puntatore.

Lettura e scrittura

  • Per scrivere in un membro:
void nome_funzione(nome_della_Struttura *p, int valore_da_scrivere) {
   p->nome_membro = valore_da_scrivere;
}


  • per leggere un membro, ad esempio per ritornare un valore Integer:
 int nome_funzione(nome_della_Struttura *p) {
   return p->nome_membro;
}

Per ritornare il valore di un membro di una sub-Struttura vettoriale contenuta nella Struttura principale, si tiene conto dell'indice della sub-Struttura vettoriale prescelta:

int nome_funzione(nome_della_Struttura *p) {
   return p->nome_sub_Struttura_vettoriale[numero_indice].nome_membro;
}
  • oppure per ritornare una Stringa:
char * nome_funzione(nome_della_Struttura *p) {
   return p->nome_membro;
}
  • oppure per ritornare un puntatore ad una Struttura secondaria contenuta in un'altra Struttura principale:
nome_Struttura_secondaria * nome_funzione(nome_della_Struttura_principale *p) {
   return &p->nome_membro_che_punta_alla_Struttura_secondaria;
}

Anche in questo caso se la Struttura non è dichiarata con la parola chiave "typedef", allora il nome della Struttura andrà preceduto dalla paola struct, oppure union se si tratta di una Union:

union nome_della_union * nome_funzione(nome_della_Struttura_principale *p) {
   return &p->nome_membro_che_punta_alla_Union;
}


Riferimento al file header della libreria esterna principale

Ovviamente in testa al codice della nostra libreria ad hoc, va posto il tag #include "fileheader.h" riferito al file header della libreria principale, della quale si intendono utilizzare le risorse nell'applicativo Gambas, ed alle quali - tutte o solo alcune - si fa riferimento nella nostra libreria ad hoc:

// In testa il riferimento al file header della libreria principale:
#include "liberiaprincipale.h"


Applicazione in ausilio

Potremo anche creare dall'applicazione principale Gambas la nostra apposita libreria esterna condivisa:

Private Procedure Genera_Struttura()
 
 Dim st As New String[][]
 Dim percorso, s As String
 Dim b As Byte
 
' Vengono inseriti i membri della Struttura da gestire con sicurezza.
' Nella prima dimensione della matrice vanno inseriti la definizione della Struttura e la tipologia di ciascun suo membro nel rispetto della loro posizione all'interno della Struttura medesima.
' Nella seconda dimensione della matrice vengono inseriti gli identificatori di ciascun membro della Struttura in corrispondenza dei rispettivi tipi presenti negli elementi della prima dimensione.
' Riguardo al primo elemento di ciascuna delle due dimensioni bisognerà fare attenzione in particolare se nella Struttura è presente la parola chiave "typedef" e/o il nome alias.
 st.Add(["struct ", "char ", "short ", "int "])
 st.Add(["STRUTTURA ", "c", "s", "i"])
 
' Qui si inserisce la libreria esterna .h (il suo file "header"), nella quale è contenuta la Struttura da gestire con sicurezza:
 s = "#include <libreria_esterna.h>\n\n\n"
 
' Questa riga crea la funzione per ottenere la dimensione della Struttura da gestire con sicurezza:
 s &= "\nint Dim_" & st[1][0] & "() {\n   return sizeof(" & st[0][0] & st[1][0] & ");\n}"

' Qui si creano le funzioni di lettura e di scrittura dei membri della Struttura da gestire con sicurezza:
 For b = 1 To st[0].Max
   s &= String$(4, "\n") & st[0][b] & "Legge_" & st[1][b] & "(" & st[0][0] & st[1][0] & "* p) {" &
        "\n   return p->" & st[1][b] & ";\n}"
   s &= "\n\nvoid Scrive_" & st[1][b] & "(" & st[0][0] & st[1][0] & "* p, " & st[0][b] & "v) {" &
        "\n   p->" & st[1][b] & " = v;\n}"
 Next
 
' Viene salvato il sorgente della Libreria condivisa ".so" ad hoc, da noi creata, per gestire con sicurezza la Struttura esterna:
 File.Save("/tmp/Libadhoc.c", s)
 
' Viene infine generata la Libreria  condivisa ".so" ad hoc, da noi creata:
 Shell "gcc -o /tmp/Libadhoc.so /tmp/membri.c -shared" Wait
 
End


Gestione mediante l'uso del metodo GetExternSymbol() della Classe System di Gambas

Una seconda possibilità, per gestire le risorse della nostra libreria esterna .so ad hoc (creata per poter utilizzare con sicurezza le Strutture in C presenti in uno o più file header della libreria esterna principale), è quella offerta dal metodo .GetExternSymbol() della Classe System.

Al riguardo possiamo adottare almeno due modalità.


Scrivere una funzione per ogni azione da esercitare su un membro

All'interno della libreria condivisa esterna, da noi creata, verrà scritta una o due funzioni (lettura e/o scrittura) da eseguire su un membro della Struttura esterna.

Vediamo un esempio pratico.
Poniamo il caso che la Struttura esterna da gestire, dichiarata nel file header della libreria esterna principale, sia la seguente:

struct STRUTTURA {
   short s;
   int i;
};

struct STRUTTURA st;

e che intendiamo leggere e scrivere dati da/sul membro int i.

Dunque la libreria condivisa esterna ad hoc, che dovremo noi creare, sarà la seguente:

#include "/percorso/del/file.h"


void Scrivi(struct STRUTTURA *p, int val) {

     p->i = val;
}

int Leggi(struct STRUTTURA *p) {

     return p->i;
}

Il codice Gambas dell'applicazione sarà il seguente:

Library "/percorso/della/libreria/esterna/da/noi/creata"

Private Extern Scrivi(po As Pointer, i As Integer)
Private Extern Leggi(po As Pointer) As Integer


Public Sub Main()

 Dim p As Pointer
 
 p = System.GetExternSymbol("/percorso/della/libreria/esterna/da/noi/creata", "st")
 
 Scrivi(p, 99)
  
 Print Leggi(p)

End


Puntare a variabili Globali che si riferiscono ai membri della Struttura esterna

Questa modalità prevede il puntamento a variabili globali, alle quali vengono assegnati direttamente i valori contenuti dai rispettivi membri della Struttura esterna da gestire, oppure per scrivervi.

La nostra speciale libreria esterna .so sarà sostanzialmente così impostata:

// In testa il riferimento al file header della libreria principale:
#include "liberiaprincipale.h"


// Se non v'è necessità di puntare ai particolari membri delle Strutture in C, bensì soltanto ad esse, si dichiareranno come globali le variabili del tipo di quelle Strutture da utilizzare.
// Quindi con il metodo System.GetExternSymbol() si richiameranno tali variabili globali delle Strutture':
Struttura_Utilizzata  variabile_struttura_1;

// Se devono essere richiamate Strutture puntate all'interno dei membri di una Struttura principale, vanno qui dichiarate anche le variabili di tali Strutture 'secondarie' :
Sub-Struttura_di_una_Struttura_Principale  variabile_sub-struttura;


// Si dichiareranno come globali le variabili del tipo dei particolari membri delle Strutture utilizzate, di cui si intende leggere il valore contenuto:
char * c;    // Contiene caratteri testuali
int i;       // Contiene un intero
long l;      // Contiene un long



// Se, invece, è necessario leggere nei membri di una singola Struttura utilizzata, si utilizerà un'apposita Funzione:
int funzione_lettura(Struttura_Utilizzata *variabile_struttura_2) {

 c = variabile_struttura_2->primo_membro;
 i = variabile_struttura_2->secondo_membro_che_punta_ad_un'altra_struttura(sub-struttura).membro_della_sub-struttura;
 l = variabile_struttura_2->terzo_membro;

// Caso in cui si deve passare direttamente una sub-struttura presente come membro della Struttura principale:
variabile_sub-struttura = variabile_struttura_2->membro_della_sub-struttura;

 return (0);

}

Da precisare che i simboli, puntabili dal metodo System.GetExternSymbol() di Gambas, sono ovviamente le diverse variabili, purché poste come globali, nonché quelle poste come argomenti delle funzioni contenute dalla nostra libreria ad hoc.


Esempi pratici

Mostriamo alcuni esempi pratici circa quanto esposto nei precedenti paragrafi della presente pagina.

Conoscere la quantità di memoria occupata complessivamente da una Struttura

Mostriamo di seguito un codice semplicemente per conoscere la quantità di memoria occupata complessivamente da una Struttura (in questo esempio la Struttura da gestire sarà la Struttura "XGCValues" presente nel file header /X11/Xlib.h):

' Dichiariamo che la funzione esterna, che useremo, è presente nella libreria, da noi appositamente creata, "libadhoc.so":
Library "/tmp/libadhoc"

' Dichiariamo la funzione esterna presente nella libreria, da noi appositamente creata, "libadhoc.so":
' int Dim_XGCValues()
Private Extern Dim_XGCValues() As Integer


Public Sub Main()

 Dim i As Integer
 
' Invochiamo la sottoprocedura per generare la nostra apposita libreria condivisa "libadhoc.so":
 CreaSo()
 
' Invochiamo la funzione esterna presente nella libreria condivisa "libadhoc.so", da noi appositamente creata, che ci dirà la quantità di memoria occupata dalla Struttura prescelta:
 i = Dim_XGCValues()
   
' Mostriamo il risultato:
 Print "La Struttura 'XGCValues()' occupa "; i; " byte."

End


Private Procedure CreaSo()
 
' Scriviamo il codice in C per creare l'apposita libreria condivisa:
 File.Save("/tmp/libadhoc.c", "#include <X11/Xlib.h>\n" &
           "\nint Dim_XGCValues() {\n" &
           "  return sizeof(XGCValues);\n}")
             
' Generiamo la nostra libreria condivisa "libadhoc.so":
 Shell "gcc -o /tmp/libadhoc.so /tmp/libadhoc.c -shared -lX11" Wait
 
End

Leggere e scrivere dati nei membri di una Struttura

In quest'altro esempio, oltre a conoscere la dimensione della Struttura esterna da gestire con sicurezza ed appartenente ovviamente ad una libreria esterna, provvederemo a scrivere e successivamente a leggere un dato da un membro della predetta Struttura esterna.

Ai fini didattici di questo esempio, generiamo la libreria esterna principale di cui dovremo utilizzare e gestire la Struttura.
Poniamo, dunque, il caso che il codice sorgente, scritto in C e posto in un file che chiameremo struttura.c, della libreria esterna principale (quella appunto contenente la Struttura esterna da gestire con sicurezza) sia il seguente:

#include "/tmp/struttura.h"


int Struttura_init(struct STRUTTURA *st) {

/* Moltiplica per 10 il valore presente nel membro "c" della Struttura */
  st->c *= 10;
  
  return (0);
}

ed il suo file header (che chiameremo struttura.h) sia il seguente:

struct STRUTTURA {
  char c;
  short s;
  int i;
};

Poniamo ad esempio entrambi i suddetti file nella cartella dei file temporanei /tmp, e generiamo da terminale la libreria esterna principale con la seguente riga di comando:

~ $ gcc -o /tmp/struttura.so /tmp/struttura.c -shared


Fatto ciò preliminarmente, possiamo sperimentare l'esempio e verificarne gli effetti e risultati.

Nel codice del programma Gambas che deve utilizzare le risorse (ossia la funzione chiamata Struttura_init() e la Struttura chimata STRUTTURA) presenti in questa libreria esterna, bisognerà utilizzare sia la funzione sia la Struttura. Il codice Gambas prevede che, per gestire con sicurezza la Struttura della libreria esterna, sia necessario crea una nostra apposita libreria condivisa (che chiameremo libadhoc.c e che porremo nella cartella /tmp), scritta in linguaggio C, mediante la quale:

  • viene letta la dimensione della Struttura chiamata STRUTTURA;
  • viene scritto un valore al membro, chiamato "c" di tipo char, della Struttura esterna denominata STRUTTURA;
  • viene invocata la funzione Struttura_init(), la quale moltiplicherà il valore, assegnato al membro "c" della Struttura;
  • viene letto il valore finale contenuto dal membro "c" della Struttura chiamata STRUTTURA.

Il codice del programma Gambas sarà il seguente:

Library "/tmp/struttura"   ' La libreria condivisa ".so" esterna principale

' int Struttura_init()
' Moltiplica il valore assegnato al membro "c" della Struttura per 10:
Private Extern Struttura_init(po As Pointer) As Integer


Library "/tmp/libadhoc"    ' La nostra libreria condivisa ".so" esterna per gestire con "sicurezza" la Struttura presente nella libreria esterna principale

' int Dim_struttura()
' Legge la dimensione della "Struttura" esterna
Private Extern Dim_struttura() As Integer

' void Scrive(struct STRUTTURA *p, int valore)
' Scrive un valore in un membro "Struttura" esterna
Private Extern Scrive(po As Pointer, v As Integer)

' int Legge(struct STRUTTURA *p)
' Legge un valore da un membro "Struttura" esterna
Private Extern Legge(po As Pointer) As Integer


Public Sub Main()

  Dim p As Pointer
  Dim i As Integer
 
' Crea la nostra libreria ".so" ad hoc che ci consente di gestire con sicurezza la Struttura presente nella libreria ".so" esterna principale:
  CreaSo()
   
' Ottiene la dimensione in byte della Struttura da gestire e contenuta dalla libreria esterna principale:
  i = Dim_struttura()
  If i = 0 then Error.Raise("Errore nella lettura della dimensione della Struttura esterna !")
  Print i
   
' Alloca una quantità di memoria pari alla dimensione della Struttura esterna:
  p = Alloc(SizeOf(gb.Byte), i)
  
' Scrive un valore nel membro, chiamato "c", della Struttura esterna:
  Scrive(p, 4)
   
' Invoca per utilizzare la funzione esterna presente nella libreria esterna principale, passandole il "Puntatore" all'area di memoria riservata:
  Struttura_init(p)
  
' Legge il valore finale contenuto nel membro, chiamato "c", della Struttura esterna:
  i = Legge(p)
  Print "Valore finale del membro 'c' della Struttura esterna: "; i
   
' Libera l'area di memoria precedentemente allocata e assicura che il Puntatore non punti ad un indirizzo rilevante:
  Free(p)
  p = 0
  
End


Private Procedure CreaSo()
 
  File.Save("/tmp/libadhoc.c", "#include \"/tmp/struttura.h\"" &
            "\n\nint Dim_struttura() {" &
            "\n   return sizeof(struct STRUTTURA);" &
            "\n}" &
            "\n\nvoid Scrive(struct STRUTTURA *p, int valore) {" &
            "\n   p->c = valore;" &
            "\n}" &
            "\n\nint Legge(struct STRUTTURA *p) {" &
            "\n   return p->c;" &
            "\n}")
  
  Shell "gcc -o /tmp/libadhoc.so /tmp/libadhoc.c -shared" Wait
  
End


Uso di apposito programma

Ai nostri scopi potremmo utilizzare un piccolo programma capace di creare l'apposita libreria condivisa, scritta in C, la quale sia atta a scrivere funzioni per ottenere la dimensione di una Struttura esterna e di leggere e scrivere valori in un membro di detta Struttura esterna.

Mostriamo un codice pratico, nel quale si prenderà come semplice esempio la Struttura esterna "struct aiocb" presente nel file header /usr/include/aio.h:

Library "/tmp/libadhoc"

' int Dim_aiocb()
' Ottiene la dimensione della Struttura "aiocb".
Private Extern Dim_aiocb() As Integer

' void Scrive_aio_fildes(struct *aiocb)
' Scrive un valore nel membro "aio_fildes".
Private Extern Scrive_aio_fildes(po As Pointer, v As Integer)

' int Legge_aio_fildes(struct *aiocb)
' Legge il valore contenuto dal membro "aio_fildes".
Private Extern Legge_aio_fildes(po As Pointer) As Integer

' void Scrive_lio_opcode(struct *aiocb)
' Scrive un valore nel membro "aio_lio_opcode".
Private Extern Scrive_aio_lio_opcode(po As Pointer, v As Integer)

' int Legge_lio_opcode(struct *aiocb)
' Legge il valore contenuto dal membro "aio_lio_opcode".
Private Extern Legge_aio_lio_opcode(po As Pointer) As Integer


Public Sub Main()
 
  Dim i As Integer
  Dim p As Pointer
 
  CreaSo("/usr/include/aio.h", "struct aiocb", ["aio_fildes", "aio_lio_opcode"], "/tmp/libadhoc")
  
  i = Dim_aiocb()
  Print "La dimensione della Struttura è:     ", i; " byte"
  p = Alloc(SizeOf(gb.Byte), i)
  
  Scrive_aio_fildes(p, 99)
  
  i = Legge_aio_fildes(p)
  Print "Valore letto dal membro 'aio_fildes': ", i
  
  Scrive_aio_lio_opcode(p, 200)
  
  i = Legge_aio_lio_opcode(p)
  Print "Valore letto dal membro 'aio_fildes': ", i
  
' Libera l'area di memoria precedentemente allocata e assicura che il Puntatore non punti ad un indirizzo rilevante:
  Free(p)
  p = 0
  
End


Private Procedure CreaSo(Percorso_del_file_header As String, Nome_della_Struttura As String, Nome_dei_Membri As String[], libreria_adhoc As String)
 
 Dim s As String
 Dim b As Byte
 
 s = "#include <" & Percorso_del_file_header & ">\n\n" &
     "int Dim_" & LTrim(Replace(Nome_della_Struttura, "struct", Null)) & "() {\n" &
     "   return sizeof(" & Nome_della_Struttura & ");\n}" &
     "\n\n\n"
       
 For b = 0 To Nome_dei_Membri.Max
   s &= "void Scrive_" & Nome_dei_Membri[b] & "(" & Nome_della_Struttura & " *p, int valore) {\n" &
   "   p->" & Nome_dei_Membri[b] & " = valore;\n}"
   "\n\n\n" &
   "int Legge_" & Nome_dei_Membri[b] & "(" & Nome_della_Struttura & " *p) {\n" &
   "   return p->" & Nome_dei_Membri[b] & ";\n}"
 Next
       
 File.Save(libreria_adhoc & ".c", s)
  
 Shell "gcc -o " &/ libreria_adhoc & ".so " &/ libreria_adhoc & ".c -shared" Wait
  
End


Uso del metodo System.GetExternSymbol()

Per l'uso del metodo "System.GetExternSymbol()" si rinvia alla preliminare e necessaria lettura della seguente pagina della wiki: Utilizzare il metodo System.GetExternSymbol() per richiamare funzioni esterne di librerie dinamiche, poiché si procederà in modo analogo a quanto ivi descritto, tenendo conto comunque anche di quanto descritto nei codici dei precedenti due paragrafi della presente pagina.

Ottenere il Puntatore ad un membro di una Struttura esterna

Mostriamo di seguito le modlità per ottenere il Puntatore ad un membro di una Struttura esterna, utile per una gestione successiva del medesimo.

Modalità conoscendo la dimensione di una Struttura da utilizzare

Mostriamo un semplice esempio, nel quale abbiamo una semplice libreria esterna, che chiameremo "LibreriaEsempio.c", il cui codice C è il seguente:

struct STRUTTURA {
  int i;
  short s;
  char c;
  long l;
} stru;


int Dim_Stru() {

  return sizeof(stru);

}


void* Ottiene_PuntMembro(struct STRUTTURA * p) {

  return &p->c;

}

int Legge_StruChar(struct STRUTTURA * p) {

  return p->c;

}

Il codice sorgente di detta libreria condivisa sarà posto nella cartella Dati del nostro progetto.


Il codice principale di Gambas sarà:

Library "/tmp/LibreriaEsempio"

Private Extern Dim_Stru() As Integer
Private Extern Ottiene_PuntMembro(po As Pointer) As Pointer
Private Extern Legge_StruChar(poC As Pointer) As Integer


Public Sub Main()

  Dim p, puntatore_membro As Pointer
  Dim st As Stream

  Shell "gcc -o /tmp/LibreriaEsempio.so " &/ Application.Path &/ "LibreriaEsempio.c -shared -fPIC" Wait
 
  p = Alloc(SizeOf(gb.Byte), Dim_Stru())
  
  puntatore_membro = Ottiene_PuntMembro(p)

' Scriviamo per verifica:
  st = Memory puntatore_membro For Read Write
    Write #st, 66 As Byte
  st.Close

' Leggiamo per verifica:
  Print Legge_StruChar(p)

' Libera l'area di memoria precedentemente allocata e assicura che il Puntatore non punti ad un indirizzo rilevante:
  Free(p)
  p = 0

End


Modalità con System.GetExternSymbol()

Anche in quest'altro caso abbiamo una semplice libreria esterna, che chiameremo "LibreriaEsempio.c", il cui codice C è il seguente:

struct STRUTTURA {
  int i;
  short s;
  char c;
  long l;
} stru;


void* Ottiene_PuntMembro(struct STRUTTURA * p) {

 return &p->c;

}

int Legge_StruChar(struct STRUTTURA * p) {

 return p->c;

}

Il codice sorgente di detta libreria condivisa sarà posto nella cartella Dati del nostro progetto.


Il codice principale di Gambas sarà:

Library "/tmp/LibreriaEsempio"

Private Extern Ottiene_PuntMembro(po As Pointer) As Pointer
Private Extern Legge_StruChar(poC As Pointer) As Integer


Public Sub Main()

 Dim p, puntatore_membro As Pointer
 Dim st As Stream

 Shell "gcc -o /tmp/LibreriaEsempio.so " &/ Application.Path &/ "LibreriaEsempio.c -shared -fPIC" Wait
 
 p = System.GetExternSymbol("/tmp/LibreriaEsempio", "stru")
 
 puntatore_membro = Ottiene_PuntMembro(p)

' Scriviamo per verifica:
 st = Memory puntatore_membro For Read Write
 Write #st, 66 As Byte
 st.Close

' Leggiamo per verifica:
 Print Legge_StruChar(p)

End