读书人

C#与C++怎么共用内存?比如都访问一个结

发布时间: 2012-03-25 20:55:17 作者: rapoo

C#与C++如何共用内存?比如都访问一个结构体!注意,c#和C++在一个项目中
C#与C++如何共用内存?比如都访问一个结构体!注意,c#和C++在一个项目中


Ivony推荐此问题。

由于.NET中引入了托管的概念,在对象的管理和传递方面与C++传统模式产生了很大的区别,所以在Native代码和托管代码之间的互操作就会出现很多的问题。本问题就是其中一个代表。

尽管本问题在提问技巧上略显不足,但引起的讨论却很有价值,推荐阅读。


[解决办法]
可以在C#里面申请好内存,传给C++,一般以API函数的方式传

这样就是共享的了
[解决办法]
共享内存操作类

C# code
using System;using System.Collections.Generic;using System.Text;using System.Runtime.InteropServices;namespace ShareMemLib{    public class ShareMem    {        [DllImport("user32.dll", CharSet = CharSet.Auto)]        public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, IntPtr lParam);        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]        public static extern IntPtr CreateFileMapping(int hFile, IntPtr lpAttributes, uint flProtect, uint dwMaxSizeHi, uint dwMaxSizeLow, string lpName);                [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]        public static extern IntPtr OpenFileMapping(int dwDesiredAccess,[MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,string lpName);        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]        public static extern IntPtr MapViewOfFile(IntPtr hFileMapping,uint dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow,uint dwNumberOfBytesToMap);        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]        public static extern bool UnmapViewOfFile(IntPtr pvBaseAddress);        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]        public static extern bool CloseHandle(IntPtr handle);        [DllImport("kernel32", EntryPoint="GetLastError")]        public static extern int GetLastError ();        const int ERROR_ALREADY_EXISTS = 183;        const int FILE_MAP_COPY = 0x0001;        const int FILE_MAP_WRITE = 0x0002;        const int FILE_MAP_READ = 0x0004;        const int FILE_MAP_ALL_ACCESS = 0x0002 | 0x0004;        const int PAGE_READONLY = 0x02;        const int PAGE_READWRITE = 0x04;        const int PAGE_WRITECOPY = 0x08;        const int PAGE_EXECUTE = 0x10;        const int PAGE_EXECUTE_READ = 0x20;        const int PAGE_EXECUTE_READWRITE = 0x40;        const int SEC_COMMIT = 0x8000000;        const int SEC_IMAGE = 0x1000000;        const int SEC_NOCACHE = 0x10000000;        const int SEC_RESERVE = 0x4000000;        const int INVALID_HANDLE_VALUE = -1;        IntPtr m_hSharedMemoryFile = IntPtr.Zero;        IntPtr m_pwData = IntPtr.Zero;        bool m_bAlreadyExist = false;        bool m_bInit = false;        long m_MemSize=0;        public ShareMem()        {        }        ~ShareMem()        {            Close();        }        /// <summary>        /// 初始化共享内存        /// </summary>        /// <param name="strName">共享内存名称</param>        /// <param name="lngSize">共享内存大小</param>        /// <returns></returns>        public int Init(string strName, long lngSize)        {            if (lngSize <= 0 || lngSize > 0x00800000) lngSize = 0x00800000;            m_MemSize = lngSize;            if (strName.Length > 0)            {                //创建内存共享体(INVALID_HANDLE_VALUE)                m_hSharedMemoryFile = CreateFileMapping(INVALID_HANDLE_VALUE, IntPtr.Zero, (uint)PAGE_READWRITE, 0, (uint)lngSize, strName);                if (m_hSharedMemoryFile == IntPtr.Zero)                {                    m_bAlreadyExist = false;                    m_bInit = false;                    return 2; //创建共享体失败                }                else                {                    if (GetLastError() == ERROR_ALREADY_EXISTS)  //已经创建                    {                        m_bAlreadyExist = true;                    }                    else                                         //新创建                    {                        m_bAlreadyExist = false;                    }                }                //---------------------------------------                //创建内存映射                m_pwData = MapViewOfFile(m_hSharedMemoryFile, FILE_MAP_WRITE, 0, 0, (uint)lngSize);                if (m_pwData == IntPtr.Zero)                {                    m_bInit = false;                    CloseHandle(m_hSharedMemoryFile);                    return 3; //创建内存映射失败                }                else                {                    m_bInit = true;                    if (m_bAlreadyExist == false)                    {                        //初始化                    }                }                //----------------------------------------            }            else            {                return 1; //参数错误                 }            return 0;     //创建成功        }        /// <summary>        /// 关闭共享内存        /// </summary>        public void Close()        {            if (m_bInit)            {                UnmapViewOfFile(m_pwData);                CloseHandle(m_hSharedMemoryFile);            }        }        /// <summary>        /// 读数据        /// </summary>        /// <param name="bytData">数据</param>        /// <param name="lngAddr">起始地址</param>        /// <param name="lngSize">个数</param>        /// <returns></returns>        public int Read(ref byte[] bytData, int lngAddr, int lngSize)        {            if (lngAddr + lngSize > m_MemSize) return 2; //超出数据区            if (m_bInit)            {                               Marshal.Copy(m_pwData, bytData, lngAddr, lngSize);            }            else            {                return 1; //共享内存未初始化            }            return 0;     //读成功        }        /// <summary>        /// 写数据        /// </summary>        /// <param name="bytData">数据</param>        /// <param name="lngAddr">起始地址</param>        /// <param name="lngSize">个数</param>        /// <returns></returns>        public int Write(byte[] bytData, int lngAddr, int lngSize)        {            if (lngAddr + lngSize > m_MemSize) return 2; //超出数据区            if (m_bInit)            {                Marshal.Copy(bytData, lngAddr, m_pwData, lngSize);            }            else            {                return 1; //共享内存未初始化            }            return 0;     //写成功        }    }} 


[解决办法]
我觉得 lizhizhe2000 老大可能理解错了lz的意思,lz的意思并不是要一个共享内存,而是c++和C#之间的数据交互。而 lizhizhe2000 老大给出的是一个进程间相互通讯的共享内存的例子。
至于楼主的问题,我觉得主要看C++是托管的还是非托管的,如果是托管的,就可以直接相互调用,如果是非托管的,就需要C#中定义一个完全一致的结构体,然后当成参数传递。例子的话CSDN上有很多吧,官方教程:
http://msdn.microsoft.com/zh-cn/library/04fy9ya1(VS.80).aspx
[解决办法]
假设你在C++中有一个结构体为登录信息,如下:

C/C++ code
typedef struct _LoginInfoType{    wchar_t szDSN[128];    wchar_t szUser[128];    wchar_t szPassword[128];} LoginInfoType;
[解决办法]
当你在VC中将此信息写如内存后,在C#中所需要做的就是导入那些内存映射函数并读取或写入那块内存,也就是我转载的那个程序,在C#中创建相应的结构体的示例如下:
C# code
    [StructLayoutAttribute(LayoutKind.Sequential,CharSet=CharSet.Auto,Pack=1)]    public struct LoginInfoType    {        [MarshalAs(UnmanagedType.ByValTStr,SizeConst=128)]        public string strDSN;        [MarshalAs(UnmanagedType.ByValTStr,SizeConst=128)]        public string strUser;        [MarshalAs(UnmanagedType.ByValTStr,SizeConst=128)]        public string strPassword;    }
[解决办法]
[StructLayoutAttribute(LayoutKind.Sequential,CharSet=CharSet.Auto,Pack=1)]
public struct LoginInfoType
{
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=128)]
public string strDSN;
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=128)]
public string strUser;
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=128)]
public string strPassword;
}
这种方法可行 我用过
[解决办法]
lizhizhe2000 老大,我的意思就是按照你的定义这样,但是没有必要非用内存映射的。按照你那样定义两个结构体,就可以直接把这个结构体当参数在两种语言之间相互传递了,就像下面代码那么调用就行了。
C# code
[DllImport("c.dll", CharSet = CharSet.Auto)]        public static extern void F(LoginInfoType l);
[解决办法]
可以到http://msdn.microsoft.com/zh-cn/library/04fy9ya1(VS.80).aspx上去搜索
封送类、结构和联合,看到托管代码和非托管代码之间如何传递值的。
[解决办法]
C++?
如果代码都是自己写的话用C++/CLI是最好的办法.
可以剩下不少代码.
[解决办法]
用CCW包装器,,使用COM互操作.很简单的.性能损失也不大.如果C++和C#都是你写的代码.
[解决办法]
如果你想互相共享数据可以做个webservice,在webservice中定义一个方法处理共享数据,C++和C#都可以调用webservice中的方法,来操作你需要的数据
[解决办法]
***************************************************************************

思想决定行动,行动决定习惯,习惯决定命运.
程序员在深圳QQ群,交流产生思想碰撞.

部份专业群:
程序员在深圳c++群15195967
程序员在深圳英语学习群:23864353
程序员在深圳c++Ⅱ17409451
程序员在深圳嵌入式开发群37489763
程序员在深圳移动开发群31501597
程序员在深圳创业群33653422

部份高级程序员群:
高级群I:17538442
高级群II:7120862

部份初、中级程序员群:
第三群:2650485
第五群:29537639
第四群:28702746
第六群:10590618
第七群:10543585
第八群:12006492
第九群:19063074
第十群:2883885
第十一群:25460595
第十二群:9663807

深圳程序员QQ群联盟成立三年多,拥有三十个以上的QQ群,人数超二千多人,大量经验丰富的老手,成员从业于大公司(如微软、IBM,SUN,华为)、来自国内著名高校和研究院成员,和有丰富实践经验的高级程序员、系统分析员(包括参加过上亿元的项目的架构师),有很热爱技术的成员(包括自己写操作系统),还有少数女程序员。推荐:深程高级群I:17538442 深程高级群II:7120862 (深程高级群不欢迎新手,如果在深圳,月薪6K以下的别加入) c++:15195967 mobile:31501597嵌入式:37489763
——————————————————————————————————————————
如果你不是第一次看到此广告,说明我们最近T了一些人,因为我们要不断提升群的质量,保证名副其实.
-------------------------------------------------
在通过电邮、新闻组或者聊天室提出技术问题前,检查你有没有做到:


1. 通读手册,试着自己找答案。
2. 在FAQ里找答案(一份维护得好的FAQ可以包罗万象:)。
3. 在网上搜索(个人推荐google~)。
4. 向你身边精于此道的朋友打听。
我想我们首先应该靠自己解决问题,然后才是问!

*****************************************************************************

[解决办法]
可以用Marshall.Copy把内存复制到托管堆,然后用BinaryFormater和MemoryStream Deserialize
[解决办法]
帮顶,,我也遇到过此类问题。。
当时是C++写的非托管dll中使用到结构体,并且结构体中有一个成员是int[].
结果C#在调用dll时也传递同样的结构体作为参数,,
但,结构体中的int[]数据丢失了。。。。

顶顶顶。。。。
[解决办法]
顺便
问个问题
c++ dll
//TestInterface这是个纯虚类
extern "C" __declspec(dllexport)int TestFun(int* pSinkEvent)
{
((TestInterface*)pSinkEvent)->OnEventFun();
return 1;
}
////////////////////////////////////////////////////
C#
public interface TestInterface
{
void OnEventFun();
}
public class CoreTest : TestInterface
{
public void OnEventFun()
{
MessageBox.Show("asdfasdf");
}
}
....//其他代码略之
问题如何调用dll里的TestFun呀?(C++里不想用回调函数),不知在C#里有没有办法呀
http://topic.csdn.net/u/20080702/00/d3c8b1fe-9cc1-45cb-93fe-2e08dc09bf28.html?seed=1245100039

读书人网 >C#

热点推荐