[gnumeric] xll: initial support.



commit 3e3c8e6e7815e7c1128226d586d5ef469a48765a
Author: Morten Welinder <terra gnome org>
Date:   Tue Feb 2 13:26:51 2010 -0500

    xll: initial support.

 NEWS                                      |    3 +
 configure.in                              |    1 +
 plugins/Makefile.am                       |    2 +-
 plugins/excelplugins/.gitignore           |    9 +
 plugins/excelplugins/ExcelTestModule.c    |  293 +++++++++
 plugins/excelplugins/Makefile.am          |   21 +
 plugins/excelplugins/excelplugins.c       |  971 +++++++++++++++++++++++++++++
 plugins/excelplugins/plugin.xml.in        |   11 +
 plugins/excelplugins/win32replacements.h  |   72 +++
 plugins/excelplugins/xlcall.h             |  971 +++++++++++++++++++++++++++++
 plugins/excelplugins/xlcall32_emulation.c |   87 +++
 po-functions/POTFILES.in                  |    1 +
 po-functions/POTFILES.skip                |    1 +
 po/POTFILES.in                            |    2 +
 14 files changed, 2444 insertions(+), 1 deletions(-)
---
diff --git a/NEWS b/NEWS
index 48009e0..0cde722 100644
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,9 @@ Morten:
 	* Fix TDIST border case.  [#607008]
 	* Fix problem with hpaned for tabs/scrollbar.  [#607794]
 
+Peter Jaeckel:
+	* Support for XLL files.  [#597849]
+
 --------------------------------------------------------------------------
 Gnumeric 1.9.18
 
diff --git a/configure.in b/configure.in
index ea89f33..c7ce4cb 100644
--- a/configure.in
+++ b/configure.in
@@ -1066,6 +1066,7 @@ plugins/applix/Makefile
 plugins/corba/Makefile
 plugins/dif/Makefile
 plugins/excel/Makefile
+plugins/excelplugins/Makefile
 plugins/gda/Makefile
 plugins/gnome-db/Makefile
 plugins/gnome-glossary/Makefile
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 8f0dea1..cb20731 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -23,7 +23,7 @@ if WITH_GNOMEDB
   SUBDIRS_FUNCTIONS += gnome-db
 endif
 
-SUBDIRS_LOADERS =
+SUBDIRS_LOADERS = excelplugins
 SUBDIRS_EXAMPLES = uihello
 
 # Do not build by default until the libtool problems with
diff --git a/plugins/excelplugins/.gitignore b/plugins/excelplugins/.gitignore
new file mode 100644
index 0000000..e64b392
--- /dev/null
+++ b/plugins/excelplugins/.gitignore
@@ -0,0 +1,9 @@
+Makefile.in
+Makefile
+.deps
+.libs
+*.lo
+*.la
+plugin.xml
+*.loT
+*.sw*
diff --git a/plugins/excelplugins/ExcelTestModule.c b/plugins/excelplugins/ExcelTestModule.c
new file mode 100644
index 0000000..55e1d14
--- /dev/null
+++ b/plugins/excelplugins/ExcelTestModule.c
@@ -0,0 +1,293 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * ExcelTestModule.c: Standalone XLL code for test purposes.
+ *
+ * Author:
+ *   Peter Jaeckel (peter jaeckel gmail com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <gmodule.h>
+
+#if defined( WIN32 ) || defined( WIN64 )
+#include <windef.h>
+#else
+#include "win32replacements.h"
+#endif
+
+#include "xlcall.h"
+
+/* All bits that are mutually exclusive in the type field of an xloper. */
+#define xltypeType       0x0FFF
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_G_SLICE_ALLOC
+#define g_slice_new_array0(T,c) ((T*) g_slice_alloc0 ((sizeof (T))*(c)))
+#define ALLOC_ARRAY(T,c) (g_slice_new_array0 (T,c))
+#define FREE_ARRAY(p,c) (g_slice_free1 (sizeof(*p)*(c),(p)))
+#else
+#define ALLOC_ARRAY(T,c) (g_new0 (T,c))
+#define FREE_ARRAY(p,c)  (g_free ((p)))
+#endif
+
+static char * pascal_string_from_c_string(const char *s){
+	char *o=NULL;
+	if (NULL!=s){
+		guint l = strlen(s);
+		g_assert(l<(UINT_MAX-2U));
+		o = g_malloc(l+2U);
+		g_strlcpy(o+1,s,l+1);
+		if (l>UCHAR_MAX)
+			l=UCHAR_MAX;
+		o[0]=(unsigned char)l;
+	}
+	return o;
+}
+
+;
+
+static char * duplicate_pascal_string(const char *s){
+	return NULL==s?NULL:g_memdup(s,s[0]+1);
+}
+
+#define CASE( x ) case (x): return #x
+
+static const char * xloper_type_name(const XLOPER*x){
+	if (NULL!=x){
+		switch(x->xltype & xltypeType){
+		CASE(xltypeNum);
+		CASE(xltypeStr);
+		CASE(xltypeBool);
+		CASE(xltypeRef);
+		CASE(xltypeErr);
+		CASE(xltypeFlow);
+		CASE(xltypeMulti);
+		CASE(xltypeMissing);
+		CASE(xltypeNil);
+		CASE(xltypeSRef);
+		CASE(xltypeInt);
+		default: return "<unknown>";
+		}
+	}
+	return "(nil)";
+}
+
+static void unsupported_xloper_type(const XLOPER*x){
+	g_warning(("Unsupported xloper type \"%s\""),xloper_type_name(x));
+}
+
+static void destruct_xloper(XLOPER*x){
+	int i,n;
+	if (NULL!=x){
+		switch(x->xltype & xltypeType){
+		case xltypeNum:							break;
+		case xltypeStr:		g_free(x->val.str); x->val.str=0;	break;
+		case xltypeBool:						break;
+		case xltypeRef:		unsupported_xloper_type(x);		break;
+		case xltypeErr:							break;
+		case xltypeFlow:	unsupported_xloper_type(x);		break;
+		case xltypeMulti:
+			n=x->val.array.rows*x->val.array.columns;
+			for (i=0;i<n;++i){
+				destruct_xloper(x->val.array.lparray+i);
+			}
+			FREE_ARRAY(x->val.array.lparray,n);
+			break;
+		case xltypeMissing:						break;
+		case xltypeNil:							break;
+		case xltypeSRef:	unsupported_xloper_type(x);		break;
+		case xltypeInt:							break;
+		default:		unsupported_xloper_type(x);
+		}
+	}
+	x->xltype=xltypeNil;
+}
+
+static void copy_construct_xloper(XLOPER*x,const XLOPER*y){
+	int i,n;
+	if (NULL!=x){
+		x->xltype=xltypeMissing;
+		if(NULL!=y){
+			g_memmove(x,y,sizeof(XLOPER));
+			switch(y->xltype & xltypeType){
+			case xltypeStr:
+				x->val.str=duplicate_pascal_string(y->val.str);
+				break;
+			case xltypeMulti:
+				n=y->val.array.rows*y->val.array.columns;
+				x->val.array.lparray=ALLOC_ARRAY(XLOPER,n);
+				for (i=0;i<n;++i){
+					copy_construct_xloper(x->val.array.lparray+i,y->val.array.lparray+i);
+				}
+				break;
+			default:;
+			}
+			x->xltype = (y->xltype & xltypeType);
+		}
+
+	}
+}
+
+G_MODULE_EXPORT BOOL APIENTRY DllMain( HANDLE hDLL, DWORD dwReason, LPVOID lpReserved ) {
+  return TRUE;
+}
+
+G_MODULE_EXPORT const XLOPER* hello(){
+	XLOPER*r=ALLOC_ARRAY(XLOPER,1);
+	r->xltype=xltypeStr|xlbitDLLFree;
+	r->val.str=pascal_string_from_c_string("Hello!");
+	return r;
+}
+
+G_MODULE_EXPORT const XLOPER* helloWorld(){
+	XLOPER*r=ALLOC_ARRAY(XLOPER,1);
+	r->xltype=xltypeStr|xlbitDLLFree;
+	r->val.str=pascal_string_from_c_string("Hello World!");
+	return r;
+}
+
+G_MODULE_EXPORT const XLOPER* convertAstronomicalUnitsToKilometers(const XLOPER*x){
+	XLOPER*r=NULL;
+	if ( NULL!=x && (x->xltype&xltypeType)==xltypeNum ) {
+		r=ALLOC_ARRAY(XLOPER,1);
+		r->xltype=xltypeNum|xlbitDLLFree;
+		r->val.num=x->val.num*149600000.;
+	}
+	return r;
+}
+
+G_MODULE_EXPORT const XLOPER* multiplyTwoNumbers(const XLOPER*x,const XLOPER*y){
+	XLOPER*r=NULL;
+	if ( NULL!=x && (x->xltype&xltypeType)==xltypeNum && NULL!=y && (y->xltype&xltypeType)==xltypeNum ) {
+		r=ALLOC_ARRAY(XLOPER,1);
+		r->xltype=xltypeNum|xlbitDLLFree;
+		r->val.num=x->val.num*y->val.num;
+	}
+	return r;
+}
+
+G_MODULE_EXPORT const XLOPER* arrangeInSquareMatrix(const XLOPER*a,const XLOPER*b,const XLOPER*c,const XLOPER*d){
+	XLOPER*r=NULL;
+	if ( NULL!=a && NULL!=b && NULL!=c && NULL!=d ) {
+		r=ALLOC_ARRAY(XLOPER,1);
+		r->xltype=xltypeMulti|xlbitDLLFree;
+		r->val.array.rows=2;
+		r->val.array.columns=2;
+		r->val.array.lparray=ALLOC_ARRAY(XLOPER,4);
+		copy_construct_xloper(r->val.array.lparray  ,a);
+		copy_construct_xloper(r->val.array.lparray+1,b);
+		copy_construct_xloper(r->val.array.lparray+2,c);
+		copy_construct_xloper(r->val.array.lparray+3,d);
+
+	}
+	return r;
+}
+
+G_MODULE_EXPORT const XLOPER* sumAndProduct(const XLOPER*m){
+	XLOPER*r=NULL;
+	if ( NULL!=m ) {
+		r=ALLOC_ARRAY(XLOPER,1);
+		r->xltype=xltypeMulti|xlbitDLLFree;
+		r->val.array.rows=1;
+		r->val.array.columns=2;
+		r->val.array.lparray=ALLOC_ARRAY(XLOPER,2);
+		r->val.array.lparray[0].xltype=xltypeNum;
+		r->val.array.lparray[0].val.num = 0;
+		r->val.array.lparray[1].xltype=xltypeNum;
+		r->val.array.lparray[1].val.num = 1;
+		if ((m->xltype&xltypeType)==xltypeMulti){
+			int i,j;
+			for (i=0;i<m->val.array.columns;++i){
+				for (j=0;j<m->val.array.rows;++j){
+					const double x = m->val.array.lparray[i*m->val.array.rows+j].val.num;
+					r->val.array.lparray[0].val.num += x;
+					r->val.array.lparray[1].val.num *= x;
+				}
+			}
+		}
+
+	}
+	return r;
+}
+
+typedef const char * Excel4RegistrationInfo[30];
+
+static Excel4RegistrationInfo registration_info[] = {
+  {
+    "helloWorld", "P", "helloWorld", "", "1", "Friendly", "", "", "helloWorld() returns \"Hello World!\".",
+    NULL
+  },
+  {
+    "hello", "P", "hello",      "", "1", "Friendly", "", "", "hello() returns \"Hello\".",
+    NULL
+  },
+  {
+    "convertAstronomicalUnitsToKilometers", "PP", "convertAstronomicalUnitsToKilometers", "au", "1", "Astronomical", "", "", "convertAstronomicalUnitsToKilometers(au) returns au * 149600000.",
+    "astronomical units", NULL
+  },
+  {
+    "multiplyTwoNumbers", "PPP", "multiplyTwoNumbers", "x,y", "1", "Mathematics", "", "", "multiplyTwoNumbers(X,Y) returns X*Y.",
+    "first multiplicand", "second multiplicand", NULL
+  },
+  {
+    "arrangeInSquareMatrix", "PPPPP", "arrangeInSquareMatrix", "a,b,c,d", "1", "Mathematics", "", "", "arrangeInSquareMatrix(a,b,c,d) returns a square matrix {{a,b},{c,d}}.",
+    "top left entry", "top right entry", "bottom left entry", "bottom right entry", NULL
+  },
+  {
+    "sumAndProduct", "PP", "sumAndProduct", "M", "1", "Mathematics", "", "", "sumAndProduct(M) returns the sum and the product of the matrix M.",
+    "a matrix", NULL
+  }
+};
+
+static void registerAllFunctions(void){
+  XLOPER xlopers[30];
+  XLOPER *excel4vArgs[30];
+  XLOPER xlRet;
+  unsigned long i,j;
+  const unsigned long n = sizeof(registration_info)/sizeof(Excel4RegistrationInfo);
+  for (i=0;i<30;++i){
+    excel4vArgs[i]=xlopers+i;
+  }
+  Excel4(xlGetName, excel4vArgs[0], 0);
+  for (i=0;i<n;++i){
+    for (j=0;j<29&&NULL!=registration_info[i][j];++j){
+      excel4vArgs[1+j]->xltype=xltypeStr;
+      excel4vArgs[1+j]->val.str=pascal_string_from_c_string(registration_info[i][j]);
+    }
+    Excel4v(xlfRegister, &xlRet, j+1, excel4vArgs);
+    for (j=0;j<29&&NULL!=registration_info[i][j];++j){
+      g_free(excel4vArgs[1+j]->val.str);
+    }
+  }
+}
+
+G_MODULE_EXPORT int xlAutoOpen() {
+  registerAllFunctions();
+  return 1;
+}
+
+G_MODULE_EXPORT int xlAutoClose() {
+  return 1;
+}
+
+G_MODULE_EXPORT void xlAutoFree(XLOPER*p) {
+  destruct_xloper(p);
+  FREE_ARRAY(p,1);
+  return;
+}
diff --git a/plugins/excelplugins/Makefile.am b/plugins/excelplugins/Makefile.am
new file mode 100644
index 0000000..1b5e429
--- /dev/null
+++ b/plugins/excelplugins/Makefile.am
@@ -0,0 +1,21 @@
+AM_CPPFLAGS = \
+    -DGNOMELOCALEDIR=\""$(datadir)/locale"\" 	\
+    -I$(top_srcdir)/src	-I$(top_builddir)/src	\
+    $(GNUMERIC_CFLAGS)
+
+gnumeric_plugin_excelpluginsdir = $(gnumeric_plugindir)/excelplugins
+xmldir = $(gnumeric_plugin_excelpluginsdir)
+gnumeric_plugin_excelplugins_LTLIBRARIES = plugin.la xlcall32.la
+plugin_la_LDFLAGS = -module $(GNUMERIC_PLUGIN_LDFLAGS)
+plugin_la_LIBADD = ../../src/.libs/libspreadsheet.la
+plugin_la_SOURCES = excelplugins.c
+xlcall32_la_LDFLAGS = -module $(GNUMERIC_PLUGIN_LDFLAGS)
+xlcall32_la_SOURCES = xlcall32_emulation.c
+
+xml_in_files = plugin.xml.in
+xml_DATA = $(xml_in_files:.xml.in=.xml)
+
+ INTLTOOL_XML_RULE@
+
+EXTRA_DIST = $(xml_in_files)
+DISTCLEANFILES = $(xml_DATA)
diff --git a/plugins/excelplugins/excelplugins.c b/plugins/excelplugins/excelplugins.c
new file mode 100644
index 0000000..8e6ed9e
--- /dev/null
+++ b/plugins/excelplugins/excelplugins.c
@@ -0,0 +1,971 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * excelplugins.c: Adapter interface to load worksheet functions defined in Excel plugins (also known as XLLs).  Note
+ *                 that this adapter interface only works for XLL worksheet functions that expect all their arguments
+ *                 to be of type OPER (type 'P' in the Excel SDK documentation) or of type eXtended exceL OPER (type
+ *                 'R' in the Excel SDK documentation known as XLOPER) and that return their results as an OPER (type
+ *                 'P'). Note that type 'R' can give rise to sheet references to be passed in which this code here
+ *                 cannot handle whence it is best to only use type 'P'.
+ *
+ * Author:
+ *   Peter Jaeckel (peter jaeckel gmail com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <gnumeric-config.h>
+#include <gnumeric.h>
+#include <func.h>
+#include <value.h>
+#include <gnm-i18n.h>
+#include <gnm-plugin.h>
+#include <goffice/utils/go-glib-extras.h>
+#include <stdint.h>
+#include <glib/gstdio.h>
+#include <workbook.h>
+#include <sheet.h>
+#include <cell.h>
+#include <expr-impl.h>
+#include <string.h>
+
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <sys/mman.h>
+#endif
+
+#if defined( HAVE_G_SLICE_ALLOC )
+#define g_slice_new_array0(T,c) ((T*) g_slice_alloc0 ((sizeof (T))*(c)))
+#define ALLOC_ARRAY(T,c) ( g_slice_new_array0 (T,c) )
+#define FREE_ARRAY(p,c)  ( g_slice_free1 (sizeof(*p)*(c),(p)) )
+#else
+#define ALLOC_ARRAY(T,c) ( g_new0 (T,c) )
+#define FREE_ARRAY(p,c)  ( g_free ((p)) )
+#endif
+
+GNM_PLUGIN_MODULE_HEADER;
+
+/***************************************************************************/
+
+/* When Gnumeric calls a worksheet function, it directly calls into the given entry point, and passes in data in
+ * Gnumeric style. Since an external XLL's exposed functions expect data in Excel format, those functions' entry points
+ * cannot simply be forwarded to Gnumeric. Instead, a conversion function is invoked. Luckily, the Gnumeric
+ * infrastructure provides EvalFunctionInfo pointer at the time of call. Given the EvalFunctionInfo *ei, we have the
+ * name of the function we are calling in ei->func_call->func->name. We can use this, to look up which function is
+ * actually to be called. For the look-up, we create a global function map (name->some structure) at the time of
+ * go_plugin_init that we peruse later. At the heart of the communication between Gnumeric and the XLL is a little
+ * adapter function, sometimes called a "shim". This function is the one that is actually called by Gnumeric when it
+ * tries to call one of the functions that actually live in the XLL. The shim is called
+ *
+ *	genericXLLFunction() .
+ *
+ * Once it has looked up the function name in its information database, it knows how many arguments of what type the
+ * external XLL function expects, and can convert argument types, call the actual XLL function, convert the returned
+ * value, clean up memory, and return to Gnumeric.
+ *
+ */
+
+#if defined( WIN32 ) || defined( WIN64 )
+#include <windef.h>
+#else
+#include "win32replacements.h"
+#endif
+
+#include "xlcall.h"
+
+/* All bits that are mutually exclusive in the type field of an xloper. */
+#define xltypeType       0x0FFF
+
+struct _XLL {
+	gchar * name;
+	GModule * handle;
+	void (*xlAutoFree)(XLOPER*);
+	unsigned long number_of_functions;
+};
+
+typedef struct _XLL XLL;
+
+struct _XLLFunctionInfo {
+	XLL* xll; /* Not owned. Included for availability of information during callbacks, and for access to xlAutoFree. */
+	XLOPER* (*xll_function)(void);
+	gchar* category;
+	GnmFuncDescriptor gnm_func_descriptor;
+	guint number_of_arguments;
+	GnmFunc* gnm_func;
+};
+
+typedef struct _XLLFunctionInfo XLLFunctionInfo;
+
+static GModule *xlcall32_handle=NULL;
+static void (*register_actual_excel4v)(void*p) = NULL;
+
+static GSList* XLLs=NULL;
+
+/* This balanced tree maps from function name (gchar*) to XLLFunctionInfo*. It is consulted when gnumeric attempts to
+   call one of the registered functions. Note that the memory of any key is handled as part of the memory of its
+   associated value since the key is the same as the element gnm_func_descriptor.name. */
+static GTree* xll_function_info_map=NULL;
+
+static GnmFuncEvalInfo * current_eval_info=NULL;
+static XLL * currently_called_xll = NULL;
+
+/* The limit of 30 arguments is hardwired in Excel. We take advantage of this below when we convert from argv[] calling
+   convention to vararg calling convention (...) */
+enum { MAXIMUM_NUMBER_OF_EXCEL_FUNCTION_ARGUMENTS = 30 };
+
+/* If data types other than XLOPER* are to be allowed, then something like the Foreign Function Interface library
+   (libffi) would have to be used in order to get the arguments pushed on the stack prior to calling the XLL
+   function. As long as all data are XLOPER*, we can use this one function type to call all XLL functions. */
+typedef XLOPER*(*XLLFunctionWithVarArgs)(XLOPER* first, ...);
+
+#define CASE( x ) case (x): return #x
+
+#ifdef THIS_IS_HERE_FOR_DEBUG_PURPOSES
+static const char * gnm_value_type_name(const GnmValue*g){
+	if (NULL!=g){
+		switch (g->type){
+		CASE(VALUE_EMPTY);
+		CASE(VALUE_BOOLEAN);
+		CASE(VALUE_INTEGER);
+		CASE(VALUE_FLOAT);
+		CASE(VALUE_ERROR);
+		CASE(VALUE_STRING);
+		CASE(VALUE_CELLRANGE);
+		CASE(VALUE_ARRAY);
+		default: return "<unknown>";
+		}
+	}
+	return "(nil)";
+}
+#endif
+
+static const char * xloper_type_name(const XLOPER*x){
+	if (NULL!=x){
+		switch(x->xltype & xltypeType){
+		CASE(xltypeNum);
+		CASE(xltypeStr);
+		CASE(xltypeBool);
+		CASE(xltypeRef);
+		CASE(xltypeErr);
+		CASE(xltypeFlow);
+		CASE(xltypeMulti);
+		CASE(xltypeMissing);
+		CASE(xltypeNil);
+		CASE(xltypeSRef);
+		CASE(xltypeInt);
+		default: return "<unknown>";
+		}
+	}
+	return "(nil)";
+}
+
+static void unsupported_xloper_type(const XLOPER*x){
+	g_warning(_("Unsupported xloper type \"%s\""),xloper_type_name(x));
+}
+
+static GnmValue * gnm_value_error_std[GNM_ERROR_UNKNOWN];
+
+static GnmStdError gnm_value_error_from_xloper(const XLOPER*x){
+	g_assert(NULL!=x);
+	g_assert((x->xltype&xltypeType)==xltypeErr);
+	switch(x->val.err){
+	case xlerrNull:  return GNM_ERROR_NULL;
+	case xlerrDiv0:  return GNM_ERROR_DIV0;
+	case xlerrValue: return GNM_ERROR_VALUE;
+	case xlerrRef:   return GNM_ERROR_REF;
+	case xlerrName:  return GNM_ERROR_NAME;
+	case xlerrNum:   return GNM_ERROR_NUM;
+	case xlerrNA:    return GNM_ERROR_NA;
+	default:;
+	}
+	return GNM_ERROR_UNKNOWN;
+}
+
+static WORD xloper_error_code_from_gnm_value(const GnmValue*g){
+	guint i;
+	g_assert(NULL!=g);
+	g_assert(VALUE_IS_ERROR(g));
+	if (VALUE_TERMINATE!=g){
+		for (i=0;i<GNM_ERROR_UNKNOWN;++i){
+			if (g->v_err.mesg==gnm_value_error_std[i]->v_err.mesg){
+				switch (i){
+				case GNM_ERROR_NULL:  return xlerrNull;
+				case GNM_ERROR_DIV0:  return xlerrDiv0;
+				case GNM_ERROR_VALUE: return xlerrValue;
+				case GNM_ERROR_REF:   return xlerrRef;
+				case GNM_ERROR_NAME:  return xlerrName;
+				case GNM_ERROR_NUM:   return xlerrNum;
+				case GNM_ERROR_NA:    return xlerrNA;
+				default:;
+				}
+			}
+		}
+	}
+	return xlerrValue;
+}
+
+/*
+ *     For most standard types, there is a natural mapping between XLOPER and GnmValue.
+ *     In addition, we use the following correspondence:
+ *
+ *                              |   GnmValue * v               |    XLOPER * x                                              |
+ *      ------------------------+------------------------------+------------------------------------------------------------+
+ *                              |   v       == NULL           <->   x->xltype == xltypeMissing                              |
+ *                              |   v->type == VALUE_EMPTY    <->   x->xltype == xltypeNil                                  |
+ *                              |   v->type == VALUE_ERROR    <->   x->xltype == xltypeErr                                  |
+ *      ------------------------+------------------------------+------------------------------------------------------------+
+ *
+ */
+
+static char * pascal_string_from_c_string(const char *s){
+	char *o=NULL;
+	if (NULL!=s){
+		guint l = strlen(s);
+		g_return_val_if_fail (l<(UINT_MAX-2U),NULL);
+		o = g_malloc(l+2U);
+		g_strlcpy(o+1,s,l+1);
+		if (l>UCHAR_MAX)
+			l=UCHAR_MAX;
+		o[0]=(unsigned char)l;
+	}
+	return o;
+}
+
+static char * c_string_from_pascal_string(const char *s){
+	if (NULL!=s){
+		const guint m = ((unsigned char)s[0])+1U;
+		char * o = g_malloc(m);
+		g_strlcpy(o,s+1,m);
+		return o;
+	}
+	return NULL;
+}
+
+static void copy_construct_xloper_from_gnm_value(XLOPER*out, const GnmValue*in, GnmFuncEvalInfo *ei){
+	int i,j,m,n;
+	g_assert(NULL!=out);
+	out->xltype = xltypeMissing;
+	out->val.num = 0.;
+	if (NULL!=in){
+		switch(in->type){
+		case VALUE_EMPTY:	out->xltype=xltypeNil;							break;
+		case VALUE_BOOLEAN:	out->xltype=xltypeBool;	out->val.boolean=(WORD)in->v_bool.val;		break;
+		case VALUE_INTEGER:
+		case VALUE_FLOAT:	out->xltype=xltypeNum;	out->val.num=in->v_float.val;			break;
+		case VALUE_ERROR:
+			out->xltype	=	xltypeErr;
+			out->val.err	=	xloper_error_code_from_gnm_value(in);
+			break;
+		case VALUE_STRING:	out->xltype=xltypeStr;	out->val.str=pascal_string_from_c_string(in->v_str.val->str);	break;
+		case VALUE_CELLRANGE:
+			{
+				GnmSheetRange sr;
+				GnmRangeRef const *rr = value_get_rangeref (in);
+				Sheet *end_sheet=NULL;
+				GnmValue *cell_value;
+				GnmCell  *cell;
+				gnm_rangeref_normalize (rr, ei->pos, &sr.sheet, &end_sheet, &sr.range);
+				if (sr.sheet != end_sheet){
+					/* We don't attempt to flatten a 3D range to an array. */
+					g_warning(_("Cannot convert 3D cell range to XLOPER."));
+				} else {
+					m			=	sr.range.end.col-sr.range.start.col+1;
+					n			=	sr.range.end.row-sr.range.start.row+1;
+					out->xltype		=	xltypeMulti;
+					out->val.array.lparray	=	ALLOC_ARRAY(XLOPER,m*n);
+					out->val.array.columns	=	m;
+					out->val.array.rows	=	n;
+					for (i=0;i<m;++i){
+						for (j=0;j<n;++j){
+							cell=sheet_cell_get(sr.sheet,sr.range.start.col+i,sr.range.start.row+j);
+							cell_value=NULL;
+							if (NULL!=cell){
+								gnm_cell_eval(cell);
+								cell_value=cell->value;
+							}
+							copy_construct_xloper_from_gnm_value(out->val.array.lparray+i+j*m,cell_value,ei);
+						}
+					}
+				}
+			}
+			break;
+		case VALUE_ARRAY:
+			m			=	in->v_array.x;
+			n			=	in->v_array.y;
+			out->xltype		=	xltypeMulti;
+			out->val.array.lparray	=	ALLOC_ARRAY(XLOPER,m*n);
+			out->val.array.columns	=	m;
+			out->val.array.rows	=	n;
+			for (i=0;i<m;++i){
+				for (j=0;j<n;++j){
+					copy_construct_xloper_from_gnm_value(out->val.array.lparray+i+j*m,in->v_array.vals[i][j],ei);
+				}
+			}
+			break;
+		default:;
+			g_warning(_("Unsupported GnmValue type (%d)"),in->type);
+		}
+	}
+}
+
+static void delete_string(gchar**s){
+	if (NULL!=s && NULL!=*s ){
+		g_free(*s);
+		*s=NULL;
+	}
+}
+
+static void destruct_xloper(XLOPER*x){
+	int i,n;
+	if (NULL!=x){
+		switch(x->xltype & xltypeType){
+		case xltypeNum:							break;
+		case xltypeStr:		delete_string(&x->val.str);		break;
+		case xltypeBool:						break;
+		case xltypeRef:
+			if (NULL!=x->val.mref.lpmref&&x->val.mref.lpmref->count!=1) {
+				unsupported_xloper_type(x);
+			} else {
+				if (NULL!=x->val.mref.lpmref)
+					FREE_ARRAY(x->val.mref.lpmref,1);
+				x->val.mref.lpmref=NULL;
+			}
+		break;
+		case xltypeErr:							break;
+		case xltypeFlow:	unsupported_xloper_type(x);		break;
+		case xltypeMulti:
+			n=x->val.array.rows*x->val.array.columns;
+			for (i=0;i<n;++i){
+				destruct_xloper(x->val.array.lparray+i);
+			}
+			FREE_ARRAY(x->val.array.lparray,n);
+			break;
+		case xltypeMissing:						break;
+		case xltypeNil:							break;
+		case xltypeSRef:	unsupported_xloper_type(x);		break;
+		case xltypeInt:							break;
+		default:		unsupported_xloper_type(x);
+		}
+	}
+	x->xltype=xltypeNil;
+}
+
+static GnmValue* new_gnm_value_from_xloper(const XLOPER*x){
+	guint i,j,m,n;
+	char *o=NULL,*s=NULL;
+	GnmValue * g = NULL;
+	if (NULL!=x) {
+		switch (x->xltype&xltypeType){
+		case xltypeNum:		g=value_new_float(x->val.num);					break;
+		case xltypeStr:
+			s=x->val.str;
+			if (NULL!=s){
+				const guint m = ((unsigned char)s[0])+1U;
+				o=ALLOC_ARRAY(char,m);
+				g_strlcpy(o,s+1,m);
+			}
+			g=value_new_string(o);
+			if (NULL!=s){
+				FREE_ARRAY(o,((unsigned char)s[0])+1U);
+			}
+			o=NULL;
+			s=NULL;
+			break;
+		case xltypeBool:	g=value_new_bool(x->val.boolean);				break;
+		case xltypeRef:		unsupported_xloper_type(x);					break;
+		case xltypeErr:		g=value_new_error_std(NULL,gnm_value_error_from_xloper(x));	break;
+		case xltypeFlow:	unsupported_xloper_type(x);					break;
+		case xltypeMulti:
+			m=x->val.array.columns;
+			n=x->val.array.rows;
+			if (m*n>0){
+				g=value_new_array_empty(m,n);
+				for (i=0;i<m;++i){
+					for (j=0;j<n;++j){
+						g->v_array.vals[i][j]=new_gnm_value_from_xloper(x->val.array.lparray+i+j*m);
+					}
+				}
+			} else {
+				g=value_new_error_std(NULL,GNM_ERROR_VALUE);
+			}
+			break;
+		case xltypeMissing:									break;
+		case xltypeNil:		g=value_new_empty();						break;
+		case xltypeSRef:	unsupported_xloper_type(x);					break;
+		case xltypeInt:		g=value_new_int(x->val.w);					break;
+		default:		unsupported_xloper_type(x);
+		}
+	} else {
+		g=value_new_error_std(NULL,GNM_ERROR_NUM);
+	}
+	return g;
+}
+
+static GnmValue * genericXLLFunction (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
+{
+	XLOPER x[MAXIMUM_NUMBER_OF_EXCEL_FUNCTION_ARGUMENTS], *r = 0;
+	XLLFunctionWithVarArgs func = NULL;
+	GnmValue *g=NULL;
+	guint i,m;
+	const XLLFunctionInfo*info=NULL;
+	g_assert(NULL!=xll_function_info_map);
+	info=g_tree_lookup (xll_function_info_map,ei->func_call->func->name);
+	g_assert(NULL!=info);
+	m=ei->func_call->argc;
+	if ( m > MAXIMUM_NUMBER_OF_EXCEL_FUNCTION_ARGUMENTS )
+		m = MAXIMUM_NUMBER_OF_EXCEL_FUNCTION_ARGUMENTS;
+	for (i=0;i<m;++i)
+		copy_construct_xloper_from_gnm_value(x+i,argv[i],ei);
+	m = info->number_of_arguments;
+	if ( m > MAXIMUM_NUMBER_OF_EXCEL_FUNCTION_ARGUMENTS )
+		m = MAXIMUM_NUMBER_OF_EXCEL_FUNCTION_ARGUMENTS;
+	for (;i<m;++i)
+		x[i].xltype=xltypeMissing;
+	func = (XLLFunctionWithVarArgs)info->xll_function;
+	g_assert(NULL!=func);
+	currently_called_xll = info->xll;
+	current_eval_info    = ei;
+	switch (info->number_of_arguments){
+	case  0: r=info->xll_function(); break;
+	/*
+	  bash script to generate code below
+	  n=0; while [ $n -le 30 ] ; do echo -n "	case "; if [ $n -lt 10 ] ; then echo -n " "; fi; echo -n "$n: r=func("; j=0; while [ $j -lt $n ]; do echo -n "x+$j"; if [ $[ $j + 1] -lt $n ] ; then echo -n "," ; fi ; j=$[ $j + 1 ] ; done ; echo "); break;" ; n=$[ $n + 1 ] ; done
+	*/
+	case  1: r=func(x+0); break;
+	case  2: r=func(x+0,x+1); break;
+	case  3: r=func(x+0,x+1,x+2); break;
+	case  4: r=func(x+0,x+1,x+2,x+3); break;
+	case  5: r=func(x+0,x+1,x+2,x+3,x+4); break;
+	case  6: r=func(x+0,x+1,x+2,x+3,x+4,x+5); break;
+	case  7: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6); break;
+	case  8: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7); break;
+	case  9: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8); break;
+	case 10: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8,x+9); break;
+	case 11: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8,x+9,x+10); break;
+	case 12: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8,x+9,x+10,x+11); break;
+	case 13: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8,x+9,x+10,x+11,x+12); break;
+	case 14: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8,x+9,x+10,x+11,x+12,x+13); break;
+	case 15: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8,x+9,x+10,x+11,x+12,x+13,x+14); break;
+	case 16: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8,x+9,x+10,x+11,x+12,x+13,x+14,x+15); break;
+	case 17: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8,x+9,x+10,x+11,x+12,x+13,x+14,x+15,x+16); break;
+	case 18: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8,x+9,x+10,x+11,x+12,x+13,x+14,x+15,x+16,x+17); break;
+	case 19: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8,x+9,x+10,x+11,x+12,x+13,x+14,x+15,x+16,x+17,x+18); break;
+	case 20: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8,x+9,x+10,x+11,x+12,x+13,x+14,x+15,x+16,x+17,x+18,x+19); break;
+	case 21: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8,x+9,x+10,x+11,x+12,x+13,x+14,x+15,x+16,x+17,x+18,x+19,x+20); break;
+	case 22: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8,x+9,x+10,x+11,x+12,x+13,x+14,x+15,x+16,x+17,x+18,x+19,x+20,x+21); break;
+	case 23: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8,x+9,x+10,x+11,x+12,x+13,x+14,x+15,x+16,x+17,x+18,x+19,x+20,x+21,x+22); break;
+	case 24: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8,x+9,x+10,x+11,x+12,x+13,x+14,x+15,x+16,x+17,x+18,x+19,x+20,x+21,x+22,x+23); break;
+	case 25: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8,x+9,x+10,x+11,x+12,x+13,x+14,x+15,x+16,x+17,x+18,x+19,x+20,x+21,x+22,x+23,x+24); break;
+	case 26: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8,x+9,x+10,x+11,x+12,x+13,x+14,x+15,x+16,x+17,x+18,x+19,x+20,x+21,x+22,x+23,x+24,x+25); break;
+	case 27: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8,x+9,x+10,x+11,x+12,x+13,x+14,x+15,x+16,x+17,x+18,x+19,x+20,x+21,x+22,x+23,x+24,x+25,x+26); break;
+	case 28: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8,x+9,x+10,x+11,x+12,x+13,x+14,x+15,x+16,x+17,x+18,x+19,x+20,x+21,x+22,x+23,x+24,x+25,x+26,x+27); break;
+	case 29: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8,x+9,x+10,x+11,x+12,x+13,x+14,x+15,x+16,x+17,x+18,x+19,x+20,x+21,x+22,x+23,x+24,x+25,x+26,x+27,x+28); break;
+	case 30: r=func(x+0,x+1,x+2,x+3,x+4,x+5,x+6,x+7,x+8,x+9,x+10,x+11,x+12,x+13,x+14,x+15,x+16,x+17,x+18,x+19,x+20,x+21,x+22,x+23,x+24,x+25,x+26,x+27,x+28,x+29); break;
+	}
+	g=new_gnm_value_from_xloper(r);
+	if ( r && (r->xltype & xlbitDLLFree) && (NULL!=info->xll->xlAutoFree) )
+		info->xll->xlAutoFree( r );
+	currently_called_xll = NULL;
+	current_eval_info    = NULL;
+	for (i=0;i<info->number_of_arguments;++i)
+		destruct_xloper(x+i);
+	return g;
+}
+
+/***************************************************************************/
+
+static int gnm_func_help_entries(int number_of_arguments){
+	return number_of_arguments + 4; /* NAME,DESCRIPTION,EXCEL,ARG1,...ARGn,END */
+}
+
+static void free_xll_function_info(gpointer data){
+	XLLFunctionInfo*info=(XLLFunctionInfo*)data;
+	const guint n = info->number_of_arguments;
+	if (NULL!=info->gnm_func){
+		gnm_func_free(info->gnm_func);
+		info->gnm_func=NULL;
+	}
+	delete_string(&info->category);
+	delete_string((gchar**)&info->gnm_func_descriptor.name);
+	delete_string((gchar**)&info->gnm_func_descriptor.arg_spec);
+	if (NULL!=info->gnm_func_descriptor.help){
+		guint i, m=gnm_func_help_entries(n);
+		for (i=0;i<m;++i){
+			delete_string((gchar**)&info->gnm_func_descriptor.help[i].text);
+		}
+		FREE_ARRAY((GnmFuncHelp*)info->gnm_func_descriptor.help,m);
+		info->gnm_func_descriptor.help=NULL;
+	}
+	info->gnm_func_descriptor.fn_args=NULL;
+	info->number_of_arguments=0;
+	info->xll_function=NULL;
+	info->gnm_func_descriptor.fn_args=NULL;
+	FREE_ARRAY(info,1);
+}
+
+typedef int WINAPI (*XLAutoOpenFunc)(void);
+typedef int WINAPI (*XLAutoCloseFunc)(void);
+
+static void free_XLL(gpointer data){
+	XLL*xll=(XLL*)data;
+	if (NULL!=xll->handle){
+		XLAutoCloseFunc xlAutoCloseFunc=NULL;
+		g_module_symbol (xll->handle, "xlAutoClose", (gpointer) &xlAutoCloseFunc);
+		if (NULL!=xlAutoCloseFunc){
+			currently_called_xll = xll;
+			xlAutoCloseFunc();
+			currently_called_xll = NULL;
+		}
+		if (!g_module_close (xll->handle))
+			g_warning (_("%s: %s"), xll->name, g_module_error ());
+		xll->handle=NULL;
+	}
+	delete_string(&xll->name);
+	FREE_ARRAY(xll,1);
+}
+
+static gint
+g_strcmp0_with_ignored_data(gconstpointer str1, gconstpointer str2, gpointer user_data){
+	return g_strcmp0(str1,str2);
+}
+
+static gboolean add_xll_function(const char * exported_function_symbol, XLLFunctionInfo* info){
+	g_module_symbol (info->xll->handle, exported_function_symbol, (gpointer) &info->xll_function);
+	if (NULL!=info->xll_function){
+		XLLFunctionInfo* info_in_map = NULL;
+		GnmFunc *gnm_func=NULL;
+		if (0==xll_function_info_map)
+			xll_function_info_map=g_tree_new_full(g_strcmp0_with_ignored_data,NULL,NULL,free_xll_function_info);
+		info_in_map = g_tree_lookup (xll_function_info_map,info->gnm_func_descriptor.name);
+		if (NULL!=info_in_map)
+			g_warning(_("Overriding function %s from XLL/DLL/SO file %s with function of the same name from XLL/DLL/SO file %s."),
+				  info->gnm_func_descriptor.name,info_in_map->xll->name,info->xll->name);
+		gnm_func = gnm_func_add(gnm_func_group_fetch(info->category,NULL),&info->gnm_func_descriptor,NULL);
+		if (gnm_func){
+			info->gnm_func=gnm_func;
+			g_tree_insert(xll_function_info_map,(gpointer)info->gnm_func_descriptor.name,info);
+			++info->xll->number_of_functions;
+			return TRUE;
+		}
+	} else {
+		g_warning(_("Failed to find function \"%s\" in XLL/DLL/SO %s .\n"),info->gnm_func_descriptor.name,info->xll->name);
+	}
+	return FALSE;
+}
+
+static int actual_Excel4v(int xlfn, XLOPER* operRes, int count, XLOPER** opers) {
+	switch(xlfn) {
+	case xlfRegister: {
+		XLLFunctionInfo* info = NULL;
+		GnmFuncHelp *    help = NULL;
+		GnmFuncFlags    flags = GNM_FUNC_SIMPLE; /* We may have to include GNM_FUNC_RETURNS_NON_SCALAR here
+							    since all Excel functions may return an array. Having said
+							    that, all array functions seem to work fine without this
+							    flag. */
+		GString * argument_specifications=g_string_sized_new(21);
+		gchar ** arg_names=NULL, *exported_function_symbol=NULL, *function_description=NULL;
+		guint number_of_arguments=0;
+		gboolean success = FALSE;
+		int i,j,m,n;
+		/*
+		 * Check http://msdn.microsoft.com/en-us/library/bb687900.aspx for details.
+		 *
+		 * opers[ 0] : DLL name (string). Might have been queried by the XLL by calling in here as xlGetName prior to registering (that's how it's usually done).
+		 *             This feature allows, in principle, for one XLL (the one calling Excel4v) to register functions that physically reside in another DLL.
+			       We do not allow for this feature here.
+			       IGNORED HERE.
+		 * opers[ 1] : exported function symbol in XLL/DLL (string). To be located with g_module_symbol().
+			       MANDATORY.
+		 * opers[ 2] : return and argument types string. Should be a string of only 'P's or 'R's in this context (apart from volatile markers etc).
+			       MANDATORY.
+		 * opers[ 3] : function name that is to be shown as the effective, user-visible, work sheet function.
+			       DEFAULTS to opers[1].
+		 * opers[ 4] : string of comma separated argument names.
+			       DEFAULTS to NULL.
+		 * opers[ 5] : function type as xltypeNum. 0.=hidden, 1.=function, 2.=command.
+			       IGNORED HERE.
+		 * opers[ 6] : function category as string.
+			       DEFAULTS to "XLL functions".
+		 * opers[ 7] : short cut text as string.
+			       IGNORED HERE.
+		 * opers[ 8] : help topic as string.
+			       IGNORED HERE.
+		 * opers[ 9] : function description as string.
+			       DEFAULTS to NULL.
+		 * opers[10 .. 10+n-1] : Help on the n arguments of actual function that is being registered.
+			       DEFAULT to NULL.
+		 */
+		if (count<3){
+			g_warning(_("Excel plugin loader / xlfRegister: at least three XLOPER arguments must be provided (DLL name[ignored],exported name[mandatory],types string[mandatory]). You supplied %d in some function loaded from XLL/DLL/SO file %s."),count,currently_called_xll->name);
+			return xlretInvCount; /* "An invalid number of arguments was entered. In versions up to Excel
+						  2003, the maximum number of arguments any function can take is 30. In
+						  Excel 2007, the maximum number is 255. Some require a fixed or minimum
+						  number of arguments." */
+		}
+		if ( xltypeStr != (opers[1]->xltype&xltypeType) ||  xltypeStr != (opers[2]->xltype&xltypeType) ){
+			g_warning(_("Excel plugin loader / xlfRegister: the second and third argument must be strings (DLL name[ignored],exported name[mandatory],types string[mandatory])."));
+			return xlretInvXloper; /* "An invalid XLOPER or XLOPER12 was passed to the function, or an argument of the wrong type was used." */
+		}
+		m=0;
+		if (opers[2]->val.str)
+			m=(unsigned char)opers[2]->val.str[0];
+		for (i=0;i<m;++i){
+			switch(opers[2]->val.str[i+1]){
+			case 'p':
+			case 'P':
+			case 'r':
+			case 'R':
+				argument_specifications=g_string_append_c(argument_specifications,'?');
+				++number_of_arguments;
+				break;
+			case '\r': /* Various junk we may as well ignore. */
+			case '\n':
+			case '\t':
+			case ',':
+			case ';':
+			case ' ':
+			case '#': /* This signals a request for this function or macro to have access to macro specific call back functions. Ignored.  */
+				break;
+			case '!':
+				flags |= GNM_FUNC_VOLATILE;
+				break;
+			default:;
+			}
+		}
+		exported_function_symbol=c_string_from_pascal_string(opers[1]->val.str);
+		g_assert(argument_specifications->len==number_of_arguments);
+		if (number_of_arguments>0){
+			--number_of_arguments; /* Subtract the return type count. The if statement is only to protect against sloppy XLLs. */
+			argument_specifications->str[0]='|'; /* All arguments are optional to an Excel function that accepts arguments type 'P'. */
+		}
+		info=ALLOC_ARRAY(XLLFunctionInfo,1);
+		info->xll=currently_called_xll;
+		info->number_of_arguments=number_of_arguments;
+		info->gnm_func_descriptor.arg_spec=g_strdup(argument_specifications->str);
+		info->gnm_func_descriptor.flags=flags;
+		if (count>3 && (opers[3]->xltype&xltypeType)==xltypeStr){
+			info->gnm_func_descriptor.name = c_string_from_pascal_string(opers[3]->val.str);
+		} else {
+			info->gnm_func_descriptor.name = g_strdup(exported_function_symbol);
+		}
+		if (count>4 && (opers[4]->xltype&xltypeType)==xltypeStr){
+			gchar* xll_arg_names = c_string_from_pascal_string(opers[4]->val.str);
+			arg_names=g_strsplit(xll_arg_names,",",number_of_arguments);
+			delete_string(&xll_arg_names);
+		}
+		if (count>6 && (opers[6]->xltype&xltypeType)==xltypeStr){
+			info->category = c_string_from_pascal_string(opers[6]->val.str);
+		} else {
+			info->category = g_strdup("XLL functions");
+		}
+		if (count>9 && (opers[9]->xltype&xltypeType)==xltypeStr){
+			function_description = c_string_from_pascal_string(opers[9]->val.str);
+		}
+		m=0;
+		n=gnm_func_help_entries(number_of_arguments);
+		help=ALLOC_ARRAY(GnmFuncHelp,n);
+		g_assert(m<n);
+		help[m].type=GNM_FUNC_HELP_NAME;
+		help[m].text=g_strdup(info->gnm_func_descriptor.name);
+		++m;
+		g_assert(m<n);
+		help[m].type=GNM_FUNC_HELP_DESCRIPTION;
+		help[m].text=function_description;           /* Memory ownership handed over. */
+		++m;
+		g_assert(m<n);
+		help[m].type=GNM_FUNC_HELP_EXCEL;
+		help[m].text=g_strdup("This function has been loaded from an Excel-compatible plugin (XLL). It is NOT a built-in function of Excel or Gnumeric.\n");
+		/* We limit the number of argument strings we copy to the minimum of the number of arguments indicated
+		   in the types string and the number of arguments strings given. We always provide enough space for as
+		   many as indicated in the types string. */
+		for (i=10,j=0; i<count && i-10<(int)number_of_arguments; ++i){
+			++m;
+			help[m].type=GNM_FUNC_HELP_ARG;
+			if ((opers[i]->xltype&xltypeType)==xltypeStr){
+				gchar * arg_name = (NULL!=arg_names && NULL!=arg_names[j]) ? arg_names[j++] : NULL;
+				gchar * arg_help = c_string_from_pascal_string(opers[i]->val.str);
+				g_assert(m<n);
+				if (NULL!=arg_name){
+					gchar *tmp=arg_help;
+					arg_help = g_strconcat(arg_name,":",arg_help,NULL);
+					delete_string(&tmp);
+				}
+				help[m].text = arg_help;
+			}
+		}
+		++m;
+		g_assert(m<n);
+		help[m].type=GNM_FUNC_HELP_END;
+		if (NULL!=arg_names){
+			g_strfreev(arg_names);
+			arg_names=NULL;
+		}
+		info->gnm_func_descriptor.help = help;
+		info->gnm_func_descriptor.fn_args = genericXLLFunction;
+		info->gnm_func_descriptor.impl_status = GNM_FUNC_IMPL_STATUS_COMPLETE;
+		info->gnm_func_descriptor.test_status = GNM_FUNC_TEST_STATUS_BASIC;
+
+		success = add_xll_function(exported_function_symbol,info);
+
+		delete_string(&exported_function_symbol);
+
+		if (success) {
+			if (NULL!=operRes){
+				operRes->xltype=xltypeNum;
+				operRes->val.num=(unsigned long)info; /* This should be set to the resulting registration id. We use the info pointer as a proxy here. */
+			}
+			return xlretSuccess;
+		}
+		free_xll_function_info(info);
+		return xlretInvXloper; /* "An invalid XLOPER or XLOPER12 was passed to the function, or an argument of the wrong type was used." */
+	}
+	case xlFree:
+		while (count--){
+			destruct_xloper(opers[count]);
+		}
+		return xlretSuccess;
+	case xlGetName:  /* The name of the DLL that is calling */
+		if (NULL!=operRes){
+			operRes->xltype=xltypeStr;
+			operRes->val.str=pascal_string_from_c_string(currently_called_xll->name);
+			return xlretSuccess;
+		}
+		return xlretInvXloper;
+	case xlfRow:     /* Pass in the output of xlfCaller to get the row of the calling worksheet cell as an XLOPER of
+			    type integer or number. Note that the output may be an array similar to the output from
+			    xlSheetNm. */
+		if (NULL!=operRes){
+			if ( count>0 && xltypeRef==(opers[0]->xltype&xltypeType) && NULL!=operRes->val.mref.lpmref ){
+				operRes->xltype = xltypeInt;
+				operRes->val.w = operRes->val.mref.lpmref->reftbl[1].rwFirst;
+				return xlretSuccess;
+			}
+			if (NULL!=current_eval_info){
+				operRes->xltype = xltypeInt;
+				operRes->val.w = (short int) current_eval_info->pos->eval.row;
+				return xlretSuccess;
+			}
+		}
+		return xlretInvXloper;
+	case xlfColumn:  /* Pass in the output of xlfCaller to get the column of the calling worksheet cell as an XLOPER of
+			    type integer or number. Note that the output may be an array similar to the output from
+			    xlSheetNm. */
+		if (NULL!=operRes){
+			if ( count>0 && xltypeRef==(opers[0]->xltype&xltypeType) && NULL!=operRes->val.mref.lpmref ){
+				operRes->xltype = xltypeInt;
+				operRes->val.w = operRes->val.mref.lpmref->reftbl[1].colFirst;
+				return xlretSuccess;
+			}
+			if (NULL!=current_eval_info){
+				operRes->xltype = xltypeInt;
+				operRes->val.w = (short int) current_eval_info->pos->eval.col;
+				return xlretSuccess;
+			}
+		}
+		return xlretInvXloper;
+
+
+	/* Commonly called functions. None of these are fully implemented. */
+	case xlfCaller:  /* Information about the location that is calling a worksheet function. The result of this can
+			    be scalar XLOPER or a range, depending on whether a function is called as an array function,
+			    or as a single cell function call. The result should be passed back in when calling
+			    xlSheetNm, xlfRow, or xlfColumn. */
+		if (NULL!=operRes && NULL!=current_eval_info){
+			operRes->xltype           = xltypeRef;
+			operRes->val.mref.idSheet = current_eval_info->pos->sheet->index_in_wb; /* This is not globally unique but better than nothing. */
+			operRes->val.mref.lpmref  = ALLOC_ARRAY(XLMREF,1);
+			operRes->val.mref.lpmref->count=1;
+			operRes->val.mref.lpmref->reftbl[1].rwFirst  = current_eval_info->pos->eval.row;
+			operRes->val.mref.lpmref->reftbl[1].rwLast   = current_eval_info->pos->eval.row;
+			operRes->val.mref.lpmref->reftbl[1].colFirst = current_eval_info->pos->eval.col;
+			operRes->val.mref.lpmref->reftbl[1].colLast  = current_eval_info->pos->eval.col;
+			return xlretSuccess;
+		}
+		return xlretInvXloper;
+	case xlSheetNm:  /* Pass in the output of xlfCaller to get the name of the calling worksheet as an XLOPER of
+			    type string. Note that the output of this can be an array if the output of xlfCaller was an
+			    array. To play safe, always check if it is an array, and use element (0,0) if it is, else
+			    use the scalar. */
+		if (NULL!=operRes && NULL!=current_eval_info){
+			int index_in_wb = current_eval_info->pos->sheet->index_in_wb, row=current_eval_info->pos->eval.row, col=current_eval_info->pos->eval.col;
+			Workbook * workbook = current_eval_info->pos->sheet->workbook;
+			Sheet *sheet        = current_eval_info->pos->sheet;
+			if (count>0 && xltypeRef == (opers[0]->xltype&xltypeType)){
+				index_in_wb=opers[0]->val.mref.idSheet;
+				if (NULL!=operRes->val.mref.lpmref){
+					row=operRes->val.mref.lpmref->reftbl[1].rwFirst;
+					col=operRes->val.mref.lpmref->reftbl[1].colFirst;
+				}
+				sheet=workbook_sheet_by_index(workbook,index_in_wb);
+			}
+			operRes->xltype=xltypeStr;
+			operRes->val.str=pascal_string_from_c_string(sheet->name_unquoted);
+			return xlretSuccess;
+		}
+		return xlretInvXloper;
+	case xlGetHwnd:  /* The WIN32 window handle of the "Excel" window */
+	case xlAbort:    /* Query if the user hammered escape. May take one argument if the calling XLL wants to tell us that we are to continue.*/
+		if (NULL!=operRes){
+			operRes->xltype=xltypeBool;
+			operRes->val.boolean=0;
+		}
+		return xlretSuccess;
+	case xlcMessage: /* Set message bar. Expects one argument but no return value. */
+		return xlretSuccess;
+	default:;
+	}
+	return xlretInvXlfn; /* "An invalid function number was supplied. If you are using constants from XLCALL.H, this
+				 should not occur unless you are calling something that is not supported in the version
+				 of Excel you are running." */
+}
+
+static void
+load_xlcall32(GOPlugin *plugin){
+	gchar *full_module_file_name;
+	if (!g_module_supported ()) {
+		g_warning (_("Dynamic module loading is not supported on this system."));
+		return;
+	}
+	full_module_file_name = g_build_filename (go_plugin_get_dir_name (plugin), "xlcall32", NULL);
+#ifdef WIN32
+	SetErrorMode(SEM_FAILCRITICALERRORS); // avoid message box if library not found
+#endif
+	xlcall32_handle = g_module_open (full_module_file_name, G_MODULE_BIND_LAZY);
+#ifdef WIN32
+	SetErrorMode(0);
+#endif
+	if (xlcall32_handle == NULL) {
+		g_warning (_("Unable to open module file \"%s\"."),full_module_file_name);
+		return;
+	}
+	g_module_symbol (xlcall32_handle, "register_actual_excel4v", (gpointer) &register_actual_excel4v);
+	if (register_actual_excel4v == NULL) {
+		g_warning (_("Module \"%s\" doesn't contain (\"register_actual_excel4v\" symbol)."),full_module_file_name);
+		return;
+	}
+	register_actual_excel4v(actual_Excel4v);
+	g_free (full_module_file_name);
+}
+
+static void scan_for_XLLs_and_register_functions(const gchar*dir_name) {
+	GDir*dir=g_dir_open(dir_name,0,NULL);
+	gchar * full_entry_name;
+	const gchar *d_name;
+	struct stat d_info;
+	GModule *handle;
+	int stat_success;
+	if (NULL!=dir){
+		while ((d_name = g_dir_read_name (dir)) != NULL) {
+			if ( ! (strcmp (d_name, ".") == 0 || strcmp (d_name, "..") == 0) ){
+				full_entry_name = g_build_filename (dir_name, d_name, NULL);
+				stat_success = g_stat(full_entry_name,&d_info);
+				if (0==stat_success){
+					if (S_ISDIR(d_info.st_mode)){
+						scan_for_XLLs_and_register_functions(full_entry_name);
+					} else {
+#ifdef WIN32
+						SetErrorMode(SEM_FAILCRITICALERRORS); // avoid message box if library not found
+#endif
+						handle = g_module_open (full_entry_name, G_MODULE_BIND_LAZY);
+#ifdef WIN32
+						SetErrorMode(0);
+#endif
+						if (NULL!=handle){
+							XLL*xll = ALLOC_ARRAY(XLL,1);
+							XLAutoOpenFunc xlAutoOpenFunc=NULL;
+							xll->name   = g_strdup(full_entry_name);
+							xll->handle = handle;
+							g_module_symbol (xll->handle, "xlAutoFree", (gpointer) &xll->xlAutoFree);
+							xlAutoOpenFunc=NULL;
+							if (g_module_symbol (xll->handle, "xlAutoOpen", (gpointer) &xlAutoOpenFunc)){
+								currently_called_xll = xll;
+								xlAutoOpenFunc();
+								currently_called_xll = NULL;
+								if (0==xll->number_of_functions){
+									g_warning(_("No loadable worksheet functions found in XLL/DLL/SO file %s ."),full_entry_name);
+								} else {
+									GO_SLIST_PREPEND(XLLs,xll);
+									g_message(_("Loaded %lu functions from XLL/DLL/SO %s ."),xll->number_of_functions,full_entry_name);
+								}
+							}
+							if (0==xll->number_of_functions){
+								free_XLL(xll);
+							}
+						}
+					}
+				}
+				g_free(full_entry_name);
+			}
+		}
+		g_dir_close (dir);
+	}
+}
+
+G_MODULE_EXPORT void go_plugin_init (GOPlugin *plugin, GOCmdContext *cc) {
+	guint i;
+
+	load_xlcall32(plugin);
+
+	if (NULL==xlcall32_handle) /* If we couldn't load the helper dll, there is no point in continuing. */
+		return;
+
+	for (i=0;i<GNM_ERROR_UNKNOWN;++i){
+		gnm_value_error_std[i]=value_new_error_std(NULL,(GnmStdError)i);
+	}
+
+	/* Find all external XLL functions that are to be adapted into Gnumeric. We scan for all shared libraries that
+	   expose xlAutoOpen, in this directory, and all sub directories. Find them, load them, find xlAutoFree if
+	   present, call xlAutoOpen, and record via the exposed actual_Excel4v function what worksheet functions they
+	   want to register with Excel. Then, put all this information in a table and make theFuncCollection point to
+	   it. */
+
+	/* We search recursively the directory in which this plugin resides and all of its subdirectories. This is not
+	   for any philosophical reasons and can be changed as desired. */
+
+	scan_for_XLLs_and_register_functions(go_plugin_get_dir_name(plugin));
+
+}
+
+G_MODULE_EXPORT void go_plugin_shutdown (GOPlugin *plugin, GOCmdContext *cc) {
+	guint i;
+
+	/* To be formally correct, we should unregister all of the loaded XLL functions. To write this code is a lot of
+	   effort, and in all likelihood, it is never needed. Postponed until it becomes really necessary. In practice,
+	   XLL writers usually don't call the xlfUnregister procedure in Excel for each of the registered functions
+	   either. */
+
+	if (NULL!=xll_function_info_map){
+		g_tree_destroy(xll_function_info_map);
+		xll_function_info_map=NULL;
+	}
+
+	go_slist_free_custom (XLLs, free_XLL);
+	XLLs=NULL;
+
+	if (register_actual_excel4v)
+		register_actual_excel4v(NULL);
+	register_actual_excel4v=NULL;
+
+	if (NULL!=xlcall32_handle)
+		g_module_close(xlcall32_handle);
+	xlcall32_handle = NULL;
+
+	for (i=0;i<GNM_ERROR_UNKNOWN;++i){
+		value_release(gnm_value_error_std[i]);
+		gnm_value_error_std[i]=0;
+	}
+
+}
+
+/***************************************************************************/
diff --git a/plugins/excelplugins/plugin.xml.in b/plugins/excelplugins/plugin.xml.in
new file mode 100644
index 0000000..cde7b75
--- /dev/null
+++ b/plugins/excelplugins/plugin.xml.in
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin id="Gnumeric_excelplugins">
+	<information>
+		<_name>Excel plugins</_name>
+		<_description>Adapter interface to load Excel plugins (also known as XLLs). Only operational for worksheet functions that expect only arguments of LPXLOPER type (type 'P' or 'R') and return an LPXLOPER (type 'P' or 'R').</_description>
+		<autoload/>
+	</information>
+	<loader type="Gnumeric_Builtin:module">
+		<attribute name="module_file" value="plugin"/>
+	</loader>
+</plugin>
diff --git a/plugins/excelplugins/win32replacements.h b/plugins/excelplugins/win32replacements.h
new file mode 100644
index 0000000..5565def
--- /dev/null
+++ b/plugins/excelplugins/win32replacements.h
@@ -0,0 +1,72 @@
+#ifndef GNM_XLL_WIN32REPALCEMENTS_H
+#define GNM_XLL_WIN32REPALCEMENTS_H
+
+#ifndef _WORD_DEFINED
+typedef unsigned short WORD;
+#define _WORD_DEFINED
+#endif
+
+#ifndef _DWORD_DEFINED
+typedef unsigned long DWORD;
+#define _DWORD_DEFINED
+#endif
+
+#ifndef _BOOL_DEFINED
+typedef int BOOL;
+#define _BOOL_DEFINED
+#endif
+
+#ifndef _BYTE_DEFINED
+typedef unsigned char BYTE;
+#define _BYTE_DEFINED
+#endif
+
+#ifndef _LPSTR_DEFINED
+typedef char * LPSTR;
+#define _LPSTR_DEFINED
+#endif
+
+#ifndef FAR
+#define FAR
+#endif
+
+#ifndef far
+#define far
+#endif
+
+#ifndef _HANDLE_DEFINED
+typedef void * HANDLE;
+#define _HANDLE_DEFINED
+#endif
+
+#ifndef _cdecl
+#define _cdecl
+#endif
+
+#ifndef pascal
+#define pascal
+#endif
+
+#if ( defined( WIN32 ) || defined( WIN64 ) ) && ! defined( WINAPI )
+#define WINAPI __attribute__((stdcall))
+#else
+#define WINAPI /* By default, C/C++ calling conventions are used throughout. This can be changed if required. */
+#endif
+
+#ifndef APIENTRY
+#define APIENTRY WINAPI
+#endif
+
+#ifndef LPVOID
+#define LPVOID void*
+#endif
+
+#ifndef TRUE
+#define TRUE                1
+#endif
+
+#ifndef FALSE
+#define FALSE               0
+#endif
+
+#endif
diff --git a/plugins/excelplugins/xlcall.h b/plugins/excelplugins/xlcall.h
new file mode 100644
index 0000000..fdb67ad
--- /dev/null
+++ b/plugins/excelplugins/xlcall.h
@@ -0,0 +1,971 @@
+/*
+**  Microsoft Excel Developer's Toolkit
+**  Version 5.0
+**
+**  File:           INCLUDE\XLCALL.H
+**  Description:    Header file for for Microsoft Excel callbacks
+**  Platform:       Microsoft Windows
+**
+**  This file defines the constants and
+**  data types which are used in the
+**  Microsoft Excel C API. Include
+**  <windows.h> before you include this.
+**
+*/
+#ifndef xlsdk_xlcall_h
+#define xlsdk_xlcall_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif	/* __cplusplus */
+
+/*
+** XLREF structure
+**
+** Describes a single rectangular reference
+*/
+
+typedef struct xlref
+{
+    WORD rwFirst;
+    WORD rwLast;
+    BYTE colFirst;
+    BYTE colLast;
+} XLREF, FAR *LPXLREF;
+
+
+/*
+** XLMREF structure
+**
+** Describes multiple rectangular references.
+** This is a variable size structure, default
+** size is 1 reference.
+*/
+
+typedef struct xlmref
+{
+    WORD count;
+    XLREF reftbl[1];                        /* actually reftbl[count] */
+} XLMREF, FAR *LPXLMREF;
+
+
+/*
+** XLOPER structure
+**
+** Excel's fundamental data type: can hold data
+** of any type. Use "R" as the argument type in the
+** REGISTER function.
+**/
+
+typedef struct xloper
+{
+    union
+    {
+        double num;                     /* xltypeNum */
+        LPSTR str;                      /* xltypeStr */
+        // bool is a reserved keyword
+        // WORD bool;                      /* xltypeBool */
+        WORD boolean;                      /* xltypeBool */
+        WORD err;                       /* xltypeErr */
+        short int w;                    /* xltypeInt */
+        struct
+        {
+            WORD count;                 /* always = 1 */
+            XLREF ref;
+        } sref;                         /* xltypeSRef */
+        struct
+        {
+            XLMREF far *lpmref;
+            DWORD idSheet;
+        } mref;                         /* xltypeRef */
+        struct
+        {
+            struct xloper far *lparray;
+            WORD rows;
+            WORD columns;
+        } array;                        /* xltypeMulti */
+        struct
+        {
+            union
+            {
+                short int level;        /* xlflowRestart */
+                short int tbctrl;       /* xlflowPause */
+                DWORD idSheet;          /* xlflowGoto */
+            } valflow;
+            WORD rw;                    /* xlflowGoto */
+            BYTE col;                   /* xlflowGoto */
+            BYTE xlflow;
+        } flow;                         /* xltypeFlow */
+        struct
+        {
+            union
+            {
+                BYTE far *lpbData;      /* data passed to XL */
+                HANDLE hdata;           /* data returned from XL */
+            } h;
+            long cbData;
+        } bigdata;                      /* xltypeBigData */
+    } val;
+    WORD xltype;
+} XLOPER, FAR *LPXLOPER;
+
+
+/*
+** XLOPER data types
+**
+** Used for xltype field of XLOPER structure
+*/
+
+#define xltypeNum        0x0001
+#define xltypeStr        0x0002
+#define xltypeBool       0x0004
+#define xltypeRef        0x0008
+#define xltypeErr        0x0010
+#define xltypeFlow       0x0020
+#define xltypeMulti      0x0040
+#define xltypeMissing    0x0080
+#define xltypeNil        0x0100
+#define xltypeSRef       0x0400
+#define xltypeInt        0x0800
+#define xlbitXLFree      0x1000
+#define xlbitDLLFree     0x4000
+
+#define xltypeBigData    (xltypeStr | xltypeInt)
+
+
+/*
+** Error codes
+**
+** Used for val.err field of XLOPER structure
+** when constructing error XLOPERs
+*/
+
+#define xlerrNull    0
+#define xlerrDiv0    7
+#define xlerrValue   15
+#define xlerrRef     23
+#define xlerrName    29
+#define xlerrNum     36
+#define xlerrNA      42
+
+
+/*
+** Flow data types
+**
+** Used for val.flow.xlflow field of XLOPER structure
+** when constructing flow-control XLOPERs
+**/
+
+#define xlflowHalt       1
+#define xlflowGoto       2
+#define xlflowRestart    8
+#define xlflowPause      16
+#define xlflowResume     64
+
+
+/*
+** Function prototypes
+*/
+
+int far _cdecl Excel4(int xlfn, LPXLOPER operRes, int count,... );
+/* followed by count LPXLOPERs */
+
+int far pascal Excel4v(int xlfn, LPXLOPER operRes, int count, LPXLOPER far opers[]);
+int far pascal XLCallVer(void);
+
+
+/*
+** Return codes
+**
+** These values can be returned from Excel4() or Excel4v().
+*/
+
+#define xlretSuccess    0     /* success */
+#define xlretAbort      1     /* macro halted */
+#define xlretInvXlfn    2     /* invalid function number */
+#define xlretInvCount   4     /* invalid number of arguments */
+#define xlretInvXloper  8     /* invalid OPER structure */
+#define xlretStackOvfl  16    /* stack overflow */
+#define xlretFailed     32    /* command failed */
+#define xlretUncalced   64    /* uncalced cell */
+
+
+/*
+** Function number bits
+*/
+
+#define xlCommand    0x8000
+#define xlSpecial    0x4000
+#define xlIntl       0x2000
+#define xlPrompt     0x1000
+
+
+/*
+** Auxiliary function numbers
+**
+** These functions are available only from the C API,
+** not from the Excel macro language.
+*/
+
+#define xlFree             (0  | xlSpecial)
+#define xlStack            (1  | xlSpecial)
+#define xlCoerce           (2  | xlSpecial)
+#define xlSet              (3  | xlSpecial)
+#define xlSheetId          (4  | xlSpecial)
+#define xlSheetNm          (5  | xlSpecial)
+#define xlAbort            (6  | xlSpecial)
+#define xlGetInst          (7  | xlSpecial)
+#define xlGetHwnd          (8  | xlSpecial)
+#define xlGetName          (9  | xlSpecial)
+#define xlEnableXLMsgs     (10 | xlSpecial)
+#define xlDisableXLMsgs    (11 | xlSpecial)
+#define xlDefineBinaryName (12 | xlSpecial)
+#define xlGetBinaryName    (13 | xlSpecial)
+
+
+/*
+** User defined function
+**
+** First argument should be a function reference.
+*/
+
+#define xlUDF      255
+
+
+/*
+** Built-in Functions and Command Equivalents
+*/
+
+
+/* Excel function numbers */
+#define xlfCount 0
+#define xlfIsna 2
+#define xlfIserror 3
+#define xlfSum 4
+#define xlfAverage 5
+#define xlfMin 6
+#define xlfMax 7
+#define xlfRow 8
+#define xlfColumn 9
+#define xlfNa 10
+#define xlfNpv 11
+#define xlfStdev 12
+#define xlfDollar 13
+#define xlfFixed 14
+#define xlfSin 15
+#define xlfCos 16
+#define xlfTan 17
+#define xlfAtan 18
+#define xlfPi 19
+#define xlfSqrt 20
+#define xlfExp 21
+#define xlfLn 22
+#define xlfLog10 23
+#define xlfAbs 24
+#define xlfInt 25
+#define xlfSign 26
+#define xlfRound 27
+#define xlfLookup 28
+#define xlfIndex 29
+#define xlfRept 30
+#define xlfMid 31
+#define xlfLen 32
+#define xlfValue 33
+#define xlfTrue 34
+#define xlfFalse 35
+#define xlfAnd 36
+#define xlfOr 37
+#define xlfNot 38
+#define xlfMod 39
+#define xlfDcount 40
+#define xlfDsum 41
+#define xlfDaverage 42
+#define xlfDmin 43
+#define xlfDmax 44
+#define xlfDstdev 45
+#define xlfVar 46
+#define xlfDvar 47
+#define xlfText 48
+#define xlfLinest 49
+#define xlfTrend 50
+#define xlfLogest 51
+#define xlfGrowth 52
+#define xlfGoto 53
+#define xlfHalt 54
+#define xlfPv 56
+#define xlfFv 57
+#define xlfNper 58
+#define xlfPmt 59
+#define xlfRate 60
+#define xlfMirr 61
+#define xlfIrr 62
+#define xlfRand 63
+#define xlfMatch 64
+#define xlfDate 65
+#define xlfTime 66
+#define xlfDay 67
+#define xlfMonth 68
+#define xlfYear 69
+#define xlfWeekday 70
+#define xlfHour 71
+#define xlfMinute 72
+#define xlfSecond 73
+#define xlfNow 74
+#define xlfAreas 75
+#define xlfRows 76
+#define xlfColumns 77
+#define xlfOffset 78
+#define xlfAbsref 79
+#define xlfRelref 80
+#define xlfArgument 81
+#define xlfSearch 82
+#define xlfTranspose 83
+#define xlfError 84
+#define xlfStep 85
+#define xlfType 86
+#define xlfEcho 87
+#define xlfSetName 88
+#define xlfCaller 89
+#define xlfDeref 90
+#define xlfWindows 91
+#define xlfSeries 92
+#define xlfDocuments 93
+#define xlfActiveCell 94
+#define xlfSelection 95
+#define xlfResult 96
+#define xlfAtan2 97
+#define xlfAsin 98
+#define xlfAcos 99
+#define xlfChoose 100
+#define xlfHlookup 101
+#define xlfVlookup 102
+#define xlfLinks 103
+#define xlfInput 104
+#define xlfIsref 105
+#define xlfGetFormula 106
+#define xlfGetName 107
+#define xlfSetValue 108
+#define xlfLog 109
+#define xlfExec 110
+#define xlfChar 111
+#define xlfLower 112
+#define xlfUpper 113
+#define xlfProper 114
+#define xlfLeft 115
+#define xlfRight 116
+#define xlfExact 117
+#define xlfTrim 118
+#define xlfReplace 119
+#define xlfSubstitute 120
+#define xlfCode 121
+#define xlfNames 122
+#define xlfDirectory 123
+#define xlfFind 124
+#define xlfCell 125
+#define xlfIserr 126
+#define xlfIstext 127
+#define xlfIsnumber 128
+#define xlfIsblank 129
+#define xlfT 130
+#define xlfN 131
+#define xlfFopen 132
+#define xlfFclose 133
+#define xlfFsize 134
+#define xlfFreadln 135
+#define xlfFread 136
+#define xlfFwriteln 137
+#define xlfFwrite 138
+#define xlfFpos 139
+#define xlfDatevalue 140
+#define xlfTimevalue 141
+#define xlfSln 142
+#define xlfSyd 143
+#define xlfDdb 144
+#define xlfGetDef 145
+#define xlfReftext 146
+#define xlfTextref 147
+#define xlfIndirect 148
+#define xlfRegister 149
+#define xlfCall 150
+#define xlfAddBar 151
+#define xlfAddMenu 152
+#define xlfAddCommand 153
+#define xlfEnableCommand 154
+#define xlfCheckCommand 155
+#define xlfRenameCommand 156
+#define xlfShowBar 157
+#define xlfDeleteMenu 158
+#define xlfDeleteCommand 159
+#define xlfGetChartItem 160
+#define xlfDialogBox 161
+#define xlfClean 162
+#define xlfMdeterm 163
+#define xlfMinverse 164
+#define xlfMmult 165
+#define xlfFiles 166
+#define xlfIpmt 167
+#define xlfPpmt 168
+#define xlfCounta 169
+#define xlfCancelKey 170
+#define xlfInitiate 175
+#define xlfRequest 176
+#define xlfPoke 177
+#define xlfExecute 178
+#define xlfTerminate 179
+#define xlfRestart 180
+#define xlfHelp 181
+#define xlfGetBar 182
+#define xlfProduct 183
+#define xlfFact 184
+#define xlfGetCell 185
+#define xlfGetWorkspace 186
+#define xlfGetWindow 187
+#define xlfGetDocument 188
+#define xlfDproduct 189
+#define xlfIsnontext 190
+#define xlfGetNote 191
+#define xlfNote 192
+#define xlfStdevp 193
+#define xlfVarp 194
+#define xlfDstdevp 195
+#define xlfDvarp 196
+#define xlfTrunc 197
+#define xlfIslogical 198
+#define xlfDcounta 199
+#define xlfDeleteBar 200
+#define xlfUnregister 201
+#define xlfUsdollar 204
+#define xlfFindb 205
+#define xlfSearchb 206
+#define xlfReplaceb 207
+#define xlfLeftb 208
+#define xlfRightb 209
+#define xlfMidb 210
+#define xlfLenb 211
+#define xlfRoundup 212
+#define xlfRounddown 213
+#define xlfAsc 214
+#define xlfDbcs 215
+#define xlfRank 216
+#define xlfAddress 219
+#define xlfDays360 220
+#define xlfToday 221
+#define xlfVdb 222
+#define xlfMedian 227
+#define xlfSumproduct 228
+#define xlfSinh 229
+#define xlfCosh 230
+#define xlfTanh 231
+#define xlfAsinh 232
+#define xlfAcosh 233
+#define xlfAtanh 234
+#define xlfDget 235
+#define xlfCreateObject 236
+#define xlfVolatile 237
+#define xlfLastError 238
+#define xlfCustomUndo 239
+#define xlfCustomRepeat 240
+#define xlfFormulaConvert 241
+#define xlfGetLinkInfo 242
+#define xlfTextBox 243
+#define xlfInfo 244
+#define xlfGroup 245
+#define xlfGetObject 246
+#define xlfDb 247
+#define xlfPause 248
+#define xlfResume 251
+#define xlfFrequency 252
+#define xlfAddToolbar 253
+#define xlfDeleteToolbar 254
+#define xlfResetToolbar 256
+#define xlfEvaluate 257
+#define xlfGetToolbar 258
+#define xlfGetTool 259
+#define xlfSpellingCheck 260
+#define xlfErrorType 261
+#define xlfAppTitle 262
+#define xlfWindowTitle 263
+#define xlfSaveToolbar 264
+#define xlfEnableTool 265
+#define xlfPressTool 266
+#define xlfRegisterId 267
+#define xlfGetWorkbook 268
+#define xlfAvedev 269
+#define xlfBetadist 270
+#define xlfGammaln 271
+#define xlfBetainv 272
+#define xlfBinomdist 273
+#define xlfChidist 274
+#define xlfChiinv 275
+#define xlfCombin 276
+#define xlfConfidence 277
+#define xlfCritbinom 278
+#define xlfEven 279
+#define xlfExpondist 280
+#define xlfFdist 281
+#define xlfFinv 282
+#define xlfFisher 283
+#define xlfFisherinv 284
+#define xlfFloor 285
+#define xlfGammadist 286
+#define xlfGammainv 287
+#define xlfCeiling 288
+#define xlfHypgeomdist 289
+#define xlfLognormdist 290
+#define xlfLoginv 291
+#define xlfNegbinomdist 292
+#define xlfNormdist 293
+#define xlfNormsdist 294
+#define xlfNorminv 295
+#define xlfNormsinv 296
+#define xlfStandardize 297
+#define xlfOdd 298
+#define xlfPermut 299
+#define xlfPoisson 300
+#define xlfTdist 301
+#define xlfWeibull 302
+#define xlfSumxmy2 303
+#define xlfSumx2my2 304
+#define xlfSumx2py2 305
+#define xlfChitest 306
+#define xlfCorrel 307
+#define xlfCovar 308
+#define xlfForecast 309
+#define xlfFtest 310
+#define xlfIntercept 311
+#define xlfPearson 312
+#define xlfRsq 313
+#define xlfSteyx 314
+#define xlfSlope 315
+#define xlfTtest 316
+#define xlfProb 317
+#define xlfDevsq 318
+#define xlfGeomean 319
+#define xlfHarmean 320
+#define xlfSumsq 321
+#define xlfKurt 322
+#define xlfSkew 323
+#define xlfZtest 324
+#define xlfLarge 325
+#define xlfSmall 326
+#define xlfQuartile 327
+#define xlfPercentile 328
+#define xlfPercentrank 329
+#define xlfMode 330
+#define xlfTrimmean 331
+#define xlfTinv 332
+#define xlfMovieCommand 334
+#define xlfGetMovie 335
+#define xlfConcatenate 336
+#define xlfPower 337
+#define xlfPivotAddData 338
+#define xlfGetPivotTable 339
+#define xlfGetPivotField 340
+#define xlfGetPivotItem 341
+#define xlfRadians 342
+#define xlfDegrees 343
+#define xlfSubtotal 344
+#define xlfSumif 345
+#define xlfCountif 346
+#define xlfCountblank 347
+#define xlfScenarioGet 348
+#define xlfOptionsListsGet 349
+#define xlfIspmt 350
+#define xlfDatedif 351
+#define xlfDatestring 352
+#define xlfNumberstring 353
+#define xlfRoman 354
+#define xlfOpenDialog 355
+#define xlfSaveDialog 356
+
+/* Excel command numbers */
+#define xlcBeep (0 | xlCommand)
+#define xlcOpen (1 | xlCommand)
+#define xlcOpenLinks (2 | xlCommand)
+#define xlcCloseAll (3 | xlCommand)
+#define xlcSave (4 | xlCommand)
+#define xlcSaveAs (5 | xlCommand)
+#define xlcFileDelete (6 | xlCommand)
+#define xlcPageSetup (7 | xlCommand)
+#define xlcPrint (8 | xlCommand)
+#define xlcPrinterSetup (9 | xlCommand)
+#define xlcQuit (10 | xlCommand)
+#define xlcNewWindow (11 | xlCommand)
+#define xlcArrangeAll (12 | xlCommand)
+#define xlcWindowSize (13 | xlCommand)
+#define xlcWindowMove (14 | xlCommand)
+#define xlcFull (15 | xlCommand)
+#define xlcClose (16 | xlCommand)
+#define xlcRun (17 | xlCommand)
+#define xlcSetPrintArea (22 | xlCommand)
+#define xlcSetPrintTitles (23 | xlCommand)
+#define xlcSetPageBreak (24 | xlCommand)
+#define xlcRemovePageBreak (25 | xlCommand)
+#define xlcFont (26 | xlCommand)
+#define xlcDisplay (27 | xlCommand)
+#define xlcProtectDocument (28 | xlCommand)
+#define xlcPrecision (29 | xlCommand)
+#define xlcA1R1c1 (30 | xlCommand)
+#define xlcCalculateNow (31 | xlCommand)
+#define xlcCalculation (32 | xlCommand)
+#define xlcDataFind (34 | xlCommand)
+#define xlcExtract (35 | xlCommand)
+#define xlcDataDelete (36 | xlCommand)
+#define xlcSetDatabase (37 | xlCommand)
+#define xlcSetCriteria (38 | xlCommand)
+#define xlcSort (39 | xlCommand)
+#define xlcDataSeries (40 | xlCommand)
+#define xlcTable (41 | xlCommand)
+#define xlcFormatNumber (42 | xlCommand)
+#define xlcAlignment (43 | xlCommand)
+#define xlcStyle (44 | xlCommand)
+#define xlcBorder (45 | xlCommand)
+#define xlcCellProtection (46 | xlCommand)
+#define xlcColumnWidth (47 | xlCommand)
+#define xlcUndo (48 | xlCommand)
+#define xlcCut (49 | xlCommand)
+#define xlcCopy (50 | xlCommand)
+#define xlcPaste (51 | xlCommand)
+#define xlcClear (52 | xlCommand)
+#define xlcPasteSpecial (53 | xlCommand)
+#define xlcEditDelete (54 | xlCommand)
+#define xlcInsert (55 | xlCommand)
+#define xlcFillRight (56 | xlCommand)
+#define xlcFillDown (57 | xlCommand)
+#define xlcDefineName (61 | xlCommand)
+#define xlcCreateNames (62 | xlCommand)
+#define xlcFormulaGoto (63 | xlCommand)
+#define xlcFormulaFind (64 | xlCommand)
+#define xlcSelectLastCell (65 | xlCommand)
+#define xlcShowActiveCell (66 | xlCommand)
+#define xlcGalleryArea (67 | xlCommand)
+#define xlcGalleryBar (68 | xlCommand)
+#define xlcGalleryColumn (69 | xlCommand)
+#define xlcGalleryLine (70 | xlCommand)
+#define xlcGalleryPie (71 | xlCommand)
+#define xlcGalleryScatter (72 | xlCommand)
+#define xlcCombination (73 | xlCommand)
+#define xlcPreferred (74 | xlCommand)
+#define xlcAddOverlay (75 | xlCommand)
+#define xlcGridlines (76 | xlCommand)
+#define xlcSetPreferred (77 | xlCommand)
+#define xlcAxes (78 | xlCommand)
+#define xlcLegend (79 | xlCommand)
+#define xlcAttachText (80 | xlCommand)
+#define xlcAddArrow (81 | xlCommand)
+#define xlcSelectChart (82 | xlCommand)
+#define xlcSelectPlotArea (83 | xlCommand)
+#define xlcPatterns (84 | xlCommand)
+#define xlcMainChart (85 | xlCommand)
+#define xlcOverlay (86 | xlCommand)
+#define xlcScale (87 | xlCommand)
+#define xlcFormatLegend (88 | xlCommand)
+#define xlcFormatText (89 | xlCommand)
+#define xlcEditRepeat (90 | xlCommand)
+#define xlcParse (91 | xlCommand)
+#define xlcJustify (92 | xlCommand)
+#define xlcHide (93 | xlCommand)
+#define xlcUnhide (94 | xlCommand)
+#define xlcWorkspace (95 | xlCommand)
+#define xlcFormula (96 | xlCommand)
+#define xlcFormulaFill (97 | xlCommand)
+#define xlcFormulaArray (98 | xlCommand)
+#define xlcDataFindNext (99 | xlCommand)
+#define xlcDataFindPrev (100 | xlCommand)
+#define xlcFormulaFindNext (101 | xlCommand)
+#define xlcFormulaFindPrev (102 | xlCommand)
+#define xlcActivate (103 | xlCommand)
+#define xlcActivateNext (104 | xlCommand)
+#define xlcActivatePrev (105 | xlCommand)
+#define xlcUnlockedNext (106 | xlCommand)
+#define xlcUnlockedPrev (107 | xlCommand)
+#define xlcCopyPicture (108 | xlCommand)
+#define xlcSelect (109 | xlCommand)
+#define xlcDeleteName (110 | xlCommand)
+#define xlcDeleteFormat (111 | xlCommand)
+#define xlcVline (112 | xlCommand)
+#define xlcHline (113 | xlCommand)
+#define xlcVpage (114 | xlCommand)
+#define xlcHpage (115 | xlCommand)
+#define xlcVscroll (116 | xlCommand)
+#define xlcHscroll (117 | xlCommand)
+#define xlcAlert (118 | xlCommand)
+#define xlcNew (119 | xlCommand)
+#define xlcCancelCopy (120 | xlCommand)
+#define xlcShowClipboard (121 | xlCommand)
+#define xlcMessage (122 | xlCommand)
+#define xlcPasteLink (124 | xlCommand)
+#define xlcAppActivate (125 | xlCommand)
+#define xlcDeleteArrow (126 | xlCommand)
+#define xlcRowHeight (127 | xlCommand)
+#define xlcFormatMove (128 | xlCommand)
+#define xlcFormatSize (129 | xlCommand)
+#define xlcFormulaReplace (130 | xlCommand)
+#define xlcSendKeys (131 | xlCommand)
+#define xlcSelectSpecial (132 | xlCommand)
+#define xlcApplyNames (133 | xlCommand)
+#define xlcReplaceFont (134 | xlCommand)
+#define xlcFreezePanes (135 | xlCommand)
+#define xlcShowInfo (136 | xlCommand)
+#define xlcSplit (137 | xlCommand)
+#define xlcOnWindow (138 | xlCommand)
+#define xlcOnData (139 | xlCommand)
+#define xlcDisableInput (140 | xlCommand)
+#define xlcEcho (141 | xlCommand)
+#define xlcOutline (142 | xlCommand)
+#define xlcListNames (143 | xlCommand)
+#define xlcFileClose (144 | xlCommand)
+#define xlcSaveWorkbook (145 | xlCommand)
+#define xlcDataForm (146 | xlCommand)
+#define xlcCopyChart (147 | xlCommand)
+#define xlcOnTime (148 | xlCommand)
+#define xlcWait (149 | xlCommand)
+#define xlcFormatFont (150 | xlCommand)
+#define xlcFillUp (151 | xlCommand)
+#define xlcFillLeft (152 | xlCommand)
+#define xlcDeleteOverlay (153 | xlCommand)
+#define xlcNote (154 | xlCommand)
+#define xlcShortMenus (155 | xlCommand)
+#define xlcSetUpdateStatus (159 | xlCommand)
+#define xlcColorPalette (161 | xlCommand)
+#define xlcDeleteStyle (162 | xlCommand)
+#define xlcWindowRestore (163 | xlCommand)
+#define xlcWindowMaximize (164 | xlCommand)
+#define xlcError (165 | xlCommand)
+#define xlcChangeLink (166 | xlCommand)
+#define xlcCalculateDocument (167 | xlCommand)
+#define xlcOnKey (168 | xlCommand)
+#define xlcAppRestore (169 | xlCommand)
+#define xlcAppMove (170 | xlCommand)
+#define xlcAppSize (171 | xlCommand)
+#define xlcAppMinimize (172 | xlCommand)
+#define xlcAppMaximize (173 | xlCommand)
+#define xlcBringToFront (174 | xlCommand)
+#define xlcSendToBack (175 | xlCommand)
+#define xlcMainChartType (185 | xlCommand)
+#define xlcOverlayChartType (186 | xlCommand)
+#define xlcSelectEnd (187 | xlCommand)
+#define xlcOpenMail (188 | xlCommand)
+#define xlcSendMail (189 | xlCommand)
+#define xlcStandardFont (190 | xlCommand)
+#define xlcConsolidate (191 | xlCommand)
+#define xlcSortSpecial (192 | xlCommand)
+#define xlcGallery3dArea (193 | xlCommand)
+#define xlcGallery3dColumn (194 | xlCommand)
+#define xlcGallery3dLine (195 | xlCommand)
+#define xlcGallery3dPie (196 | xlCommand)
+#define xlcView3d (197 | xlCommand)
+#define xlcGoalSeek (198 | xlCommand)
+#define xlcWorkgroup (199 | xlCommand)
+#define xlcFillGroup (200 | xlCommand)
+#define xlcUpdateLink (201 | xlCommand)
+#define xlcPromote (202 | xlCommand)
+#define xlcDemote (203 | xlCommand)
+#define xlcShowDetail (204 | xlCommand)
+#define xlcUngroup (206 | xlCommand)
+#define xlcObjectProperties (207 | xlCommand)
+#define xlcSaveNewObject (208 | xlCommand)
+#define xlcShare (209 | xlCommand)
+#define xlcShareName (210 | xlCommand)
+#define xlcDuplicate (211 | xlCommand)
+#define xlcApplyStyle (212 | xlCommand)
+#define xlcAssignToObject (213 | xlCommand)
+#define xlcObjectProtection (214 | xlCommand)
+#define xlcHideObject (215 | xlCommand)
+#define xlcSetExtract (216 | xlCommand)
+#define xlcCreatePublisher (217 | xlCommand)
+#define xlcSubscribeTo (218 | xlCommand)
+#define xlcAttributes (219 | xlCommand)
+#define xlcShowToolbar (220 | xlCommand)
+#define xlcPrintPreview (222 | xlCommand)
+#define xlcEditColor (223 | xlCommand)
+#define xlcShowLevels (224 | xlCommand)
+#define xlcFormatMain (225 | xlCommand)
+#define xlcFormatOverlay (226 | xlCommand)
+#define xlcOnRecalc (227 | xlCommand)
+#define xlcEditSeries (228 | xlCommand)
+#define xlcDefineStyle (229 | xlCommand)
+#define xlcLinePrint (240 | xlCommand)
+#define xlcEnterData (243 | xlCommand)
+#define xlcGalleryRadar (249 | xlCommand)
+#define xlcMergeStyles (250 | xlCommand)
+#define xlcEditionOptions (251 | xlCommand)
+#define xlcPastePicture (252 | xlCommand)
+#define xlcPastePictureLink (253 | xlCommand)
+#define xlcSpelling (254 | xlCommand)
+#define xlcZoom (256 | xlCommand)
+#define xlcResume (258 | xlCommand)
+#define xlcInsertObject (259 | xlCommand)
+#define xlcWindowMinimize (260 | xlCommand)
+#define xlcSize (261 | xlCommand)
+#define xlcMove (262 | xlCommand)
+#define xlcSoundNote (265 | xlCommand)
+#define xlcSoundPlay (266 | xlCommand)
+#define xlcFormatShape (267 | xlCommand)
+#define xlcExtendPolygon (268 | xlCommand)
+#define xlcFormatAuto (269 | xlCommand)
+#define xlcGallery3dBar (272 | xlCommand)
+#define xlcGallery3dSurface (273 | xlCommand)
+#define xlcFillAuto (274 | xlCommand)
+#define xlcCustomizeToolbar (276 | xlCommand)
+#define xlcAddTool (277 | xlCommand)
+#define xlcEditObject (278 | xlCommand)
+#define xlcOnDoubleclick (279 | xlCommand)
+#define xlcOnEntry (280 | xlCommand)
+#define xlcWorkbookAdd (281 | xlCommand)
+#define xlcWorkbookMove (282 | xlCommand)
+#define xlcWorkbookCopy (283 | xlCommand)
+#define xlcWorkbookOptions (284 | xlCommand)
+#define xlcSaveWorkspace (285 | xlCommand)
+#define xlcChartWizard (288 | xlCommand)
+#define xlcDeleteTool (289 | xlCommand)
+#define xlcMoveTool (290 | xlCommand)
+#define xlcWorkbookSelect (291 | xlCommand)
+#define xlcWorkbookActivate (292 | xlCommand)
+#define xlcAssignToTool (293 | xlCommand)
+#define xlcCopyTool (295 | xlCommand)
+#define xlcResetTool (296 | xlCommand)
+#define xlcConstrainNumeric (297 | xlCommand)
+#define xlcPasteTool (298 | xlCommand)
+#define xlcPlacement (300 | xlCommand)
+#define xlcFillWorkgroup (301 | xlCommand)
+#define xlcWorkbookNew (302 | xlCommand)
+#define xlcScenarioCells (305 | xlCommand)
+#define xlcScenarioDelete (306 | xlCommand)
+#define xlcScenarioAdd (307 | xlCommand)
+#define xlcScenarioEdit (308 | xlCommand)
+#define xlcScenarioShow (309 | xlCommand)
+#define xlcScenarioShowNext (310 | xlCommand)
+#define xlcScenarioSummary (311 | xlCommand)
+#define xlcPivotTableWizard (312 | xlCommand)
+#define xlcPivotFieldProperties (313 | xlCommand)
+#define xlcPivotField (314 | xlCommand)
+#define xlcPivotItem (315 | xlCommand)
+#define xlcPivotAddFields (316 | xlCommand)
+#define xlcOptionsCalculation (318 | xlCommand)
+#define xlcOptionsEdit (319 | xlCommand)
+#define xlcOptionsView (320 | xlCommand)
+#define xlcAddinManager (321 | xlCommand)
+#define xlcMenuEditor (322 | xlCommand)
+#define xlcAttachToolbars (323 | xlCommand)
+#define xlcVbaReset (324 | xlCommand)
+#define xlcOptionsChart (325 | xlCommand)
+#define xlcStart (326 | xlCommand)
+#define xlcVbaEnd (327 | xlCommand)
+#define xlcVbaInsertFile (328 | xlCommand)
+#define xlcVbaProcedureDefinition (330 | xlCommand)
+#define xlcVbaReferences (331 | xlCommand)
+#define xlcVbaStepInto (332 | xlCommand)
+#define xlcVbaStepOver (333 | xlCommand)
+#define xlcVbaToggleBreakpoint (334 | xlCommand)
+#define xlcVbaClearBreakpoints (335 | xlCommand)
+#define xlcRoutingSlip (336 | xlCommand)
+#define xlcRouteDocument (338 | xlCommand)
+#define xlcMailLogon (339 | xlCommand)
+#define xlcInsertPicture (342 | xlCommand)
+#define xlcEditTool (343 | xlCommand)
+#define xlcGalleryDoughnut (344 | xlCommand)
+#define xlcVbaObjectBrowser (345 | xlCommand)
+#define xlcVbaDebugWindow (346 | xlCommand)
+#define xlcVbaAddWatch (347 | xlCommand)
+#define xlcVbaEditWatch (348 | xlCommand)
+#define xlcVbaInstantWatch (349 | xlCommand)
+#define xlcChartTrend (350 | xlCommand)
+#define xlcPivotItemProperties (352 | xlCommand)
+#define xlcWorkbookInsert (354 | xlCommand)
+#define xlcOptionsTransition (355 | xlCommand)
+#define xlcOptionsGeneral (356 | xlCommand)
+#define xlcFilterAdvanced (370 | xlCommand)
+#define xlcMailAddMailer (373 | xlCommand)
+#define xlcMailDeleteMailer (374 | xlCommand)
+#define xlcMailReply (375 | xlCommand)
+#define xlcMailReplyAll (376 | xlCommand)
+#define xlcMailForward (377 | xlCommand)
+#define xlcMailNextLetter (378 | xlCommand)
+#define xlcDataLabel (379 | xlCommand)
+#define xlcInsertTitle (380 | xlCommand)
+#define xlcFontProperties (381 | xlCommand)
+#define xlcMacroOptions (382 | xlCommand)
+#define xlcWorkbookHide (383 | xlCommand)
+#define xlcWorkbookUnhide (384 | xlCommand)
+#define xlcWorkbookDelete (385 | xlCommand)
+#define xlcWorkbookName (386 | xlCommand)
+#define xlcGalleryCustom (388 | xlCommand)
+#define xlcAddChartAutoformat (390 | xlCommand)
+#define xlcDeleteChartAutoformat (391 | xlCommand)
+#define xlcChartAddData (392 | xlCommand)
+#define xlcAutoOutline (393 | xlCommand)
+#define xlcTabOrder (394 | xlCommand)
+#define xlcShowDialog (395 | xlCommand)
+#define xlcSelectAll (396 | xlCommand)
+#define xlcUngroupSheets (397 | xlCommand)
+#define xlcSubtotalCreate (398 | xlCommand)
+#define xlcSubtotalRemove (399 | xlCommand)
+#define xlcRenameObject (400 | xlCommand)
+#define xlcWorkbookScroll (412 | xlCommand)
+#define xlcWorkbookNext (413 | xlCommand)
+#define xlcWorkbookPrev (414 | xlCommand)
+#define xlcWorkbookTabSplit (415 | xlCommand)
+#define xlcFullScreen (416 | xlCommand)
+#define xlcWorkbookProtect (417 | xlCommand)
+#define xlcScrollbarProperties (420 | xlCommand)
+#define xlcPivotShowPages (421 | xlCommand)
+#define xlcTextToColumns (422 | xlCommand)
+#define xlcFormatCharttype (423 | xlCommand)
+#define xlcLinkFormat (424 | xlCommand)
+#define xlcTracerDisplay (425 | xlCommand)
+#define xlcTracerNavigate (430 | xlCommand)
+#define xlcTracerClear (431 | xlCommand)
+#define xlcTracerError (432 | xlCommand)
+#define xlcPivotFieldGroup (433 | xlCommand)
+#define xlcPivotFieldUngroup (434 | xlCommand)
+#define xlcCheckboxProperties (435 | xlCommand)
+#define xlcLabelProperties (436 | xlCommand)
+#define xlcListboxProperties (437 | xlCommand)
+#define xlcEditboxProperties (438 | xlCommand)
+#define xlcPivotRefresh (439 | xlCommand)
+#define xlcLinkCombo (440 | xlCommand)
+#define xlcOpenText (441 | xlCommand)
+#define xlcHideDialog (442 | xlCommand)
+#define xlcSetDialogFocus (443 | xlCommand)
+#define xlcEnableObject (444 | xlCommand)
+#define xlcPushbuttonProperties (445 | xlCommand)
+#define xlcSetDialogDefault (446 | xlCommand)
+#define xlcFilter (447 | xlCommand)
+#define xlcFilterShowAll (448 | xlCommand)
+#define xlcClearOutline (449 | xlCommand)
+#define xlcFunctionWizard (450 | xlCommand)
+#define xlcAddListItem (451 | xlCommand)
+#define xlcSetListItem (452 | xlCommand)
+#define xlcRemoveListItem (453 | xlCommand)
+#define xlcSelectListItem (454 | xlCommand)
+#define xlcSetControlValue (455 | xlCommand)
+#define xlcSaveCopyAs (456 | xlCommand)
+#define xlcOptionsListsAdd (458 | xlCommand)
+#define xlcOptionsListsDelete (459 | xlCommand)
+#define xlcSeriesAxes (460 | xlCommand)
+#define xlcSeriesX (461 | xlCommand)
+#define xlcSeriesY (462 | xlCommand)
+#define xlcErrorbarX (463 | xlCommand)
+#define xlcErrorbarY (464 | xlCommand)
+#define xlcFormatChart (465 | xlCommand)
+#define xlcSeriesOrder (466 | xlCommand)
+#define xlcMailLogoff (467 | xlCommand)
+#define xlcClearRoutingSlip (468 | xlCommand)
+#define xlcAppActivateMicrosoft (469 | xlCommand)
+#define xlcMailEditMailer (470 | xlCommand)
+#define xlcOnSheet (471 | xlCommand)
+#define xlcStandardWidth (472 | xlCommand)
+#define xlcScenarioMerge (473 | xlCommand)
+#define xlcSummaryInfo (474 | xlCommand)
+#define xlcFindFile (475 | xlCommand)
+#define xlcActiveCellFont (476 | xlCommand)
+#define xlcEnableTipwizard (477 | xlCommand)
+#define xlcVbaMakeAddin (478 | xlCommand)
+#define xlcMailSendMailer (482 | xlCommand)
+
+#ifdef __cplusplus
+}			/* End of extern "C" { */
+#endif	/* __cplusplus */
+
+#endif
diff --git a/plugins/excelplugins/xlcall32_emulation.c b/plugins/excelplugins/xlcall32_emulation.c
new file mode 100644
index 0000000..c36dc32
--- /dev/null
+++ b/plugins/excelplugins/xlcall32_emulation.c
@@ -0,0 +1,87 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * xlcall32_emulation.c:  callback module required by (genuine) Excel plugins (also known as XLLs).
+ *
+ * Author:
+ *   Peter Jaeckel (peter jaeckel gmail com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* For quick manual building, use something like
+ *
+ *     gcc -fPIC -shared -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include xlcall32_emulation.c -Wl,-soname -Wl,xlcall32.so -o .libs/xlcall32.so
+ * or
+ *     i586-mingw32msvc-gcc -shared -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include xlcall32_emulation.c -Wl,-soname -Wl,xlcall32.dll -o .libs/xlcall32.dll
+ */
+
+#include <gmodule.h>
+
+#if defined( WIN32 ) || defined( WIN64 )
+#include <windef.h>
+#else
+#include "win32replacements.h"
+#endif
+
+G_MODULE_EXPORT void register_actual_excel4v(void*p);
+
+G_MODULE_EXPORT int far _cdecl Excel4(int xlfn, void* operRes, int count, ...);
+
+G_MODULE_EXPORT int far pascal Excel4v(int xlfn, void* operRes, int count, void** opers);
+
+G_MODULE_EXPORT int far pascal XLCallVer(void);
+
+typedef int (*Excel4vFunc)(int xlfn, void* /* XLOper * operRes */, int /*count*/, void** /* XLOper ** opers */ );
+
+static Excel4vFunc actual_excel4v = NULL;
+
+G_MODULE_EXPORT void register_actual_excel4v(void*p){
+        actual_excel4v = (Excel4vFunc)p;
+}
+
+G_MODULE_EXPORT int far pascal Excel4v(int xlfn, void* operRes, int count, void** opers) {
+        if (NULL!=actual_excel4v)
+                return actual_excel4v(xlfn,operRes,count,opers);
+        return -1;
+}
+
+G_MODULE_EXPORT int far _cdecl Excel4(int xlfn, void* operRes, int count, ...) {
+	void **opers=(void**)alloca(count*sizeof(void*));
+	va_list arg_list;
+	int i;
+        va_start(arg_list,count);
+	for (i=0;i<count;++i)
+		opers[i]=va_arg(arg_list,void*);
+	va_end(arg_list);
+	return Excel4v(xlfn,operRes,count,(void**)opers);
+}
+
+int far pascal XLCallVer(void){
+	/*
+	 * From http://msdn.microsoft.com/en-us/library/bb687851.aspx
+	 *
+	 * "You can call this function from any XLL command or function and is thread safe.
+	 *
+	 *  In Excel 97 through Excel 2003, XLCallVer returns 1280 = 0x0500 hex = 5 x 256, which indicates Excel version
+	 *  5. In Excel 2007, it returns 3072 = 0x0c00 hex = 12 x 256, which similarly indicates version 12."
+	 *
+	 */
+	return 1280;
+}
+
+#ifdef WIN32
+asm (".section .drectve");
+asm (".ascii \"-export:Excel4v=Excel4v 16,XLCallVer=XLCallVer 0\"");
+#endif
diff --git a/po-functions/POTFILES.in b/po-functions/POTFILES.in
index 12468ba..d57ce35 100644
--- a/po-functions/POTFILES.in
+++ b/po-functions/POTFILES.in
@@ -10,6 +10,7 @@ plugins/excel/ms-formula-read.c
 plugins/excel/ms-formula-write.c
 plugins/excel/xlsx-read.c
 plugins/excel/xlsx-read-pivot.c
+plugins/excelplugins/excelplugins.c
 plugins/fn-christian-date/functions.c
 plugins/fn-complex/functions.c
 plugins/fn-database/functions.c
diff --git a/po-functions/POTFILES.skip b/po-functions/POTFILES.skip
index 445709f..bcefdeb 100644
--- a/po-functions/POTFILES.skip
+++ b/po-functions/POTFILES.skip
@@ -16,6 +16,7 @@ plugins/applix/plugin.xml.in
 plugins/corba/plugin.xml.in
 plugins/dif/plugin.xml.in
 plugins/excel/plugin.xml.in
+plugins/excelplugins/plugin.xml.in
 plugins/fn-christian-date/plugin.xml.in
 plugins/fn-complex/plugin.xml.in
 plugins/fn-database/plugin.xml.in
diff --git a/po/POTFILES.in b/po/POTFILES.in
index cfd981f..e6ddfad 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -18,6 +18,8 @@ plugins/excel/ms-formula-write.c
 plugins/excel/plugin.xml.in
 plugins/excel/xlsx-read.c
 plugins/excel/xlsx-read-pivot.c
+plugins/excelplugins/excelplugins.c
+plugins/excelplugins/plugin.xml.in
 plugins/fn-christian-date/functions.c
 plugins/fn-christian-date/plugin.xml.in
 plugins/fn-complex/functions.c



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]