c# - 在 C# 中使用 GLFW 的 AccessViolationException

标签 c# .net dllimport access-violation glfw

我对 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/

相关文章:

c# - 从 UWP C# 应用程序使用 pinvoke 调用 LoadLibrary

c# - 如何让 C# 连接到 excel API

c# - 无法加载 DLL ' mydll.dll' : The specified module could not be found

c# - 从C#到C++的编码字符串

C#/WPF : Creating and running an event on a separate thread at startup

c# - 如何从 System.Net.EndPoint 获取主机地址和端口?

c# - String.Compare 的不同重载之间的区别

c# - 捕获 .NET TextBox 的 MouseDown 事件

c# - 使用 SqlCommand Async 方法处理大数据时性能糟糕

c# - 如何从 C# Windows 应用程序项目调用 C++ dll