开发环境
win7,vs2008sp1,C++,C#
开发背景
基于MFC编写的OCX,供C#调用,其中的OCX接口如下:
void Command( void * value ) // 来自于 ocx的 .idl文件
DISP_FUNCTION_ID(CusViewCtrl, "Command", dispidCommand, Command, VT_EMPTY, VTS_I4 ) // 来自于 ocx的.cpp文件
而该Command的参数 void* 在C#中则体现为 intPtr,该 32位和64位的 ocx 被 C#2008.exe(vs2008编写) 都正常使用。
BUG现象
但客户那边用vs2022编写的c#2022.exe却报错,提示
System.AccessViolationException:"尝试读取或写入受保护的内存。这通常显示其它内存已损坏。"
很奇怪,问题就出在函数的参数类型上,经过多方面查证,C#的参数类型intPtr有以下注意事项:
1)intPtr在经 vs2008 编译后,当程序是32位为32bit,当程序64位时是64bit。
2)intPtr经过 vs2022 编译后,当程序无论是32位还是64位,都认为是32bit
因此 C#2022.exe 传buffer(类似数组首地址)给 C++2008.ocx 时,作为经vs2022编译的C#2022.exe(64位程序),该地址会被截断,导致OCX会报内存错误。(32位程序能正常运行)
解决办法
是直接将 void Command( void * value ) 改成 void Command( longlong value );然后在OCX中直接将 longlong value 强转成 void* value 处理即可。
补充示例
C#.exe 里传数组给C++.ocx 方法:
C#.exe 代码:
private void SameFunction( )
{
//...
byte[] buffer = new byte[1000]; // 开辟一个数组
SendDataToOcx( buffer ); // 将数组发送给OCX
//...
}
private void SendDataToOcx( byte[] buffer )
{
IntPtr pBuffer = Marshal.AllocHGlobal( buffer.Length );// 开辟非托管内存
Marshal.Copy(buffer, 0, pBuffer, buffer.Length); // 拷贝内容
axOcx.Command( pBuffer.ToInt64() ); // 将地址以64位int方式传给ocx
Marshal.FreeHGlobal(pBuffer); // 释放非托管内存
}
C++.ocx 代码
void Ocx::Command( LONGLONG value )
{
//...
char* pBuffer = ( char* )value; // 强转后直接用即可
//...
}