├── .gitignore ├── ExPy ├── ExPy.py └── xlltypes.py ├── LICENSE ├── Makefile ├── README.md ├── cbits ├── Makefile ├── chutils.h ├── expy.c ├── xlcall.h └── xlcall32.lib └── xls └── ExPyExamples.xlsx /.gitignore: -------------------------------------------------------------------------------- 1 | /cbits/Makefile~ 2 | /cbits/*.dll 3 | /cbits/*.o 4 | /cbits/expy.xll 5 | /Makefile~ 6 | /*.zip 7 | -------------------------------------------------------------------------------- /ExPy/ExPy.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Bojan Nikolic 2010, 2013 2 | # License: See the LICENSE file distributed with this git repository 3 | """ 4 | Registration of functions with Excel and their dispatch back into Python 5 | """ 6 | 7 | import __main__ 8 | import types 9 | import ctypes 10 | import xlltypes 11 | 12 | __version__ = "0.4" 13 | 14 | # Holds ancillary data about all registred functions 15 | fnregstry = {} 16 | 17 | # This is the list of all results, used to prevent garbage collection 18 | # of results passed back to Excel. This will eventually cause memory 19 | # problems. See github issue #2 20 | reslist = [] 21 | 22 | 23 | def nArgs(formula): 24 | """ 25 | Number of arguments that an excel-available function takes 26 | """ 27 | fname=formula[1:].split("(")[0] 28 | return (fnregstry[fname][0],) 29 | 30 | def dispatch(formula, 31 | firstarg=None, 32 | restargs=None): 33 | """ 34 | Dispatch an excel-available function to its Python implementation 35 | """ 36 | fname=formula[1:].split("(")[0] 37 | arglist=[] 38 | if firstarg is not None: 39 | arglist.append(xlltypes.XLOper.from_address(firstarg)) 40 | if restargs is not None: 41 | arglist.extend([xlltypes.XLOper.from_address(x) for x in restargs]) 42 | try: 43 | res=getattr(__main__, fname)(*arglist) 44 | except BaseException, e: 45 | res=str(e) 46 | res=xlltypes.mkXLOper(res) 47 | if res: 48 | reslist.append(res) 49 | return (ctypes.addressof(res),) 50 | else: 51 | return (0,) 52 | 53 | def register(fnname, nargs): 54 | """ 55 | Register a function with excel 56 | """ 57 | if type(fnname) == types.FunctionType: 58 | fnname=fnname.func_name 59 | r=RegisterFnXLL(str(getXLLDLL()), 60 | "ExPyDispatch", 61 | "P"+"P"*nargs+"#", 62 | fnname) 63 | fnregstry[fnname]=(nargs,) 64 | return r 65 | 66 | 67 | def RegisterFnXLL(*fargs): 68 | """ 69 | Register a function with Excel 70 | """ 71 | args=(ctypes.POINTER(xlltypes.XLOper)*4)() 72 | xargs=[xlltypes.mkXLOper(x) for x in fargs] 73 | for i in range(4): 74 | args[i]=ctypes.POINTER(xlltypes.XLOper)(xargs[i]) 75 | rr=xlltypes.XLOper() 76 | r=ctypes.windll.xlcall32.Excel4v(149, #This is xlfRegister 77 | ctypes.byref(rr), 78 | 4, 79 | args) 80 | fnregstry[fargs[3]]=(len(fargs[2])-2,) 81 | return r 82 | 83 | def mkEx4(n=0): 84 | p=ctypes.CFUNCTYPE(ctypes.c_int, 85 | ctypes.c_int, 86 | ctypes.POINTER(xlltypes.XLOper), 87 | ctypes.c_int, 88 | *([ctypes.POINTER(xlltypes.XLOper)]*n)) 89 | return p(ctypes.windll.xlcall32.Excel4) 90 | 91 | 92 | def getXLLDLL(): 93 | rr=xlltypes.XLOper() 94 | fn=ctypes.windll.xlcall32.Excel4v 95 | r=fn(9|0x4000, #xlGetName 96 | ctypes.byref(rr), 97 | 0, 98 | None) 99 | return rr 100 | 101 | def xlStack(): 102 | rr=xlltypes.XLOper() 103 | fn=ctypes.windll.xlcall32.Excel4v 104 | r=fn(1|0x4000, #xlStack 105 | ctypes.byref(rr), 106 | 0, 107 | None) 108 | return rr 109 | 110 | 111 | def Splash(): 112 | title="BN Algortihms Excel/Python add-in " 113 | blurb= """ 114 | This is the ExPy Python add-in for Microsoft Excel 115 | 116 | Version: %s 117 | 118 | Visit us at: http://www.bnikolic.co.uk/expy 119 | Inquiries/bug reports to: webs@bnikolic.co.uk 120 | 121 | """% (__version__,) 122 | lic=""" 123 | Copyright (C) Copyright (c) Bojan Nikolic 2010, 2013, 2014 124 | 125 | Redistribution and use in source and binary forms, with or without 126 | modification, are permitted provided that the following conditions are 127 | met: 128 | 129 | * Redistributions of source code must retain the above copyright 130 | notice, this list of conditions and the following disclaimer. 131 | 132 | * Redistributions in binary form must reproduce the above 133 | copyright notice, this list of conditions and the following 134 | disclaimer in the documentation and/or other materials provided 135 | with the distribution. 136 | 137 | * Neither the name of the ExPy Developers nor the names of any 138 | contributors may be used to endorse or promote products derived 139 | from this software without specific prior written permission. 140 | 141 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 142 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 143 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 144 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 145 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 146 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 147 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 148 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 149 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 150 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 151 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 152 | 153 | """ 154 | ctypes.windll.user32.MessageBoxA(0, 155 | blurb+lic, 156 | title, 157 | 0x40) 158 | -------------------------------------------------------------------------------- /ExPy/xlltypes.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Bojan Nikolic 2010, 2013 2 | # License: See the LICENSE file distributed with this git repository 3 | """ 4 | Definition of types for interaction with excel 5 | """ 6 | 7 | import ctypes 8 | import numpy 9 | 10 | class XLRef(ctypes.Structure): 11 | _fields_=[("rwFirst", ctypes.c_int16), 12 | ("rwLast", ctypes.c_int16), 13 | ("colFirst", ctypes.c_int8), 14 | ("colLast", ctypes.c_int8)] 15 | 16 | class XLOper(ctypes.Structure): 17 | 18 | def float(self): 19 | if self.xltype==xltypeNum: 20 | return self.val.double 21 | else: 22 | raise BaseException("XLOper is not of type double") 23 | 24 | def array(self): 25 | if self.xltype==xltypeMulti: 26 | r=[] 27 | for i in range(self.val.array.rows): 28 | rr=[] 29 | for j in range(self.val.array.columns): 30 | rr.append(self.val.array.lparray[i*self.val.array.columns+j].float()) 31 | r.append(rr) 32 | return r 33 | else: 34 | raise BaseException("XLOper is not of array type") 35 | 36 | def __str__(self): 37 | if self.xltype==xltypeStr: 38 | slen=ord(self.val.xstr[0]) 39 | return str(self.val.xstr[1:1+slen]) 40 | if self.xltype==xltypeMulti: 41 | return "Array %iR X %iC" (self.val.array.rows, 42 | self.val.array.columns) 43 | else: 44 | return "No simple text representation" 45 | 46 | class SRef(ctypes.Structure): 47 | """ 48 | Single reference 49 | """ 50 | _fields_=[("count", ctypes.c_int16), 51 | ("ref", XLRef)] 52 | 53 | class XLMRef(ctypes.Structure): 54 | _fields_=[("count", ctypes.c_int16), 55 | ("reftbl", ctypes.POINTER(XLRef))] 56 | 57 | class MRef(ctypes.Structure): 58 | """ 59 | Multiple references 60 | """ 61 | _fields_=[("lpmref", ctypes.POINTER(XLMRef)), 62 | ("idSheet", ctypes.c_int32)] 63 | 64 | class Array(ctypes.Structure): 65 | _fields_=[("lparray", ctypes.POINTER(XLOper)), 66 | ("rows", ctypes.c_int16), 67 | ("columns", ctypes.c_int16)] 68 | 69 | 70 | class ValFlow(ctypes.Union): 71 | _fields_=[("level", ctypes.c_int16), 72 | ("tbctrl", ctypes.c_int16), 73 | ("idSheet", ctypes.c_int32),] 74 | 75 | class Flow(ctypes.Structure): 76 | _fields_=[("valflow", ValFlow), 77 | ("rw", ctypes.c_int16), 78 | ("col", ctypes.c_int8), 79 | ("xlflow", ctypes.c_int8)] 80 | 81 | 82 | class H(ctypes.Union): 83 | _fields_=[("lpbData", ctypes.POINTER(ctypes.c_int8)), 84 | ("hdata", ctypes.c_void_p)] 85 | 86 | class BigData(ctypes.Structure): 87 | _fields_=[("h", H), 88 | ("cbData", ctypes.c_int32)] 89 | 90 | class Val(ctypes.Union): 91 | _fields_=[("double", ctypes.c_double), 92 | ("xstr", ctypes.c_char_p), 93 | ("xbool", ctypes.c_int16), 94 | ("err", ctypes.c_int16), 95 | ("xint", ctypes.c_int8), 96 | ("sref", SRef), 97 | ("mref", MRef), 98 | ("array", Array), 99 | ("flow", Flow), 100 | ("bigdata", BigData)] 101 | 102 | XLOper._fields_=[("val", Val), 103 | ("xltype", ctypes.c_int16)] 104 | 105 | 106 | xltypeNum=0x0001 107 | xltypeStr=0x0002 108 | xltypeBool=0x0004 109 | xltypeRef=0x0008 110 | xltypeErr=0x0010 111 | xltypeFlow=0x0020 112 | xltypeMulti=0x0040 113 | xltypeMissing=0x0080 114 | xltypeNil=0x0100 115 | xltypeSRef=0x0400 116 | xltypeInt=0x0800 117 | xlbitXLFree=0x1000 118 | xlbitDLLFree=0x4000 119 | xltypeBigData= (xltypeStr | xltypeInt) 120 | 121 | 122 | def fillXLOper(r, d): 123 | """ 124 | Make an XLOper object 125 | """ 126 | if type(d) == str: 127 | if len(d)>255: 128 | raise BaseException("Strings longer than 255 characters can not be passed into XLOPER") 129 | r._s=ctypes.create_string_buffer(len(d)+1) 130 | r._s[1:len(d)+1]=d[:] 131 | r._s[0]=chr(len(d)) 132 | r.xltype=xltypeStr 133 | r.val.xstr=ctypes.c_char_p(r._s.raw) 134 | elif (type(d) == int) or (type(d) == float ) or type(d) == numpy.float64: 135 | r.xltype=xltypeNum 136 | r.val.double=float(d) 137 | elif type(d)==numpy.ndarray: 138 | nn=len(d.shape) 139 | if nn==1: 140 | nrows=d.shape[0] 141 | ncolumns=1 142 | elif len(d.shape)==2: 143 | nrows,ncolumns=d.shape 144 | else: 145 | raise BaseException("Can't convert more than 2d array:" +str(d.shape)) 146 | r.xltype=xltypeMulti 147 | r.val.array.rows=nrows 148 | r.val.array.columns=ncolumns 149 | print "Got an array" , nrows, ncolumns 150 | atype=XLOper*(nrows*ncolumns) 151 | r.val.array.lparray=atype() 152 | for i in range(nrows): 153 | for j in range(ncolumns): 154 | if nn==1: 155 | fillXLOper(r.val.array.lparray[i*ncolumns+j], d[i]) 156 | else: 157 | fillXLOper(r.val.array.lparray[i*ncolumns+j], d[i,j]) 158 | else: 159 | raise BaseException("Don't know how to convert objects of type:" +str(type(d))) 160 | return r 161 | 162 | def mkXLOper(d): 163 | """ 164 | Make an XLOper object 165 | """ 166 | r=XLOper() 167 | try: 168 | fillXLOper(r, d) 169 | return r 170 | except BaseException, e: 171 | print e 172 | return None 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Redistribution and use in source and binary forms, with or without 2 | modification, are permitted provided that the following conditions are 3 | met: 4 | 5 | * Redistributions of source code must retain the above copyright 6 | notice, this list of conditions and the following disclaimer. 7 | 8 | * Redistributions in binary form must reproduce the above 9 | copyright notice, this list of conditions and the following 10 | disclaimer in the documentation and/or other materials provided 11 | with the distribution. 12 | 13 | * Neither the name of the ExPy Developers nor the names of any 14 | contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) Bojan Nikolic 2014 2 | # 3 | # License: BSD-3, see the LICENSE file distributed at the root of this 4 | # git repository 5 | # 6 | # Top-level makefile for ExPy 7 | 8 | GITREV := $(shell git describe --dirty) 9 | 10 | PACK := ExPy-${GITREV}.zip 11 | 12 | default: ${PACK} 13 | 14 | PYFILES := ExPy/ExPy.py ExPy/xlltypes.py 15 | XLLFILES := cbits/expy.xll 16 | 17 | ${PACK}: ${XLLFILES} ${PYFILES} 18 | cd cbits && $(MAKE) 19 | rm -f $@ 20 | zip $@ -j ${XLLFILES} ${PYFILES} 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ExPy 2 | ==== 3 | 4 | In-process Python for use within Excel. 5 | 6 | Currently tested against Python 2.7 and Excel 32bit. Works with, for 7 | example, the Windows 32 bit Anaconda distribution. 8 | 9 | BSD-3 type license, see LICENSE. 10 | 11 | For more information see 12 | http://www.bnikolic.co.uk/expy/expy.html. Build of current latest 13 | version is available at: http://www.bnikolic.co.uk/soft/ExPy-0.4.zip 14 | 15 | Inquiries to webs@bnikolic.co.uk 16 | 17 | Description 18 | ----------- 19 | 20 | ExPy allows the use of Python in Excel by loading Python into the same 21 | process as excel and exposing function using the Excel Addin 22 | interface. This is a relatively high-performance and robust interface 23 | mechanism. ExcelDNA works in a similar way (providing interfacing to 24 | .Net languages) as well many other application-specific Excel addins. 25 | 26 | Alternatives ways of interfacing are via COM (e.g., excelpython, 27 | https://github.com/ericremoreynolds/excelpython ) or client/server 28 | architectures (e.g., I believe xlloop). 29 | 30 | Installation - Binaries 31 | ----------------------- 32 | 33 | Binaries only work against Python 2.7.x versions 32bit and Excel 32 34 | bit. 35 | 36 | 1. Ensure you have installed Python version 2.7.x and it is in the 37 | PATH environment variable. The recommended way of doing this is by 38 | installing the Anaconda distribution: http://continuum.io/downloads 39 | 40 | 2. Unpack the zip file 41 | 42 | 3. Open the expy.xll file and confirm you want to give it privileges 43 | to run 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /cbits/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) Bojan Nikolic 2014 2 | # 3 | # License: BSD-3, see the LICENSE file distributed at the root of this 4 | # git repository 5 | # 6 | # Quick makefile for the c parts of ExPy. Note: I build in Linux but 7 | # using wine-hosted MinGW. YMMV. 8 | 9 | WINEP = ${HOME}/.wine-expy32 10 | WEXEC = WINEPREFIX=${WINEP} wine 11 | 12 | CC = ${WEXEC} C:\\MinGW\\bin\\gcc.exe 13 | 14 | CCFLAGS = -IC:\\Python27\\include 15 | 16 | LDFLAGS = -mdll -Wl,--add-stdcall-alias 17 | 18 | CFILES = expy.c 19 | 20 | default: expy.xll 21 | 22 | clean: 23 | rm ${CFILES:.c=.o} expy.xll 24 | 25 | %.o : %.c 26 | ${CC} ${CCFLAGS} -c $< -o $@ 27 | 28 | expy.xll : ${CFILES:.c=.o} 29 | ${CC} ${LDFLAGS} $< -o $@ ${WINEP}/drive_c/windows/syswow64/python27.dll ./xlcall32.lib 30 | 31 | 32 | -------------------------------------------------------------------------------- /cbits/chutils.h: -------------------------------------------------------------------------------- 1 | /* 2 | Code here comes from Chicken Scheme, git describe: 4.5.0rc1-2450-g627ea21 3 | ; 4 | ; Copyright (c) 2008-2014, The CHICKEN Team 5 | ; Copyright (c) 2000-2007, Felix L. Winkelmann 6 | ; All rights reserved. 7 | ; 8 | ; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following 9 | ; conditions are met: 10 | ; 11 | ; Redistributions of source code must retain the above copyright notice, this list of conditions and the following 12 | ; disclaimer. 13 | ; Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 14 | ; disclaimer in the documentation and/or other materials provided with the distribution. 15 | ; Neither the name of the author nor the names of its contributors may be used to endorse or promote 16 | ; products derived from this software without specific prior written permission. 17 | ; 18 | ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 19 | ; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 20 | ; AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 21 | ; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | ; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | ; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | ; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | ; POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | #ifndef __EXPY_CHUTILS_H__ 29 | #define __EXPY_CHUTILS_H__ 30 | 31 | /* These are wrappers around the following idiom: 32 | * assert(SOME_PRED(obj)); 33 | * do_something_with(obj); 34 | * This works around the fact obj may be an expression with side-effects. 35 | * 36 | * To make this work with nested expansions, we need semantics like 37 | * (let ((x 1)) (let ((x x)) x)) => 1, but in C, int x = x; results in 38 | * undefined behaviour because x refers to itself. As a workaround, 39 | * we keep around a reference to the previous level (one scope up). 40 | * After initialisation, "previous" is redefined to mean "current". 41 | */ 42 | # define C_VAL1(x) C__PREV_TMPST.n1 43 | # define C_VAL2(x) C__PREV_TMPST.n2 44 | # define C__STR(x) #x 45 | # define C__CHECK_panic(a,s,f,l) \ 46 | ((a) ? (void)0 : \ 47 | C_panic_hook("Low-level type assertion " s " failed at " f ":" C__STR(l))) 48 | # define C__CHECK_core(v,a,s,x) \ 49 | ({ struct { \ 50 | typeof(v) n1; \ 51 | } C__TMPST = { .n1 = (v) }; \ 52 | typeof(C__TMPST) C__PREV_TMPST=C__TMPST; \ 53 | C__CHECK_panic(a,s,__FILE__,__LINE__); \ 54 | x; }) 55 | # define C__CHECK2_core(v1,v2,a,s,x) \ 56 | ({ struct { \ 57 | typeof(v1) n1; \ 58 | typeof(v2) n2; \ 59 | } C__TMPST = { .n1 = (v1), .n2 = (v2) }; \ 60 | typeof(C__TMPST) C__PREV_TMPST=C__TMPST; \ 61 | C__CHECK_panic(a,s,__FILE__,__LINE__); \ 62 | x; }) 63 | # define C_CHECK(v,a,x) C__CHECK_core(v,a,#a,x) 64 | # define C_CHECK2(v1,v2,a,x) C__CHECK2_core(v1,v2,a,#a,x) 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /cbits/expy.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) Bojan Nikolic 2010, 2013, 2014 3 | 4 | License: See the LICENSE file distributed with this git repository 5 | 6 | */ 7 | 8 | #include "chutils.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include "xlcall.h" 18 | 19 | __declspec(dllexport) __stdcall char * _ExPyEval(const char *cmd, int stoken); 20 | // Add a path to the Python load path 21 | void addToPath(char *s); 22 | 23 | void msgBox(const char *msg) 24 | { 25 | MessageBox(GetFocus(), 26 | msg, 27 | NULL, 28 | MB_OK | MB_ICONSTOP); 29 | } 30 | 31 | void (*C_panic_hook) (const char *msg) = msgBox; 32 | 33 | #define EXPY_NFUNC 2 34 | 35 | static char* expy_funcs[EXPY_NFUNC][7] = { 36 | {"ExPyEvalSS", "CC#", "ExPyEvalSS"}, 37 | {"ExPyScript", "CC#", "ExPyScript"} 38 | }; 39 | 40 | XLOPER* new_xlstring(const char* text) 41 | { 42 | size_t len; 43 | 44 | if(!text || 45 | !(len = strlen(text))) 46 | return NULL; 47 | 48 | XLOPER* x = (XLOPER *)malloc(sizeof(XLOPER) + len + 2); 49 | if (!x) 50 | return 0; 51 | char* p = (char*)(((char*) x) + sizeof(XLOPER)); 52 | memcpy(p + 1, text, len + 1); 53 | p[0] = (BYTE)len; 54 | x->xltype = xltypeStr; 55 | x->val.str = p; 56 | return x; 57 | } 58 | 59 | char * xl2str(const XLOPER *xl) 60 | { 61 | const char *xlstr= C_CHECK(xl, xl->xltype==xltypeStr, C_VAL1(xl)->val.str); 62 | char *res=malloc(sizeof(char) * xlstr[0]); 63 | if (res) 64 | memcpy(res, xlstr+1, xlstr[0]); 65 | return res; 66 | } 67 | 68 | __declspec(dllexport) int __stdcall xlAutoOpen(void) 69 | { 70 | 71 | //check_init(); 72 | static XLOPER xDLL; 73 | int i; 74 | 75 | Excel4(xlGetName, &xDLL, 0); 76 | 77 | char *dllName=xl2str(&xDLL); 78 | HMODULE dllh=GetModuleHandle(dllName); 79 | 80 | 81 | static XLOPER xRegister; 82 | xRegister.xltype = xltypeStr; 83 | 84 | for (i=0; i1) 220 | { 221 | char fmt[nargs]; 222 | size_t i; 223 | for(i=0; i