2011-05-19 23 views
6

Estoy intentando que Java Access Bridge (2.02) funcione con C# (.NET 3.5). Lo tengo trabajando para algunas funciones, pero cuando llamo a una función que hace referencia a una estructura (getAccessibleContextInfo), aparece este mensaje de error: System.AccessViolationException: Intenté leer o escribir en la memoria protegida. Esto a menudo es una indicación de que otra memoria está corrupta.System.AccessViolationException al llamar a C++ dll

Aquí está mi código:

[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"); 
} 
} 

no creo que sea un problema con el archivo DLL de Java, ya que funciona bien con el ejemplo C++ programa que viene con la API.

Supongo que al buscar en google que es un problema con la forma en que estoy organizando la estructura AccessibleContextInfo, pero no tengo ni idea de cómo hacerlo correctamente.

Aquí es la forma en que la estructura se declara en "AccessBridgePackages.h" del programa de ejemplo

#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; 

Cualquier ayuda es muy apreciada!

+0

Por lo que puedo ver, puede haber un problema con los tamaños de tipo en .NET y C++, 'BOOL' en C++ tiene el tamaño de un byte, mientras que bool de .NET tiene el tamaño de 4 bytes. Mostrar la definición de C++ podría ayudar. –

+0

El argumento vmID no es largo, es int en C#. –

Respuesta

0

Normalmente, AccessViolations indica que ha estropeado la firma de PInvoke, pero parece que generalmente está bien.

puedo pensar en dos cosas a probar que puede ayuda

1: uso potencialmente sospechosa de Charset.Unicode a nivel de estructura.

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

Uno podría esperar que el CharSet=Unicode en la estructura debe "propagar" a sus miembros, pero he visto situaciones en las que no parece hacer esto. Puede intentar especificar CharSet=Unicode en el atributo MarshalAs de cada cadena.

No estoy seguro de si esto marcaría la diferencia, dado que la clasificación predeterminada de las cadenas de .NET ya es Unicode, pero puede valer la pena intentarlo.

2: Tal vez tratar de pasar la estructura AccessibleContextInfo como parámetro ref en lugar de un parámetro out - por ejemplo

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

Actualización: También, como Hans Passant señala en un comentario, recuerde long en C# es un 64-bit int, mientras que en C/C++ es de 32 bits. Dependiendo de las declaraciones de la función C++, eso puede ser incorrecto

Cuestiones relacionadas