/* *************************************************************************** ** Standard Excel function to provide the library name to Excel. *************************************************************************** */ XLFUNC(LPXLOPER) xlAddInManagerInfo(LPXLOPER xAction) { static XLOPER xInfo, xIntAction; static char xLibName[JPMCDS_MAX_LIB_NAME]; LPXLOPER pxInfo; /* ** This code coerces the passed-in value to an integer. This is how the ** code determines what is being requested. If it receives a 1, ** it returns a string representing the long name. If it receives ** anything else, it returns a #VALUE! error. */ Excel(xlCoerce, &xIntAction, 2, xAction, TempInt(xltypeInt)); if(xIntAction.val.w == 1) { xInfo.xltype = xltypeStr; xLibName[0] = strlen(gtoLibName); strncpy (xLibName+1, gtoLibName, xLibName[0]); xInfo.val.str = xLibName; } else { xInfo.xltype = xltypeErr; xInfo.val.err = xlerrValue; } Excel(xlFree, 0, 1, (LPXLOPER) &xIntAction ,0); pxInfo = &xInfo; return pxInfo; }
XLL_DEC OPER *ohRemoveInvalidColumns(OPER *xInputRange) { // initialize Function Call object boost::shared_ptr<reposit::FunctionCall> functionCall; reposit::Xloper xMulti; static OPER xRet; xRet.val.array.lparray = 0; try { functionCall = boost::shared_ptr<reposit::FunctionCall> (new reposit::FunctionCall("ohRemoveInvalidColumns")); Excel(xlCoerce, &xMulti, 2, xInputRange, TempInt(xltypeMulti)); int numValidCols = countValidColumns(xMulti()); if (!numValidCols) return 0; int numRows = xMulti->val.array.rows; xRet.val.array.rows = numRows; xRet.val.array.columns = numValidCols; xRet.val.array.lparray = new OPER[numRows * numValidCols]; xRet.xltype = xltypeMulti | xlbitDLLFree; for (int i=0; i<xMulti->val.array.rows; ++i) { int j2 = 0; for (int j=0; j<xMulti->val.array.columns; ++j) { if (columnIsValid(xMulti(), j)) { int indexSource = i * xMulti->val.array.columns + j; int indexTarget = i * numValidCols + j2; operToOper(&xRet.val.array.lparray[indexTarget], &xMulti->val.array.lparray[indexSource]); j2++; } } } return &xRet; } catch (const std::exception &e) { // free any memory that may have been allocated if (xRet.xltype & xltypeMulti && xRet.val.array.lparray) { for (int i=0; i<xRet.val.array.columns * xRet.val.array.rows; ++i) { if (xRet.val.array.lparray[i].xltype & xltypeStr && xRet.val.array.lparray[i].val.str) delete [] xRet.val.array.lparray[i].val.str; } delete [] xRet.val.array.lparray; } // log the exception and return a null pointer (#NUM!) to Excel reposit::RepositoryXL::instance().logError(e.what(), functionCall); return 0; } }
XLL_DEC OPER *ohFilter( OPER *xInput, OPER *flags) { // declare a shared pointer to the Function Call object boost::shared_ptr<ObjectHandler::FunctionCall> functionCall; try { // instantiate the Function Call object functionCall = boost::shared_ptr<ObjectHandler::FunctionCall>( new ObjectHandler::FunctionCall("ohFilter")); // convert input datatypes to C++ datatypes std::vector<bool> flagsCpp = ObjectHandler::operToVector<bool>(*flags, "flags"); const OPER *xMulti; ObjectHandler::Xloper xTemp; if (xInput->xltype == xltypeMulti) { xMulti = xInput; } else { Excel(xlCoerce, &xTemp, 2, xInput, TempInt(xltypeMulti)); xMulti = &xTemp; } int sizeInput = xMulti->val.array.rows * xMulti->val.array.columns; OH_REQUIRE(sizeInput == flagsCpp.size(), "size mismatch between value vector (" << sizeInput << ") and flag vector (" << flagsCpp.size() << ")"); static OPER xRet; xRet.val.array.rows = count(flagsCpp.begin(), flagsCpp.end(), true); xRet.val.array.columns = 1; xRet.val.array.lparray = new OPER[xRet.val.array.rows]; xRet.xltype = xltypeMulti | xlbitDLLFree; int idx = 0; for (int i=0; i<sizeInput; i++) { if (flagsCpp[i]) { operToOper(&xRet.val.array.lparray[idx++], &xMulti->val.array.lparray[i]); } } return &xRet; } catch (const std::exception &e) { ObjectHandler::RepositoryXL::instance().logError(e.what(), functionCall); return 0; } }
/* *************************************************************************** ** Standard Excel function for addin unloaded event. *************************************************************************** */ XLFUNC(int) xlAutoRemove(void) { char buf[JPMCDS_MAX_LIB_NAME+32]; strcpy(buf, " "); strcat(buf, gtoLibName); strcat(buf, " add-in has been removed"); Excel(xlcAlert, 0, 2, TempStr(buf), TempInt(2)); return 1; }
/* *************************************************************************** ** Standard Excel function for addin loaded event. *************************************************************************** */ XLFUNC(int) xlAutoAdd(void) { char buf[JPMCDS_MAX_LIB_NAME+32]; strcpy(buf, " "); strcat(buf, gtoLibName); strcat(buf, " add-in has been loaded"); /* Display a dialog box indicating that the XLL was successfully added */ Excel(xlcAlert, 0, 2, TempStr(buf), TempInt(2)); return 1; }
QuantLib::Array operToQlArray(const OPER &xVector, const std::string paramName) { OPER xTemp; bool excelToFree = false; bool xllToFree = false; try { RP_REQUIRE(!(xVector.xltype & xltypeErr), "input value '" << paramName << "' has type=error"); if (xVector.xltype & (xltypeMissing | xltypeNil)) return QuantLib::Array(); const OPER *xMulti; if (xVector.xltype == xltypeMulti) { xMulti = &xVector; } else if (xVector.xltype == xltypeStr) { splitOper(&xVector, &xTemp); xMulti = &xTemp; xllToFree = true; } else { Excel(xlCoerce, &xTemp, 2, &xVector, TempInt(xltypeMulti)); xMulti = &xTemp; excelToFree = true; } int size = xMulti->val.array.rows * xMulti->val.array.columns; QuantLib::Array a(size); for (int i=0; i<size; ++i) { a[i] = reposit::convert2<double>(reposit::ConvertOper(xMulti->val.array.lparray[i])); } if (excelToFree) { Excel(xlFree, 0, 1, &xTemp); } else if (xllToFree) { freeOper(&xTemp); } return a; } catch (const std::exception &e) { if (excelToFree) { Excel(xlFree, 0, 1, &xTemp); } else if (xllToFree) { freeOper(&xTemp); } RP_FAIL("operToVector: error converting parameter '" << paramName << "' : " << e.what()); } }
DLLEXPORT XLOPER *xlAddInManagerInfo(XLOPER *xlAction) { XLOPER xlReturn; static XLOPER xlLongName; // Coerce the argument XLOPER to an integer. Excel(xlCoerce, &xlReturn, 2, xlAction, TempInt(xltypeInt)); // The only valid argument value is 1. In this case we return the // long name for the XLL. Any other value should result in the // return of a #VALUE! error. if (1 == xlReturn.val.w) { ObjectHandler::scalarToOper(std::string("ObjectHandler 1.2.0"), xlLongName); } else { xlLongName.xltype = xltypeErr; xlLongName.val.err = xlerrValue; } return &xlLongName; }
/* *************************************************************************** ** Standard Excel addin entry point. *************************************************************************** */ XLFUNC(short) xlAutoOpen(void) { int xlret; char buf[128]; XLOPER xDLL; LPXLOPER pxDLL = &xDLL; size_t i; xlret = Excel(xlGetName, pxDLL, 0); if (xlret != xlretSuccess) { sprintf(buf, " Excel get DLL name function failed: %s", JpmcdsExcelFormatReturnStatus(xlret)); Excel(xlcAlert,0,2,TempStr(buf),TempInt(2)); return 1; } for (i = 0 ; i < gtoFuncDefCount ; i++) RegisterFunction(pxDLL, FNPREFIX, gtoFuncDefList[i]); Excel(xlFree,0,1,pxDLL); return 1; }
std::vector<std::vector<T> > operToMatrixImpl( const ConvertOper &xMatrix, const std::string ¶mName) { try { if (xMatrix.missing()) return std::vector<std::vector<T> >(); OH_REQUIRE(!xMatrix.error(), "input value has type=error"); const OPER *xMulti; Xloper xCoerce; // Freed automatically if (xMatrix->xltype == xltypeMulti) xMulti = xMatrix.get(); else { Excel(xlCoerce, &xCoerce, 2, xMatrix.get(), TempInt(xltypeMulti)); xMulti = &xCoerce; } std::vector<std::vector<T> > ret; ret.reserve(xMulti->val.array.rows); for (int i=0; i<xMulti->val.array.rows; ++i) { std::vector<T> row; row.reserve(xMulti->val.array.columns); for (int j=0; j<xMulti->val.array.columns; ++j) { row.push_back(convert2<T>(ConvertOper(xMulti->val.array.lparray[i * xMulti->val.array.columns + j]))); } ret.push_back(row); } return ret; } catch (const std::exception &e) { OH_FAIL("operToMatrixImpl: error converting parameter '" << paramName << "' to type '" << typeid(T).name() << "' : " << e.what()); } }
void loop( const boost::shared_ptr<FunctionCall> &functionCall, LoopFunction &loopFunction, OPER *xIn, XLOPER &xOut) { // FIXME - xTemp may not be cleaned up properly in the event of an exception. OPER xTemp, *xMulti; bool excelToFree = false; bool xllToFree = false; // If the input is an array then take its address & carry on if (xIn->xltype == xltypeMulti) { xMulti = xIn; // If the input is a list then call split on it } else if (isList(xIn)) { splitOper(xIn, &xTemp); xMulti = &xTemp; xllToFree = true; // If the input is a scalar then just call the function once & return } else if (xIn->xltype == xltypeNum || xIn->xltype == xltypeBool || xIn->xltype == xltypeStr) { LoopIteration<LoopFunction, InputType, OutputType>()( loopFunction, *xIn, xOut, true); return; // Some other input (e.g. a reference) - try to convert to an array } else { Excel(xlCoerce, &xTemp, 2, xIn, TempInt(xltypeMulti)); xMulti = &xTemp; excelToFree = true; } xOut.val.array.rows = xMulti->val.array.rows; xOut.val.array.columns = xMulti->val.array.columns; int numCells = xMulti->val.array.rows * xMulti->val.array.columns; xOut.val.array.lparray = new XLOPER[numCells]; xOut.xltype = xltypeMulti | xlbitDLLFree; int errorCount = 0; std::ostringstream err; LoopIteration<LoopFunction, InputType, OutputType> loopIteration; for (int i=0; i<numCells; ++i) { try { loopIteration(loopFunction, xMulti->val.array.lparray[i], xOut.val.array.lparray[i], false); } catch (const std::exception &e) { xOut.val.array.lparray[i].xltype = xltypeErr; xOut.val.array.lparray[i].val.err = xlerrNum; if (errorCount > ERROR_LIMIT) { // Limit exceeded. Take no action. For performance reasons we test // this case first since it's most common on big loop w/many errors ; } else if (errorCount < ERROR_LIMIT) { err << std::endl << std::endl << "iteration #" << i << " - " << e.what(); errorCount++; } else { // errorCount == ERROR_LIMIT err << std::endl << std::endl << "iteration #" << i << " - " << e.what() << std::endl << std::endl << "Count of failed iterations in looping function hit " << "limit of " << ERROR_LIMIT + 1 << " - logging discontinued"; errorCount++; } } } if (errorCount) RepositoryXL::instance().logError(err.str(), functionCall); // Free memory if (excelToFree) { Excel(xlFree, 0, 1, &xTemp); } else if (xllToFree) { freeOper(&xTemp); } }
const XLOPER *FunctionCall::callerArray() { if (!xMulti_->xltype) Excel(xlCoerce, &xMulti_, 2, &xCaller_, TempInt(xltypeMulti)); return &xMulti_; }
/* *************************************************************************** ** Function to register one function given by its add-in function ** definition. *************************************************************************** */ static void RegisterFunction(LPXLOPER pxDLL, char *prefix, TFuncDef *funcDef) { int status = FAILURE; /* ** These are all pascal strings to be used with string type OPERs ** for calls to Excel. We will want to use standard C-string ** functionality while building the strings, so we need an extra ** character at the end. Thus 257 is the maximum length. */ static char errMsg[257]; static char argTypes[33]; /* Argument types - a string of P's */ static char argNames[257]; /* Argument names */ static char funcName[257]; /* Function name */ static char cFuncName[257];/* C-function name */ static char catName[257]; /* Category name */ static char funcDesc[257]; /* function description */ size_t nameLen; size_t numArgs; size_t lenArgNames; TBoolean namesAreTooLong; size_t maxArgs = sizeof(argTypes)-2; size_t maxLenArgNames = sizeof(argNames)-2; size_t ipos; size_t nargs; /* Define the category name as a pascal string. */ catName[0] = strlen(FUNCTION_CATEGORY); strcpy (catName+1, FUNCTION_CATEGORY); /* Define the function name as a pascal string. */ funcName[0] = strlen(prefix) + strlen(funcDef->name) + 1; strcpy (funcName+1, prefix); strcat (funcName, "_"); strcat (funcName, funcDef->name); strncpy (cFuncName, funcName, sizeof(funcName)); maxLenArgNames -= (funcName[0] + 2); /* it seems to be this way! */ /* *********************************************************************** ** Define the list of argument types as a pascal string. ** ** There is always one output, plus the standard inputs. ** ** If the function is an object constructor then the base name is ** needed. *********************************************************************** */ numArgs = 1 + funcDef->numInputs; if (numArgs > maxArgs) { sprintf (errMsg+1, "%s: Too many arguments (%d)\n", funcName+1, numArgs); goto done; } argTypes[0] = (char)numArgs; memset (argTypes+1, '\0', maxArgs+1); memset (argTypes+1, 'P', numArgs); /* *********************************************************************** ** Build up the list of argument names as a pascal string. ** ** For convenience, there will be a comma at the beginning of the ** string in the short term! ** ** If this exceeds the maximum length, then we will use a short format. *********************************************************************** */ namesAreTooLong = FALSE; lenArgNames = 0; argNames[1] = '\0'; /* Start with an empty string */ for (ipos = 0; ipos < funcDef->numInputs; ++ipos) { TParamDef *paramDef; paramDef = funcDef->params + ipos; nameLen = strlen(paramDef->name); if ((lenArgNames + nameLen + 1) > maxLenArgNames) { namesAreTooLong = TRUE; break; /* No need to do any more... */ } else { argNames[lenArgNames] = ','; ++lenArgNames; strcpy (argNames+lenArgNames, paramDef->name); lenArgNames += nameLen; } } if (namesAreTooLong) { sprintf (errMsg+1, "%s: Argument names are too long for Excel. Maximum length = %ld.", funcName+1, maxLenArgNames); goto done; } argNames[0] = (char)(lenArgNames); /* Define the function description as a pascal string. */ if (funcDef->description != NULL) { funcDesc[0] = ' '; strncpy(funcDesc + 1, funcDef->description, 255); funcDesc[256] = '\0'; } else { funcDesc[0] = ' '; funcDesc[1] = '\0'; } /* ** Since we use TempStr, it doesn't matter what is in the first character ** of the strings, since TempStr replaces it with the string length. ** ** As it happens, it should be the correct length already! */ nargs = funcDef->numInputs; if (nargs > 20) nargs = 20; /* Excel has limit of 30 LXOPERS - so cannot register remaining parameters descriptions */ Excel (xlfRegister, 0, /* not interested in any return details */ 10 + nargs, /* number of input parameters in this registration call */ pxDLL, TempStr(funcName), TempStr(argTypes), TempStr(cFuncName), TempStr(argNames), TempStr(" 1"), TempStr(catName), TempStr(" "), /* hot key / short cut */ TempStr(" "), /* help id, eg. "alib.hlp!123" */ TempStr(funcDesc), /* function description */ /* argument descriptions */ ParameterDescription(funcDef, 0), ParameterDescription(funcDef, 1), ParameterDescription(funcDef, 2), ParameterDescription(funcDef, 3), ParameterDescription(funcDef, 4), ParameterDescription(funcDef, 5), ParameterDescription(funcDef, 6), ParameterDescription(funcDef, 7), ParameterDescription(funcDef, 8), ParameterDescription(funcDef, 9), ParameterDescription(funcDef, 10), ParameterDescription(funcDef, 11), ParameterDescription(funcDef, 12), ParameterDescription(funcDef, 13), ParameterDescription(funcDef, 14), ParameterDescription(funcDef, 15), ParameterDescription(funcDef, 16), ParameterDescription(funcDef, 17), ParameterDescription(funcDef, 18), ParameterDescription(funcDef, 19)); status = SUCCESS; done: if (status != SUCCESS) { Excel (xlcAlert, 0, 2, TempStr(errMsg), TempInt(2)); } }