XLL+ Class Library

Limits of argument descriptions

The last arguments' descriptions are the same as the description of an earlier argument

Problem

If a function description is long, then the last N arguments' descriptions are lost, and the description for the (N+1) from last argument is used instead.

Summary

  1. There is a limit (imposed by Excel, not by XLL+) to the total number of characters and words of description that can be associated with one function.
  2. The table below describes the limits.
  3. A checking function XlCheckFnStrings() is provided below, which can be used to check whether the strings provided are too long. This function can be called during initialisation to print warnings to the console.

String size limits

Arguments Maximum characters in function description + argument list
8 452
9 429
10 238
11 238
12 216
13 180
14 163
15 156
16 142
16 123
18 111
19 99

Size checking functions

Add the functions below to your code, before the InitInstance() event handler.

 
BOOL XlCheckFnStrings(CXllFn* pfn) {
    static int anLimits[] = {
        8,  452,
        9,  429,
        10, 238,
        11, 238,
        12, 216,
        13, 180,
        14, 163,
        15, 156,
        16, 142,
        17, 123,
        18, 111,
        19, 99,
        0, 0
    };
    int i;
    int cChars = pfn->m_stArgNames.GetLength() + pfn->m_stHelpText.GetLength();
    for (i = 0; anLimits[i]; i += 2) {
        if (pfn->m_astArgHelpText.GetSize() < anLimits[i])
            return TRUE;
        if (pfn->m_astArgHelpText.GetSize() == anLimits[i])
        {   
            if (cChars <= anLimits[i+1])
                return TRUE;
            else 
                break;
        }
    }
    if (anLimits[i])
    {
        TRACE("!!WARNING\n"
              "  Function '%s': m_stArgNames.GetLength()=%d; m_stHelpText.GetLength()=%d\n"
              "  Total = %d; limit for combined length = %d\n\n",
            (LPCSTR)pfn->m_stName,
            pfn->m_stArgNames.GetLength(),
            pfn->m_stHelpText.GetLength(),
            pfn->m_stArgNames.GetLength()+pfn->m_stHelpText.GetLength(),
            anLimits[i+1]);
    }
    else
    {
        TRACE("!!WARNING\n"
              "  Function '%s': argument count > 19\n"
              "  %d argument(s) will have no descriptions\n\n",
            (LPCSTR)pfn->m_stName,
            pfn->m_astArgHelpText.GetSize() - 19);
    }
    return FALSE;
}

BOOL XlCheckFnStrings(CXllApp* app, const char* pszExportedName) {
    CXllFn* pfn = app->FindFn(pszExportedName);
    if (pfn == 0)
    {
        TRACE("Function '%s' not found\n", pszExportedName);
        return FALSE;
    }
    return XlCheckFnStrings(pfn);
}

BOOL XlCheckFnStrings(CXllApp* app) {
    CXllApp::POSITION pos = app->GetStartFnPosition();
    CXllFn* pfn;
    CString fnName;
    BOOL bAnyBad = FALSE;
    while (pos != NULL) {
        app->GetNextFnAssoc(pos, fnName, pfn);
        if (!XlCheckFnStrings(pfn))
            bAnyBad = TRUE;
    }
    return !bAnyBad;
}

Call the string size checker in your InitInstance() function

Add a call to XlCheckFnStrings(app) in your InitInstance() function, as in the example below:

 
BOOL CCarefulApp::InitInstance() 
{
    // Call the base class
    if ( !CXllApp::InitInstance() )
        return FALSE;

    // Set the name of the library to the default value
    m_stName = m_pszDefName;

    // Add the statically defined function specifications
    AddStaticFns();

    // TODO: Add your specialized code here
#ifdef _DEBUG
    if (!XlCheckFnStrings(this)) 
    {
        MessageBox(NULL, "At least one function will lose its argument descriptions.\n"
            "See the console Debug window for more information", "XLL+",
            MB_OK+MB_ICONEXCLAMATION);
    }
#endif
    return TRUE;
}