我对 glfwSetCharCallback 函数有疑问。每当我调用它时,glfwPollEvents 都会抛出一个 AccessViolationException 说:“试图读取或写入 protected 内存。这通常表明其他内存已损坏。”
我创建了一个非常简单的包装器来演示这个问题:
using System;
using System.Runtime.InteropServices;
using System.Security;
namespace Test
{
public delegate void GlfwCharCallback(GlfwWindow window, Char character);
[StructLayout(LayoutKind.Explicit)]
public struct GlfwMonitor
{
private GlfwMonitor(IntPtr ptr)
{
_nativePtr = ptr;
}
[FieldOffset(0)] private readonly IntPtr _nativePtr;
public static readonly GlfwMonitor Null = new GlfwMonitor(IntPtr.Zero);
}
[StructLayout(LayoutKind.Explicit)]
public struct GlfwWindow
{
private GlfwWindow(IntPtr ptr)
{
_nativePtr = ptr;
}
[FieldOffset(0)] private readonly IntPtr _nativePtr;
public static GlfwWindow Null = new GlfwWindow(IntPtr.Zero);
}
public class Wrap
{
[DllImport("GLFW3", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
private static extern Int32 glfwInit();
[DllImport("GLFW3", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
internal static extern GlfwWindow glfwCreateWindow(Int32 width, Int32 height,
[MarshalAs(UnmanagedType.LPStr)] String title,
GlfwMonitor monitor, GlfwWindow share);
[DllImport("GLFW3", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
internal static extern void glfwSetCharCallback(GlfwWindow window, GlfwCharCallback callback);
[DllImport("GLFW3", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
internal static extern void glfwPollEvents();
public static Boolean Init()
{
return glfwInit() == 1;
}
public static GlfwWindow CreateWindow(Int32 width, Int32 height, String title, GlfwMonitor monitor,
GlfwWindow share)
{
return glfwCreateWindow(width, height, title, monitor, share);
}
public static void SetCharCallback(GlfwWindow window, GlfwCharCallback callback)
{
glfwSetCharCallback(window, callback);
}
public static void PollEvents()
{
glfwPollEvents();
}
}
}
我称它为 GLFW:
using System;
namespace Test
{
class Program
{
static void Main()
{
Wrap.Init();
var window = Wrap.CreateWindow(800, 600, "None", GlfwMonitor.Null, GlfwWindow.Null);
Wrap.SetCharCallback(window, (glfwWindow, character) => Console.WriteLine(character));
while(true)
{
Wrap.PollEvents();
}
}
}
}
字符被打印到控制台,我得到 AccessViolationException。
我做错了什么?所有 DllImports 都指定了 CDecl 调用约定(我已经在 PollEvents 和 SetCharCallback 上尝试了其他的),我已经在 SetCharCallback 函数上尝试了所有 CharSets 但没有任何效果。
有人可以帮帮我吗?
编辑:
这是我正在使用的 GLFW3 Dll: http://www.mediafire.com/?n4uc2bdiwdzddda
编辑2:
使用最新的“lib-msvc110”DLL 使 glfwSetCharCallback 工作。 glfwSetKeyCallback 和 glfwSetCursorPosCallback 不起作用并继续抛出 AccessViolationException。我将尝试弄清楚是什么让 CharCallback 如此特别,但老实说,我已经通读了 GLFW 源代码,所有函数似乎都以相同的方式完成它们的工作。也许我忽略了一些东西。
编辑 3:
我已经尝试了所有方法,cdecl、stdcall、所有字符集、所有版本的 dll、所有参数组合等。我已经确保不会通过存储对回调的引用来处置回调。我还试图通过不保留 glfwSetCharCallback 的任何参数空间(目前有效)来故意使应用程序崩溃,但我还没有成功。这让我相信论点本身对申请没有影响。
真正让我觉得问题出在 GLFW 本身的事情是,如果我针对 x86-64 dll 进行编译,一切都会完美无缺。在 x86-64 上使用 cdecl 有点奇怪,因为 MSDN 明确指出唯一的调用约定是 fastcall。
最佳答案
我花了一段时间,但我解决了。所有委托(delegate)都描述了 C# 函数,不能从 C 调用。解决方案是让委托(delegate)描述类 C 函数,这可以通过 UnmanagedFunctionPointer
属性实现。
将属性添加到所有委托(delegate)(如下所示)解决了问题。
[UnmanagedFunctionPointer(CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public delegate void GlfwCharCallback(GlfwWindow window, Char character);
关于c# - 在 C# 中使用 GLFW 的 AccessViolationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17969941/