Ejemplo n.º 1
0
        public HRESULT CreateInstance([In] IntPtr pUnkOuter, [In] ref IID riid, [Out] out IntPtr ppvObject)
        {
            ppvObject = IntPtr.Zero;
            object instance = Activator.CreateInstance(_comClass.Type);

            if (_comClass.IsRtdServer)
            {
                // wrap instance in RtdWrapper
                RtdServerWrapper rtdServerWrapper = new RtdServerWrapper(instance, _comClass.ProgId);
                instance = rtdServerWrapper;
            }

            if (pUnkOuter != IntPtr.Zero)
            {
                // For now no aggregation support - could do Marshal.CreateAggregatedObject?
                return ComAPI.CLASS_E_NOAGGREGATION;
            }
            if (riid == ComAPI.guidIUnknown)
            {
                ppvObject = Marshal.GetIUnknownForObject(instance);
            }
            else
            {
                ppvObject = Marshal.GetIUnknownForObject(instance);
                HRESULT hrQI = Marshal.QueryInterface(ppvObject, ref riid, out ppvObject);
                Marshal.Release(ppvObject);
                if (hrQI != ComAPI.S_OK)
                {
                    return ComAPI.E_NOINTERFACE;
                }
            }
            return ComAPI.S_OK;
        }
Ejemplo n.º 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);
            }
        }
Ejemplo n.º 3
0
        public HRESULT CreateInstance([In] IntPtr pUnkOuter, [In] ref IID riid, [Out] out IntPtr ppvObject)
        {
            // Suspend the C API (helps to prevent some Excel-crashing scenarios)
            using (XlCall.Suspend())
            {
                ppvObject = IntPtr.Zero;
                object instance = Activator.CreateInstance(_comClass.Type);

                // If not an ExcelRtdServer, create safe wrapper that also maps types.
                if (_comClass.IsRtdServer && !instance.GetType().IsSubclassOf(typeof(ExcelRtdServer)))
                {
                    // wrap instance in RtdWrapper
                    RtdServerWrapper rtdServerWrapper = new RtdServerWrapper(instance, _comClass.ProgId);
                    instance = rtdServerWrapper;
                }

                if (pUnkOuter != IntPtr.Zero)
                {
                    // For now no aggregation support - could do Marshal.CreateAggregatedObject?
                    return ComAPI.CLASS_E_NOAGGREGATION;
                }
                if (riid == ComAPI.guidIUnknown)
                {
                    ppvObject = Marshal.GetIUnknownForObject(instance);
                }
                else
                {
                    ppvObject = Marshal.GetIUnknownForObject(instance);
                    HRESULT hrQI = Marshal.QueryInterface(ppvObject, ref riid, out ppvObject);
                    Marshal.Release(ppvObject);
                    if (hrQI != ComAPI.S_OK)
                    {
                        return ComAPI.E_NOINTERFACE;
                    }
                }
                return ComAPI.S_OK;
            }
        }
Ejemplo n.º 4
0
        // Forwarded from XlCall
        // Loads the RTD server with temporary ProgId.
        // CAUTION: Might fail when called from array formula (the first call in every array-group fails).
        //          When it fails, the xlfRtd call returns xlReturnUncalced.
        //          In that case, this function returns null, and does not keep a reference to the created server object.
        //          The next call should then succeed (though a new server object will be created).
        public static bool TryRTD(out object result, string progId, string server, params string[] topics)
        {
            Debug.Print("### RtdRegistration.RTD " + progId);
            // Check if this is any of our business.
            Type rtdServerType;

            if (!string.IsNullOrEmpty(server) || !registeredRtdServerTypes.TryGetValue(progId, out rtdServerType))
            {
                // Just pass on to Excel.
                return(TryCallRTD(out result, progId, null, topics));
            }

            // TODO: Check that ExcelRtdServer with stable ProgId case also works right here -
            //       might need to add to loadedRtdServers somehow

            // Check if already loaded.
            string loadedProgId;

            if (loadedRtdServers.TryGetValue(progId, out loadedProgId))
            {
                if (ExcelRtd2010BugHelper.ExcelVersionHasRtdBug && rtdServerType.IsSubclassOf(typeof(ExcelRtdServer)))
                {
                    ExcelRtd2010BugHelper.RecordRtdCall(progId, topics);
                }
                // Call Excel using the synthetic RtdSrv_xxx (or actual from attribute) ProgId
                return(TryCallRTD(out result, loadedProgId, null, topics));
            }

            // Not loaded already - need to get the Rtd server loaded
            // TODO: Need to reconsider registration here.....
            //       Sometimes need stable ProgIds.
            object rtdServer;

            if (ExcelRtd2010BugHelper.ExcelVersionHasRtdBug && rtdServerType.IsSubclassOf(typeof(ExcelRtdServer)))
            {
                Debug.Print("### Creating Wrapper " + progId);
                rtdServer = new ExcelRtd2010BugHelper(progId, rtdServerType);
            }
            else
            {
                using (XlCall.Suspend())
                {
                    rtdServer = Activator.CreateInstance(rtdServerType);
                }
                ExcelRtdServer excelRtdServer = rtdServer as ExcelRtdServer;
                if (excelRtdServer != null)
                {
                    // Set ProgId so that it can be 'unregistered' (removed from loadedRtdServers) when the RTD server terminates.
                    excelRtdServer.RegisteredProgId = progId;
                }
                else
                {
                    // Make a wrapper if we are not an ExcelRtdServer
                    // (ExcelRtdServer implements exception-handling and XLCall supension itself)
                    rtdServer = new RtdServerWrapper(rtdServer, progId);
                }
            }

            // We pick a new Guid as ClassId for this add-in...
            CLSID clsId = Guid.NewGuid();

            // ... (bad idea - this will cause Excel to try to load this RTD server while it is not registered.)
            // Guid typeGuid = GuidUtilit.CreateGuid(..., DnaLibrary.XllPath + ":" + rtdServerType.FullName);
            // or something based on ExcelDnaUtil.XllGuid
            // string progIdRegistered = "RtdSrv_" + typeGuid.ToString("N");

            // by making a fresh progId, we are sure Excel will try to load when we are ready.
            // Change from RtdSrv.xxx to RtdSrv_xxx to avoid McAfee bug that blocks registry writes with a "." anywhere
            string progIdRegistered = "RtdSrv_" + clsId.ToString("N");

            Debug.Print("RTD - Using ProgId: {0} for type: {1}", progIdRegistered, rtdServerType.FullName);

            try
            {
                using (new SingletonClassFactoryRegistration(rtdServer, clsId))
                    using (new ProgIdRegistration(progIdRegistered, clsId))
                        using (new ClsIdRegistration(clsId, progIdRegistered))
                        {
                            Debug.Print("### About to call TryCallRTD " + progId);
                            if (TryCallRTD(out result, progIdRegistered, null, topics))
                            {
                                // Mark as loaded - ServerTerminate in the wrapper will remove.
                                loadedRtdServers[progId] = progIdRegistered;
                                Debug.Print("### Added to loadedRtdServers " + progId);
                                return(true);
                            }
                            return(false);
                        }
            }
            catch (UnauthorizedAccessException secex)
            {
                Logger.RtdServer.Error("The RTD server of type {0} required by add-in {1} could not be registered.\r\nThis may be due to restricted permissions on the user's HKCU\\Software\\Classes key.\r\nError message: {2}", rtdServerType.FullName, DnaLibrary.CurrentLibrary.Name, secex.Message);
                result = ExcelErrorUtil.ToComError(ExcelError.ExcelErrorValue);
                // Return true to have the #VALUE stick, just as it was before the array-call refactoring
                return(true);
            }
            catch (Exception ex)
            {
                Logger.RtdServer.Error("The RTD server of type {0} required by add-in {1} could not be registered.\r\nThis is an unexpected error.\r\nError message: {2}", rtdServerType.FullName, DnaLibrary.CurrentLibrary.Name, ex.Message);
                Debug.Print("RtdRegistration.RTD exception: " + ex.ToString());
                result = ExcelErrorUtil.ToComError(ExcelError.ExcelErrorValue);
                // Return true to have the #VALUE stick, just as it was before the array-call refactoring
                return(true);
            }
        }
Ejemplo n.º 5
0
        // Forwarded from XlCall
        // Loads the RTD server with temporary ProgId.
        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);

            ExcelRtdServer excelRtdServer = rtdServer as ExcelRtdServer;

            if (excelRtdServer != null)
            {
                // Set ProgId so that it can be 'unregistered' (removed from loadedRtdServers) when the RTD sever terminates.
                excelRtdServer.RegisteredProgId = progId;
            }
            else
            {
                // Make a wrapper if we are not an ExcelRtdServer
                // (ExcelRtdServer implements exception-handling and XLCall supension itself)
                rtdServer = new RtdServerWrapper(rtdServer, progId);
            }

            // We pick a new Guid as ClassId for this add-in...
            CLSID clsId = Guid.NewGuid();

            // ... (bad idea - this will cause Excel to try to load this RTD server while it is not registered.)
            // Guid typeGuid = GuidUtilit.CreateGuid(..., 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);

            try
            {
                using (new SingletonClassFactoryRegistration(rtdServer, clsId))
                    using (new ProgIdRegistration(progIdRegistered, clsId))
                        using (new ClsIdRegistration(clsId, progIdRegistered))
                        {
                            object result;
                            if (TryCallRTD(out result, progIdRegistered, null, topics))
                            {
                                // Mark as loaded - ServerTerminate in the wrapper will remove.
                                // TODO: Consider multithread race condition...
                                loadedRtdServers[progId] = progIdRegistered;
                            }
                            return(result);
                        }
            }
            catch (UnauthorizedAccessException secex)
            {
                Logging.LogDisplay.WriteLine("The RTD server of type {0} required by add-in {1} could not be registered.\r\nThis may be due to restricted permissions on the user's HKCU\\Software\\Classes key.\r\nError message: {2}", rtdServerType.FullName, DnaLibrary.CurrentLibrary.Name, secex.Message);
                return(ExcelErrorUtil.ToComError(ExcelError.ExcelErrorValue));
            }
        }
Ejemplo n.º 6
0
        // Forwarded from XlCall
        // Loads the RTD server with temporary ProgId.
        public static object RTD(string progId, string server, params string[] topics)
        {
            Debug.Print("### RtdRegistration.RTD " + progId);
            // Check if this is any of our business.
            Type rtdServerType;
            if (!string.IsNullOrEmpty(server) || !registeredRtdServerTypes.TryGetValue(progId, out rtdServerType))
            {
                // Just pass on to Excel.
                return CallRTD(progId, null, topics);
            }

            // TODO: Check that ExcelRtdServer with stable ProgId case also works right here -
            //       might need to add to loadedRtdServers somehow

            // Check if already loaded.
            string loadedProgId;
            if (loadedRtdServers.TryGetValue(progId, out loadedProgId))
            {
                if (ExcelRtd2010BugHelper.ExcelVersionHasRtdBug && rtdServerType.IsSubclassOf(typeof(ExcelRtdServer)))
                {
                    ExcelRtd2010BugHelper.RecordRtdCall(progId, topics);
                }
                // Call Excel using the synthetic RtdSrv.xxx (or actual from attribute) ProgId
                return CallRTD(loadedProgId, null, topics);
            }

            // Not loaded already - need to get the Rtd server loaded
            // TODO: Need to reconsider registration here.....
            //       Sometimes need stable ProgIds.
            object rtdServer;
            if (ExcelRtd2010BugHelper.ExcelVersionHasRtdBug && rtdServerType.IsSubclassOf(typeof(ExcelRtdServer)))
            {
                Debug.Print("### Creating Wrapper " + progId);
                rtdServer = new ExcelRtd2010BugHelper(progId, rtdServerType);
            }
            else
            {
                using (XlCall.Suspend())
                {
                    rtdServer = Activator.CreateInstance(rtdServerType);
                }
                ExcelRtdServer excelRtdServer = rtdServer as ExcelRtdServer;
                if (excelRtdServer != null)
                {
                    // Set ProgId so that it can be 'unregistered' (removed from loadedRtdServers) when the RTD server terminates.
                    excelRtdServer.RegisteredProgId = progId;
                }
                else
                {
                    // Make a wrapper if we are not an ExcelRtdServer
                    // (ExcelRtdServer implements exception-handling and XLCall supension itself)
                    rtdServer = new RtdServerWrapper(rtdServer, progId);
                }
            }

            // We pick a new Guid as ClassId for this add-in...
            CLSID clsId = Guid.NewGuid();

            // ... (bad idea - this will cause Excel to try to load this RTD server while it is not registered.)
            // Guid typeGuid = GuidUtilit.CreateGuid(..., DnaLibrary.XllPath + ":" + rtdServerType.FullName);
            // or something based on ExcelDnaUtil.XllGuid
            // 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);

            try
            {
                using (new SingletonClassFactoryRegistration(rtdServer, clsId))
                using (new ProgIdRegistration(progIdRegistered, clsId))
                using (new ClsIdRegistration(clsId, progIdRegistered))
                {
                    object result;
                    Debug.Print("### About to call TryCallRTD " + progId);
                    if (TryCallRTD(out result, progIdRegistered, null, topics))
                    {
                        // Mark as loaded - ServerTerminate in the wrapper will remove.
                        loadedRtdServers[progId] = progIdRegistered;
                        Debug.Print("### Added to loadedRtdServers " + progId);
                    }
                    return result;
                }
            }
            catch (UnauthorizedAccessException secex)
            {
                Logging.LogDisplay.WriteLine("The RTD server of type {0} required by add-in {1} could not be registered.\r\nThis may be due to restricted permissions on the user's HKCU\\Software\\Classes key.\r\nError message: {2}", rtdServerType.FullName, DnaLibrary.CurrentLibrary.Name, secex.Message );
                return ExcelErrorUtil.ToComError(ExcelError.ExcelErrorValue);
            }
            catch (Exception ex)
            {
                Logging.LogDisplay.WriteLine("The RTD server of type {0} required by add-in {1} could not be registered.\r\nThis is an unexpected error.\r\nError message: {2}", rtdServerType.FullName, DnaLibrary.CurrentLibrary.Name, ex.Message);
                Debug.Print("RtdRegistration.RTD exception: " + ex.ToString());
                return ExcelErrorUtil.ToComError(ExcelError.ExcelErrorValue);
            }
        }
Ejemplo n.º 7
0
        // Forwarded from XlCall
        // Loads the RTD server with temporary ProgId.
        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);

            ExcelRtdServer excelRtdServer = rtdServer as ExcelRtdServer;
            if (excelRtdServer != null)
            {
                // Set ProgId so that it can be 'unregistered' (removed from loadedRtdServers) when the RTD sever terminates.
                excelRtdServer.RegisteredProgId = progId;
            }
            else
            {
                // Make a wrapper if we are not an ExcelRtdServer
                // (ExcelRtdServer implements exception-handling and XLCall supension itself)
                rtdServer = new RtdServerWrapper(rtdServer, progId);
            }

            // We pick a new Guid as ClassId for this add-in...
            CLSID clsId = Guid.NewGuid();

            // ... (bad idea - this will cause Excel to try to load this RTD server while it is not registered.)
            // Guid typeGuid = GuidUtilit.CreateGuid(..., 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);

            try
            {
                using (new SingletonClassFactoryRegistration(rtdServer, clsId))
                using (new ProgIdRegistration(progIdRegistered, clsId))
                using (new ClsIdRegistration(clsId, progIdRegistered))
                {
                    object result;
                    if (TryCallRTD(out result, progIdRegistered, null, topics))
                    {
                        // Mark as loaded - ServerTerminate in the wrapper will remove.
                        // TODO: Consider multithread race condition...
                        loadedRtdServers[progId] = progIdRegistered;
                    }
                    return result;
                }
            }
            catch (UnauthorizedAccessException secex)
            {
                Logging.LogDisplay.WriteLine("The RTD server of type {0} required by add-in {1} could not be registered.\r\nThis may be due to restricted permissions on the user's HKCU\\Software\\Classes key.\r\nError message: {2}", rtdServerType.FullName, DnaLibrary.CurrentLibrary.Name, secex.Message );
                return ExcelErrorUtil.ToComError(ExcelError.ExcelErrorValue);
            }
        }