C#与C++如何共用内存?比如都访问一个结构体!注意,c#和C++在一个项目中
C#与C++如何共用内存?比如都访问一个结构体!注意,c#和C++在一个项目中
Ivony推荐此问题。
由于.NET中引入了托管的概念,在对象的管理和传递方面与C++传统模式产生了很大的区别,所以在Native代码和托管代码之间的互操作就会出现很多的问题。本问题就是其中一个代表。
尽管本问题在提问技巧上略显不足,但引起的讨论却很有价值,推荐阅读。
[解决办法]
可以在C#里面申请好内存,传给C++,一般以API函数的方式传
这样就是共享的了
[解决办法]
共享内存操作类
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++中有一个结构体为登录信息,如下:
typedef struct _LoginInfoType{ wchar_t szDSN[128]; wchar_t szUser[128]; wchar_t szPassword[128];} LoginInfoType;
[解决办法]
当你在VC中将此信息写如内存后,在C#中所需要做的就是导入那些内存映射函数并读取或写入那块内存,也就是我转载的那个程序,在C#中创建相应的结构体的示例如下:
[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 老大,我的意思就是按照你的定义这样,但是没有必要非用内存映射的。按照你那样定义两个结构体,就可以直接把这个结构体当参数在两种语言之间相互传递了,就像下面代码那么调用就行了。
[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