我正在尝试让 Java Access Bridge (2.02) 与 C# (.NET 3.5) 一起工作。我确实让它适用于某些函数,但是当我调用引用结构 (getAccessibleContextInfo) 的函数时,我收到此错误消息: System.AccessViolationException:试图读取或写入 protected 内存。这通常表明其他内存已损坏。
这是我的代码:
[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++ 程序一起正常工作。
我通过搜索 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;
非常感谢任何帮助!
最佳答案
通常 AccessViolations 表示您弄乱了 PInvoke 签名,但看起来通常没问题。
我想出了两件可能有帮助的事情
1:在结构级别对 Charset.Unicode
的潜在可疑使用。
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct AccessibleContextInfo
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
public string name;
...
人们可能期望结构上的 CharSet=Unicode
应该“传播”到它的成员,但我见过它似乎没有这样做的情况。
您可以尝试在每个字符串的 MarshalAs
属性上指定 CharSet=Unicode
。
鉴于 .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++ 函数声明,这可能是错误的
关于c# - 调用 C++ dll 时出现 System.AccessViolationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6059621/