using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace ryCommon.Model
{
    public class ryMemoryShare
    {
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, IntPtr lParam);

        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr CreateFileMapping(int hFile, IntPtr lpAttributes, uint flProtect, uint dwMaxSizeHi, uint dwMaxSizeLow, string lpName);

        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr OpenFileMapping(uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, string lpName);

        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr MapViewOfFile(IntPtr hFileMapping, uint dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, uint dwNumberOfBytesToMap);

        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
        private static extern bool UnmapViewOfFile(IntPtr pvBaseAddress);

        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
        private static extern bool CloseHandle(IntPtr handle);
        [DllImport("kernel32", EntryPoint = "GetLastError")]
        private static extern int GetLastError();
        [DllImport("user32.dll", EntryPoint = "FindWindow")]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        [DllImport("User32.dll")]
        private static extern bool PostMessage(IntPtr hWnd, uint uMsg, int wParam, int lParam);
        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;
        /// <summary>
        /// 写共享内存
        /// </summary>
        /// <param name="structSize">需要映射的文件的字节数量</param>
        /// <param name="obj">映射对象（简单类型、结构体等）</param>
        /// <param name="fileName">文件映射对象的名称</param>
        /// <returns></returns>
        public static int WriteToMemory(uint structSize, Object obj, string fileName)
        {
            return WriteToMemory(structSize, obj, fileName, null, 0);
        }
        /// <summary>
        /// 写共享内存
        /// </summary>
        /// <param name="structSize">需要映射的文件的字节数量</param>
        /// <param name="obj">映射对象（简单类型、结构体等）</param>
        /// <param name="fileName">文件映射对象的名称</param>
        /// <param name="windowName">发送消息的窗口句柄</param>
        /// <param name="Msg">发送消息</param>
        /// <returns></returns>
        public static int WriteToMemory(uint structSize, Object obj, string fileName, string windowName, uint Msg)
        {
            IntPtr hShareMemoryHandle = IntPtr.Zero;
            IntPtr hVoid = IntPtr.Zero;

            //判断参数的合法性
            if (structSize > 0 && fileName.Length > 0)
            {
                hShareMemoryHandle = CreateFileMapping(INVALID_HANDLE_VALUE, IntPtr.Zero, (uint)PAGE_READWRITE, 0, (uint)structSize, fileName);
                if (hShareMemoryHandle == IntPtr.Zero)
                {
                    //创建共享内存失败，记log
                   // MessageBox.Show("创建共享内存失败" + publicInfo.GetLastError().ToString());
                    return -2;
                }
                else
                {
                    if (ERROR_ALREADY_EXISTS == GetLastError())
                    {
                        //共享内存已经存在，记log
                        //MessageBox.Show("共享内存已经存在");
                        return -3;
                    }
                }
                hVoid = MapViewOfFile(hShareMemoryHandle, FILE_MAP_WRITE, 0, 0, structSize);
                if (hVoid == IntPtr.Zero)
                {
                    CloseHandle(hShareMemoryHandle);
                    //文件映射失败，记log
                    //MessageBox.Show("文件映射失败");
                    return -4;
                }
                Marshal.StructureToPtr(obj, hVoid, false);
                //发送消息，通知接收
                if (windowName != null)
                {
                    IntPtr handle = FindWindow(null, windowName.Trim());
                    if (handle == IntPtr.Zero)
                    {
                        //查找窗口失败，记log
                        //MessageBox.Show("查找窗口失败");
                        return -5;
                    }
                    else
                    {
                        if (PostMessage(handle, (uint)Msg, 0, 0))
                        {
                            //发送消息成功
                            //MessageBox.Show("写共享内存，通知发送消息成功");
                        }
                    }
                }
            }
            else
            {
                //参数不合法，记log
                //MessageBox.Show("共享内存已经存在");
                return -1;
            }
            return 0;
        }
        /// <summary>
        /// 读共享内存
        /// </summary>
        /// <param name="structSize">需要映射的文件的字节数量</param>
        /// <param name="type">类型</param>
        /// <param name="fileName">文件映射对象的名称</param>
        /// <returns>返回读到的映射对象</returns>
        public static Object ReadFromMemory(uint structSize, Type type, string fileName)
        {

            IntPtr hMappingHandle = IntPtr.Zero;
            IntPtr hVoid = IntPtr.Zero;

            hMappingHandle = OpenFileMapping((uint)FILE_MAP_READ, false, fileName);
            if (hMappingHandle == IntPtr.Zero)
            {
                //打开共享内存失败，记log
                //MessageBox.Show("打开共享内存失败:" + publicInfo.GetLastError().ToString());
                return null;
            }
            hVoid = MapViewOfFile(hMappingHandle, FILE_MAP_READ, 0, 0, structSize);
            if (hVoid == IntPtr.Zero)
            {
                //文件映射失败，记log
               // MessageBox.Show("文件映射失败——读共享内存");
                return null;
            }

            Object obj = Marshal.PtrToStructure(hVoid, type);

            if (hVoid != IntPtr.Zero)
            {
                UnmapViewOfFile(hVoid);
                hVoid = IntPtr.Zero;
            }
            if (hMappingHandle != IntPtr.Zero)
            {
                CloseHandle(hMappingHandle);
                hMappingHandle = IntPtr.Zero;
            }
            return obj;
        }
        /// <summary>
        /// 读共享内存
        /// </summary>
        /// <param name="structSize">需要映射的文件的字节数量</param>
        /// <param name="type">类型</param>
        /// <param name="fileName">文件映射对象的名称</param>
        /// <returns>返回读到的映射字节数据</returns>
        public static byte[] ReadFromMemory2(uint structSize, Type type, string fileName)
        {

            IntPtr hMappingHandle = IntPtr.Zero;
            IntPtr hVoid = IntPtr.Zero;

            hMappingHandle = OpenFileMapping((uint)FILE_MAP_READ, false, fileName);
            if (hMappingHandle == IntPtr.Zero)
            {
                //打开共享内存失败，记log
                //MessageBox.Show("打开共享内存失败:" + publicInfo.GetLastError().ToString());
                return null;
            }
            hVoid = MapViewOfFile(hMappingHandle, FILE_MAP_READ, 0, 0, structSize);
            if (hVoid == IntPtr.Zero)
            {
                //文件映射失败，记log
                //MessageBox.Show("文件映射失败——读共享内存");
                return null;
            }

            //Object obj = Marshal.PtrToStructure(hVoid, type);
            byte[] bytes = new byte[structSize];
            Marshal.Copy(hVoid, bytes, 0, bytes.Length);

            if (hVoid != IntPtr.Zero)
            {
                UnmapViewOfFile(hVoid);
                hVoid = IntPtr.Zero;
            }
            if (hMappingHandle != IntPtr.Zero)
            {
                CloseHandle(hMappingHandle);
                hMappingHandle = IntPtr.Zero;
            }
            return bytes;
        }
    }
}
