Search code examples
c#excel-dna

Why is ExcelDNA registering some functions as UDFs that I have not asked it to?


I have an ExcelDNA-based add-in (XLL) written in C# that does a bunch of different things, including register some UDFs with Excel for use in cell formulae.

The weird thing is that I have the following code for a UDF that successfully registers the 'ConvertUnit' function with Excel as a UDF, BUT ALSO ends up with the called function 'ConvertUnits' function from another class being registered as well:

// This is in a public static class called MyFunctions in the global namespace
[ExcelFunction(Description = "Convert value", IsMacroType = false)]
public static object ConvertUnit(
    [ExcelArgument(Name = "Value", Description = "Value to be converted")] string value,
    [ExcelArgument(Name = "Property Group", Description = "Type of property to be converted e.g. \"temperature\", \"diff_temperature\"")] string unitGroup,
    [ExcelArgument(Name = "From Units", Description = "Units of measure to convert from")] string fromUom,
    [ExcelArgument(Name = "To Units", Description = "Units of measure to convert to")] string toUom)
{ // UDF to convert a between UoM

    double dblValue;
    bool isValue = double.TryParse(value, out dblValue);
    if (!isValue) return Common.errValue;
    { return UnitConversion.ConvertUnits(dblValue, unitGroup, fromUom, toUom); }
}

The UnitConversion.ConvertUnits function is in a different namespace, called DataTool:

public static object ConvertUnits(double value, string unitGroup, string fromUom, string toUom)
{ // Use this to expose via a UDF for users to convert between UoM for a specified unitGroup
    string defaultUnit;
    double toJM_Multiplier; double fromJM_Multiplier;

    if (unitGroup == "temperature")
    {
        double tempVal;
        switch (fromUom)
        {
            case "C":
                tempVal = value;
                break;
            case "F":
                tempVal = (value - 32.0) / 1.8;
                break;
            case "K":
                tempVal = value - 273.15;
                break;
            case "R":
                tempVal = (value - 491.67) / 1.8;
                break;
            default:
                return Common.errUOM;
        }
        switch (toUom)
        {
            case "C":
                return tempVal;
            case "F":
                return tempVal * 1.8 + 32.0;
            case "K":
                return tempVal + 273.15;
            case "R":
                return tempVal * 1.8 + 491.67;
            default:
                return Common.errUOM;
        }
    }

    if (defaultUoM.ContainsKey(unitGroup))
    { // Get the default (JM) UoM for the unit group - should always exist but handle missing config file
        defaultUnit = defaultUoM[unitGroup];
    }
    else
    { return Common.errConfigFile; }

    if (!conversions.ContainsKey(unitGroup)) return Common.errConfigFile;

    if (conversions[unitGroup].ContainsKey(fromUom))
    { // Get the conversion factor if it is mapped in the config file
        toJM_Multiplier = conversions[unitGroup][fromUom];
    }
    else
    { return Common.errUOM; }

    if (conversions[unitGroup].ContainsKey(toUom))
    { // Get the conversion factor if it is mapped in the config file
        fromJM_Multiplier = conversions[unitGroup][toUom];
    }
    else
    { return Common.errUOM; }

    if (toJM_Multiplier != 0.0)
    { return value / toJM_Multiplier * fromJM_Multiplier; }
    else
    { return null; }
}

Then in the built XLL, I end up seeing both functions appearing in Excel as UDFs, despite there being no ExcelDNA content in my UnitConversion class. Why!?


Solution

  • By default, all the public static methods are registered in the AddIn.

    Have a look here

    I see both parameters which can help you:

    <!-- Prevents every static public function from becomming a UDF, they will need an explicit [ExcelFunction] annotation. -->
    <!-- Default value: false -->
    <ExcelAddInExplicitExports></ExcelAddInExplicitExports>
    
    <!-- Prevents automatic registration of functions and commands. -->
    <!-- Default value: false -->
    <ExcelAddInExplicitRegistration></ExcelAddInExplicitRegistration>