Exemple #1
0
        /// <summary>
        /// Constructor.  Specify whether the mutex it to be owned initially
        /// by the caller as well as the mutex's name.  Note that with this
        /// constructor, the mutex will not be owned initially by the caller.
        /// </summary>
        /// <param name="name">Name of the mutex.</param>
        public GlobalMutex(string name)
        {
            SecurityAttributes sa = new SecurityAttributes(SecurityAccess.Unrestricted);

            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.");
            }

            this.name = name;

            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.

                string mutexName = @"Global\LT:MX:" + name;
                int    error;

retry:

                // Here's what the name abbreviations mean:
                //
                //      LT = LillTek
                //      MX = Mutex

                hMutex = WinApi.CreateMutex(sa.AttributesPtr, false, mutexName);
                error  = WinApi.GetLastError();

                if (hMutex == IntPtr.Zero)
                {
                    if (mutexName.ToLowerInvariant().StartsWith(@"global\") && error == WinErr.ERROR_ACCESS_DENIED)
                    {
                        mutexName = "LT:MX:" + name;
                        goto retry;
                    }

                    throw new Exception("Win32 mutex creation failed.");
                }
            }
            finally
            {
                sa.Close();
            }
        }
Exemple #2
0
        /// <summary>
        /// This constructor initializes the event.
        /// </summary>
        /// <param name="name">
        /// The name of the event.  The name is limited to MAX_PATH characters and
        /// is case sensitive.  May be passed as null.
        /// </param>
        /// <param name="requestedState">The requested initial event state: true for signalled.</param>
        /// <param name="actualState">This will be set to the actual state of the created event.</param>
        public GlobalManualResetEvent(string name, bool requestedState, out bool actualState)
        {
            SafeWaitHandle     hEvent;
            SecurityAttributes sa;
            int err;

            if (name != null)
            {
                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.");
                }
            }

            sa          = new SecurityAttributes(SecurityAccess.Unrestricted);
            actualState = false;
            try
            {
                // Here's what the name abbreviations mean:
                //
                //      LT = LillTek
                //      EV = Event

                if (name != null)
                {
                    name = @"Global\LT:EV:" + name;
                }

                hEvent = WinApi.CreateEvent(sa.AttributesPtr, true, requestedState, name);
                err    = WinApi.GetLastError();
                if (hEvent.IsInvalid)
                {
                    throw new Exception("Unable to create the global event.");
                }

                if (requestedState)
                {
                    actualState = err != WinApi.ERROR_ALREADY_EXISTS;
                }
            }
            finally
            {
                sa.Close();
            }

            this.name = name;
            this.evt  = new ManualResetEvent(actualState);
            this.evt.SafeWaitHandle = hEvent;
        }
Exemple #3
0
        /// <summary>
        /// Constructor.  Specify whether the mutex it to be owned initially
        /// by the caller as well as the mutex's name.
        /// </summary>
        /// <param name="requestedState">The requsted initial state of the mutex (<c>true</c> if this is to be owned by the caller).</param>
        /// <param name="name">Name of the mutex.</param>
        /// <param name="actualState">Set to <c>true</c> if ownership of the mutex was granted to the caller.</param>
        public GlobalMutex(string name, bool requestedState, out bool actualState)
        {
            SecurityAttributes sa = new SecurityAttributes(SecurityAccess.Unrestricted);
            int err;

            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.");
            }

            this.name = name;

            actualState = false;
            try
            {
                // Here's what the name abbreviations mean:
                //
                //      LT = LillTek
                //      EV = Event

                hMutex = WinApi.CreateMutex(sa.AttributesPtr, requestedState, @"Global\LT:MX:" + name);
                err    = WinApi.GetLastError();
                if (hMutex == IntPtr.Zero)
                {
                    throw new Exception("Win32 mutex creation failed.");
                }

                if (requestedState)
                {
                    actualState = err != WinApi.ERROR_ALREADY_EXISTS;
                }
            }
            finally
            {
                sa.Close();
            }
        }
Exemple #4
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;
                    }
                }
            }
        }
Exemple #5
0
        /// <summary>
        /// This constructor initializes the event.  Note that this constructor
        /// will always return an event in the reset state.
        /// </summary>
        /// <param name="name">
        /// The name of the event.  The name is limited to 128 characters and
        /// is case sensitive.  May be passed as null.
        /// </param>
        public GlobalManualResetEvent(string name)
        {
            SafeWaitHandle     hEvent;
            SecurityAttributes sa;

            if (name != null)
            {
                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.");
                }
            }

            sa = new SecurityAttributes(SecurityAccess.Unrestricted);
            try
            {
                // Here's what the name abbreviations mean:
                //
                //      LT = LillTek
                //      EV = Event

                if (name != null)
                {
                    name = @"Global\LT:EV:" + name;
                }

                // $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 merfetryory 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:

                hEvent = WinApi.CreateEvent(sa.AttributesPtr, true, false, name);

                if (hEvent.IsInvalid)
                {
                    if (name.ToLowerInvariant().StartsWith(@"global\") && WinApi.GetLastError() == WinErr.ERROR_ACCESS_DENIED)
                    {
                        name = name.Substring(7);   // @"global\".Length
                        goto retry;
                    }

                    throw new Exception("Unable to create the global event.");
                }
            }
            finally
            {
                sa.Close();
            }

            this.name = name;
            this.evt  = new ManualResetEvent(false);
            this.evt.SafeWaitHandle = hEvent;
        }