2012-04-15 15 views
5

Ich versuche, JNA zu verwenden, um die effektiven Berechtigungen für eine Datei in Windows abzufragen. Schließlich plane ich die Verwendung der GetEffectiveRightsFromAcl function, aber dazu muss ich einen Zeiger auf eine TRUSTEE structure bereitstellen. Die JNA-Plattform (platform.jar) scheint diese Struktur nicht zu definieren, also versuche ich sie stattdessen selbst zu definieren. Hier ist, was ich bisher:Konvertieren von Zeichenfolge in Zeiger für 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; 
} 

Ich versuche, die Struktur wie folgt zu füllen:

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 threadString Felder in Strukturen unter Verwendung empfiehlt, wenn ein char * für aufgerufen wird. Ich denke jedoch nicht, dass dies in meiner Situation angemessen ist, wenn man bedenkt, dass das Feld ptstrName auf verschiedene Arten von Dingen verweisen kann, abhängig vom Wert von TrusteeForm. Also, ich denke ich muss irgendwie von String zu Pointer konvertieren. Ich fand die NativeString Klasse in JNA, die funktionieren würde, außer es ist eine Paket-private Klasse.

Was ist die empfohlene Möglichkeit, ein Java String in ein natives Format zu konvertieren und eine Pointer zu erhalten? Benutze ich sogar den richtigen Datentyp für die Struktur TRUSTEE? Ich bin etwas neu für JNA, also bitte entschuldigen Sie, wenn ich etwas Offensichtliches vermisse.

aktualisiert

ich eine Lösung für mein Problem gefunden, aber wenn jemand eine bessere Lösung hat würde ich immer noch, es zu hören.

Antwort

2

Ich löste das Problem durch Kopieren des Quellcodes für package-private NativeString Klasse und Erstellen einer öffentlichen Kopie in meinem Projekt. Ich musste eine kleine Änderung wegen der Verwendung einer package-private-Methode im Konstruktor vornehmen.

Update: Wie @fragorl in den Kommentaren bemerkt, ist die unten gezeigte Implementierung von NativeString inzwischen ziemlich veraltet.


Verbrauch:

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

Danke, das scheint der "richtige" Weg zu sein. Eine Frage - warum haben Sie nicht den 1-arg NativeString-Konstruktor anstelle des 2-Arg-Konstruktors verwendet? – fragorl

+0

@fragorl Für meine Anwendung verwendete ich Wide-Character (Unicode) Strings, also musste ich den 'wide' Parameter auf' true' setzen. Der 1-arg-Konstruktor setzt es auf 'false'. –

+0

Ahh, mein Fehler, ich habe mir die neueste Version von jna angeschaut, wo sie den 1-arg-Konstruktor geändert haben. Es liest jetzt: this (string, Native.getDefaultStringEncoding()) ;. Aber du hast hier einen Quellcode für eine ältere Version - natürlich, dein Beitrag stammt aus dem Jahr 2012, woops>< – fragorl

0

versuchen Sie, Zeigerklasse in http://jna.java.net/javadoc/com/sun/jna/Pointer.html zu verwenden.

+0

Ich weiß, dass ich ein 'Pointer' brauchen, ich denke, die Frage ist mehr wie ein Java' String' in einem nativen Format konvertieren und erhalten eine 'Pointer' dagegen angehen. –

9

Angenommen, Sie char * auf der nativen Seite (Sie können zugeordnet mehr Speicher benötigen, wenn die Zeichenfolge nicht-ASCII-Zeichen enthält),

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

Sie können dann m verwenden, wo immer Sie auf die "native" Zeichenfolge verweisen müssen.

Für Wide-Strings (wchar_t *),

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

setString (offset, value) ruft setString auf (offset, value, Native.getDefaultStringEncoding()). Es scheint unsicher, anzunehmen, dass Native.getDefaultStringEncoding() immer ein Format zurückgibt, das nur 1 Byte pro Zeichen verwendet. – fragorl

+0

Sie sind richtig, die Antwort wurde entsprechend aktualisiert. – technomage

+0

Pointer m = new Speicher (Native.WCHAR_SIZE * (myString.length() + 1); ist eine Klammer fehlt, dann ist dies Pointer m = new Speicher (Native.WCHAR_SIZE * (myString.length sein soll () + 1)); ? – fragorl

Verwandte Themen