public static void AddImageToImageList(this TabControl @this, Image image, string key)
        {
#if NET40
            Contract.Requires(image != null);
            Contract.Requires(!string.IsNullOrEmpty(key));
#endif

            var imageList = @this.ImageList;
#if NET40
            Contract.Assert(imageList != null, "Can only work on TabControls with assigned ImageList.");
#endif

            imageList.Images.Add(key, image);
            if (!ImageAnimator.CanAnimate(image))
            {
                return;
            }

            var uniquePart = new Random().Next(); // NOTE: we shuffle the key to prevent users accidentially using the generated images
            string KeyGenerator(string @base, int index) => @base + "\0" + uniquePart + "\0" + index;

            var numImages     = image.GetFrameCount(FrameDimension.Time);
            var createdImages = new Dictionary <string, Image>();
            for (var i = numImages - 1; i >= 0; --i)
            {
                image.SelectActiveFrame(FrameDimension.Time, i);
                var image2 = (Image)image.Clone();
                var subKey = KeyGenerator(key, i);
                createdImages.Add(subKey, image2);
                imageList.Images.Add(subKey, image2);
            }

            var currentlyShownImageIndex = 0;

            void OnFrameChangedHandler(object _, EventArgs __)
            {
                currentlyShownImageIndex = (currentlyShownImageIndex + 1) % numImages;
                var currentKey = KeyGenerator(key, currentlyShownImageIndex);

                // refresh all tabpages using this image
                @this.SafelyInvoke(() => @this.TabPages.Cast <TabPage>().Where(t => t.ImageKey == key || t.ImageKey.StartsWith(key + "\0")).ForEach(tp => tp.ImageKey = currentKey));
            }

            // start animating
            ImageAnimator.Animate(image, OnFrameChangedHandler);

            // remove handler and dispose image on destruction of tabcontrol
            @this.Disposed += (_, __) => {
                ImageAnimator.StopAnimate(image, OnFrameChangedHandler);
                foreach (var kvp in createdImages)
                {
                    imageList.Images.RemoveByKey(kvp.Key);
                    kvp.Value.Dispose();
                }
            };
        }