/// <summary>
        /// Monitor changes in the registry.
        /// Note: This operation is the main Run() loop for the Registry Monitor Thread.
        /// </summary>
        private void MonitorChanges()
        {
            //use a hashtable to keep track of bulk changes to the registry so that we only fire one event each
            //if multiple changes are made to the registry at once (like when a key is renamed)
            Hashtable regChangeList = new Hashtable();
            while (true)
            {
                SafeHandle[] monitorHandles;
                RegistryKeyMonitor[] monitors;

                lock (this) //lock here so that we don't encounter race conditions if registry listeners are being added/removed
                {
                    monitorHandles = MonitorHandles;
                    monitors = (RegistryKeyMonitor[])ArrayHelper.CollectionToArray(keyMonitors.Values, (typeof(RegistryKeyMonitor)));
                }

                using (SafeHandleArrayHelper safeHandleArrayHelper = new SafeHandleArrayHelper(monitorHandles))
                {
                    uint result =
                        Kernel32.WaitForMultipleObjects((uint)monitorHandles.Length, safeHandleArrayHelper.IntPtrs, false,
                                                        Kernel32.INFINITE);
                    if (result >= 0 && result < FIXED_MONITOR_EVENTS.Length)
                    {
                        //a FIXED_MONITOR_EVENT occured, so handle it.
                        if (result == MONITOR_HANDLES_UPDATED_INDEX)
                        {
                            //the monitorHandlesUpdatedEvent was signalled, so reset it and re-loop
                            //so that we get the latest list of events to monitor.
                            monitorHandlesUpdatedEvent.Reset();
                        }
                        else if (result == MONITOR_ABORT_INDEX)
                        {
                            //the monitorAbortEvent was signaled, so exit the method.
                            //Debug.WriteLine("registry monitor stopped", "RegistryMonitor");
                            monitorAbortEvent.Reset();
                            return;
                        }
                        else
                        {
                            Debug.Fail("unknown FIXED_MONITOR_EVENT detected!");
                        }
                    }
                    else if (result >= WAIT.OBJECT_0 && result <= (WAIT.OBJECT_0 + monitorHandles.Length - 1))
                    {
                        //one or more registry keys have changed, so loop to gather up all of the signaled events
                        uint nextResult = result;
                        while ((result >= WAIT.OBJECT_0 && result <= (WAIT.OBJECT_0 + monitorHandles.Length - 1))
                               && !(result >= 0 && result < FIXED_MONITOR_EVENTS.Length))
                        {
                            //a registry change event occured, so add the monitor to the notification list.
                            RegistryKeyMonitor keyMonitor = monitors[result - FIXED_MONITOR_EVENTS.Length];
                            regChangeList[keyMonitor.FullKey] = keyMonitor;

                            //re-register the monitor for change events from the OS
                            RegisterForRegistryKeyChanged(keyMonitor);

                            //get the next pending event from the kernel (without blocking)
                            result =
                                Kernel32.WaitForMultipleObjects((uint)monitorHandles.Length, safeHandleArrayHelper.IntPtrs, false, 0);
                        }

                        //notify the listeners the keys have changed (use the backgroundWorkerQueue so that this thread can't get hosed!)
                        RegistryKeyMonitor[] changedMonitors =
                            (RegistryKeyMonitor[])
                            ArrayHelper.CollectionToArray(regChangeList.Values, typeof(RegistryKeyMonitor));
                        workerQueue.AddWorker(new WaitCallback(backgroundWorker_HandleRegistryKeyChanged),
                                              changedMonitors);

                        //clear the change list.
                        regChangeList.Clear();
                    }
                    else if (result == WAIT.FAILED)
                    {
                        Debug.Fail("Wait failed: " + Marshal.GetLastWin32Error());
                    }
                    else if (result == WAIT.TIMEOUT)
                    {
                        //just re-loop so that we have the latest list of events to monitor.
                    }
                    else
                    {
                        Debug.Fail("unexpected WaitForMultipleObjects() return code!: " + result);
                    }
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Monitor changes in the registry.
        /// Note: This operation is the main Run() loop for the Registry Monitor Thread.
        /// </summary>
        private void MonitorChanges()
        {
            //use a hashtable to keep track of bulk changes to the registry so that we only fire one event each
            //if multiple changes are made to the registry at once (like when a key is renamed)
            Hashtable regChangeList = new Hashtable();

            while (true)
            {
                SafeHandle[]         monitorHandles;
                RegistryKeyMonitor[] monitors;

                lock (this)                //lock here so that we don't encounter race conditions if registry listeners are being added/removed
                {
                    monitorHandles = MonitorHandles;
                    monitors       = (RegistryKeyMonitor[])ArrayHelper.CollectionToArray(keyMonitors.Values, (typeof(RegistryKeyMonitor)));
                }

                using (SafeHandleArrayHelper safeHandleArrayHelper = new SafeHandleArrayHelper(monitorHandles))
                {
                    uint result =
                        Kernel32.WaitForMultipleObjects((uint)monitorHandles.Length, safeHandleArrayHelper.IntPtrs, false,
                                                        Kernel32.INFINITE);
                    if (result >= 0 && result < FIXED_MONITOR_EVENTS.Length)
                    {
                        //a FIXED_MONITOR_EVENT occured, so handle it.
                        if (result == MONITOR_HANDLES_UPDATED_INDEX)
                        {
                            //the monitorHandlesUpdatedEvent was signalled, so reset it and re-loop
                            //so that we get the latest list of events to monitor.
                            monitorHandlesUpdatedEvent.Reset();
                        }
                        else if (result == MONITOR_ABORT_INDEX)
                        {
                            //the monitorAbortEvent was signaled, so exit the method.
                            //Debug.WriteLine("registry monitor stopped", "RegistryMonitor");
                            monitorAbortEvent.Reset();
                            return;
                        }
                        else
                        {
                            Debug.Fail("unknown FIXED_MONITOR_EVENT detected!");
                        }
                    }
                    else if (result >= WAIT.OBJECT_0 && result <= (WAIT.OBJECT_0 + monitorHandles.Length - 1))
                    {
                        //one or more registry keys have changed, so loop to gather up all of the signaled events
                        uint nextResult = result;
                        while ((result >= WAIT.OBJECT_0 && result <= (WAIT.OBJECT_0 + monitorHandles.Length - 1)) &&
                               !(result >= 0 && result < FIXED_MONITOR_EVENTS.Length))
                        {
                            //a registry change event occured, so add the monitor to the notification list.
                            RegistryKeyMonitor keyMonitor = monitors[result - FIXED_MONITOR_EVENTS.Length];
                            regChangeList[keyMonitor.FullKey] = keyMonitor;

                            //re-register the monitor for change events from the OS
                            RegisterForRegistryKeyChanged(keyMonitor);

                            //get the next pending event from the kernel (without blocking)
                            result =
                                Kernel32.WaitForMultipleObjects((uint)monitorHandles.Length, safeHandleArrayHelper.IntPtrs, false, 0);
                        }

                        //notify the listeners the keys have changed (use the backgroundWorkerQueue so that this thread can't get hosed!)
                        RegistryKeyMonitor[] changedMonitors =
                            (RegistryKeyMonitor[])
                            ArrayHelper.CollectionToArray(regChangeList.Values, typeof(RegistryKeyMonitor));
                        workerQueue.AddWorker(new WaitCallback(backgroundWorker_HandleRegistryKeyChanged),
                                              changedMonitors);

                        //clear the change list.
                        regChangeList.Clear();
                    }
                    else if (result == WAIT.FAILED)
                    {
                        Debug.Fail("Wait failed: " + Marshal.GetLastWin32Error());
                    }
                    else if (result == WAIT.TIMEOUT)
                    {
                        //just re-loop so that we have the latest list of events to monitor.
                    }
                    else
                    {
                        Debug.Fail("unexpected WaitForMultipleObjects() return code!: " + result);
                    }
                }
            }
        }