2011-05-19 2 views
6

Я пытаюсь заставить Java Access Bridge (2.02) работать с C# (.NET 3.5). У меня есть работа для некоторых функций, но когда я вызываю функцию, ссылающуюся на struct (getAccessibleContextInfo), я получаю это сообщение об ошибке: System.AccessViolationException: Попытка чтения или записи защищенной памяти. Это часто свидетельствует о том, что другая память повреждена.System.AccessViolationException при вызове C++ dll

Вот мой код:

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

Я не думаю, что это проблема с DLL Java, как это прекрасно работает на примере C++ программа, которая поставляется с API.

Я угадываю от поиска google, что это проблема с тем, как я сортирую структуру AccessibleContextInfo, но у меня нет подсказки относительно того, как это сделать правильно.

Вот способ, структура объявляется в примере программы в «AccessBridgePackages.h»

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

Любая помощь очень ценится!

+0

Насколько я вижу, может возникнуть проблема с размерами типов в .NET и C++, 'BOOL' в C++ имеет размер байта, тогда как bool .NET имеет размер 4 байта. Показ определения C++ может помочь. –

+0

Аргумент vmID не длинный, это int в C#. –

ответ

0

Обычно AccessViolations указывает, что вы испортили подпись PInvoke, но похоже, что это вообще нормально.

Я могу думать о двух вещах, чтобы попробовать, что может помощь

1: потенциально подозрительное использование Charset.Unicode на уровне структуры.

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

Можно было бы ожидать, что CharSet=Unicode на структуры должны «распространяться» членам это, но я видел ситуации, когда он не появляется, чтобы сделать это. Вы можете попробовать указать CharSet=Unicode атрибут каждой строки MarshalAs.

Я не уверен, что если бы это имело бы значение, учитывая, что стандартная сортировка строк из .NET уже является Unicode, но это может стоить того.

2: Возможно попробовать прохождения AccessibleContextInfo-структуру в качестве параметра ref, а не out параметра - например

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

Update: Кроме того, как Ханс Passant отмечает в комментарии, помните long в C# - это 64-разрядный int, тогда как в C/C++ он 32-разрядный. В зависимости от деклараций функций C++ это может быть неверно

Смежные вопросы