2011-05-19 29 views
6

Sto cercando di far funzionare Java Access Bridge (2.02) con C# (.NET 3.5). Ho funzionato per alcune funzioni, ma quando chiamo una funzione che fa riferimento a una struct (getAccessibleContextInfo), ottengo questo messaggio di errore: System.AccessViolationException: Tentativo di leggere o scrivere memoria protetta. Questo è spesso un'indicazione che un'altra memoria è corrotta.System.AccessViolationException quando si chiama C++ dll

Ecco il mio codice:

[DllImport("Windowsaccessbridge.dll", CallingConvention = CallingConvention.Cdecl)] 
internal extern static void Windows_run(); 

[DllImport("Windowsaccessbridge.dll", CallingConvention = CallingConvention.Cdecl)] 
private extern static void releaseJavaObject(long vmID, IntPtr javaObject); 

[DllImport("Windowsaccessbridge.dll", CallingConvention = CallingConvention.Cdecl)] 
private extern static bool isJavaWindow(IntPtr window); 

[DllImport("Windowsaccessbridge.dll", CallingConvention = CallingConvention.Cdecl)] 
private extern static bool getAccessibleContextInfo(long vmID, IntPtr ac, out AccessibleContextInfo textInfo); 

[DllImport("Windowsaccessbridge.dll", CallingConvention = CallingConvention.Cdecl)] 
private static extern bool getAccessibleContextFromHWND(IntPtr hwnd, out long vmID, out IntPtr ac); 

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
public struct AccessibleContextInfo 
{ 
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)] 
public string name; 
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)] 
public string description; 

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] 
public string role; 
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] 
public string role_en_US; 
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] 
public string states; 
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] 
public string states_en_US; 

[MarshalAs(UnmanagedType.I4)] 
public int indexInParent; 
[MarshalAs(UnmanagedType.I4)] 
public int childrenCount; 
[MarshalAs(UnmanagedType.I4)] 
public int x; 
[MarshalAs(UnmanagedType.I4)] 
public int y; 
[MarshalAs(UnmanagedType.I4)] 
public int width; 
[MarshalAs(UnmanagedType.I4)] 
public int height; 

[MarshalAs(UnmanagedType.Bool)] 
public bool accessibleComponent; 
[MarshalAs(UnmanagedType.Bool)] 
public bool accessibleAction; 
[MarshalAs(UnmanagedType.Bool)] 
public bool accessibleSelection; 
[MarshalAs(UnmanagedType.Bool)] 
public bool accessibleText; 
[MarshalAs(UnmanagedType.Bool)] 
public bool accessibleInterfaces; 
}; 

private void Form1_Load(object sender, EventArgs e) 
{ 
Windows_run(); 
} 

private void button1_Click(object sender, EventArgs e) 
{ 
long vmID; 
IntPtr ac; 
if (getAccessibleContextFromHWND(mainWindowHwnd, out vmID, out ac)) 
{ 
MessageBox.Show("Got Context: " + vmID.ToString() + ", " + ac.ToString()); 
AccessibleContextInfo info; 

if (getAccessibleContextInfo(vmID, ac, out info)) //this is where the error is thrown 
{ 
MessageBox.Show("Got Context Info: " + info.name); 
} 
else 
{ 
MessageBox.Show("Getting info failed"); 
} 
} 
else 
{ 
MessageBox.Show("Accessing failed"); 
} 
} 

non credo che sia un problema con la dll Java, in quanto funziona bene con l'esempio programma C++ che viene fornito con l'API.

Sto indovinando dalla ricerca di Google che si tratta di un problema con il modo in cui sto eseguendo il marshalling della struttura AccessibleContextInfo, ma non ho idea di come farlo correttamente.

Ecco il modo in cui la struct è dichiarata in "AccessBridgePackages.h" del programma di esempio

#define MAX_STRING_SIZE 1024 
#define SHORT_STRING_SIZE 256 

typedef struct AccessibleContextInfoTag { 
    wchar_t name[MAX_STRING_SIZE];  // the AccessibleName of the object 
    wchar_t description[MAX_STRING_SIZE]; // the AccessibleDescription of the object 

    wchar_t role[SHORT_STRING_SIZE]; // localized AccesibleRole string 
    wchar_t role_en_US[SHORT_STRING_SIZE]; // AccesibleRole string in the en_US locale 
    wchar_t states[SHORT_STRING_SIZE]; // localized AccesibleStateSet string (comma separated) 
    wchar_t states_en_US[SHORT_STRING_SIZE]; // AccesibleStateSet string in the en_US locale (comma separated) 

    jint indexInParent;   // index of object in parent 
    jint childrenCount;   // # of children, if any 

    jint x;     // screen coords in pixels 
    jint y;     // " 
    jint width;    // pixel width of object 
    jint height;    // pixel height of object 

    BOOL accessibleComponent;   // flags for various additional 
    BOOL accessibleAction;   // Java Accessibility interfaces 
    BOOL accessibleSelection;  // FALSE if this object doesn't 
    BOOL accessibleText;   // implement the additional interface 
               // in question 

    // BOOL accessibleValue;    // old BOOL indicating whether AccessibleValue is supported 
    BOOL accessibleInterfaces;  // new bitfield containing additional interface flags 

    } AccessibleContextInfo; 

Ogni aiuto è molto apprezzato!

+0

Per quanto posso vedere, potrebbe esserci un problema con le dimensioni dei tipi in .NET e C++, 'BOOL' in C++ ha le dimensioni di un byte, mentre .NET's bool ha la dimensione di 4 byte. Potrebbe essere utile mostrare la definizione del C++. –

+0

L'argomento vmID non è lungo, è int in C#. –

risposta

0

Normalmente AccessViolations indica che hai incasinato la firma PInvoke, ma sembra che sia generalmente OK.

Mi vengono in mente due cose da provare che può aiuto

1: uso potenzialmente sospetti di Charset.Unicode a livello struct.

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
public struct AccessibleContextInfo 
{ 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)] 
    public string name; 
    ... 

Ci si potrebbe aspettare che la CharSet=Unicode sul struct dovrebbe "propagare" per i suoi membri, ma ho visto situazioni in cui non appare per fare questo. Si potrebbe provare a specificare CharSet=Unicode sull'attributo MarshalAs di ciascuna stringa.

Non sono sicuro se ciò farebbe la differenza, dato che il marshalling predefinito di stringhe da .NET è già Unicode, ma potrebbe valere la pena di essere girato.

2: Forse provare passando il AccessibleContextInfo struct come parametro ref piuttosto che un parametro out - ad esempio

[DllImport("Windowsaccessbridge.dll", CallingConvention = CallingConvention.Cdecl)] 
private extern static bool getAccessibleContextInfo(long vmID, IntPtr ac, ref AccessibleContextInfo textInfo); 

Aggiornamento: Inoltre, come nota Hans passant in un commento, ricordate long in C# è un a 64 bit int, mentre in C/C++ è a 32 bit. A seconda delle dichiarazioni della funzione C++, potrebbe essere errato

Problemi correlati