ADXExcelTaskPane events not firing

Add-in Express™ Support Service
That's what is more important than anything else

ADXExcelTaskPane events not firing
 
OliverM


Guest


My add-in provides for every workbook a task pane, containing book specific information. As the information is volatile and may change various times within a single second, I delegated the job to a backgroundworker.
The worker does in no way touch the object model and is safe to use. The worker can be started and stopped with a button on the task pane. Everything works like a charme except one scenario: If the add-in is unloaded (NOT unregistered) via the COM add-in dialog. The task pane unloads but none of its event fire. As a consequence there is no chance to kill the worker. I tried to work around the issue by consuming the AddinModule_AddinBeginShutdown and cancel the worker in the event handler. I get the event I call CancelAsync but the worker does not fire its Worker_Completed event. If I then reload the add-in and start the worker process by clicking the start/stop button in the task pane everything looks like normal to the point where I stop and start the worker again.
Suddenly I have 2 workers (and of course a hell of a mess!). The new one I created after reloading the add-in and the old one I was trying to kill in the AddinModule_AddinBeginShutdown event.
This scenario holds true if I shutdown Excel after unloading the add-in, then restart Excel, reload the add-in, start-stop-start the worker as described above.

This would not happen if Form_Closing or Form_Closed would fire on AddinBeginShutdown. In a normal scenario (Add-in stays loaded and Excel shuts down) I work around the issue by consuming the Workbook_Close event and cancel the worker there.

Any ideas how to solve that?
Posted 08 Sep, 2016 11:31:42 Top
OliverM


Guest


Update

This would not happen if Form_Closing or Form_Closed would fire on AddinBeginShutdown


This conclusion was dead wrong, I got the form's closing/closed events going with

private void CurrentInstance_AddinBeginShutdown(object sender, EventArgs e)
        {
            Close();
        }


but still no luck. CancelAsync executes but the worker does not fire the Worker_Completed event.
This makes me wonder whether the moment the AddinBeginShutdown fires the message chain is already completely cut off.
Posted 08 Sep, 2016 14:13:07 Top
OliverM


Guest


I wrapped the Backgroundworker object in a helper class which holds a reference to the particular thread the worker is using. The helper class has a CancelOnAddinShutDown() method which is designed to interrupt the thread and if not successful, nuke it.

Consuming the CurrentInstance_AddinBeginShutdown event in the ADXTaskPane, I can now reliably terminate the backgroundworker thread.





private void CurrentInstance_AddinBeginShutdown(object sender, EventArgs e)
     {
        Logger.Info("Add-in is shutting down");

        _enhancedBackgroundWorker.CancelOnAddinShutDown();
     }

private void EnhancedBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
     {
        Logger.Debug("Received the workers completed event");
     }





public class EnhancedBackgroundWorker
    {
        private static readonly ILogger Logger = LogManager.GetLogger(typeof(LogManager));
        private Thread _workerThread;
        private BackgroundWorker _worker;
        
        public EnhancedBackgroundWorker()
        {
            _worker = new BackgroundWorker {WorkerSupportsCancellation = true};
            _worker.DoWork += _worker_DoWork;
            _worker.RunWorkerCompleted += _worker_RunWorkerCompleted;


        }
        
        // For sake of convenience..
        public event EventHandler<RunWorkerCompletedEventArgs> RunWorkerCompleted;

        private void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Logger.Debug("Received internal worker completed event");

            RunWorkerCompleted.Invoke(this, e);
        }

        private void _worker_DoWork(object sender, DoWorkEventArgs e)
        {
            _workerThread=Thread.CurrentThread;

            Logger.Debug("Started Backgroundworker with thread id " + _workerThread.ManagedThreadId);
            
            try
            {
                while (!_worker.CancellationPending)
                {
                    // Do something useful...
                    Thread.Sleep(1000);

                    Logger.Debug("Done another loop");
                }
            }
            catch (ThreadInterruptedException exception)
            {
                Logger.Debug("Thread id " + Thread.CurrentThread.ManagedThreadId + " has been interrupted");

            }
            catch (ThreadAbortException abortExc)
            {
                Logger.Debug("Thread id " + Thread.CurrentThread.ManagedThreadId + " has been aborted");
            }
            catch (Exception exc)
            {
                Logger.Debug("Thread id " + Thread.CurrentThread.ManagedThreadId + " Other exception: " + exc.Message);
            }

        }

        public void CancelOnAddinShutDown()
        {
            if (!_worker.IsBusy) return;

            // If in WaitSleepJoin state
            _workerThread.Interrupt();

            // Set reasonable timespan for thread to terminate
            if (!_workerThread.Join(1000))
                // Still alive? Nuke it!
                _workerThread.Abort();

            // Clean up
            _worker.Dispose();
        }

        public void RunWorkerAsync(object arguments = null)
        {
            _worker.RunWorkerAsync(arguments);
        }

        public void CancelAsync()
        {
            _worker.CancelAsync();
        }
    }



2016-09-09 14:14:29,792 [4] DEBUG - Started Backgroundworker with thread id 4
2016-09-09 14:14:30,802 [4] DEBUG - Done another loop
2016-09-09 14:14:31,803 [4] DEBUG - Done another loop
2016-09-09 14:14:32,804 [4] DEBUG - Done another loop
2016-09-09 14:14:33,769 [1] INFO - Add-in is shutting down
2016-09-09 14:14:33,778 [4] DEBUG - Thread id 4 has been interrupted
2016-09-09 14:14:33,779 [5] DEBUG - Received internal worker completed event. Thread id: 4
2016-09-09 14:14:33,780 [5] DEBUG - Received EnhancedBackgroundWorker completed event
Posted 09 Sep, 2016 07:23:29 Top
Andrei Smolin


Add-in Express team


Posts: 18829
Joined: 2006-05-11
Hello Oliver,

Thank you very much for posting the solution!


Andrei Smolin
Add-in Express Team Leader
Posted 09 Sep, 2016 07:50:31 Top