C ++/CLI委托作为函数指针(System.AccessViolationException) [英] C++/CLI delegate as function pointer (System.AccessViolationException)

查看:73
本文介绍了C ++/CLI委托作为函数指针(System.AccessViolationException)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试C ++/CLI委托(当我试图创建.NET参考库时),并且遇到了以下问题.

I have been experimenting with C++/CLI delegates (as I am trying to make a .NET reference library), and I have been having the following problem.

我在C ++/CLI中定义了一个委托,然后在C#中创建了该委托的一个实例,然后通过一个函数指针通过非托管C ++调用了该委托的实例.这一切都按预期进行.

I define a delegate in C++/CLI, and then create an instance of the delegate in C#, and then call the instance of the delegate through unmanaged C++ via a function pointer. This all works as expected.

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

Code to illustrate this (first my C#)

using System;

namespace TestProgram
{
    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();
            Console.Read();
        }

        static void Message()
        {
            Console.WriteLine(1024);
        }
    }
}

接下来我的托管c ++文件(Managed.cpp)

Next my managed c++ file (Managed.cpp)

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

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

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

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

        void WriteMessage()
        {
            Unmanaged::WriteMessage(delegatePointer);
        }
    };
}

还有我的非托管C ++文件(Unmanaged.cpp)

And my unmanaged C++ file (Unmanaged.cpp)

#include "Unmanaged.hpp"

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

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

此代码均按预期工作,并且输出为"1024",因为Method()是由指向委托方法的函数指针调用的.

This code all works as expected, and the output is "1024", as Method() is called by the function pointer to the delegate method.

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

My problem arises when trying to apply the same method with a delegate with arguments, that is: delegate void MessageDelegate(int number);

我的代码如下(C#):

My code is now as follows (C#):

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

我的托管C ++文件:

My managed C++ file:

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

还有我的非托管C ++文件:

And my unmanaged C++ file:

#include "Unmanaged.hpp"

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

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

当我执行程序时,出现以下错误:

When I execute the program I get the following error:

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

An unhandled exception of type 'System.AccessViolationException' occurred in Unmanaged Library Test.dll

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

Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

顺便说一句,控制台窗口的确显示1024,但随后是一个随机整数(〜1000000),然后我得到了错误消息.

Incidentally, the console window does show 1024, but is then followed by a random int (~1000000), and then I get the error.

我可以开始想象出现此错误的一些原因,但是我不确定并且很难找出原因.如果有人能告诉我为什么会出现此错误,以及如何解决该错误,我将不胜感激.

I can begin to imagine some of the reasons I am getting this error, but I'm not sure and am having difficulty finding out. If anyone could tell me why I am getting this error, and what I could do to fix it, I would greatly appreciate it.

推荐答案

 void WriteMessage(void* Function, int number)

将函数指针作为void *传递是一个非常糟糕的主意.它可以防止编译器检查您做错了什么.尽管在这种特定情况下编译器无法检测到错误,但还是有问题.委托被编组为使用__stdcall调用约定的函数指针,实际的函数指针使用__cdecl调用约定(本机代码的默认值).这会导致堆栈在调用中变得不平衡.

Passing function pointers as void* is a pretty bad idea. It prevents the compiler from checking you are doing anything wrong. There is something wrong, although the compiler cannot detect it in this specific case. The delegate is marshaled as a function pointer that uses the __stdcall calling convention, your actual function pointer uses the __cdecl calling convention, the default for native code. Which causes the stack to get imbalanced on the call.

您可以通过应用来解决此问题委托声明的[UnmanagedFunctionPointer]属性,指定CallingConvention :: Cdecl.

You can fix it by applying the [UnmanagedFunctionPointer] attribute to the delegate declaration, specify CallingConvention::Cdecl.

这篇关于C ++/CLI委托作为函数指针(System.AccessViolationException)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆