程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> c#讀寫共享內存操作函數封裝

c#讀寫共享內存操作函數封裝

編輯:C#入門知識

 c#共享內存操作相對c++共享內存操作來說原理是一樣,但是c#會顯得有點復雜。

        現把昨天封裝的讀寫共享內存封裝的函數記錄下來,一方面希望給需要這塊的有點幫助,另一方面則是做個備份吧。

[csharp]
/// <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); 
                //發送消息,通知接收 
                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; 
        } 
   寫共享內存函數並沒有什麼需要說明,完全按照:
創建共享內存文件(CreateFileMapping)---》映射文件視圖到調用進程的地址空間(MapViewOfFile)---》寫數據到共享內存(Marshal.StructureToPtr)----》發送消息通知需要讀共享內存的窗口(PostMessage)


[csharp]
/// <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; 
        } 
         讀共享內存,上邊代碼是一種方式,這裡是傳入一個Type類型,這樣就確保可以傳入任何類型。當讀到共享內存的數據時,采用

         public static object PtrToStructure(IntPtr ptr, Type structureType);

        函數,把非托管指針(共享內存獲得的指針)轉換為需要轉換的Type類型的對象。如果需要的話,可以通過顯示類型轉換轉換為需要的類型(例子繼續看)。

      

[csharp]
/// <summary> 
        /// 讀共享內存 
        /// </summary> 
        /// <param name="structSize">需要映射的文件的字節數量</param> 
        /// <param name="type">類型</param> 
        /// <param name="fileName">文件映射對象的名稱</param> 
        /// <returns>返回讀到的映射字節數據</returns> 
        public static byte[] 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); 
            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; 
        } 
        此代碼和第一個讀共享內存不同的是,采用byte[]讀需要的共享內存。使用托管類中的Copy來轉換指針。
[csharp]
byte[] bytes = new byte[structSize]; 
arshal.Copy(hVoid, bytes, 0, bytes.Length); 
      調用簡單例子部分代碼如下:

注:passiveInfo是NotifyInfo結構體對象。

      寫共享內存:


[csharp]
int iRet = publicInfo.WriteToMemory((uint)Marshal.SizeOf(passiveInfo),(Object)passiveInfo, "memName","FormMsg",(uint)publicInfo.WM_NOTIFY); 
     讀共享內存:

第一種情況調用:

[csharp]
passiveInfo = (NotifyPassiveInfo)publicInfo.ReadFromMemory((uint)Marshal.SizeOf(passiveInfo), typeof(NotifyPassiveInfo), publicInfo.SN_PASSIVEINFO); 
      第二種情況調用:
[csharp]
byte[] bytes = publicInfo.ReadFromMemory((uint)Marshal.SizeOf(passiveInfo), "memName"); 
passiveInfo = (NotifyInfo)BytesToStuct(bytes, typeof(NotifyInfo)); 

      希望對你有幫助。



摘自 richerg85的專欄

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved