C#传委托给C语言的函数指针调用问题

C代码如下:
#include "stdio.h"
__declspec(dllexport) int Call(int (*qq)(int num),char * str)
{    
    printf(str);
    return qq(123);
}

多次验证发现在C#中传委托给C中的函数指针,如果委托不带参数则都能成功运行,但是委托一带参数不管是int参数还是string参数或者其他参数,都会报“ 尝试读取或写入受保护的内存。这通常指示其他内存已损坏”的错误,或是“读取位置0x......  时发生访问冲突”的错误。

这些都是指针的访问出现了问题。

找了一天才找到解决方法:在C#的委托声明上加[UnmanagedFunctionPointer(CallingConvention.Cdecl)],正确调用如下:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate int MyDeg(int num);
    class Program
    {
        static void Main(string[] args)
        {
            
            try
            {
                MyDeg myd = new MyDeg(FF);
                Console.WriteLine(Call(myd, "helloworld"));
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

        }

        static int FF(int num)
        {
            Console.WriteLine(num);
            return num + 1;

        }

        [DllImport("my.dll", EntryPoint = "Call")]
        public extern static int Call(MyDeg mm ,string  str);
    }

参考:C#传委托给C的函数指针调用问题

其他参考:
  很多的Dll都是C和C++写的,那么如果C#想要调用Dll中的函数怎么办,尤其是Dll函数其中一个参数是函数指针的,即里面有回调函数的用C#怎么实现?
  C中的回调函数在C#中有中特殊的处理方式叫委托,即要实现的回掉函数委托给另一个和它返回值类型以及函数参数类型、数量一样的方法来实现。
链接:C#委托实现C++ Dll中的回调函数

另外需要注意:要防止定义的委托被gc回收,参考
托管C++随笔二:回调函数
一般的报错信息是:对“xxxx::Invoke”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用。


 

posted @ 2022-06-10 20:31  peterYong  阅读(420)  评论(0编辑  收藏  举报