Exemple #1
0
 /// <summary>
 /// Default constructor.
 /// </summary>
 public SharedMem()
 {
     m_hMap    = IntPtr.Zero;
     m_pvBlock = null;
     m_cLock   = 0;
     m_cbBlock = 0;
     m_mutex   = null;
 }
Exemple #2
0
        /// <summary>
        /// This method creates a shared memory object with the name passed in pszName
        /// and size of cbMem.  The method returns <c>true</c> if the memory was created
        /// successfully, <c>false</c> if the operation failed for some reason.  If the shared
        /// memory block is being created for the first time then this method will
        /// zero the memory block.  If the shared memory block has already been created
        /// then this method will link to the existing block.  Note that any successfull
        /// call to Open() needs to be matched by a call to <see cref="Close" />.  This method is
        /// threadsafe.
        /// </summary>
        /// <param name="name">
        /// Name of the inbox.  This can be a maximum of 128 characters and may
        /// not include the backslash (\) character.
        /// </param>
        /// <param name="cbMem">Size of the memory in bytes.</param>
        /// <param name="mode">The opening mode.</param>
        public void Open(string name, int cbMem, OpenMode mode)
        {
            string memName;
            string mutexName;
            bool   fExists;
            bool   createdNew;

            if (name.Length > 128)
            {
                throw new ArgumentException("Name exceeds 128 characters.", "name");
            }

            if (name.IndexOfAny(new char[] { '/', '\\' }) != -1)
            {
                throw new ArgumentException("Name may not include forward or backslashes.");
            }

            lock (syncLock)
            {
                Assertion.Test(m_hMap == IntPtr.Zero);

                // Here's what the abbreviations mean:
                //
                //      LT  = LillTek
                //      SM  = SharedMem

                memName = @"Global\LT:SM:" + name;

#if SHAREDMEM_DRIVER
                bool fCreated;

                m_hMap  = WinApi.MEM_Open(memName, cbMem, out fCreated);
                fExists = !fCreated;
#else
                // Create the memory object

                SecurityAttributes sa;

                sa = new SecurityAttributes(SecurityAccess.Unrestricted);

                try
                {
                    // $hack(jeff.lill):
                    //
                    // Beginning with a late service Windows XP service pack, applications not running in
                    // Windows session 0 as a service cannot create global shared memory or other objects.
                    // This results in the API below failing by returning a NULL handle and GetLastError()
                    // returning ERROR_ACCESS_DENIED.  Windows added this restriction to prevent malicious
                    // code from creating global objects that will be used by well known services and then
                    // squating on them.
                    //
                    // The work-around below detects this situation and tries creating a non-global object
                    // instead.  This will work for most unit testing scenarios.

retry:

                    m_hMap = WinApi.CreateFileMapping(new IntPtr(-1), sa.AttributesPtr, WinApi.PAGE_READWRITE, 0, (uint)cbMem, memName);
                    if (m_hMap == IntPtr.Zero)
                    {
                        int error = WinApi.GetLastError();

                        if (memName.ToLowerInvariant().StartsWith(@"global\") && error == WinErr.ERROR_ACCESS_DENIED)
                        {
                            memName = "LT:SM:" + name;
                            goto retry;
                        }

                        throw new InvalidOperationException(string.Format(null, "Failed on Windows error [{0}].", error));
                    }

                    // For some weird reason, Marshal.GetLastWin32Error() is returning ERROR_IO_PENDING
                    // when CreateFileMapping() is called on an exising block of shared memory instead
                    // of returning ERROR_ALREADY_EXISTS.  So I'm going to call GetLastError() directly.
                    // This will be a bit of a performance hit but Open() will be called infrequently
                    // in real applications.

                    fExists = WinApi.GetLastError() == WinApi.ERROR_ALREADY_EXISTS;
                }
                finally
                {
                    sa.Close();
                }
#endif // SHAREDMEM_DRIVER

                m_pvBlock = null;
                m_cbBlock = cbMem;
                m_cLock   = 0;

                if (!fExists && mode == OpenMode.OPEN_ONLY)
                {
#if SHAREDMEM_DRIVER
                    WinApi.MEM_Close(m_hMap);
#else
                    WinApi.CloseHandle(m_hMap);
#endif
                    m_hMap = IntPtr.Zero;
                    throw new InvalidOperationException("Shared memory does not exist.");
                }
                else if (fExists && mode == OpenMode.CREATE_ONLY)
                {
#if SHAREDMEM_DRIVER
                    WinApi.MEM_Close(m_hMap);
#else
                    WinApi.CloseHandle(m_hMap);
#endif
                    m_hMap = IntPtr.Zero;
                    throw new InvalidOperationException("Shared memory already exists.");
                }

                // Here's what the abbreviations mean:
                //
                //      LT = LillTek
                //      SM = Shared Memory
                //      MX = Mutex

                mutexName = "LT:SM:MX:" + name;
                if (fExists)
                {
                    try
                    {
                        // Open the mutex

                        m_mutex = new GlobalMutex(mutexName);
                    }
                    catch
                    {
#if SHAREDMEM_DRIVER
                        WinApi.MEM_Close(m_hMap);
#else
                        WinApi.CloseHandle(m_hMap);
#endif
                        m_hMap = IntPtr.Zero;
                        throw;
                    }
                }
                else
                {
                    try
                    {
                        // Create the mutex

                        m_mutex = new GlobalMutex(mutexName, true, out createdNew);
                        if (createdNew)
                        {
                            // Map the shared memory and zero it.

                            byte *p;

                            p = Lock();
                            for (int i = 0; i < m_cbBlock; p[i++] = 0)
                            {
                                ;
                            }
                            Unlock();

                            m_mutex.ReleaseMutex();
                        }
                    }
                    catch
                    {
#if SHAREDMEM_DRIVER
                        WinApi.MEM_Close(m_hMap);
#else
                        WinApi.CloseHandle(m_hMap);
#endif
                        m_hMap = IntPtr.Zero;
                        throw;
                    }
                }
            }
        }