调用C ++ DLL时出现System.AccessViolationException

时间:2011-05-19 13:41:49

标签: c# exception dllimport

我试图让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");
}
}

我认为这不是java dll的问题,因为它适用于API附带的示例C ++程序。

我猜测搜索谷歌这是我编组结构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 :(得分: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);

更新:另外,正如Hans Passant在评论中指出的那样,记住C#中的long 64位 int,而在C / C ++中它是32位。根据C ++函数声明,这可能是错误的