关于C#与C++共享内存空间时string类型映射的问题

本文介绍了一个具体的案例,演示如何通过共享内存机制在C#与C++程序间进行数据交换。详细展示了创建共享内存的过程,并针对字符串传递的问题进行了深入探讨与解决。

首先是网上抄来的方法。

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++还是不太熟悉。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值