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 }