System.AccessViolationException при вызове C ++ dll - PullRequest
6 голосов
/ 19 мая 2011

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

Вот мой код:

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

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

1 Ответ

0 голосов
/ 13 ноября 2012

Обычно 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);

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

...