AccessViolationException with GLFW in C#

本文关键字:in GLFW with AccessViolationException | 更新日期: 2023-09-27 18:25:34

我的glfwSetCharCallback函数有问题。每当我调用它时,glfwPollEvents都会抛出一个AccessViolationException,说:"试图读取或写入受保护的内存。这通常表明其他内存已损坏。"

我创建了一个非常简单的包装器来演示这个问题:

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函数上尝试过所有CharSet,但都没有成功。

有人能帮帮我吗?

编辑:

这是我正在使用的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。

AccessViolationException with GLFW in C#

我花了一段时间,但我解决了它。所有的委托都在描述C#函数,而这些函数不能从C调用。解决方案是让委托描述类C函数,这可以通过UnmanagedFunctionPointer属性实现。

将属性添加到所有代理(如下所示)解决了问题。

[UnmanagedFunctionPointer(CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public delegate void GlfwCharCallback(GlfwWindow window, Char character);