首先是网上抄来的方法。
C#程序创建共享空间
public struct ServiceMsg
{
public int Id;
public long NowTime;
public string Message;
}
public unsafe void CreateShare()
{
//定义内存大小
int size = 1024;
//创建共享内存
MemoryMappedFile shareMemory = MemoryMappedFile.CreateOrOpen("shareTest", size);
Debug.WriteLine("创建共享内存完成...");
var stream = shareMemory.CreateViewStream(0, size);
ServiceMsg serviceMsg = new ServiceMsg()
{
Id = 1,
NowTime = DateTime.Now.Ticks,
Message = "Im CSharp"
};
Debug.WriteLine($"写入数据 id{serviceMsg.Id} , nowTime{serviceMsg.NowTime}, message{serviceMsg.Message}");
int typeSize = Marshal.SizeOf(serviceMsg);
byte[] data = new byte[typeSize];
fixed (byte* pb = &data[0])
{
Marshal.StructureToPtr(serviceMsg, new IntPtr(pb), true);
}
stream.Write(data);
//线程等待10秒
System.Threading.Thread.Sleep(10000);
stream.Dispose();
}
C++程序接入共享内存
struct ServiceMsg
{
int Id;
INT64 NowTime;
char* Message;
};
int main()
{
LPVOID pBuffer;
string strMapName("shareTest");
HANDLE hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, 0, strMapName.c_str());
if (NULL == hMap)
{
cout << "无共享内存..." << endl;
}
else
{
while (true)
{
Sleep(1000);
pBuffer = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
ServiceMsg* data = (ServiceMsg*)pBuffer;
//std::string cliToStd = marshal_as<std::string>(data->Message);
cout << "读取共享内存数据:Id:" << data->Id << "NowTime:" << data->NowTime << "Message:" << data->Message << endl;
}
}
}
运行结果:C++只能获取Id和NowTime字段的值,Message无法获取。
查找原因:
1.查看C#内存发现Message存放的是一个指针,指向了C#进程空间的地址。
很明显,圈出来的地方就是Message存放的地址,转到该地址0x000001BA7884D3B0就是我们Message的内容。
2.既然C#将地址写入了共享内存,那么来看看C++中该地址是什么。
转到该地址,什么也没有,这地址不在C++程序的内存范围内。Message的地址当然不在C++的内存空间中。
解决问题:
我们可以给Messahe字段加上[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 30)]特性,注意SizeConst需要大于等于你给定的字符串长度,否则会截取。
然后在C++中使用char[]接收Message
//C#
public struct ServiceMsg
{
public int Id;
public long NowTime;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 30)]
public string Message;
}
//C++
struct ServiceMsg
{
int Id;
INT64 NowTime;
char Message[];
};
查看结果:
其他:
我尝试在C++中使用std::string来接收Message,但发现其指向了p字符,不太清楚怎么回事,对C++还是不太熟悉。