Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net C++/CLI委托作为函数指针(System.AccessViolationException)_.net_C# 4.0_Interop_C++ Cli - Fatal编程技术网

.net C++/CLI委托作为函数指针(System.AccessViolationException)

.net C++/CLI委托作为函数指针(System.AccessViolationException),.net,c#-4.0,interop,c++-cli,.net,C# 4.0,Interop,C++ Cli,我一直在尝试使用C++/CLI委托(因为我正在尝试创建一个.NET参考库),我遇到了以下问题 在C++中定义委托,然后在C++中创建委托实例,然后通过函数指针调用委托的实例。这一切都按预期进行 说明这一点的代码(首先是我的C#) 下一步,我的托管C++文件(托管.CPP) 这段代码按预期工作,输出为“1024”,因为指向委托方法的函数指针调用了Method() 我的问题出现在尝试对带有参数的委托应用相同的方法时,即:delegate void MessageDelegate(int number

我一直在尝试使用C++/CLI委托(因为我正在尝试创建一个.NET参考库),我遇到了以下问题

在C++中定义委托,然后在C++中创建委托实例,然后通过函数指针调用委托的实例。这一切都按预期进行

说明这一点的代码(首先是我的C#)

下一步,我的托管C++文件(托管.CPP)

这段代码按预期工作,输出为“1024”,因为指向委托方法的函数指针调用了Method()

我的问题出现在尝试对带有参数的委托应用相同的方法时,即:delegate void MessageDelegate(int number)

我的代码如下(C#):

托管的C++文件:

#include "Unmanaged.hpp"
#include <string>

namespace Library
{
    using namespace System;
    using namespace System::Runtime::InteropServices;

    public ref class Test
    {
    public:
        delegate void MessageDelegate(int number);
    internal:
        MessageDelegate^ Message;
        void* delegatePointer;

    public:
        Test(MessageDelegate^ messageDelegate)
        {
            delegatePointer = (void*)Marshal::GetFunctionPointerForDelegate(messageDelegate).ToPointer();
        }

        void WriteMessage(int number)
        {
            Unmanaged::WriteMessage(delegatePointer, number);
        }
    };
}
#include "Unmanaged.hpp"

namespace Unmanaged
{
    typedef void (*WriteMessageType)(int number);
    WriteMessageType WriteMessageFunc;

    void WriteMessage(void* Function, int number)
    {
        WriteMessageType WriteMessageFunc = (WriteMessageType)(Function);
        WriteMessageFunc(number);
    }
}
当我执行程序时,我得到以下错误:

非托管库Test.dll中发生类型为“System.AccessViolationException”的未处理异常

其他信息:尝试读取或写入受保护内存。这通常表示其他内存已损坏

顺便说一句,console窗口确实显示1024,但随后是一个随机整数(~1000000),然后我得到了错误


我可以开始想象我犯这个错误的一些原因,但我不确定,也很难找出原因。如果有人能告诉我为什么会出现这个错误,以及我能做些什么来修复它,我将不胜感激。

从委托创建的函数指针对于垃圾收集器是不可见的,并且在可达性分析期间不被计算在内

发件人:

必须手动防止垃圾收集器从托管代码中收集委托。垃圾收集器不跟踪对非托管代码的引用[sic]

如果收集委托,函数指针将悬空,程序将表现不好。访问违规是更可能的结果之一,但不是唯一的可能性。如果用于包含本机/托管蹦床的内存被用于其他数据,CPU可以尝试将其解释为指令,这可能意味着任何事情

解决方案是保持委托的可访问性,例如通过C++/CLI
gcroot
类,它是.NET
GCHandle
的薄包装

 void WriteMessage(void* Function, int number)
将函数指针传递为void*是一个非常糟糕的主意。它可以防止编译器检查您是否做错了任何事情。虽然编译器在这种特定情况下无法检测到错误,但还是有问题。委托被封送为使用u stdcall调用约定的函数指针,实际函数指针使用本机代码的默认u cdecl调用约定。这会导致堆栈在调用时变得不平衡


您可以通过将应用于委托声明,指定CallingConvention::Cdecl来解决此问题。

+1对于描述良好的问题,我无法使用GCHandle解决此问题。即使在使用GCHandle分配委托时,似乎也会发生相同的错误,因此我认为这不是垃圾收集器的问题。我还应该补充一点,当我使用/cli编译Unmanaged.cpp时,问题就消失了。非常感谢,为什么没有参数就不需要它?它仍然是必需的,它只是没有任何区别,因为没有任何东西被推到堆栈上。
using System;

namespace AddProgram
{
    class Program
    {
        static void Main(string[] args)
        {
            Library.Test.MessageDelegate messageDelegate = new Library.Test.MessageDelegate(Message);
            Library.Test test = new Library.Test(messageDelegate);
            test.WriteMessage(1024);
            Console.Read();
        }

        static void Message(int number)
        {
            Console.WriteLine(number);
        }
    }
}
#include "Unmanaged.hpp"
#include <string>

namespace Library
{
    using namespace System;
    using namespace System::Runtime::InteropServices;

    public ref class Test
    {
    public:
        delegate void MessageDelegate(int number);
    internal:
        MessageDelegate^ Message;
        void* delegatePointer;

    public:
        Test(MessageDelegate^ messageDelegate)
        {
            delegatePointer = (void*)Marshal::GetFunctionPointerForDelegate(messageDelegate).ToPointer();
        }

        void WriteMessage(int number)
        {
            Unmanaged::WriteMessage(delegatePointer, number);
        }
    };
}
#include "Unmanaged.hpp"

namespace Unmanaged
{
    typedef void (*WriteMessageType)(int number);
    WriteMessageType WriteMessageFunc;

    void WriteMessage(void* Function, int number)
    {
        WriteMessageType WriteMessageFunc = (WriteMessageType)(Function);
        WriteMessageFunc(number);
    }
}
 void WriteMessage(void* Function, int number)