在C#中调用C++ 动态库传入回调函数指针的问题,请大家帮忙!

时间:2022-05-30 19:00:25
程序中有个模块是用C++写的,封装成了 dll文件,接口名称如下:

int Test(LP_TEST_CALL_BACK_FUNC callback)
{
  m_gCallBackFun = callback;//保存回调函数指针值
}

要求传入的参数是一个回调函数指针。回调函数的原型要求为:
 
void testCallBack(BYTE *pData,int nLen)
{
  //对pData数据进行处理。
}

//dll里面的函数调用回调函数处理
void dellData()
{
 byte data[100];
 for(byte i = 0 ;i < 100;i++)
   data[i] = i;
 //调用C#传入的回调函数处理这些值
 m_gCallBackFun(data,100);  //问题在此,调用完后出错,此时C#里的回调函数代码已经执行完。
}

上层模块是用C#写的,现在用C#调用testCallBack接口

C#里 
[DllImport("Test.dll")] 
public static extern void testCallBack(BYTE []data,int nlen); 

void Test()
{
  testCallBack(testCallBack);
}

void testCallBack(BYTE *pData,int nLen)
{
  //对pData数据进行处理。
  //......

  MessageBox.show("数据执行完毕"); //dll调用回调函数处理时 本对话框已经弹出,数据已经处理完毕!
}

现在的问题是,每次dll里面执行这个回调函数指针,程序都会报错,说什么访问了非法的内存。请问有没有朋友遇到过这种问题?现在焦头烂额,请大家帮忙看看问题出在哪儿?

13 个解决方案

#1


不好意思,下面一部分写错了,是这样

程序中有个模块是用C++写的,封装成了 dll文件,接口名称如下: 

int RegCallBack(LP_TEST_CALL_BACK_FUNC callback) 

  m_gCallBackFun = callback;//保存回调函数指针值 


要求传入的参数是一个回调函数指针。回调函数的原型要求为: 

void testCallBack(BYTE *pData,int nLen) 

  //对pData数据进行处理。 


//dll里面的函数调用回调函数处理 
void dellData() 

byte data[100]; 
for(byte i = 0 ;i < 100;i++) 
  data[i] = i; 
//调用C#传入的回调函数处理这些值 
m_gCallBackFun(data,100);  //问题在此,调用完后出错,此时C#里的回调函数代码已经执行完。 


上层模块是用C#写的,现在用C#调用testCallBack接口 

C#里 
[DllImport("Test.dll")] 
public static extern void RegCallBack(BYTE []data,int nlen); 

void Test() 

  RegCallBack(testCallBack); 


void testCallBack(BYTE *pData,int nLen) 

  //对pData数据进行处理。 
  //...... 

  MessageBox.show("数据执行完毕"); //dll调用回调函数处理时 本对话框已经弹出,数据已经处理完毕! 


现在的问题是,每次dll里面执行这个回调函数指针,程序都会报错,说什么访问了非法的内存。请问有没有朋友遇到过这种问题?现在焦头烂额,请大家帮忙看看问题出在哪儿?

#2


BYTE *pData这个改成 byte[]看看 要不你去找找c++和c#类型定义表

#3


byte[]也不行,我试过了。暂时没想到好的方法,有一个workaround
就是buffer也是从C#传过去的,然后在dellData中对这个传入的buffer进行操作。

我的测试代码
C++端声明:

typedef int (*LP_TEST_CALL_BACK_FUNC)(char* pData, int nLen);
extern "C" HASP_EXT_API void Test();
extern "C" HASP_EXT_API void SetCallBack(LP_TEST_CALL_BACK_FUNC fp, char* pBuffer, int len);

实现:
LP_TEST_CALL_BACK_FUNC g_fp = NULL;
char* g_pBuffer = NULL;
int g_len = 0;

extern "C" void Test()
{
if (g_fp != NULL)
{
for(char i = 0 ;i < g_len -1;i++) 
g_pBuffer[i] = i; 

//g_fp(data,len);

}
}

extern "C" void SetCallBack(LP_TEST_CALL_BACK_FUNC fp, char* pBuffer, int len)
{
g_fp = fp;
g_pBuffer = pBuffer;
g_len = len;
}


C#端:
unsafe public delegate int Mydelegate(byte* data, int nLen);

        unsafe private int test(byte* data, int nLen)
        {
            return 1;
        } 


        unsafe private void button1_Click(object sender, EventArgs e)
        {
            byte[] buffer = new byte[100];
            for (int i = 0; i<100; ++i)
            {
                buffer[i] = 0;
            }
            Mydelegate pf = new Mydelegate(test);
            SetCallBack(pf, buffer, 100);

            Test();

        }

        [DllImport("TestPVCallback.dll")]
        public static extern void SetCallBack(Mydelegate fp, byte[] data, int nLen); 

        [DllImport("TestPVCallback.dll")]
        public static extern void Test(); 

#4


Good luck!

#5


有没有高手帮帮忙啊? 因为我们有很多个dll模块都是要求传入这样一样类似的函数指针,由模块与其他程序和各种设备进行通讯,然后传给上层的C#程序.以前我用C++写程序就不会有这个问题,怎么换成了C#就这么麻烦.着急呀,老大.

#6


unsafe private int test(byte* data, int nLen)
加个static试一试

#8


用委托试下?

#9


难道每一个高手弄过吗?痛苦哦。
我用得unsafe语句,没用,跟这个无关。

#10


C++的函数指针在C#的DllImport里要声明成委托

#11


希望有高手能自己写段简单的代码自己测试一下! 3楼的朋友很感谢你,就是那样的写法,但问题没解决呀!

#12


还没解决。关注,帮顶。

lz,实在不行我还有一个workaround.

就是在C++端编码,变成可视字符,然后在C#端解码。
例如使用Base64编码成字符串,再在C#端解码变成byte[]

#13


把指针换成IntPtr,不能使用byte【】这种形式,我上次也出现过这种问题的,网上很多说要用数组的形式,其实是不对的,要用IntPtr类型,在到C#这边就行转换就可以了。。

#1


不好意思,下面一部分写错了,是这样

程序中有个模块是用C++写的,封装成了 dll文件,接口名称如下: 

int RegCallBack(LP_TEST_CALL_BACK_FUNC callback) 

  m_gCallBackFun = callback;//保存回调函数指针值 


要求传入的参数是一个回调函数指针。回调函数的原型要求为: 

void testCallBack(BYTE *pData,int nLen) 

  //对pData数据进行处理。 


//dll里面的函数调用回调函数处理 
void dellData() 

byte data[100]; 
for(byte i = 0 ;i < 100;i++) 
  data[i] = i; 
//调用C#传入的回调函数处理这些值 
m_gCallBackFun(data,100);  //问题在此,调用完后出错,此时C#里的回调函数代码已经执行完。 


上层模块是用C#写的,现在用C#调用testCallBack接口 

C#里 
[DllImport("Test.dll")] 
public static extern void RegCallBack(BYTE []data,int nlen); 

void Test() 

  RegCallBack(testCallBack); 


void testCallBack(BYTE *pData,int nLen) 

  //对pData数据进行处理。 
  //...... 

  MessageBox.show("数据执行完毕"); //dll调用回调函数处理时 本对话框已经弹出,数据已经处理完毕! 


现在的问题是,每次dll里面执行这个回调函数指针,程序都会报错,说什么访问了非法的内存。请问有没有朋友遇到过这种问题?现在焦头烂额,请大家帮忙看看问题出在哪儿?

#2


BYTE *pData这个改成 byte[]看看 要不你去找找c++和c#类型定义表

#3


byte[]也不行,我试过了。暂时没想到好的方法,有一个workaround
就是buffer也是从C#传过去的,然后在dellData中对这个传入的buffer进行操作。

我的测试代码
C++端声明:

typedef int (*LP_TEST_CALL_BACK_FUNC)(char* pData, int nLen);
extern "C" HASP_EXT_API void Test();
extern "C" HASP_EXT_API void SetCallBack(LP_TEST_CALL_BACK_FUNC fp, char* pBuffer, int len);

实现:
LP_TEST_CALL_BACK_FUNC g_fp = NULL;
char* g_pBuffer = NULL;
int g_len = 0;

extern "C" void Test()
{
if (g_fp != NULL)
{
for(char i = 0 ;i < g_len -1;i++) 
g_pBuffer[i] = i; 

//g_fp(data,len);

}
}

extern "C" void SetCallBack(LP_TEST_CALL_BACK_FUNC fp, char* pBuffer, int len)
{
g_fp = fp;
g_pBuffer = pBuffer;
g_len = len;
}


C#端:
unsafe public delegate int Mydelegate(byte* data, int nLen);

        unsafe private int test(byte* data, int nLen)
        {
            return 1;
        } 


        unsafe private void button1_Click(object sender, EventArgs e)
        {
            byte[] buffer = new byte[100];
            for (int i = 0; i<100; ++i)
            {
                buffer[i] = 0;
            }
            Mydelegate pf = new Mydelegate(test);
            SetCallBack(pf, buffer, 100);

            Test();

        }

        [DllImport("TestPVCallback.dll")]
        public static extern void SetCallBack(Mydelegate fp, byte[] data, int nLen); 

        [DllImport("TestPVCallback.dll")]
        public static extern void Test(); 

#4


Good luck!

#5


有没有高手帮帮忙啊? 因为我们有很多个dll模块都是要求传入这样一样类似的函数指针,由模块与其他程序和各种设备进行通讯,然后传给上层的C#程序.以前我用C++写程序就不会有这个问题,怎么换成了C#就这么麻烦.着急呀,老大.

#6


unsafe private int test(byte* data, int nLen)
加个static试一试

#7


#8


用委托试下?

#9


难道每一个高手弄过吗?痛苦哦。
我用得unsafe语句,没用,跟这个无关。

#10


C++的函数指针在C#的DllImport里要声明成委托

#11


希望有高手能自己写段简单的代码自己测试一下! 3楼的朋友很感谢你,就是那样的写法,但问题没解决呀!

#12


还没解决。关注,帮顶。

lz,实在不行我还有一个workaround.

就是在C++端编码,变成可视字符,然后在C#端解码。
例如使用Base64编码成字符串,再在C#端解码变成byte[]

#13


把指针换成IntPtr,不能使用byte【】这种形式,我上次也出现过这种问题的,网上很多说要用数组的形式,其实是不对的,要用IntPtr类型,在到C#这边就行转换就可以了。。