传统的应用程序间跨进程高速的传输数据有多种方式,作为Win32下的主流,很多程序中都会看到CreateFileMapping函数,这让大家分享一下如何合理而且安全的建立一个内核对象,以及整个环境的背景和作业流程。
[StructLayout(LayoutKind.Sequential)]
         internal class SECURITY_ATTRIBUTES
         {
             public int nLength;
             public SafeLocalMemHandle lpSecurityDescriptor;
             public bool bInheritHandle;
             public SECURITY_ATTRIBUTES()
             {
                 this.nLength = 12;
                 this.lpSecurityDescriptor = new SafeLocalMemHandle(IntPtr.Zero, false);
             }
         }         [SuppressUnmanagedCodeSecurity, HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort = true)]
         internal sealed class SafeFileMappingHandle : SafeHandleZeroOrMinusOneIsInvalid
         {
             [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
             internal SafeFileMappingHandle() : base(true) { }
             [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
             internal SafeFileMappingHandle(IntPtr handle, bool ownsHandle)
                 : base(ownsHandle)
             {
                 SetHandle(handle);
             }
             [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
             private static extern bool CloseHandle(IntPtr handle);
             protected override bool ReleaseHandle()
             {
                 return CloseHandle(handle);
             }        }
        [SuppressUnmanagedCodeSecurity, HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort = true)]
         internal sealed class SafeLocalMemHandle : SafeHandleZeroOrMinusOneIsInvalid
         {
             internal SafeLocalMemHandle() : base(true) { }
             [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
             internal SafeLocalMemHandle(IntPtr existingHandle, bool ownsHandle)
                 : base(ownsHandle)
             {
                 SetHandle(existingHandle);
             }
             [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
             internal static extern bool ConvertStringSecurityDescriptorToSecurityDescriptor(string StringSecurityDescriptor, int StringSDRevision, out SafeLocalMemHandle pSecurityDescriptor, IntPtr SecurityDescriptorSize);
             [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), DllImport("kernel32.dll")]
             private static extern IntPtr LocalFree(IntPtr hMem);
             protected override bool ReleaseHandle()
             {
                 return (LocalFree(handle) == IntPtr.Zero);
             }
         }        internal sealed class SafeViewOfFileHandle : SafeHandleZeroOrMinusOneIsInvalid
         {
             [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
             internal SafeViewOfFileHandle() : base(true) { }
             [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
             internal SafeViewOfFileHandle(IntPtr handle, bool ownsHandle) : base(ownsHandle) { SetHandle(handle); }
             protected override bool ReleaseHandle()
             {
                 if (UnmapViewOfFile(handle))
                 {
                     base.handle = IntPtr.Zero;
                     return true;
                 }
                 return false;
             }
         }         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;
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
         static extern SafeFileMappingHandle OpenFileMapping(int dwDesiredAccess, bool bInheritHandle, string lpName);        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
         static extern SafeFileMappingHandle CreateFileMapping(IntPtr hFile, SECURITY_ATTRIBUTES lpFileMappingAttributes, int flProtect, int dwMaximumSizeHigh, int dwMaximumSizeLow, string lpName);
         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), DllImport("kernel32.dll", ExactSpelling = true)]
         static extern bool UnmapViewOfFile(IntPtr lpBaseAddress);        [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
         static extern SafeViewOfFileHandle MapViewOfFile(SafeFileMappingHandle handle, uint dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, UIntPtr dwNumerOfBytesToMap);安全的建立非托管平台的handle是整篇我推崇的地方,因为内核对象如果以外的未能释放会产生内存泄漏,危害很严重。.net平台下PInvoke支持多种封送策略,所以尽量的使用安全的handle显得尤为重要。
下面简要讲一下环境,方法流程和顺序参数。
 环境:
 文件映射的主体是文件,所有的映射会把文件流在当前建立视图的进程区建立一个地址映射,对这个内存地址的作业,就是对文件的作业,由于是在内存中建立了映射,所以每个进程可以独立的读写自己的映射区,最后可以调用方法同步刷新到文件流上(本文内未实现)。  更为详细的介绍请自行google,需要注意的是命名对象的建立会和建立的进程相关。
方法流程和顺序参数:
 CreateFileMapping 第一位是一个文件的handle,如果用INVALID_HANDLE_VALUE将会使用默认的内存页文件作为映射。第二位是一个安全设置,为空的话会使用默认的安全控制表。第三位是读写权限和映射设置,支持OR操作。第三位是64位最大高位地址(为0,因为不会有这么大的文件)第四位是64位最大低位地址(未实际对象的物理内存长度)第五位是命名,为空是匿名对象,这里不讨论。
OpenFileMapping 第一位访问权限,第二位指定子进程是否可以共享该handle资源(涉及到handle的复制)。第三位就是命名。
MapViewOfFile第一位是上面两个方法获得的handle实例,第二位是访问权限,第三和第四位同CreateFileMapping意义上是视图相对的位移量。第五位是映射字节数,为0则映射整个建立块区。
从建立(或打开)映射开始,到建立视图,现在就可以在.net环境下使用对内存的读写了。
 可以使用Marshal类的Copy方法,前面建立的安全handle上的DangerousGetHandle()方法将返回作业的安全指针。
handle是可以自释放的。
好了到了结束部分了,本来打算用这来实现某些功能,后来发现不太符合我的需求,结果这些代码就要被我废弃了,大致上我看了十个不到的实现特例,其中以C++为主,而且这些作者都习惯性的作了包装类。
请看完这篇以后参考我的建议,不要在这之上再更多的去包装,对于简单的数据传送和共享已经够了,我觉得毫无必要再繁琐下去加一个自己命名的class也不会突现什么万一设计不当反而会招人唾骂......当然如果刻意要做什么,除非你也往里面加了很多原子操作以及其他的同步作业控制,我也不能飞过来反对。就这样吧,希望大家可以都学到知识。
 最后这些方法和常量完全的经过测试,请放心使用。
  
 
 
                     
            
        













 
                    

 
                 
                    