Esempio n. 1
0
        // NOTE: We are not currently removing the functions from the Jmp array
        //       That would be needed to do a proper per-method deregistration,
        //       together with a garbage-collectable story for the wrapper methods and delegates,
        //       instead of the currently runtime-compiled and loaded assemblies.
        internal static void UnregisterMethods()
        {
            object xlCallResult;

            // Remove menus and ShortCuts
            IntegrationHelpers.RemoveCommandMenus();
            UnregisterShortCuts();

            // Now take out the methods
            foreach (XlMethodInfo mi in registeredMethods)
            {
                if (mi.IsCommand)
                {
                    // Clear the name and unregister
                    XlCallImpl.TryExcelImpl(XlCallImpl.xlfSetName, out xlCallResult, mi.Name);
                    XlCallImpl.TryExcelImpl(XlCallImpl.xlfUnregister, out xlCallResult, mi.RegisterId);
                }
                else
                {
                    // And Unregister the real function
                    XlCallImpl.TryExcelImpl(XlCallImpl.xlfUnregister, out xlCallResult, mi.RegisterId);
                    // I follow the advice from X-Cell website to get function out of Wizard (with fix from kh)
                    XlCallImpl.TryExcelImpl(XlCallImpl.xlfRegister, out xlCallResult, XlAddIn.PathXll, "xlAutoRemove", "I", mi.Name, IntegrationMarshalHelpers.GetExcelMissingValue(), 2);
                    if (xlCallResult is double)
                    {
                        double fakeRegisterId = (double)xlCallResult;
                        XlCallImpl.TryExcelImpl(XlCallImpl.xlfSetName, out xlCallResult, mi.Name);
                        XlCallImpl.TryExcelImpl(XlCallImpl.xlfUnregister, out xlCallResult, fakeRegisterId);
                    }
                }
            }
            registeredMethods.Clear();
            registrationInfo.Clear();
        }
Esempio n. 2
0
        internal static short XlAutoOpen()
        {
            Debug.Print("AppDomain Id: " + AppDomain.CurrentDomain.Id + " (Default: " + AppDomain.CurrentDomain.IsDefaultAppDomain() + ")");
            short result = 0;

            try
            {
                Debug.WriteLine("In XlAddIn.XlAutoOpen");
                DeInitializeIntegration();

                object xlCallResult;
                XlCallImpl.TryExcelImpl(XlCallImpl.xlcMessage, out xlCallResult /*Ignore*/, true, "Registering library " + pathXll);

                InitializeIntegration();

                // InitializeIntegration has loaded the DnaLibrary
                IntegrationHelpers.DnaLibraryAutoOpen();

                result = 1; // All is OK
            }
            catch (Exception e)
            {
                // TODO: What to do here?
                Debug.WriteLine(e.Message);
                result = 0;
            }
            finally
            {
                // Clear the status bar message
                object xlCallResult;
                XlCallImpl.TryExcelImpl(XlCallImpl.xlcMessage, out xlCallResult /*Ignore*/, false);
            }
            return(result);
        }
Esempio n. 3
0
        static void RegisterXlMethod(XlMethodInfo mi)
        {
            int index = registeredMethods.Count;

            XlAddIn.SetJump(index, mi.FunctionPointer);
            string exportedProcName = string.Format("f{0}", index);

            object[] registerParameters = GetRegisterParameters(mi, exportedProcName);
            string   registerName       = (string)registerParameters[3];

            if (!registeredNames.Add(registerName))
            {
                // Not added to the set of names, so it was already present
                // This function will be registered with a name that has already been used (by this add-in)
                if (mi.SuppressOverwriteError)
                {
                    // Logged at Info level - to allow re-registration without error popup
                    Logger.Registration.Info("Repeated function name: '{0}' - previous registration will be overwritten. ", registerName);
                }
                else
                {
                    // This logged as an error, but the registration continues - the last function with the name wins, for backward compatibility.
                    Logger.Registration.Error("Repeated function name: '{0}' - previous registration will be overwritten. ", registerName);
                }
            }

            // Basically suppress problems here !?
            try
            {
                object xlCallResult;
                XlCallImpl.TryExcelImpl(XlCallImpl.xlfRegister, out xlCallResult, registerParameters);
                Logger.Registration.Info("Register - XllPath={0}, ProcName={1}, FunctionType={2}, Name={3} - Result={4}",
                                         registerParameters[0], registerParameters[1], registerParameters[2], registerName,
                                         xlCallResult);
                if (xlCallResult is double)
                {
                    mi.RegisterId = (double)xlCallResult;
                    registeredMethods.Add(mi);
                    if (mi.IsCommand)
                    {
                        RegisterMenu(mi);
                        RegisterShortCut(mi);
                    }
                }
                else
                {
                    Logger.Registration.Error("xlfRegister call failed for function or command: '{0}'", mi.Name);
                }
                // Now clear out the xll path and store the parameters to support RegistrationInfo access.
                registerParameters[0] = null;
                registrationInfo.Add(registerParameters);
            }
            catch (Exception e)
            {
                Logger.Registration.Error(e, "Registration failed for function or command: '{0}'", mi.Name);
            }
        }
Esempio n. 4
0
 static void RegisterShortCut(XlMethodInfo mi)
 {
     if (!string.IsNullOrEmpty(mi.ShortCut))
     {
         object xlCallResult;
         XlCallImpl.TryExcelImpl(XlCallImpl.xlcOnKey, out xlCallResult, mi.ShortCut, mi.Name);
         // CONSIDER: We ignore result and suppress errors - maybe log?
         addedShortCuts.Add(mi.ShortCut);
     }
 }
Esempio n. 5
0
 private static void UnregisterShortCuts()
 {
     foreach (string shortCut in addedShortCuts)
     {
         // xlcOnKey with no macro name:
         // "If macro_text is omitted, key_text reverts to its normal meaning in Microsoft Excel,
         // and any special key assignments made with previous ON.KEY functions are cleared."
         object xlCallResult;
         XlCallImpl.TryExcelImpl(XlCallImpl.xlcOnKey, out xlCallResult, shortCut);
     }
 }
Esempio n. 6
0
        internal static short XlAutoOpen()
        {
            Debug.Print("AppDomain Id: " + AppDomain.CurrentDomain.Id + " (Default: " + AppDomain.CurrentDomain.IsDefaultAppDomain() + ")");
            short result = 0;

            try
            {
                Debug.WriteLine("In XlAddIn.XlAutoOpen");
                if (_opened)
                {
                    DeInitializeIntegration();
                }
                object xlCallResult;
                XlCallImpl.TryExcelImpl(XlCallImpl.xlcMessage, out xlCallResult /*Ignore*/, true, "Registering library " + pathXll);
                InitializeIntegration();

                // v. 30 - moved the setting of _opened before calling AutoOpen,
                // so that checking in DeInitializeIntegration does not prevent AutoOpen - unloading via xlAutoRemove from working.
                _opened = true;

                // InitializeIntegration has loaded the DnaLibrary
                IntegrationHelpers.DnaLibraryAutoOpen();

                result = 1; // All is OK
            }
            catch (Exception e)
            {
                // TODO: What to do here - maybe prefer Trace...?

                // START HERE: Better error display (with Exception info?)
                Debug.WriteLine("ExcelDna.Loader.XlAddin.XlAutoOpen. Exception during Integration load: " + e.ToString());
                string alertMessage = string.Format("A problem occurred while an add-in was being initialized (InitializeIntegration failed - {1}).\r\nThe add-in is built with ExcelDna and is being loaded from {0}", pathXll, e.Message);
                object xlCallResult;
                XlCallImpl.TryExcelImpl(XlCallImpl.xlcAlert, out xlCallResult /*Ignored*/, alertMessage, 3 /* Only OK Button, Warning Icon*/);
                result = 0;
            }
            finally
            {
                // Clear the status bar message
                object xlCallResult;
                XlCallImpl.TryExcelImpl(XlCallImpl.xlcMessage, out xlCallResult /*Ignored*/, false);
                Debug.Print("Clear status bar message result: " + xlCallResult);
            }
            return(result);
        }
Esempio n. 7
0
        private static void RegisterXlMethod(XlMethodInfo mi)
        {
            int index = registeredMethods.Count;

            XlAddIn.SetJump(index, mi.FunctionPointer);
            String exportedProcName = String.Format("f{0}", index);

            object[] registerParameters = GetRegisterParameters(mi, exportedProcName);
            if (!mi.IsCommand && !mi.IsHidden)
            {
                RecordFunctionInfo(registerParameters);
            }

            // Basically suppress problems here !?
            try
            {
                object xlCallResult;
                XlCallImpl.TryExcelImpl(XlCallImpl.xlfRegister, out xlCallResult, registerParameters);
                Debug.Print("Register - XllPath={0}, ProcName={1}, FunctionType={2}, MethodName={3} - Result={4}",
                            registerParameters[0], registerParameters[1], registerParameters[2], registerParameters[3],
                            xlCallResult);
                if (xlCallResult is double)
                {
                    mi.RegisterId = (double)xlCallResult;
                    registeredMethods.Add(mi);
                    if (mi.IsCommand)
                    {
                        RegisterMenu(mi);
                        RegisterShortCut(mi);
                    }
                }
                else
                {
                    // TODO: What to do here? LogDisplay??
                    Debug.Print("Registration Error! - Register call failed for method {0}", mi.Name);
                }
            }
            catch (Exception e)
            {
                // TODO: What to do here? LogDisplay??
                Debug.WriteLine("Registration Error! - " + e.Message);
            }
        }
Esempio n. 8
0
        internal static short XlAutoOpen()
        {
            Debug.Print("XlAddIn.XlAutoOpen - AppDomain Id: " + AppDomain.CurrentDomain.Id + " (Default: " + AppDomain.CurrentDomain.IsDefaultAppDomain() + ")");
            short result = 0;

            try
            {
                if (_opened)
                {
                    DeInitializeIntegration();
                }
                object xlCallResult;
                XlCallImpl.TryExcelImpl(XlCallImpl.xlcMessage, out xlCallResult /*Ignore*/, true, "Registering library " + pathXll);
                InitializeIntegration();
                Logger.Initialization.Verbose("In XlAddIn.XlAutoOpen");

                // v. 30 - moved the setting of _opened before calling AutoOpen,
                // so that checking in DeInitializeIntegration does not prevent AutoOpen - unloading via xlAutoRemove from working.
                _opened = true;

                // InitializeIntegration has loaded the DnaLibrary
                ExcelIntegration.DnaLibraryAutoOpen();

                result = 1; // All is OK
            }
            catch (Exception e)
            {
                // Can't use logging here
                string alertMessage = string.Format("A problem occurred while an add-in was being initialized (InitializeIntegration failed - {1}).\r\nThe add-in is built with ExcelDna and is being loaded from {0}", pathXll, e.Message);
                object xlCallResult;
                XlCallImpl.TryExcelImpl(XlCallImpl.xlcAlert, out xlCallResult /*Ignored*/, alertMessage, 3 /* Only OK Button, Warning Icon*/);
                result = 0;
            }
            finally
            {
                // Clear the status bar message
                object xlCallResult;
                XlCallImpl.TryExcelImpl(XlCallImpl.xlcMessage, out xlCallResult /*Ignored*/, false);
                // Debug.Print("Clear status bar message result: " + xlCallResult);
            }
            return(result);
        }
Esempio n. 9
0
        static void UnregisterMethods()
        {
            object xlCallResult;

            // Remove menus and ShortCuts
            IntegrationHelpers.RemoveCommandMenus();
            UnregisterShortCuts();

            // Now take out the methods
            foreach (XlMethodInfo mi in registeredMethods)
            {
                if (!mi.IsCommand)
                {
                    // I follow the advice from X-Cell website
                    // to get function out of Wizard
                    XlCallImpl.TryExcelImpl(XlCallImpl.xlfRegister, out xlCallResult, pathXll, "xlAutoRemove", "J", mi.Name, IntegrationMarshalHelpers.GetExcelMissingValue(), 0);
                }
                XlCallImpl.TryExcelImpl(XlCallImpl.xlfSetName, out xlCallResult, mi.Name);
                XlCallImpl.TryExcelImpl(XlCallImpl.xlfUnregister, out xlCallResult, mi.RegisterId);
            }
            registeredMethods.Clear();
        }
Esempio n. 10
0
        private static void RegisterXlMethod(XlMethodInfo mi)
        {
            int index = registeredMethods.Count;

            SetJump(index, mi.FunctionPointer);
            String procName = String.Format("f{0}", index);

            string functionType     = mi.ReturnType == null ? "" : mi.ReturnType.XlType.ToString();
            string argumentNames    = "";
            bool   showDescriptions = false;

            string[] argumentDescriptions = new string[mi.Parameters.Length];
            string   helpTopic;

            for (int j = 0; j < mi.Parameters.Length; j++)
            {
                XlParameterInfo pi = mi.Parameters[j];

                functionType += pi.XlType;
                if (j > 0)
                {
                    argumentNames += ",";
                }
                argumentNames          += pi.Name;
                argumentDescriptions[j] = pi.Description;

                if (pi.Description != "")
                {
                    showDescriptions = true;
                }

                // DOCUMENT: Here is the patch for the Excel Function Description bug.
                // DOCUMENT: I add ". " to the last parameters.
                if (j == mi.Parameters.Length - 1)
                {
                    argumentDescriptions[j] += ". ";
                }
            } // for each parameter

            if (mi.IsMacroType)
            {
                functionType += "#";
            }
            else if (mi.IsThreadSafe && XlAddIn.xlCallVersion >= 12)
            {
                functionType += "$";
            }

            if (mi.IsVolatile)
            {
                functionType += "!";
            }
            // DOCUMENT: If # is set and there is an R argument,
            // Excel considers the function volatile
            // You can call xlfVolatile, false in beginning of function to clear.

            // DOCUMENT: Here is the patch for the Excel Function Description bug.
            // DOCUMENT: I add ". " if the function takes no parameters and has a description.
            string functionDescription = mi.Description;

            if (mi.Parameters.Length == 0 && functionDescription != "")
            {
                functionDescription += ". ";
            }

            // DOCUMENT: When there is no description, we don't add any.
            // This allows the user to work around the Excel bug where an extra parameter is displayed if
            // the function has no parameter but displays a description
            if (mi.Description != "")
            {
                showDescriptions = true;
            }

            int numArguments;
            // DOCUMENT: Maximum 20 Argument Descriptions when registering using Excel4 function.
            int maxDescriptions = (XlAddIn.xlCallVersion < 12) ? 20 : 245;
            int numArgumentDescriptions;

            if (showDescriptions)
            {
                numArgumentDescriptions = Math.Min(argumentDescriptions.Length, maxDescriptions);
                numArguments            = 10 + numArgumentDescriptions;
            }
            else
            {
                numArgumentDescriptions = 0;
                numArguments            = 9;
            }

            // Make HelpTopic without full path relative to xllPath
            if (mi.HelpTopic == null || mi.HelpTopic == "")
            {
                helpTopic = mi.HelpTopic;
            }
            else
            {
                if (Path.IsPathRooted(mi.HelpTopic))
                {
                    helpTopic = mi.HelpTopic;
                }
                else
                {
                    helpTopic = Path.Combine(Path.GetDirectoryName(pathXll), mi.HelpTopic);
                }
            }

            object[] registerParameters = new object[numArguments];
            registerParameters[0] = pathXll;
            registerParameters[1] = procName;
            registerParameters[2] = functionType;
            registerParameters[3] = mi.Name;
            registerParameters[4] = argumentNames;
            registerParameters[5] = mi.IsCommand ? 2                               /*macro*/
                                                          : (mi.IsHidden ? 0 : 1); /*function*/
            registerParameters[6] = mi.Category;
            registerParameters[7] = mi.ShortCut;                                   /*shortcut_text*/
            registerParameters[8] = helpTopic; /*help_topic*/;

            if (showDescriptions)
            {
                registerParameters[9] = functionDescription;

                for (int k = 0; k < numArgumentDescriptions; k++)
                {
                    registerParameters[10 + k] = argumentDescriptions[k];
                }
            }

            // Basically suppress problems here !?
            try
            {
                object xlCallResult;
                XlCallImpl.TryExcelImpl(XlCallImpl.xlfRegister, out xlCallResult, registerParameters);
                mi.RegisterId = (double)xlCallResult;
                registeredMethods.Add(mi);
            }
            catch (Exception e)
            {
                // TODO: What to do here?
                Debug.WriteLine(e.Message);
            }

            if (mi.IsCommand)
            {
                RegisterMenu(mi);
            }
        }
Esempio n. 11
0
        private static void RegisterXlMethod(XlMethodInfo mi)
        {
            int index = registeredMethods.Count;

            SetJump(index, mi.FunctionPointer);
            String procName = String.Format("f{0}", index);

            string functionType;

            if (mi.IsCommand)
            {
                if (mi.Parameters.Length == 0)
                {
                    functionType = "";  // OK since no other types will be added
                }
                else
                {
                    functionType = ">"; // Use the void / inplace indicator if needed.
                }
            }
            else
            {
                functionType = mi.ReturnType.XlType;
            }

            string argumentNames    = "";
            bool   showDescriptions = false;

            string[] argumentDescriptions = new string[mi.Parameters.Length];
            string   helpTopic;

            for (int j = 0; j < mi.Parameters.Length; j++)
            {
                XlParameterInfo pi = mi.Parameters[j];

                functionType += pi.XlType;
                if (j > 0)
                {
                    argumentNames += ",";
                }
                argumentNames          += pi.Name;
                argumentDescriptions[j] = pi.Description;

                if (pi.Description != "")
                {
                    showDescriptions = true;
                }

                // DOCUMENT: Truncate the argument description if it exceeds the Excel limit of 255 characters
                if (j < mi.Parameters.Length - 1)
                {
                    if (!string.IsNullOrEmpty(argumentDescriptions[j]) &&
                        argumentDescriptions[j].Length > 255)
                    {
                        argumentDescriptions[j] = argumentDescriptions[j].Substring(0, 255);
                        Debug.Print("Truncated argument description of {0} in method {1} as Excel limit was exceeded",
                                    pi.Name, mi.Name);
                    }
                }
                else
                {
                    // Last argument - need to deal with extra ". "
                    if (!string.IsNullOrEmpty(argumentDescriptions[j]))
                    {
                        if (argumentDescriptions[j].Length > 253)
                        {
                            argumentDescriptions[j] = argumentDescriptions[j].Substring(0, 253);
                            Debug.Print("Truncated field description of {0} in method {1} as Excel limit was exceeded",
                                        pi.Name, mi.Name);
                        }

                        // DOCUMENT: Here is the patch for the Excel Function Description bug.
                        // DOCUMENT: I add ". " to the last parameter.
                        argumentDescriptions[j] += ". ";
                    }
                }
            } // for each parameter

            if (mi.IsClusterSafe && ProcessHelper.SupportsClusterSafe)
            {
                functionType += "&";
            }

            if (mi.IsMacroType)
            {
                functionType += "#";
            }

            if (!mi.IsMacroType && mi.IsThreadSafe && XlAddIn.XlCallVersion >= 12)
            {
                functionType += "$";
            }

            if (mi.IsVolatile)
            {
                functionType += "!";
            }
            // DOCUMENT: If # is set and there is an R argument, Excel considers the function volatile anyway.
            // You can call xlfVolatile, false in beginning of function to clear.

            // DOCUMENT: There is a bug? in Excel 2007 that limits the total argumentname string to 255 chars.
            // TODO: Check whether this is fixed in Excel 2010 yet.
            // DOCUMENT: I truncate the argument string for all versions.
            if (argumentNames.Length > 255)
            {
                argumentNames = argumentNames.Substring(0, 255);
            }

            // DOCUMENT: Here is the patch for the Excel Function Description bug.
            // DOCUMENT: I add ". " if the function takes no parameters and has a description.
            string functionDescription = mi.Description;

            if (mi.Parameters.Length == 0 && functionDescription != "")
            {
                functionDescription += ". ";
            }

            // DOCUMENT: When there is no description, we don't add any.
            // This allows the user to work around the Excel bug where an extra parameter is displayed if
            // the function has no parameter but displays a description
            if (mi.Description != "")
            {
                showDescriptions = true;
            }

            int numArguments;
            // DOCUMENT: Maximum 20 Argument Descriptions when registering using Excel4 function.
            int maxDescriptions = (XlAddIn.XlCallVersion < 12) ? 20 : 245;
            int numArgumentDescriptions;

            if (showDescriptions)
            {
                numArgumentDescriptions = Math.Min(argumentDescriptions.Length, maxDescriptions);
                numArguments            = 10 + numArgumentDescriptions;
            }
            else
            {
                numArgumentDescriptions = 0;
                numArguments            = 9;
            }

            // Make HelpTopic without full path relative to xllPath
            if (string.IsNullOrEmpty(mi.HelpTopic))
            {
                helpTopic = mi.HelpTopic;
            }
            else
            {
                // DOCUMENT: If HelpTopic is not rooted - it is expanded relative to .xll path.
                // If http url does not end with !0 it is appended.
                // I don't think https is supported, but it should not be considered an 'unrooted' path anyway.
                if (mi.HelpTopic.StartsWith("http://") || mi.HelpTopic.StartsWith("https://"))
                {
                    if (!mi.HelpTopic.EndsWith("!0"))
                    {
                        helpTopic = mi.HelpTopic + "!0";
                    }
                    else
                    {
                        helpTopic = mi.HelpTopic;
                    }
                }
                else if (Path.IsPathRooted(mi.HelpTopic))
                {
                    helpTopic = mi.HelpTopic;
                }
                else
                {
                    helpTopic = Path.Combine(Path.GetDirectoryName(pathXll), mi.HelpTopic);
                }
            }

            object[] registerParameters = new object[numArguments];
            registerParameters[0] = pathXll;
            registerParameters[1] = procName;
            registerParameters[2] = functionType;
            registerParameters[3] = mi.Name;
            registerParameters[4] = argumentNames;
            registerParameters[5] = mi.IsCommand ? 2                               /*macro*/
                                                          : (mi.IsHidden ? 0 : 1); /*function*/
            registerParameters[6] = mi.Category;
            registerParameters[7] = mi.ShortCut;                                   /*shortcut_text*/
            registerParameters[8] = helpTopic; /*help_topic*/;

            if (showDescriptions)
            {
                registerParameters[9] = functionDescription;

                for (int k = 0; k < numArgumentDescriptions; k++)
                {
                    registerParameters[10 + k] = argumentDescriptions[k];
                }
            }

            // Basically suppress problems here !?
            try
            {
                object xlCallResult;
                XlCallImpl.TryExcelImpl(XlCallImpl.xlfRegister, out xlCallResult, registerParameters);
                Debug.Print("Register - XllPath={0}, ProcName={1}, FunctionType={2}, MethodName={3} - Result={4}", registerParameters[0], registerParameters[1], registerParameters[2], registerParameters[3], xlCallResult);
                if (xlCallResult is double)
                {
                    mi.RegisterId = (double)xlCallResult;
                    registeredMethods.Add(mi);
                    if (mi.IsCommand)
                    {
                        RegisterMenu(mi);
                        RegisterShortCut(mi);
                    }
                }
                else
                {
                    // TODO: What to do here? LogDisplay??
                    Debug.Print("Registration Error! - Register call failed for method {0}", mi.Name);
                }
            }
            catch (Exception e)
            {
                // TODO: What to do here? LogDisplay??
                Debug.WriteLine("Registration Error! - " + e.Message);
            }
        }
Esempio n. 12
0
 public XlCall.XlReturn TryExcelImpl(int xlFunction, out object result, params object[] parameters)
 => XlCallImpl.TryExcelImpl(xlFunction, out result, parameters);