共享内存操作类(C#源码)[转]

 VC++的共享内存操作代码实现起来相对比较容易,但是用C#语言来实现,就有一定难度,由于工作需要,把以前VC开发的共享内存代码要用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 ;      // 写成功
        }
    }
}

测试例程: 

using  System;
using  System.Collections.Generic;
using  System.ComponentModel;
using  System.Data;
using  System.Drawing;
using  System.Text;
using  System.Windows.Forms;
using  ShareMemLib;

namespace  YFShareMem
{
    
public   partial   class  frmShareMem : Form
    {
        ShareMem MemDB
= new  ShareMem();
        
public  frmShareMem()
        {
            InitializeComponent();
        }

        
private   void  btnOpen_Click( object  sender, EventArgs e)
        {
            
if  (MemDB.Init( " YFMemTest " 10240 !=   0 )
            {
                
// 初始化失败
                MessageBox.Show( " 初始化失败 " );
            }
            
else
            {
                btnOpen.Enabled 
=   false ;
                chkWrite.Enabled 
=   true ;
                tmrTime.Enabled 
=   true ;
            }
        }

        
private   void  tmrTime_Tick( object  sender, EventArgs e)
        {
            
byte [] bytData  =   new   byte [ 16 ];
            
int  intRet  =  MemDB.Read( ref  bytData,  0 16 );
            lstData.Items.Clear(); 
            
if  (intRet  ==   0 )
            {
                
for  ( int  i  =   0 ; i  <   16 ; i ++ )
                {
                    lstData.Items.Add(bytData[i].ToString());
                }

                
if  (chkWrite.Checked)
                {
                    bytData[
0 ] ++ ;
                    bytData[
1 +=   2 ;
                    
if  (bytData[ 0 >   200 ) bytData[ 0 =   0 ;
                    
if  (bytData[ 1 >   200 ) bytData[ 1 =   0 ;
                    MemDB.Write(bytData, 
0 16 );
                }
            }           
        }

    }
}
全文】

首先还是定义非托管调用,如下:


const  int  INVALID_HANDLE_VALUE  =  - 1 ;
const  int  PAGE_READWRITE  =  0x04 ;
   //共享内存
   [ DllImport ( "Kernel32.dll" , EntryPoint = "CreateFileMapping" )]
   private  static  extern  IntPtr  CreateFileMapping ( IntPtr  hFile ,  //HANDLE hFile,
    UInt32  lpAttributes , //LPSECURITY_ATTRIBUTES lpAttributes,  //0
    UInt32  flProtect , //DWORD flProtect
    UInt32  dwMaximumSizeHigh , //DWORD dwMaximumSizeHigh,
    UInt32  dwMaximumSizeLow , //DWORD dwMaximumSizeLow,
    string  lpName //LPCTSTR lpName
    );

   [ DllImport ( "Kernel32.dll" , EntryPoint = "OpenFileMapping" )]
   private  static  extern  IntPtr  OpenFileMapping (
    UInt32  dwDesiredAccess , //DWORD dwDesiredAccess,
    int  bInheritHandle , //BOOL bInheritHandle,
    string  lpName //LPCTSTR lpName
    );

   const  int  FILE_MAP_ALL_ACCESS  =  0x0002 ;
   const  int  FILE_MAP_WRITE  =  0x0002 ;

   [ DllImport ( "Kernel32.dll" , EntryPoint = "MapViewOfFile" )]
   private  static  extern  IntPtr  MapViewOfFile (
    IntPtr  hFileMappingObject , //HANDLE hFileMappingObject,
    UInt32  dwDesiredAccess , //DWORD dwDesiredAccess
    UInt32  dwFileOffsetHight , //DWORD dwFileOffsetHigh,
    UInt32  dwFileOffsetLow , //DWORD dwFileOffsetLow,
    UInt32  dwNumberOfBytesToMap //SIZE_T dwNumberOfBytesToMap
    );

   [ DllImport ( "Kernel32.dll" , EntryPoint = "UnmapViewOfFile" )]
   private  static  extern  int  UnmapViewOfFile ( IntPtr  lpBaseAddress );

   [ DllImport ( "Kernel32.dll" , EntryPoint = "CloseHandle" )]
   private  static  extern  int  CloseHandle ( IntPtr  hObject );

然后分别在AB两个进程中定义如下两个信号量及相关变量;

   private  Semaphore  m_Write ;   //可写的信号
   private  Semaphore  m_Read ;   //可读的信号
   private  IntPtr  handle ;      //文件句柄
   private  IntPtr  addr ;        //共享内存地址
   uint  mapLength ;             //共享内存长


定义这两个信号量是为读写互斥用的。
在A进程中创建共享内存:

m_Write  =  new  Semaphore ( 1 , 1 , "WriteMap" );
m_Read  =  new  Semaphore ( 0 , 1 , "ReadMap" );
mapLength  =  1024 ;
IntPtr  hFile  =  new  IntPtr ( INVALID_HANDLE_VALUE );   
handle  =  CreateFileMapping ( hFile , 0 , PAGE_READWRITE , 0 , mapLength , "shareMemory" );
addr  =  MapViewOfFile ( handle , FILE_MAP_ALL_ACCESS , 0 , 0 , 0 );

然后再向共享内存中写入数据:

m_Write . WaitOne ();
byte []  sendStr  =  Encoding . Default . GetBytes ( txtMsg . Text  +  '\0' );
//如果要是超长的话,应另外处理,最好是分配足够的内存
if ( sendStr . Length  <  mapLength )
       Copy ( sendStr , addr );
m_Read . Release ();


这是在一个单独的方法中实现的,可多次调用,但受信号量的控制。其中txtMsg是一个文本框控件,实际中可用任意字符串,加最后的'\0'是为了让在共享内存中的字符串有一个结束符,否则在内存中取出时是以'\0'为准的,就会出现取多的情况。
Copy方法的实现如下:

static  unsafe  void  Copy ( byte []  byteSrc , IntPtr  dst )
   {
    fixed  ( byte *  pSrc  =  byteSrc )
    {
     byte *  pDst  =  ( byte *) dst ;
     byte *  psrc  =  pSrc ;
     for ( int  i = 0 ; i < byteSrc . Length ; i ++)
     {
      * pDst  =  * psrc ;
      pDst ++;
      psrc  ++;
     }
    }
   }

注意unsafe 关键字,在编译时一定要打开非安全代码开关。
最后不要忘了在A进程中关闭共享内存对象,以免内存泄露。

    UnmapViewOfFile ( addr );
    CloseHandle ( handle );


要在B进程中读取共享内存中的数据,首先要打开共享内存对象:

m_Write  =  Semaphore . OpenExisting ( "WriteMap" );
m_Read  =  Semaphore . OpenExisting ( "ReadMap" );
handle  =  OpenFileMapping ( 0x0002 , 0 , "shareMemory" );

读取共享内存中的数据:

    m_Read . WaitOne ();
    string  str  =  MapViewOfFile ( handle , FILE_MAP_ALL_ACCESS , 0 , 0 , 0 );
    txtMsg . Text  =  str ;
    m_Write . Release ();

转载于:https://www.cnblogs.com/arongbest/archive/2009/05/21/1486431.html

表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
相关推荐
很多,不写全了。。下载下来好好看 ----------Database-------------- 1.DataTable帮助(DataTableHelper.cs) 2.Access数据库文件操作辅助(JetAccessUtil.cs) 5.查询条件组合辅助(SearchCondition.cs) 6.查询信息实体(SearchInfo.cs) 8.Sql命令操作函数(可用于安装程序的时候数据库脚本执行)(SqlScriptHelper.cs) ----------Device-------------- 声音播放辅助(AudioHelper.cs) 摄像头操作辅助,包括开启、关闭、抓图、设置等功能(Camera.cs) 提供用于操作【剪切板】的方法(ClipboardHelper.cs) 获取电脑信息(Computer.cs) 提供用户硬件唯一信息的辅助(FingerprintHelper.cs) 读取指定盘符的硬盘序列号(HardwareInfoHelper.cs) 提供访问键盘当前状态的属性(KeyboardHelper.cs) 全局键盘钩子。这可以用来在全球范围内捕捉键盘输入。(KeyboardHook.cs) 模拟鼠标点击(MouseHelper.cs) 全局鼠标钩子。这可以用来在全球范围内捕获鼠标输入。(MouseHook.cs) MP3文件播放操作辅助(MP3Helper.cs) 关联文件(ExtensionAttachUtil.cs) 注册文件关联的辅助(FileAssociationsHelper.cs) 打开、保存文件对话框操作辅助(FileDialogHelper.cs) 常用的文件操作辅助FileUtil(FileUtil.cs) INI文件操作辅助(INIFileUtil.cs) 独立存储操作辅助(IsolatedStorageHelper.cs) 序列号操作辅助(Serializer.cs) 获取一个对象,它提供用于访问经常引用的目录的属性。(SpecialDirectories.cs) 简单的Word操作对象(WordCombineUtil.cs) 这个提供了一些实用的方法来换XML和对象。(XmlConvertor.cs) XML操作(XmlHelper.cs) ----------Format-------------- 参数验证的通用验证程序。(ArgumentValidation.cs) 这个提供了实用方法的字节数组和图像之间的换。(ByteImageConvertor.cs) byte字节数组操作辅助(BytesTools.cs) 处理数据换,数制换、编码换相关的(ConvertHelper.cs) CRC校验辅助(CRCUtils.cs) 枚举操作公共(EnumHelper.cs) 身份证操作辅助(IDCardHelper.cs) 检测字符编码的(IdentifyEncoding.cs) RGB颜色操作辅助(MyColors.cs) 日期操作(MyDateTime.cs) 换人民币大小金额辅助(RMBUtil.cs) 常用的字符串常量(StringConstants.cs) 简要说明TextHelper。(StringUtil.cs) 获取中文字首字拼写,随机发生器,按指定概率随机执行操作(Util.cs) 各种输入格式验证辅助(ValidateUtil.cs) ----------Network-------------- Cookie操作辅助(CookieManger.cs) FTP操作辅助(FTPHelper.cs) HTML操作(HttpHelper.cs) 网页抓取帮助(HttpWebRequestHelper.cs) Net(NetworkUtil.cs) IE代理设置辅助(ProxyHelper.cs) ----------Winform-------------- 跨线程的控件安全访问方式(CallCtrlWithThreadSafety.cs) CheckBoxList(CheckBoxListUtil.cs) 窗口管理(ChildWinManagement.cs) 由马丁·米勒http://msdn.microsoft.com/en-us/library/ms996492.aspx提供一个简单的方法打印工作的一个RichTextBox一个帮手(ExRichTextBoxPrintHelper.cs) 显示,隐藏或关闭动画形式。(FormAnimator.cs) 对窗体进行冻结、解冻操作辅助(FreezeWindowUtil.cs) 窗体全屏操作辅助(FullScreenHel
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页