// function Excel4 calls always as using XLOPER12 seem problematic int xlw::XlfFuncDesc::RegisterAs(const std::string& dllName, const std::string& suggestedHelpId, double mode_) const { // alias arguments XlfArgDescList& arguments = impl_->arguments_; int nbargs = static_cast<int>(arguments.size()); std::string args(returnTypeCode_); std::string argnames; // the synchronous part of an asynchronous function returns void if (XlfExcel::Instance().excel14() && impl_->Asynchronous_) { args = ">"; } XlfArgDescList::const_iterator it = arguments.begin(); while (it != arguments.end()) { argnames += (*it).GetName(); args += (*it).GetType(); ++it; if (it != arguments.end()) argnames+=", "; } // When the arguments add up to more then 255 char is problematic. the functions // will not register see see BUG ID: 2834715 on sourceforge - nc if(argnames.length() > 255) { argnames = "Too many arguments for Function Wizard"; } // the synchronous part of an asynchronous function have an extra // bigdata xloper on the end containing the handle if (XlfExcel::Instance().excel14() && impl_->Asynchronous_) { args += "X"; } if (impl_->recalcPolicy_ == xlw::XlfFuncDesc::Volatile) { args+="!"; } if (XlfExcel::Instance().excel12() && impl_->Threadsafe_) { args+="$"; } if (XlfExcel::Instance().excel14() && impl_->ClusterSafe_) { args+="&"; } if (impl_->MacroSheetEquivalent_) { args+="#"; } args+='\0'; // null termination for C string std::vector<LPXLOPER> argArray(10 + nbargs); LPXLOPER *px = &argArray[0]; std::string functionName(GetName()); // We need to have 2 functions exposed one for less than // version 14 and that it the normal function, we also need // the Synchronous part that returns void and takes an extra int // By convension this is the same as the normal function but with // Sync on the end if (XlfExcel::Instance().excel14() && impl_->Asynchronous_) { functionName += "Sync"; } (*px++) = XlfOper4(dllName); (*px++) = XlfOper4(functionName); (*px++) = XlfOper4(args); (*px++) = XlfOper4(GetAlias()); (*px++) = XlfOper4(argnames); (*px++) = XlfOper4(mode_); (*px++) = XlfOper4(impl_->category_); (*px++) = XlfOper4(""); // shortcut // use best help context if(!helpID_.empty() && helpID_ != "auto") { (*px++) = XlfOper4(helpID_); } else { (*px++) = XlfOper4(suggestedHelpId); } (*px++) = XlfOper4(GetComment()); int counter(0); for (it = arguments.begin(); it != arguments.end(); ++it) { ++counter; if(counter < nbargs) { (*px++) = XlfOper4((*it).GetComment()); } else { // add dot space to last comment to work around known excel bug // see http://msdn.microsoft.com/en-us/library/bb687841.aspx (*px++) = XlfOper4((*it).GetComment() + ". "); } } if(XlfExcel::Instance().excel12()) { // total number of arguments limited to 255 // so we can't send more than 245 argument comments nbargs = std::min(nbargs, 245); } else { // you can't send more than 30 arguments to the register function // in up to version 2003, so just only send help for up to the first 20 parameters nbargs = std::min(nbargs, 20); } XlfOper4 res; int err = XlfExcel::Instance().Call4v(xlfRegister, res, 10 + nbargs, &argArray[0]); if(err == xlretSuccess && res.IsNumber()) { funcId_ = res.AsDouble(); } else { funcId_ = InvalidFunctionId; } return err; }
int xlw::XlfOper4::ConvertToCellMatrix(CellMatrix& output) const { if (lpxloper_->xltype == xltypeMissing || lpxloper_->xltype == xltypeNil ) { CellMatrix tmp(1,1); output = tmp; return xlretSuccess; } if (lpxloper_->xltype == xltypeNum) { CellMatrix tmp(1,1); tmp(0,0) = lpxloper_->val.num; output = tmp; return xlretSuccess; } if (lpxloper_->xltype == xltypeBool) { CellMatrix tmp(1,1); tmp(0,0) = (lpxloper_->val.xbool >0); output = tmp; return xlretSuccess; } if (lpxloper_->xltype == xltypeErr) { CellMatrix tmp(1,1); tmp(0,0) = CellValue(lpxloper_->val.err,true); output = tmp; return xlretSuccess; } if (lpxloper_->xltype == xltypeStr) { CellMatrix tmpCell(1,1); unsigned long len = *((*lpxloper_).val.str); std::string tmp; tmp.resize(len); for(unsigned long k=0; k<len; ++k) tmp[k]= ((*lpxloper_).val.str)[k+1]; tmpCell(0,0) = tmp; output = tmpCell; return xlretSuccess; } if (lpxloper_->xltype == xltypeMulti) { unsigned long rows = lpxloper_->val.array.rows; unsigned long columns = lpxloper_->val.array.columns; CellMatrix result(rows,columns); for (unsigned long i=0; i < rows; i++) for (unsigned long j=0; j < columns; j++) { unsigned long thisType = (*lpxloper_).val.array.lparray[i*columns+j].xltype; if (thisType == xltypeNum) { double x = (*lpxloper_).val.array.lparray[i*columns+j].val.num; result(i,j) = x; } else { if (thisType==xltypeStr) { unsigned long len = *((*lpxloper_).val.array.lparray[i*columns+j].val.str); std::string tmp; tmp.resize(len); for(unsigned long k=0; k<len; ++k) tmp[k]= ((*lpxloper_).val.array.lparray[i*columns+j].val.str)[k+1]; result(i,j) = tmp; } else if (thisType == xltypeBool) { result(i,j) = ((*lpxloper_).val.array.lparray[i*columns+j].val.xbool > 0); } else if (thisType== xltypeErr) { result(i,j) = CellValue(((*lpxloper_).val.array.lparray[i*columns+j].val.err),true); } else if (thisType!=xltypeMissing && thisType != xltypeNil) throw("cell contains neither number nor string nor boolean nor empty"); } } output= result; return xlretSuccess; } XlfRef ref; int xlret = ConvertToRef(ref); if (xlret != xlretSuccess) return xlret; unsigned long nbRows = ref.GetNbRows(); unsigned long nbCols = ref.GetNbCols(); output = CellMatrix(nbRows,nbCols); for (unsigned long i = 0; i < nbRows; ++i) { for (unsigned long j = 0; j < nbCols; ++j) { XlfOper4 element = ref.element<XlfOper4>(static_cast<WORD>(i), static_cast<BYTE>(j)); unsigned long type = element.lpxloper_->xltype; if (type == xltypeRef) { XlfRef xlrefij; int xlretij = element.ConvertToRef(xlrefij); if (xlretij != xlretSuccess) return xlretij; XlfOper4 refElement = xlrefij.element<XlfOper4>(0UL,0UL); type = refElement.lpxloper_->xltype; if (type == xltypeNum) { double tmp; xlret = refElement.ConvertToDouble(tmp); output(i,j) = tmp; if (xlret != xlretSuccess) return xlret; } else if (type == xltypeErr) { WORD tmp; xlret = refElement.ConvertToErr(tmp); output(i,j) = CellValue(tmp,true); if (xlret != xlretSuccess) return xlret; } else if (type == xltypeBool) { bool tmp; xlret = refElement.ConvertToBool(tmp); output(i,j) = tmp; if (xlret != xlretSuccess) return xlret; } else { if (type == xltypeStr || type == xltypeSRef) { char* tmp; xlret = refElement.ConvertToString(tmp); output(i,j) = std::string(tmp); if (xlret != xlretSuccess) return xlret; } else { if (type != xltypeMissing) return xlretInvXloper; } } } else if (type == xltypeNum) { double tmp; xlret = element.ConvertToDouble(tmp); output(i,j) = tmp; if (xlret != xlretSuccess) return xlret; } else { if (type == xltypeStr || type == xltypeSRef) { char* tmp; xlret = element.ConvertToString(tmp); output(i,j) = std::string(tmp); if (xlret != xlretSuccess) return xlret; } else { if (element.lpxloper_->xltype != xltypeMissing) return xlretInvXloper; } } } } return xlret; }
/*! Registers the command as a macro in excel. \sa XlfExcel, XlfFuncDesc. */ int xlw::XlfCmdDesc::DoRegister(const std::string& dllName, const std::string& suggestedHelpId) const { XlfArgDescList arguments = GetArguments(); // 2 = normal macro, 0 = hidden command double type = hidden_ ? 0 : 2; int nbargs = static_cast<int>(arguments.size()); std::string args("A"); std::string argnames; XlfArgDescList::const_iterator it = arguments.begin(); while (it != arguments.end()) { argnames += (*it).GetName(); args += (*it).GetType(); ++it; if (it != arguments.end()) argnames+=", "; } // When the arguments add up to more then 255 char is problematic. the functions // will not register see see BUG ID: 2834715 on sourceforge - nc if(argnames.length() > 255) { argnames = "Too many arguments for Function Wizard"; } std::vector<LPXLOPER> argArray(10 + nbargs); LPXLOPER *px = &argArray[0]; (*px++) = XlfOper4(dllName); (*px++) = XlfOper4(GetName()); (*px++) = XlfOper4(args); (*px++) = XlfOper4(GetAlias()); (*px++) = XlfOper4(argnames); (*px++) = XlfOper4(type); (*px++) = XlfOper4(""); (*px++) = XlfOper4(""); (*px++) = XlfOper4(""); (*px++) = XlfOper4(GetComment()); int counter(0); for (it = arguments.begin(); it != arguments.end(); ++it) { ++counter; if(counter < nbargs) { (*px++) = XlfOper4((*it).GetComment()); } else { // add dot space to last comment to work around known excel bug // see http://msdn.microsoft.com/en-us/library/bb687841.aspx (*px++) = XlfOper4((*it).GetComment() + ". "); } } if(XlfExcel::Instance().excel12()) { // total number of arguments limited to 255 // so we can't send more than 245 argument comments nbargs = std::min(nbargs, 245); } else { // you can't send more than 30 arguments to the register function // in up to version 2003, so just only send help for up to the first 20 parameters nbargs = std::min(nbargs, 20); } XlfOper4 res; int err = XlfExcel::Instance().Call4v(xlfRegister, res, 10 + nbargs, &argArray[0]); if(err == xlretSuccess && res.IsNumber()) { funcId_ = res.AsDouble(); } else { funcId_ = InvalidFunctionId; } return err; }