Beispiel #1
0
        public static CustomTaskPane CreateCustomTaskPane(Type userControlType, string title, object parent)
        {
            //if (!typeof(System.Windows.Forms.UserControl).IsAssignableFrom(userControlType))
            //{
            //    throw new ArgumentException("userControlType for Custom Task Pane must be derive from type System.Windows.Forms.UserControl");
            //}

            // I could use the ProgId and ClsId of the UserControl type here.
            // But then the reigstration has to be persistent or coordinated, which I dislike.
            // It's already a problem for the RTD servers.
            // Users that want persistent and consistent names, can sort out registration themselves, or use the ExcelComClass support.
            // Then the CTP is created through the CreateCustomTaskPane("My.ProgId",...) overloads.

            // So when passed the type, I always synthesize a progid.
            // We pick a new Guid as ClassId for this add-in...
            Guid clsId = Guid.NewGuid();
            // ...and make the ProgId from this Guid - max 39 chars.
            string progId = "CtpSrv." + clsId.ToString("N");

            // Register UserControl
            // (could probably get away with RegistrationServices.RegisterTypeForComClients instead of our own ClassFactoryRegistration class)
            using (ProgIdRegistration progIdReg = new ProgIdRegistration(progId, clsId))
            using (ClsIdRegistration clsIdReg = new ClsIdRegistration(clsId, progId))
            using (ClassFactoryRegistration cf = new ClassFactoryRegistration(userControlType, clsId))
            {
                return CreateCustomTaskPane(progId, title, parent);
            }
        }
Beispiel #2
0
        // Forwarded from XlCall
        public static object RTD(string progId, string server, params string[] topics)
        {
            // Check if this is any of our business.
            if (!string.IsNullOrEmpty(server) || !registeredRtdServerTypes.ContainsKey(progId))
            {
                // Just pass on to Excel.
                return CallRTD(progId, null, topics);
            }

            // Check if already loaded.
            if (loadedRtdServers.ContainsKey(progId))
            {
                // Call Excel using the synthetic RtdSrv.xxx (or actual from attribute) ProgId
                return CallRTD(loadedRtdServers[progId], null, topics);
            }

            // Not loaded already - need to get the Rtd server loaded

            // TODO: Need to reconsider registration here.....
            // Sometimes need stable ProgIds.

            Type rtdServerType = registeredRtdServerTypes[progId];
            object rtdServer = Activator.CreateInstance(rtdServerType);
            RtdServerWrapper rtdServerWrapper = new RtdServerWrapper(rtdServer, progId);

            // We pick a new Guid as ClassId for this add-in...
            CLSID clsId = Guid.NewGuid();
            
            // ... but take a stable ProgId from the XllPath and type's FullName - max 39 chars.
            // ... (bad idea - this will cause Excel to try to load this RTD server while it is not registered.)
            // Guid typeGuid = GetGuidFromString(DnaLibrary.XllPath + ":" + rtdServerType.FullName);
            // string progIdRegistered = "RtdSrv." + typeGuid.ToString("N");

            // by making a fresh progId, we are sure Excel will try to load when we are ready.
            string progIdRegistered = "RtdSrv." + clsId.ToString("N");
            Debug.Print("RTD - Using ProgId: {0} for type: {1}", progIdRegistered, rtdServerType.FullName);

            // Mark as loaded - ServerTerminate in the wrapper will remove.
            // TODO: Consider multithread race condition...
            loadedRtdServers[progId] = progIdRegistered;
            using (SingletonClassFactoryRegistration regClassFactory = new SingletonClassFactoryRegistration(rtdServerWrapper, clsId))
            using (ProgIdRegistration regProgId = new ProgIdRegistration(progIdRegistered, clsId))
            using (ClsIdRegistration regClsId = new ClsIdRegistration(clsId, progIdRegistered))
            {
                return CallRTD(progIdRegistered, null, topics);
            }
        }
Beispiel #3
0
        public static void LoadComAddIn(ExcelComAddIn addIn)
        {
            // We pick a new Guid as ClassId for this add-in.
            CLSID clsId = Guid.NewGuid();
            // and make the ProgId from this Guid - max 39 chars....
            string progId = "AddIn." + clsId.ToString("N");
            addIn.SetProgId(progId);
            // Put together some nicer descriptions for the Add-ins dialog.
            string friendlyName;
            if (addIn is ExcelRibbon)
                friendlyName = addIn.DnaLibrary.Name + " (Ribbon Helper)";
            else if (addIn is ExcelCustomTaskPaneAddIn)
                friendlyName = addIn.DnaLibrary.Name + " (Custom Task Pane Helper)";
            else 
                friendlyName = addIn.DnaLibrary.Name + " (COM Add-in Helper)";
            string description = string.Format("Dynamically created COM Add-in to load custom UI for the Excel Add-in {0}, located at {1}.", addIn.DnaLibrary.Name, DnaLibrary.XllPath);

            try
            {
                Debug.Print("Getting Application object");
                object app = ExcelDnaUtil.Application;
                Type appType = app.GetType();
                Debug.Print("Got Application object: " + app.GetType().ToString());

                CultureInfo ci = new CultureInfo(1033);

                object excelComAddIns;
                object comAddIn;
                using (SingletonClassFactoryRegistration regClassFactory = new SingletonClassFactoryRegistration(addIn, clsId))
                using (ProgIdRegistration regProgId = new ProgIdRegistration(progId, clsId))
                using (ComAddInRegistration regComAddIn = new ComAddInRegistration(progId, friendlyName, description))
                {
                    excelComAddIns = appType.InvokeMember("COMAddIns", BindingFlags.GetProperty, null, app, null, ci);
//                            Debug.Print("Got COMAddins object: " + excelComAddIns.GetType().ToString());
                    appType.InvokeMember("Update", BindingFlags.InvokeMethod, null, excelComAddIns, null, ci);
//                            Debug.Print("Updated COMAddins object with AddIn registered");
                    comAddIn = excelComAddIns.GetType().InvokeMember("Item", BindingFlags.InvokeMethod, null, excelComAddIns, new object[] { progId }, ci);
//                            Debug.Print("Got the COMAddin object: " + comAddIn.GetType().ToString());

                    // At this point Excel knows how to load our add-in by CLSID, so we could clean up the 
                    // registry aggressively, before the actual (dangerous?) loading starts.
                    // But this seems to lead to some distress - Excel has some assertion checked when 
                    // it updates the LoadBehavior after a successful load....
                    comAddIn.GetType().InvokeMember("Connect", BindingFlags.SetProperty, null, comAddIn, new object[] { true }, ci);
//                            Debug.Print("COMAddin is loaded.");
                    loadedComAddIns.Add(comAddIn);
                }
            }
            catch (Exception e)
            {
                Debug.Print("LoadComAddIn exception: " + e.ToString());
                // CONSIDER: How to deal with errors here...? For now I just re-raise the exception.
                throw;
            }
        }