Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Visual Studio Excel Add-in: How can I detect Excel Office Theme Change?

I wrote a class that detects what is the current Excel theme.

Get Excel current office theme:

//Declaration
string officeVersion;
int themeCode;

// Get Office Version first
officeVersion = "16.0";

// Goto the Registry Current Version
RegistryKey rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Office\" + officeVersion + @"\Common");

// Get Stored Theme
themeCode = (int)rk.GetValue("UI Theme", GlobalVar.COLORFUL);

Then based on the value of themeCode, I can determine what the current Excel theme is:

// Theme Constants
public const int COLORFUL = 0;
public const int DARKGREY = 3;
public const int BLACK = 4;
public const int WHITE = 5;

My question:

  • How can I detect when the user, during Excel Running, change the Office Theme from the Excel Options?
  • In Another way, is there any Excel Event triggered when the User has edited anything from the Excel Options?
  • How can I detect/trap that event please?

enter image description here

I used already Process Monitor and got the location of the Registry key where the theme is stored. But I cannot constantly check the Registry, I prefer to detect when the user clicked on More Commmand\Excel Options if that event is detectable.

Your answer and suggestions are most welcome. Thanks in advance!

like image 690
Tsiry Rakotonirina Avatar asked Nov 07 '22 08:11

Tsiry Rakotonirina


1 Answers

Great thanks to @PortlandRunner for the approach he gave me in the comments. I came up with the following code:

using Microsoft.Win32;
using System;
using System.Drawing;
using System.Management;
using System.Security.Principal;

namespace YourProject
{
    /*
     #####################################
     # GLOBAL CONSTANTS FOR OFFICE THEME #
     # By Tsiriniaina Rakotonirina       #
     #####################################
     */
    public class GlobalVar
    {
        //Theme Constants
        public const int COLORFUL = 0;
        public const int DARKGREY = 3;
        public const int BLACK = 4;
        public const int WHITE = 5;
    }

    /*
     ########################################
     # OFFICE CLASS TO RETURN TO THE ADDINS #
     # By Tsiriniaina Rakotonirina          #
     ########################################
     */
    public class ExcelTheme
    {
        private int code;             //Theme Code               
        private Color backgroundColor;//Addins Backcolor based on Theme
        private Color textForeColor;  //Addins Text Color based on Theme

        public Color BackgroundColor { get => backgroundColor; set => backgroundColor = value; }
        public Color TextForeColor { get => textForeColor; set => textForeColor = value; }
        public int Code { get => code; set => code = value; }
    }

    /*
     ###############################
     # OFFICE THEME CHANGE WATCHER #
     # By Tsiriniaina Rakotonirina #
     ###############################
     */
    class ExcelThemeWatcher
    {
        /*
         *****************************************
         * CLASS CONSTRUCTOR                     *
         * ---> The Watch start right away after *
         *      the class is created             *
         *****************************************
         */
        public ExcelThemeWatcher()
        {
            //Start Watching Office Theme Change
            //By calling the following method
            StartThemeWatcher();
        }

        /*
         *****************************************
         * GET OFFICE VERSION                    *
         * ---> Read the Registry and            *
         *      get the Current Office Version   *
         *****************************************
         */
        public int GetOfficeVersion()
        {
            //Get Current Excel Version
            try
            {
                //Get Office Version
                //Goto the Registry Current Version
                RegistryKey rk = Registry.ClassesRoot.OpenSubKey(@"Excel.Application\\CurVer");

                //Read Current Version
                string officeVersion = rk.GetValue("").ToString();

                //Office Version
                string officeNumberVersion = officeVersion.Split('.')[officeVersion.Split('.').GetUpperBound(0)];

                //Return Office Version
                return Int32.Parse(officeNumberVersion);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return 0;
            }
        }

        /*
         *****************************************
         * GET OFFICE THEME                      *
         * ---> Read the Registry and            *
         *      get the Current Office Theme     *
         *****************************************
         */
        private int GetRegistryOfficeTheme()
        {
            //Get Office Version first
            string officeVersion = GetOfficeVersion().ToString("F1");

            //Goto the Registry Current Version
            RegistryKey rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Office\" + officeVersion + @"\Common");

            return Convert.ToInt32(rk.GetValue("UI Theme", GlobalVar.COLORFUL));
        }

        /*
         *****************************************
         * GET ADDINS THEME                      *
         * ---> Based on the Office Theme        *
         *      Return the Addins Theme          *
         *****************************************
         */
        public ExcelTheme GetAddinsTheme()
        {
            ExcelTheme theme = new ExcelTheme();

            //Default Theme Code
            theme.Code = GetRegistryOfficeTheme();

            //Get Background Colors
            theme.BackgroundColor = ColorTranslator.FromHtml("#EFE9D7");
            theme.TextForeColor = ColorTranslator.FromHtml("#004B8D");

            try
            {
                switch (theme.Code)
                {
                    case GlobalVar.COLORFUL:
                        theme.BackgroundColor = ColorTranslator.FromHtml("#E6E6E6");
                        theme.TextForeColor = ColorTranslator.FromHtml("#004B8D");

                        break;

                    case GlobalVar.DARKGREY:
                        theme.BackgroundColor = ColorTranslator.FromHtml("#666666");
                        theme.TextForeColor = ColorTranslator.FromHtml("White");
                        break;

                    case GlobalVar.BLACK:
                        theme.BackgroundColor = ColorTranslator.FromHtml("#323130");
                        theme.TextForeColor = ColorTranslator.FromHtml("#CCA03B");
                        break;

                    case GlobalVar.WHITE:
                        theme.BackgroundColor = ColorTranslator.FromHtml("#FFFFFF");
                        theme.TextForeColor = ColorTranslator.FromHtml("#004B8D");

                        break;

                    default:
                        break;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            return theme;
        }

        /*
         ******************************************
         * START OFFICE THEME CHANGE WATCH        *
         * ---> Using WMI, read and watch         *
         *      Registry Section for Office Theme *
         ******************************************
         */
        private void StartThemeWatcher()
        {
            string keyPath;   //Office Theme Path
            string valueName; //Office Theme Value name

            //Get Office Version first
            string officeVersion = GetOfficeVersion().ToString("F1");

            //Set the KeyPath based on the Office Version
            keyPath = @"Software\\Microsoft\\Office\\" + officeVersion + "\\Common";
            valueName = "UI Theme";

            //Get the Current User ID
            //---> HKEY_CURRENT_USER doesn't contain Value as it is a shortcut of HKEY_USERS + User ID
            //     That is why we get that currentUser ID and use it to read the wanted location

            //Get the User ID
            var currentUser = WindowsIdentity.GetCurrent();

            //Build the Query based on 3 parameters
            //Param #1: User ID
            //Param #2: Location or Path of the Registry Key
            //Param #3: Registry Value to watch
            var query = new WqlEventQuery(string.Format(
                    "SELECT * FROM RegistryValueChangeEvent WHERE Hive='HKEY_USERS' AND KeyPath='{0}\\\\{1}' AND ValueName='{2}'",
                    currentUser.User.Value, keyPath.Replace("\\", "\\\\"), valueName));

            //Create a Watcher based on the "query" we just built
            ManagementEventWatcher watcher = new ManagementEventWatcher(query);

            //Create the Event using the "Function" to fire up, here called "KeyValueChanged"
            watcher.EventArrived += (sender, args) => KeyValueChanged();

            //Start the Watcher
            watcher.Start();

        }

        /*
         ******************************************
         * EVENT FIRED UP WHEN CHANGE OCCURS      *
         * ---> Here the event is instructed      *
         *      to update the Addins Theme        *
         ******************************************
         */
        private void KeyValueChanged()
        {
            // Here, whenever the user change the Office theme,
            // this function will automatically Update the Addins Theme
            Globals.ThisAddIn.SetAddinsInterfaceTheme();
        }
    }

}

I didn't feel the need to stop the watcher, but if you came up with the idea, tell me where to put it ;)

UPDATE:

It's good to tell as well that I was so existed when I tested to change the Office Theme and saw my Addins theme change as well. Would love to hear from you as well!

like image 107
Tsiry Rakotonirina Avatar answered Nov 12 '22 22:11

Tsiry Rakotonirina