2012-04-15 20 views
5

Sto tentando di utilizzare JNA per interrogare le autorizzazioni effettive per un file in Windows. Alla fine, prevedo di utilizzare lo GetEffectiveRightsFromAcl function, ma per farlo, ho bisogno di fornire un puntatore a uno spazio popolato da TRUSTEE structure. La piattaforma JNA (platform.jar) non appare definire questa struttura, quindi sto provando a definirlo io stesso. Ecco quello che ho finora:Conversione da stringa a puntatore per JNA

public static class TRUSTEE extends Structure { 
    public TRUSTEE() { 
     super(); 
    } 
    public TRUSTEE(Pointer p) { 
     super(p); 
     read(); 
    } 

    public Pointer pMultipleTrustee; 
    public int MultipleTrusteeOperation; 
    public int TrusteeForm; 
    public int TrusteeType; 
    public Pointer ptstrName; 
} 

Sto cercando di popolare la struttura come questa:

private TRUSTEE createTrusteeForCurrentUser() { 
    TRUSTEE result = new TRUSTEE(); 
    result.TrusteeForm = TRUSTEE_FORM.TRUSTEE_IS_NAME; 
    result.TrusteeType = TRUSTEE_TYPE.TRUSTEE_IS_USER; 

    String strName = "CURRENT_USER"; 
    // How can I set result.ptstrName using strName? 
} 

This Google Groups thread raccomanda utilizzando String campi in strutture quando un char * è richiesto. Tuttavia, non ritengo che questo sia appropriato nella mia situazione, considerando che il campo ptstrName può indicare diversi tipi di cose, a seconda del valore di TrusteeForm. Quindi, penso che in qualche modo ho bisogno di convertire da String a Pointer invece. Ho trovato la classe NativeString in JNA, che avrebbe funzionato, tranne che si trattava di una classe privata del pacchetto.

Qual è il modo consigliato per convertire un Java String in un formato nativo e ottenere un Pointer ad esso? Sto anche usando il giusto tipo di dati per la struttura TRUSTEE? Sono un po 'nuovo a JNA, quindi scusami se mi manca qualcosa di ovvio.

Aggiornamento

ho trovato una soluzione al mio problema, ma se qualcuno ha una soluzione migliore mi piace ancora di sentirlo.

risposta

2

Ho risolto il problema copiando il codice sorgente per la classe di pacchetto NativeString e creando una copia pubblica nel mio progetto. Ho dovuto fare una piccola modifica a causa dell'uso di un metodo package-private nel costruttore.

Aggiornamento: Come note @fragorl nei commenti, l'implementazione di NativeString mostrata di seguito è ormai superata.


Usage:

private static TRUSTEE createTrusteeForCurrentUser() { 
    TRUSTEE result = new TRUSTEE(); 
    result.TrusteeForm = TRUSTEE_FORM.TRUSTEE_IS_NAME; 
    result.TrusteeType = TRUSTEE_TYPE.TRUSTEE_IS_USER; 
    result.ptstrName = new NativeString("CURRENT_USER",true).getPointer(); 
    result.write(); 
    return result; 
} 

NativeString.java:

/** Provides a temporary allocation of an immutable C string 
* (<code>const char*</code> or <code>const wchar_t*</code>) for use when 
* converting a Java String into a native memory function argument. 
* 
* @author Todd Fast, [email protected] 
* @author [email protected] 
*/ 
public class NativeString implements CharSequence, Comparable { 

    private Pointer pointer; 
    private boolean wide; 

    /** Create a native string (NUL-terminated array of <code>char</code>).<p> 
    * If the system property <code>jna.encoding</code> is set, its value will 
    * be used to encode the native string. If not set or if the encoding 
    * is unavailable, the default platform encoding will be used. 
    */ 
    public NativeString(String string) { 
     this(string, false); 
    } 

    /** Create a native string as a NUL-terminated array of <code>wchar_t</code> 
    * (if <code>wide</code> is true) or <code>char</code>.<p> 
    * If the system property <code>jna.encoding</code> is set, its value will 
    * be used to encode the native <code>char</code>string. 
    * If not set or if the encoding is unavailable, the default platform 
    * encoding will be used. 
    * 
    * @param string value to write to native memory 
    * @param wide whether to store the String as <code>wchar_t</code> 
    */ 
    public NativeString(String string, boolean wide) { 
     if (string == null) { 
      throw new NullPointerException("String must not be null"); 
     } 
     // Allocate the memory to hold the string. Note, we have to 
     // make this 1 element longer in order to accommodate the terminating 
     // NUL (which is generated in Pointer.setString()). 
     this.wide = wide; 
     if (wide) { 
      int len = (string.length() + 1) * Native.WCHAR_SIZE; 
      pointer = new Memory(len); 
      pointer.setString(0, string, true); 
     } 
     else { 
      byte[] data = Native.toByteArray(string); 
      pointer = new Memory(data.length + 1); 
      pointer.write(0, data, 0, data.length); 
      pointer.setByte(data.length, (byte)0); 
     } 
    } 

    public int hashCode() { 
     return toString().hashCode(); 
    } 

    public boolean equals(Object other) { 

     if (other instanceof CharSequence) { 
      return compareTo(other) == 0; 
     } 
     return false; 
    } 

    public String toString() { 
     String s = wide ? "const wchar_t*" : "const char*"; 
     s += "(" + pointer.getString(0, wide) + ")"; 
     return s; 
    } 

    public Pointer getPointer() { 
     return pointer; 
    } 

    public char charAt(int index) { 
     return toString().charAt(index); 
    } 

    public int length() { 
     return toString().length(); 
    } 

    public CharSequence subSequence(int start, int end) { 
     return CharBuffer.wrap(toString()).subSequence(start, end); 
    } 

    public int compareTo(Object other) { 

     if (other == null) 
      return 1; 

     return toString().compareTo(other.toString()); 
    } 
} 
+0

Grazie, questo sembra essere il modo "corretto" per farlo. Una domanda: perché non hai usato il costruttore NativeString 1-arg invece di quello 2-arg? – fragorl

+0

@fragorl Per la mia applicazione stavo usando stringhe wide-character (Unicode), quindi ho dovuto impostare il parametro 'wide' su' true'. Il costruttore 1-arg lo imposta su 'false'. –

+0

Ah mio mal, stavo guardando l'ultima versione di jna, dove hanno cambiato il costruttore 1-arg. Ora legge: this (string, Native.getDefaultStringEncoding()) ;. Ma qui hai il codice sorgente per una versione precedente - ovviamente, il tuo post è del 2012, woops>< – fragorl

9

Supponendo che si desidera char * sul lato nativa (potrebbe essere necessario più memoria allocata se la stringa contiene caratteri non ASCII),

String myString = "CURRENT_USER"; 
Pointer m = new Memory(myString.length() + 1); // WARNING: assumes ascii-only string 
m.setString(0, myString); 

È quindi possibile utilizzare m ovunque sia necessario fare riferimento alla stringa "nativa".

Per ampi archi (wchar_t *),

String myString = "CURRENT_USER"; 
Pointer m = new Memory(Native.WCHAR_SIZE * (myString.length() + 1)); 
m.setWideString(0, myString); 
+0

setString (offset, valore) chiama setString (offset, valore, Native.getDefaultStringEncoding()). Sembra non sicuro assumere che Native.getDefaultStringEncoding() restituisca sempre un formato che utilizza solo 1 byte per carattere, che è ciò che si assegna? – fragorl

+0

Sei corretto, rispondi aggiornato in modo appropriato. – technomage

+0

Pointer m = new Memory (Native.WCHAR_SIZE * (MyString.Length() + 1); manca una staffa, questo vuole essere Pointer m = new Memory (Native.WCHAR_SIZE * (MyString.Length () + 1)); ? – fragorl