您的位置:首页 > 编程语言 > C#

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

2009-05-21 16:39 447 查看
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();
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: