1 /** 2 Utility functions for writing XLLs 3 */ 4 module xlld.sdk.framework; 5 6 7 import xlld.sdk.xlcall; 8 9 10 /** 11 Will free any malloc'd memory associated with the given 12 LPXLOPER, assuming it has any memory associated with it 13 14 Parameters: 15 16 LPXLOPER pxloper Pointer to the XLOPER whose associated 17 */ 18 void freeXLOper(T, A)(T pxloper, ref A allocator) 19 if(is(T == LPXLOPER) || is(T == LPXLOPER12)) 20 { 21 import std.experimental.allocator: dispose; 22 23 switch (pxloper.xltype & ~XlType.xlbitDLLFree) with(XlType) { 24 case xltypeStr: 25 if (pxloper.val.str !is null) { 26 void* bytesPtr = pxloper.val.str; 27 const numBytes = (pxloper.val.str[0] + 1) * wchar.sizeof; 28 allocator.dispose(bytesPtr[0 .. numBytes]); 29 } 30 break; 31 case xltypeRef: 32 if (pxloper.val.mref.lpmref !is null) 33 allocator.dispose(pxloper.val.mref.lpmref); 34 break; 35 case xltypeMulti: 36 auto cxloper = pxloper.val.array.rows * pxloper.val.array.columns; 37 const numOpers = cxloper; 38 if (pxloper.val.array.lparray !is null) 39 { 40 auto pxloperFree = pxloper.val.array.lparray; 41 while (cxloper > 0) 42 { 43 freeXLOper(pxloperFree, allocator); 44 pxloperFree++; 45 cxloper--; 46 } 47 allocator.dispose(pxloper.val.array.lparray[0 .. numOpers]); 48 } 49 break; 50 case xltypeBigData: 51 if (pxloper.val.bigdata.h.lpbData !is null) 52 allocator.dispose(pxloper.val.bigdata.h.lpbData); 53 break; 54 default: // todo: add error handling 55 break; 56 } 57 } 58 59 @("Free regular XLOPER") 60 unittest { 61 import xlld.memorymanager: allocator; 62 XLOPER oper; 63 freeXLOper(&oper, allocator); 64 } 65 66 @("Free XLOPER12") 67 unittest { 68 import xlld.memorymanager: allocator; 69 XLOPER12 oper; 70 freeXLOper(&oper, allocator); 71 } 72 73 /** 74 Wrapper for the Excel12 function that allows passing D arrays 75 76 Purpose: 77 A fancy wrapper for the Excel12() function. It also 78 does the following: 79 80 (1) Checks that none of the LPXLOPER12 arguments are 0, 81 which would indicate that creating a temporary XLOPER12 82 has failed. In this case, it doesn't call Excel12 83 but it does print a debug message. 84 (2) If an error occurs while calling Excel12, 85 print a useful debug message. 86 (3) When done, free all temporary memory. 87 88 #1 and #2 require _DEBUG to be defined. 89 90 Parameters: 91 92 int xlfn Function number (xl...) to call 93 LPXLOPER12 pxResult Pointer to a place to stuff the result, 94 or 0 if you don't care about the result. 95 int count Number of arguments 96 ... (all LPXLOPER12s) - the arguments. 97 98 Returns: 99 100 A return code (Some of the xlret... values, as defined 101 in XLCALL.H, OR'ed together). 102 103 Comments: 104 */ 105 106 int Excel12f(int xlfn, LPXLOPER12 pxResult, in LPXLOPER12[] args...) nothrow @nogc 107 { 108 import xlld.sdk.xlcallcpp: Excel12v; 109 import std.algorithm: all; 110 111 assert(args.all!(a => a !is null)); 112 return Excel12v(xlfn, pxResult, cast(int)args.length, cast(LPXLOPER12*)args.ptr); 113 } 114 115 /// 116 int Excel12f(int xlfn, LPXLOPER12 result, scope const(XLOPER12)[] args...) nothrow { 117 118 import std.experimental.allocator: makeArray, dispose; 119 import std.experimental.allocator.mallocator: Mallocator; 120 121 scope ptrArgs = Mallocator.instance.makeArray!(const(XLOPER12)*)(args.length); 122 scope(exit) Mallocator.instance.dispose(ptrArgs); 123 124 foreach(i, ref arg; args) 125 ptrArgs[i] = (return scope ref const(XLOPER12) a) { return &a; }(arg); 126 127 return Excel12f(xlfn, result, ptrArgs); 128 } 129 130 /// 131 int Excel12f(int xlfn, LPXLOPER12 pxResult) nothrow @nogc 132 { 133 return Excel12f(xlfn, pxResult, LPXLOPER12[].init); 134 }