简体   繁体   English

C#中使用GLFW的AccessViolationException

[英]AccessViolationException with GLFW in C#

I have a problem with the glfwSetCharCallback function. 我有一个glfwSetCharCallback函数的问题。 Whenever I call it, the glfwPollEvents throws an AccessViolationException saying: "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." 每当我调用它时,glfwPollEvents都会抛出一个AccessViolationException:“试图读取或写入受保护的内存。这通常表明其他内存已损坏。”

I have created a very simple wrapper just to demonstrate the problem: 我创建了一个非常简单的包装器来演示问题:

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();
        }
    }
}

And I call it like I would GLFW: 我称它为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();
            }
        }
    }
}

The character is printed into the console and I get the AccessViolationException. 该字符被打印到控制台,我得到AccessViolationException。

What am I doing incorrectly? 我做错了什么? All the DllImports specify the CDecl calling convention (I've tried the others on both PollEvents and SetCharCallback), I've tried all CharSets on the SetCharCallback function and nothing worked. 所有的DllImports都指定了CDecl调用约定(我在PollEvents和SetCharCallback上都试过了其他的),我在SetCharCallback函数上尝试了所有的CharSets并且没有任何效果。

Could someone please help me? 有人可以帮帮我吗?

Edit: 编辑:

Here is the GLFW3 Dll that I'm using: http://www.mediafire.com/?n4uc2bdiwdzddda 这是我正在使用的GLFW3 Dll: http//www.mediafire.com/? n4uc2bdiwdzddda

Edit 2: 编辑2:

Using the newest "lib-msvc110" DLL made glfwSetCharCallback work. 使用最新的“lib-msvc110”DLL使glfwSetCharCallback工作。 glfwSetKeyCallback and glfwSetCursorPosCallback do not work and continue to throw AccessViolationException. glfwSetKeyCallback和glfwSetCursorPosCallback不起作用并继续抛出AccessViolationException。 I will attempt to figure out what makes CharCallback so special, but honestly, I've gone through the GLFW source code through and through and all the functions seem to do their thing in the same way. 我将试图弄清楚是什么让CharCallback变得如此特别,但老实说,我已经完成了GLFW源代码,并且所有函数似乎都以同样的方式完成了它们的工作。 Maybe there's something I'm overlooking. 也许有一些我忽略的东西。

Edit 3: 编辑3:

I've tried everything, cdecl, stdcall, all the charsets, all versions of the dll, all combinations of arguments, etc. I've made sure that the callbacks are not disposed by storing a reference to them. 我已经尝试了所有的东西,cdecl,stdcall,所有的字符集,所有版本的dll,所有的参数组合等等。我已经确保回调没有通过存储对它们的引用来处理。 I've also tried to purposefully crash the application by not reserving any space of arguments of glfwSetCharCallback (which works as of now) and I haven't managed to do it. 我还试图通过不保留glfwSetCharCallback(现在的工作原理)的任何参数空间来故意使应用程序崩溃,而我还没有设法做到这一点。 This leads me to believe that the arguments themselves have no bearing on the application. 这让我相信论证本身与应用无关。

The thing that really makes me think the fault is with GLFW itself is the fact that if I compile against the x86-64 dll, everything works perfectly. 真正让我认为GLFW本身的错误的事实是,如果我针对x86-64 dll进行编译,一切都运行良好。 It is a little bit strange to use cdecl on x86-64, because MSDN specifically states that the only calling convention is fastcall. 在x86-64上使用cdecl有点奇怪,因为MSDN特别指出唯一的调用约定是fastcall。

It took me a while, but I solved it. 我花了一段时间,但我解决了它。 All the delegates are describing C# functions, which cannot be called from C. The solution is to make the delegates describe C-like functions, which can be achieved via the UnmanagedFunctionPointer attribute. 所有委托都在描述C#函数,这些函数不能从C调用。解决方案是让委托描述类似C的函数,这可以通过UnmanagedFunctionPointer属性实现。

Adding the attribute to all delegates (as shown below) solved the problem. 将属性添加到所有委托(如下所示)解决了问题。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM