c# - 调用 C++ dll 时出现 System.AccessViolationException

标签 c# exception dllimport

我正在尝试让 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/

相关文章:

c# - cookie 检查不起作用

c# - 在 AWS Elasticache 中使用 NHibernate memcached 二级缓存的问题

c# - DateTimePicker 默认值 : How to avoid it?

c# - C# 中 Exception.Data 可以为 null 吗?

c# - Try/Finally 真的是异常安全的吗?

c++ - 从 Delphi 应用程序调用外部函数 (C++) 时发生访问冲突

c# - 如何在 FluentValidation 的世界中使用带有 ValidateAsync 的规则集?

java - 错误: static class forcing UnsupportedOperationException

c# - DllImport 或 LoadLibrary 以获得最佳性能

C#:一个属性用于多个声明 (DLLImport)