AccessViolationException与C#中的GLFW

我有一个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。

我做错了什么? 所有的DllImport都指定了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。


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

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

[UnmanagedFunctionPointer(CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public delegate void GlfwCharCallback(GlfwWindow window, Char character);
链接地址: http://www.djcxy.com/p/14893.html

上一篇: AccessViolationException with GLFW in C#

下一篇: Internal Implementation of AsEnumerable() in LINQ