1 /**
2   framework.d
3   Translated from framework.c by Laeeth Isharc
4 
5    Purpose:	Framework library for Microsoft Excel.
6 
7        This library provides some basic functions
8        that help in writing Excel DLLs. It includes
9        simple functions for managing memory with XLOPER12s,
10        creating temporary XLOPER12s, robustly calling
11        Excel12(), and outputting debugging strings
12        to the debugger for the current application.
13 
14        The main purpose of this library is to help
15        you to write cleaner C code for calling Excel.
16        For example, using the framework library you
17        can write
18 
19            Excel12f(xlcDisplay, 0, 2, TempMissing12(), TempBool12(0));
20 
21        instead of the more verbose
22 
23            XLOPER12 xMissing, bool_;
24            xMissing.xltype = xltypeMissing;
25            bool_.xltype = xltypeBool;
26            bool_.val.bool_ = 0;
27            Excel12(xlcDisplay, 0, 2, (LPXLOPER12) &xMissing, (LPXLOPER12) &bool_);
28 
29 
30        The library is non-reentrant.
31 
32        Define _DEBUG to use the debugging functions.
33 
34        Source code is provided so that you may
35        enhance this library or optimize it for your
36        own application.
37 
38    Platform:    Microsoft Windows
39 
40    Functions:
41                 debugPrintf
42                 GetTempMemory
43                 FreeAllTempMemory
44                 Excel
45                 Excel12f
46                 TempNum
47                 TempNum12
48                 TempStr
49                 TempStrConst
50                 TempStr12
51                 TempBool
52                 TempBool12
53                 TempInt
54                 TempInt12
55                 TempErr
56                 TempErr12
57                 TempActiveRef
58                 TempActiveRef12
59                 TempActiveCell
60                 TempActiveCell12
61                 TempActiveRow
62                 TempActiveRow12
63                 TempActiveColumn
64                 TempActiveColumn12
65                 TempMissing
66                 TempMissing12
67                 InitFramework
68 				QuitFramework
69 
70 */
71 module xlld.framework;
72 
73 /**
74    FreeXLOper()
75 
76    Purpose:
77         Will free any malloc'd memory associated with the given
78         LPXLOPER, assuming it has any memory associated with it
79 
80    Parameters:
81 
82         LPXLOPER pxloper    Pointer to the XLOPER whose associated
83                             memory we want to free
84 
85    Returns:
86 
87    Comments:
88 
89 */
90 
91 import xlld.xlcall;
92 
93 
94 void FreeXLOper(T)(T pxloper) if(is(T == LPXLOPER) || is(T == LPXLOPER12)) {
95     import xlld.memorymanager: allocator;
96     FreeXLOper(pxloper, allocator);
97 }
98 
99 void FreeXLOper(T, A)(T pxloper, ref A allocator)
100     if(is(T == LPXLOPER) || is(T == LPXLOPER12))
101 {
102     import std.experimental.allocator: dispose;
103 
104     switch (pxloper.xltype & ~XlType.xlbitDLLFree) with(XlType)
105 	{
106 		case xltypeStr:
107                     if (pxloper.val.str !is null) {
108                         void* bytesPtr = pxloper.val.str;
109                         const numBytes = (pxloper.val.str[0] + 1) * wchar.sizeof;
110                         allocator.dispose(bytesPtr[0 .. numBytes]);
111                     }
112 			break;
113 		case xltypeRef:
114 			if (pxloper.val.mref.lpmref !is null)
115 				allocator.dispose(pxloper.val.mref.lpmref);
116 			break;
117 		case xltypeMulti:
118 			auto cxloper = pxloper.val.array.rows * pxloper.val.array.columns;
119                         const numOpers = cxloper;
120 			if (pxloper.val.array.lparray !is null)
121 			{
122 				auto pxloperFree = pxloper.val.array.lparray;
123 				while (cxloper > 0)
124 				{
125                                     FreeXLOper(pxloperFree, allocator);
126 					pxloperFree++;
127 					cxloper--;
128 				}
129 				allocator.dispose(pxloper.val.array.lparray[0 .. numOpers]);
130 			}
131 			break;
132 		case xltypeBigData:
133 			if (pxloper.val.bigdata.h.lpbData !is null)
134 				allocator.dispose(pxloper.val.bigdata.h.lpbData);
135 			break;
136 		default: // todo: add error handling
137 			break;
138 	}
139 }
140 
141 @("Free regular XLOPER")
142 unittest {
143     XLOPER oper;
144     FreeXLOper(&oper);
145 }
146 
147 @("Free XLOPER12")
148 unittest {
149     XLOPER12 oper;
150     FreeXLOper(&oper);
151 }
152 
153 /**
154    Excel12f()
155 
156    Purpose:
157         A fancy wrapper for the Excel12() function. It also
158         does the following:
159 
160         (1) Checks that none of the LPXLOPER12 arguments are 0,
161             which would indicate that creating a temporary XLOPER12
162             has failed. In this case, it doesn't call Excel12
163             but it does print a debug message.
164         (2) If an error occurs while calling Excel12,
165             print a useful debug message.
166         (3) When done, free all temporary memory.
167 
168         #1 and #2 require _DEBUG to be defined.
169 
170    Parameters:
171 
172         int xlfn            Function number (xl...) to call
173         LPXLOPER12 pxResult Pointer to a place to stuff the result,
174                             or 0 if you don't care about the result.
175         int count           Number of arguments
176         ...                 (all LPXLOPER12s) - the arguments.
177 
178    Returns:
179 
180         A return code (Some of the xlret... values, as defined
181         in XLCALL.H, OR'ed together).
182 
183    Comments:
184 */
185 
186 int Excel12f(int xlfn, LPXLOPER12 pxResult, LPXLOPER12[] args) nothrow @nogc
187 {
188 	import xlld.memorymanager: FreeAllTempMemory;
189 	import xlld.xlcallcpp: Excel12v;
190 
191 	int xlret;
192 
193 	xlret = Excel12v(xlfn,pxResult,cast(int)args.length, cast(LPXLOPER12 *)args.ptr);
194 
195 	static if(false) //debug
196 	{
197 		if (xlret != xlretSuccess)
198 		{
199 			debugPrintf("Error! Excel12(");
200 
201 			if (xlfn & xlCommand)
202 				debugPrintf("xlCommand | ");
203 			if (xlfn & xlSpecial)
204 				debugPrintf("xlSpecial | ");
205 			if (xlfn & xlIntl)
206 				debugPrintf("xlIntl | ");
207 			if (xlfn & xlPrompt)
208 				debugPrintf("xlPrompt | ");
209 
210 			debugPrintf("%u) callback failed:",xlfn & 0x0FFF);
211 
212 			/* More than one error bit may be on */
213 
214 			if (xlret & xlretAbort)
215 			{
216 				debugPrintf(" Macro Halted\r");
217 			}
218 
219 			if (xlret & xlretInvXlfn)
220 			{
221 				debugPrintf(" Invalid Function Number\r");
222 			}
223 
224 			if (xlret & xlretInvCount)
225 			{
226 				debugPrintf(" Invalid Number of Arguments\r");
227 			}
228 
229 			if (xlret & xlretInvXloper)
230 			{
231 				debugPrintf(" Invalid XLOPER12\r");
232 			}
233 
234 			if (xlret & xlretStackOvfl)
235 			{
236 				debugPrintf(" Stack Overflow\r");
237 			}
238 
239 			if (xlret & xlretFailed)
240 			{
241 				debugPrintf(" Command failed\r");
242 			}
243 
244 			if (xlret & xlretUncalced)
245 			{
246 				debugPrintf(" Uncalced cell\r");
247 			}
248 
249 		}
250 	} // debug
251 
252 	FreeAllTempMemory();
253 
254 	return xlret;
255 }
256 
257 
258 version(Windows):
259 
260 debug=0;
261 
262 import xlld.xlcallcpp;
263 import std.typecons: Flag, Yes;
264 import core.sys.windows.windows;
265 
266 enum rwMaxO8=65536;
267 enum colMaxO8=256;
268 enum cchMaxStz=255;
269 enum MAXSHORTINT =0x7fff;
270 enum CP_ACP = 0;
271 enum MAXWORD = 0xFFFF;
272 
273 static if(false) // debug
274 {
275 
276 	/**
277 	   debugPrintf()
278 
279 	   Purpose:
280 	        sends a string to the debugger for the current application.
281 
282 	   Parameters:
283 
284 	        LPSTR lpFormat  The format definition string
285 	        ...             The values to print
286 
287 	   Returns:
288 
289 	   Comments:
290 
291 	*/
292 
293 	void  debugPrintf(LPSTR lpFormat, ...) // cdecl
294 	{
295 		char[256] rgch;
296 		va_list argList;
297 
298 		va_start(argList,lpFormat);
299 		wvsprintfA(rgch,lpFormat,argList);
300 		va_end(argList);
301 		OutputDebugStringA(rgch);
302 	}
303 }
304 
305 /**
306    Excel()
307 
308    Purpose:
309         A fancy wrapper for the Excel4() function. It also
310         does the following:
311 
312         (1) Checks that none of the LPXLOPER arguments are 0,
313             which would indicate that creating a temporary XLOPER
314             has failed. In this case, it doesn't call Excel
315             but it does print a debug message.
316         (2) If an error occurs while calling Excel,
317             print a useful debug message.
318         (3) When done, free all temporary memory.
319 
320         #1 and #2 require _DEBUG to be defined.
321 
322    Parameters:
323 
324         int xlfn            Function number (xl...) to call
325         LPXLOPER pxResult   Pointer to a place to stuff the result,
326                             or 0 if you don't care about the result.
327         int count           Number of arguments
328         ...                 (all LPXLOPERs) - the arguments.
329 
330    Returns:
331 
332         A return code (Some of the xlret... values, as defined
333         in XLCALL.H, OR'ed together).
334 
335    Comments:
336 */
337 
338 int  Excel(int xlfn, LPXLOPER pxResult, LPXLOPER[] args ...) // cdecl
339 {
340     import xlld.memorymanager: FreeAllTempMemory;
341 	int xlret;
342 
343 	xlret = Excel4v(xlfn,pxResult,cast(int)args.length,cast(LPXLOPER *)args.ptr);
344 
345 	static if(false) //debug
346 	{
347 
348 		if (xlret != xlretSuccess)
349 		{
350 			debugPrintf("Error! Excel4(");
351 
352 			if (xlfn & xlCommand)
353 				debugPrintf("xlCommand | ");
354 			if (xlfn & xlSpecial)
355 				debugPrintf("xlSpecial | ");
356 			if (xlfn & xlIntl)
357 				debugPrintf("xlIntl | ");
358 			if (xlfn & xlPrompt)
359 				debugPrintf("xlPrompt | ");
360 
361 			debugPrintf("%u) callback failed:",xlfn & 0x0FFF);
362 
363 			/* More than one error bit may be on */
364 
365 			if (xlret & xlretAbort)
366 			{
367 				debugPrintf(" Macro Halted\r");
368 			}
369 
370 			if (xlret & xlretInvXlfn)
371 			{
372 				debugPrintf(" Invalid Function Number\r");
373 			}
374 
375 			if (xlret & xlretInvCount)
376 			{
377 				debugPrintf(" Invalid Number of Arguments\r");
378 			}
379 
380 			if (xlret & xlretInvXloper)
381 			{
382 				debugPrintf(" Invalid XLOPER\r");
383 			}
384 
385 			if (xlret & xlretStackOvfl)
386 			{
387 				debugPrintf(" Stack Overflow\r");
388 			}
389 
390 			if (xlret & xlretFailed)
391 			{
392 				debugPrintf(" Command failed\r");
393 			}
394 
395 			if (xlret & xlretUncalced)
396 			{
397 				debugPrintf(" Uncalced cell\r");
398 			}
399 
400 		}
401 	} // debug
402 
403 	FreeAllTempMemory();
404 
405 	return xlret;
406 }
407 
408 
409 
410 
411 /**
412    TempNum()
413 
414    Purpose:
415         Creates a temporary numeric (IEEE floating point) XLOPER.
416 
417    Parameters:
418 
419         double d        The value
420 
421    Returns:
422 
423         LPXLOPER        The temporary XLOPER, or 0
424                         if GetTempMemory() failed.
425 
426    Comments:
427 */
428 
429 LPXLOPER TempNum(Flag!"autoFree" autoFree = Yes.autoFree)(double d)
430 {
431 	LPXLOPER lpx;
432 
433 	lpx = cast(LPXLOPER) GetTempMemory!autoFree(XLOPER.sizeof);
434 
435 	if (!lpx)
436 	{
437 		return null;
438 	}
439 
440 	lpx.xltype = xltypeNum;
441 	lpx.val.num = d;
442 
443 	return lpx;
444 }
445 
446 /**
447    TempNum12()
448 
449    Purpose:
450         Creates a temporary numeric (IEEE floating point) XLOPER12.
451 
452    Parameters:
453 
454         double d        The value
455 
456    Returns:
457 
458         LPXLOPER12      The temporary XLOPER12, or 0
459                         if GetTempMemory() failed.
460 
461    Comments:
462 
463 
464 */
465 
466 LPXLOPER12 TempNum12(Flag!"autoFree" autoFree = Yes.autoFree)(double d)
467 {
468 	LPXLOPER12 lpx;
469 
470 	lpx = cast(LPXLOPER12) GetTempMemory!autoFree(XLOPER12.sizeof);
471 
472 	if (!lpx)
473 	{
474 		return null;
475 	}
476 
477 	lpx.xltype = xltypeNum;
478 	lpx.val.num = d;
479 
480 	return lpx;
481 }
482 
483 /**
484    TempStr()
485 
486    Purpose:
487         Creates a temporary string XLOPER
488 
489    Parameters:
490 
491         LPSTR lpstr     The string, as a null-terminated
492                         C string, with the first byte
493                         undefined. This function will
494                         count the bytes of the string
495                         and insert that count in the
496                         first byte of lpstr. Excel cannot
497                         handle strings longer than 255
498                         characters.
499 
500    Returns:
501 
502         LPXLOPER        The temporary XLOPER, or 0
503                         if GetTempMemory() failed.
504 
505    Comments:
506 
507         (1) This function has the side effect of inserting
508             the byte count as the first character of
509             the created string.
510 
511         (2) For highest speed, with constant strings,
512             you may want to manually count the length of
513             the string before compiling, and then avoid
514             using this function.
515 
516         (3) Behavior is undefined for non-null terminated
517             input or strings longer than 255 characters.
518 
519    Note: If lpstr passed into TempStr is readonly, TempStr
520    will crash your XLL as it will try to modify a read only
521    string in place. strings declared on the stack as described below
522    are read only by default in VC++
523 
524    char *str = " I am a string"
525 
526    Use extreme caution while calling TempStr on such strings. Refer to
527    VC++ documentation for complier options to ensure that these strings
528    are compiled as read write or use TempStrConst instead.
529 
530    TempStr is provided mainly for backwards compatability and use of
531    TempStrConst is encouraged going forward.
532 */
533 
534 LPXLOPER TempStr(Flag!"autoFree" autoFree = Yes.autoFree)(LPSTR lpstr)
535 {
536 	LPXLOPER lpx;
537 
538 	lpx = cast(LPXLOPER) GetTempMemory!autoFree(XLOPER.sizeof);
539 
540 	if (!lpx)
541 	{
542 		return null;
543 	}
544 
545 	lpstr[0] = cast(BYTE) strlen (lpstr+1);
546 	lpx.xltype = xltypeStr;
547 	lpx.val.str = lpstr;
548 
549 	return lpx;
550 }
551 
552 
553 /**
554    TempStrConst()
555 
556    Purpose:
557         Creates a temporary string XLOPER from a
558         const string with a local copy in temp memory
559 
560    Parameters:
561 
562         LPSTR lpstr     The string, as a null-terminated
563                         C string. This function will
564                         count the bytes of the string
565                         and insert that count in the
566                         first byte of the temp string.
567                         Excel cannot handle strings
568                         longer than 255 characters.
569 
570    Returns:
571 
572         LPXLOPER        The temporary XLOPER, or 0
573                         if GetTempMemory() failed.
574 
575    Comments:
576 
577         Will take a string of the form "abc\0" and make a
578         temp XLOPER of the form "\003abc"
579 
580 */
581 
582 LPXLOPER TempStrConst(Flag!"autoFree" autoFree = Yes.autoFree)(const LPSTR lpstr)
583 {
584 	LPXLOPER lpx;
585 	LPSTR lps;
586 	size_t len;
587 
588 	len = strlen(lpstr);
589 
590 	lpx = cast(LPXLOPER) (GetTempMemory!autoFree(XLOPER.sizeof + len + 1));
591 
592 	if (!lpx)
593 	{
594 		return null;
595 	}
596 
597 	lps = cast(LPSTR)lpx + XLOPER.sizeof;
598 
599 	lps[0] = cast(BYTE)len;
600 	//can't strcpy_s because of removal of null-termination
601 	memcpy_s( cast(ubyte*)lps+1, cast(uint)len+1, cast(ubyte*)lpstr, cast(uint)len);
602 	lpx.xltype = xltypeStr;
603 	lpx.val.str = lps;
604 
605 	return lpx;
606 }
607 
608 /**
609    TempStr12()
610 
611    Purpose:
612         Creates a temporary string XLOPER12 from a
613         unicode const string with a local copy in
614         temp memory
615 
616    Parameters:
617 
618         wchar lpstr     The string, as a null-terminated
619                         unicode string. This function will
620                         count the bytes of the string
621                         and insert that count in the
622                         first byte of the temp string.
623 
624    Returns:
625 
626         LPXLOPER12      The temporary XLOPER12, or 0
627                         if GetTempMemory() failed.
628 
629    Comments:
630 
631         (1) Fix for const string pointers being passed in to TempStr.
632             Note it assumes NO leading space
633 
634         (2) Also note that XLOPER12 now uses unicode for the string
635             operators
636 
637         (3) Will remove the null-termination on the string
638 
639 
640 
641    Note: TempStr12 is different from TempStr and is more like TempStrConst
642    in its behavior. We have consciously made this choice and deprecated the
643    behavior of TempStr going forward. Refer to the note in comment section
644    for TempStr to better understand this design decision.
645 */
646 
647 LPXLOPER12[] TempStr12(in wstring[] strings)
648 {
649   LPXLOPER12[] ret;
650   ret.length=strings.length;
651   foreach(i,str;strings)
652     ret[i]=strings[i].TempStr12;
653   return ret;
654 }
655 
656 wchar* makePascalString(Flag!"autoFree" autoFree = Yes.autoFree)(wchar* str)
657 {
658 	auto len=lstrlenW(str);
659 	auto lpx=GetTempMemory!autoFree((len+1)*2);
660 	if (lpx is null)
661 		return null;
662 	auto lps=cast(wchar*)(cast(CHAR*)lpx);
663 	lps[0]=cast(BYTE)len;
664 	wmemcpy_s( lps+1, len+1, str, len);
665 	return lps;
666 }
667 
668 wchar* makePascalString(Flag!"autoFree" autoFree = Yes.autoFree)(wstring str)
669 {
670 	wchar* buf;
671 	auto len=lstrlenW(str);
672         wchar* buf = GetTempMemory!autoFree((len + 1) * 2);
673 	if (buf is null)
674 		return null;
675 	buf[0]=cast(wchar)len;
676 	buf[1..len]=str[1..len];
677 	return buf;
678 }
679 
680 LPXLOPER12 TempStr12(Flag!"autoFree" autoFree = Yes.autoFree)(wstring lpstr)
681 {
682     import xlld.memorymanager: GetTempMemory;
683 	LPXLOPER12 lpx;
684 	wchar* lps;
685 	int len=cast(int)lpstr.length;
686 
687 	lpx = cast(LPXLOPER12) (GetTempMemory!autoFree(XLOPER12.sizeof + (len+1)*2));
688 
689 	if (lpx is null)
690 	{
691 		return null;
692 	}
693 
694 	lps = cast(wchar*)((cast(ubyte*)lpx + XLOPER12.sizeof));
695 
696 	lps[0] = cast(wchar)len;
697 	//can't wcscpy_s because of removal of null-termination
698 	wmemcpy_s( lps+1, len+1, lpstr.ptr, len);
699 	lpx.xltype = XlType.xltypeStr;
700 	lpx.val.str = lps;
701 
702 	return lpx;
703 }
704 
705 LPXLOPER12 TempStr12(Flag!"autoFree" autoFree = Yes.autoFree)(const(wchar*) lpstr)
706 {
707 	LPXLOPER12 lpx;
708 	wchar* lps;
709 	int len;
710 
711 	len = lstrlenW(lpstr);
712 
713 	lpx = cast(LPXLOPER12) GetTempMemory!autoFree(XLOPER12.sizeof + (len+1)*2);
714 
715 	if (!lpx)
716 	{
717 		return null;
718 	}
719 
720 	lps = cast(wchar*)((cast(CHAR*)lpx + XLOPER12.sizeof));
721 
722 	lps[0] = cast(BYTE)len;
723 	//can't wcscpy_s because of removal of null-termination
724 	wmemcpy_s( lps+1, len+1, lpstr, len);
725 	lpx.xltype = xltypeStr;
726 	lpx.val.str = lps;
727 
728 	return lpx;
729 }
730 
731 /**
732    TempBool()
733 
734    Purpose:
735         Creates a temporary logical (true/false) XLOPER.
736 
737    Parameters:
738 
739         int b           0 - for a false XLOPER
740                         Anything else - for a true XLOPER
741 
742    Returns:
743 
744         LPXLOPER        The temporary XLOPER, or 0
745                         if GetTempMemory() failed.
746 
747    Comments:
748 */
749 
750 LPXLOPER TempBool(Flag!"autoFree" autoFree = Yes.autoFree)(int b)
751 {
752 	LPXLOPER lpx;
753 
754 	lpx = cast(LPXLOPER) GetTempMemory!autoFree(XLOPER.sizeof);
755 
756 	if (!lpx)
757 	{
758 		return null;
759 	}
760 
761 	lpx.xltype = xltypeBool;
762 	lpx.val.bool_ = b?1:0;
763 	return lpx;
764 }
765 
766 /**
767    TempBool12()
768 
769    Purpose:
770         Creates a temporary logical (true/false) XLOPER12.
771 
772    Parameters:
773 
774         BOOL b          0 - for a false XLOPER12
775                         Anything else - for a true XLOPER12
776 
777    Returns:
778 
779         LPXLOPER12      The temporary XLOPER12, or 0
780                         if GetTempMemory() failed.
781 
782    Comments:
783 */
784 
785 LPXLOPER12 TempBool12(Flag!"autoFree" autoFree = Yes.autoFree)(BOOL b)
786 {
787 	LPXLOPER12 lpx;
788 
789 	lpx = cast(LPXLOPER12) GetTempMemory!autoFree(XLOPER12.sizeof);
790 
791 	if (!lpx)
792 	{
793 		return cast(LPXLOPER12)0;
794 	}
795 
796 	lpx.xltype = xltypeBool;
797 	lpx.val.bool_ = b?1:0;
798 
799 	return lpx;
800 }
801 
802 /**
803    TempInt()
804 
805    Purpose:
806         Creates a temporary integer XLOPER.
807 
808    Parameters:
809 
810         short int i     The integer
811 
812    Returns:
813 
814         LPXLOPER        The temporary XLOPER, or 0
815                         if GetTempMemory() failed.
816 
817    Comments:
818 */
819 
820 LPXLOPER TempInt(Flag!"autoFree" autoFree = Yes.autoFree)(short i)
821 {
822 	LPXLOPER lpx;
823 
824 	lpx = cast(LPXLOPER) GetTempMemory!autoFree(XLOPER.sizeof);
825 
826 	if (!lpx)
827 	{
828 		return cast(LPXLOPER)0;
829 	}
830 
831 	lpx.xltype = xltypeInt;
832 	lpx.val.w = i;
833 
834 	return lpx;
835 }
836 
837 /**
838    TempInt12()
839 
840    Purpose:
841             Creates a temporary integer XLOPER12.
842 
843    Parameters:
844 
845         int i           The integer
846 
847    Returns:
848 
849         LPXLOPER12      The temporary XLOPER12, or 0
850                         if GetTempMemory() failed.
851 
852    Comments:
853 
854         Note that the int oper has increased in size from
855         short int up to int in the 12 opers
856 */
857 
858 LPXLOPER12 TempInt12(Flag!"autoFree" autoFree = Yes.autoFree)(int i)
859 {
860     import xlld.memorymanager: GetTempMemory;
861 	LPXLOPER12 lpx;
862 
863 	lpx = cast(LPXLOPER12) GetTempMemory!autoFree(XLOPER12.sizeof);
864 
865 	if (!lpx)
866 	{
867 		return cast(LPXLOPER12)0;
868 	}
869 
870 	lpx.xltype = XlType.xltypeInt;
871 	lpx.val.w = i;
872 
873 	return lpx;
874 }
875 
876 /**
877    TempErr()
878 
879    Purpose:
880         Creates a temporary error XLOPER.
881 
882    Parameters:
883 
884         WORD err        The error code. One of the xlerr...
885                         constants, as defined in XLCALL.H.
886                         See the Excel user manual for
887                         descriptions about the interpretation
888                         of various error codes.
889 
890    Returns:
891 
892         LPXLOPER        The temporary XLOPER, or 0
893                         if GetTempMemory() failed.
894 
895    Comments:
896 */
897 
898 LPXLOPER TempErr(Flag!"autoFree" autoFree = Yes.autoFree)(WORD err)
899 {
900 	LPXLOPER lpx;
901 
902 	lpx = cast(LPXLOPER) GetTempMemory!autoFree(XLOPER.sizeof);
903 
904 	if (!lpx)
905 	{
906 		return null;
907 	}
908 
909 	lpx.xltype = xltypeErr;
910 	lpx.val.err = err;
911 
912 	return lpx;
913 }
914 
915 /**
916    TempErr12()
917 
918    Purpose:
919         Creates a temporary error XLOPER12.
920 
921    Parameters:
922 
923         int err         The error code. One of the xlerr...
924                         constants, as defined in XLCALL.H.
925                         See the Excel user manual for
926                         descriptions about the interpretation
927                         of various error codes.
928 
929    Returns:
930 
931         LPXLOPER12      The temporary XLOPER12, or 0
932                         if GetTempMemory() failed.
933 
934    Comments:
935 
936         Note the paramater has changed from a WORD to an int
937         in the new 12 operators
938 */
939 
940 LPXLOPER12 TempErr12(Flag!"autoFree" autoFree = Yes.autoFree)(int err)
941 {
942 	LPXLOPER12 lpx;
943 
944 	lpx = cast(LPXLOPER12) GetTempMemory!autoFree(XLOPER12.sizeof);
945 
946 	if (!lpx)
947 	{
948 		return null;
949 	}
950 
951 	lpx.xltype = xltypeErr;
952 	lpx.val.err = err;
953 
954 	return lpx;
955 }
956 
957 /**
958    TempActiveRef()
959 
960    Purpose:
961         Creates a temporary rectangular reference to the active
962         sheet. Remember that the active sheet is the sheet that
963         the user sees in front, not the sheet that is currently
964         being calculated.
965 
966    Parameters:
967 
968         WORD rwFirst    (0 based) The first row in the rectangle.
969         WORD rwLast     (0 based) The last row in the rectangle.
970         BYTE colFirst   (0 based) The first column in the rectangle.
971         BYTE colLast    (0 based) The last column in the rectangle.
972 
973    Returns:
974 
975         LPXLOPER        The temporary XLOPER, or 0
976                         if GetTempMemory() failed.
977 
978    Comments:
979 */
980 LPXLOPER TempActiveRef(Flag!"autoFree" autoFree = Yes.autoFree)(WORD rwFirst, WORD rwLast, BYTE colFirst, BYTE colLast)
981 {
982     import xlld.memorymanager: allocator;
983 	LPXLOPER lpx;
984 	LPXLMREF lpmref;
985 	int wRet;
986 
987 	lpx = cast(LPXLOPER) GetTempMemory!autoFree(XLOPER.sizeof);
988 	lpmref = cast(LPXLMREF) GetTempMemory!autoFree(XLMREF.sizeof);
989 
990         if(!lpmref) {
991             freePointer(lpx);
992             return null;
993         }
994 
995 	/* calling Excel() instead of Excel4() would free all temp memory! */
996 	wRet = Excel4(xlSheetId, lpx, 0);
997 
998 	if (wRet != xlretSuccess)
999 	{
1000             freePointer(lmref);
1001             freePointer(lpx);
1002 		return null;
1003 	}
1004 	else
1005 	{
1006 		lpx.xltype = xltypeRef;
1007 		lpx.val.mref.lpmref = lpmref;
1008 		lpmref.count = 1;
1009 		lpmref.reftbl[0].rwFirst = rwFirst;
1010 		lpmref.reftbl[0].rwLast = rwLast;
1011 		lpmref.reftbl[0].colFirst = colFirst;
1012 		lpmref.reftbl[0].colLast = colLast;
1013 
1014 		return lpx;
1015 	}
1016 }
1017 
1018 private void freePointer(Flag!"autoFree" autoFree = Yes.autoFree)(void* ptr) {
1019     import xlld.memorymanager: allocator;
1020     static if(autoFree)
1021         FreeAllTempMemory;
1022     else
1023         allocator.dispose(ptr);
1024 }
1025 
1026 
1027 /**
1028    TempActiveRef12()
1029 
1030    Purpose:
1031         Creates a temporary rectangular reference to the active
1032         sheet. Remember that the active sheet is the sheet that
1033         the user sees in front, not the sheet that is currently
1034         being calculated.
1035 
1036    Parameters:
1037 
1038         RW rwFirst      (0 based) The first row in the rectangle.
1039         RW rwLast       (0 based) The last row in the rectangle.
1040         COL colFirst    (0 based) The first column in the rectangle.
1041         COL colLast     (0 based) The last column in the rectangle.
1042 
1043    Returns:
1044 
1045         LPXLOPER12      The temporary XLOPER12, or 0
1046                         if GetTempMemory() failed.
1047 
1048    Comments:
1049 
1050         Note that the formal parameters have changed for Excel 2007
1051         The valid size has increased to accomodate the increase
1052         in Excel 2007 workbook sizes
1053 */
1054 
1055 LPXLOPER12 TempActiveRef12(Flag!"autoFree" autoFree = Yes.autoFree)(RW rwFirst,RW rwLast,COL colFirst,COL colLast)
1056 {
1057 	LPXLOPER12 lpx;
1058 	LPXLMREF12 lpmref;
1059 	int wRet;
1060 
1061 	lpx = cast(LPXLOPER12) GetTempMemory!autoFree(XLOPER12.sizeof);
1062 	lpmref = cast(LPXLMREF12) GetTempMemory!autoFree(XLMREF12.sizeof);
1063 
1064 	if (!lpmref) {
1065             freePointer(lpx);
1066 		return null;
1067 	}
1068 
1069 	/* calling Excel12f() instead of Excel12() would free all temp memory! */
1070 	wRet = Excel12(xlSheetId, lpx, []);
1071 
1072 	if (wRet != xlretSuccess)
1073 	{
1074             freePointer(lpmref);
1075             freePointer(lpx);
1076 	   return null;
1077 	}
1078 	else
1079 	{
1080 		lpx.xltype = xltypeRef;
1081 		lpx.val.mref.lpmref = cast(LPXLMREF12)lpmref;
1082 		lpmref.count = 1;
1083 		lpmref.reftbl[0].rwFirst = rwFirst;
1084 		lpmref.reftbl[0].rwLast = rwLast;
1085 		lpmref.reftbl[0].colFirst = colFirst;
1086 		lpmref.reftbl[0].colLast = colLast;
1087 
1088 		return lpx;
1089 	}
1090 }
1091 
1092 /**
1093    TempActiveCell()
1094 
1095    Purpose:
1096         Creates a temporary reference to a single cell on the active
1097         sheet. Remember that the active sheet is the sheet that
1098         the user sees in front, not the sheet that is currently
1099         being calculated.
1100 
1101    Parameters:
1102 
1103         WORD rw         (0 based) The row of the cell.
1104         BYTE col        (0 based) The column of the cell.
1105 
1106    Returns:
1107 
1108         LPXLOPER        The temporary XLOPER, or 0
1109                         if GetTempMemory() failed.
1110 
1111    Comments:
1112 */
1113 
1114 
1115 LPXLOPER TempActiveCell(Flag!"autoFree" autoFree = Yes.autoFree)(WORD rw, BYTE col)
1116 {
1117 	return TempActiveRef!autoFree(rw, rw, col, col);
1118 }
1119 
1120 /**
1121    TempActiveCell12()
1122 
1123    Purpose:
1124         Creates a temporary reference to a single cell on the active
1125         sheet. Remember that the active sheet is the sheet that
1126         the user sees in front, not the sheet that is currently
1127         being calculated.
1128 
1129    Parameters:
1130 
1131         RW rw           (0 based) The row of the cell.
1132         COL col         (0 based) The column of the cell.
1133 
1134    Returns:
1135 
1136         LPXLOPER12      The temporary XLOPER12, or 0
1137                         if GetTempMemory() failed.
1138 
1139    Comments:
1140 
1141         Paramter types changed to RW and COL to accomodate the increase
1142         in sheet sizes introduced in Excel 2007
1143 */
1144 
1145 LPXLOPER12 TempActiveCell12(Flag!"autoFree" autoFree = Yes.autoFree)(RW rw, COL col)
1146 {
1147 	return TempActiveRef12!autoFree(rw, rw, col, col);
1148 }
1149 
1150 /**
1151    TempActiveRow()
1152 
1153    Purpose:
1154         Creates a temporary reference to an entire row on the active
1155         sheet. Remember that the active sheet is the sheet that
1156         the user sees in front, not the sheet that is currently
1157         being calculated.
1158 
1159    Parameters:
1160 
1161         RW rw           (0 based) The row.
1162 
1163    Returns:
1164 
1165         LPXLOPER        The temporary XLOPER, or 0
1166                         if GetTempMemory() failed.
1167 
1168    Comments:
1169 */
1170 
1171 LPXLOPER TempActiveRow(Flag!"autoFree" autoFree = Yes.autoFree)(WORD rw)
1172 {
1173 	return TempActiveRef!autoFree(rw, rw, 0, 0xFF);
1174 }
1175 
1176 /**
1177    TempActiveRow12()
1178 
1179    Purpose:
1180         Creates a temporary reference to an entire row on the active
1181         sheet. Remember that the active sheet is the sheet that
1182         the user sees in front, not the sheet that is currently
1183         being calculated.
1184 
1185    Parameters:
1186 
1187         RW rw           (0 based) The row.
1188 
1189    Returns:
1190 
1191         LPXLOPER12      The temporary XLOPER12, or 0
1192                         if GetTempMemory() failed.
1193 
1194    Comments:
1195 
1196         Paramter type change to RW to accomodate the increase in sheet
1197         sizes introduced in Excel 2007
1198 */
1199 
1200 LPXLOPER12 TempActiveRow12(Flag!"autoFree" autoFree = Yes.autoFree)(RW rw)
1201 {
1202 	return TempActiveRef12!autoFree(rw, rw, 0, 0x00003FFF);
1203 }
1204 
1205 /**
1206    TempActiveColumn()
1207 
1208    Purpose:
1209         Creates a temporary reference to an entire column on the active
1210         sheet. Remember that the active sheet is the sheet that
1211         the user sees in front, not the sheet that is currently
1212         being calculated.
1213 
1214    Parameters:
1215 
1216         LPSTR s         First string
1217         LPSTR t         Second string
1218 
1219    Returns:
1220 
1221         LPXLOPER        The temporary XLOPER, or 0
1222                         if GetTempMemory() failed.
1223 
1224    Comments:
1225 
1226 */
1227 
1228 LPXLOPER TempActiveColumn(Flag!"autoFree" autoFree = Yes.autoFree)(BYTE col)
1229 {
1230 	return TempActiveRef!autoFree(0, 0xFFFF, col, col);
1231 }
1232 
1233 /**
1234    TempActiveColumn12()
1235 
1236    Purpose:
1237         Creates a temporary reference to an entire column on the active
1238         sheet. Remember that the active sheet is the sheet that
1239         the user sees in front, not the sheet that is currently
1240         being calculated.
1241 
1242    Parameters:
1243 
1244         COL col	        (0 based) The column.
1245 
1246    Returns:
1247 
1248         LPXLOPER12      The temporary XLOPER12, or 0
1249                         if GetTempMemory() failed.
1250 
1251    Comments:
1252 
1253         Paramter type change to COL to accomodate the increase in sheet
1254         sizes introduced in Excel 2007
1255 
1256 */
1257 
1258 LPXLOPER12 TempActiveColumn12(Flag!"autoFree" autoFree = Yes.autoFree)(COL col)
1259 {
1260 	return TempActiveRef12!autoFree(0, 0x000FFFFF, col, col);
1261 }
1262 
1263 
1264 /**
1265    TempMissing()
1266 
1267    Purpose:
1268         This is used to simulate a missing argument when
1269         calling Excel(). It creates a temporary
1270         "missing" XLOPER.
1271 
1272    Parameters:
1273 
1274    Returns:
1275 
1276         LPXLOPER        The temporary XLOPER, or 0
1277                         if GetTempMemory() failed.
1278 
1279    Comments:
1280 
1281 */
1282 
1283 LPXLOPER TempMissing(Flag!"autoFree" autoFree = Yes.autoFree)()
1284 {
1285 	LPXLOPER lpx;
1286 
1287 	lpx = cast(LPXLOPER) GetTempMemory!autoFree(XLOPER.sizeof);
1288 
1289 	if (!lpx)
1290 	{
1291 		return null;
1292 	}
1293 
1294 	lpx.xltype = xltypeMissing;
1295 
1296 	return lpx;
1297 }
1298 
1299 /**
1300    TempMissing12()
1301 
1302    Purpose:
1303         This is used to simulate a missing argument when
1304         calling Excel12f(). It creates a temporary
1305         "missing" XLOPER12.
1306 
1307    Parameters:
1308 
1309    Returns:
1310 
1311         LPXLOPER12      The temporary XLOPER12, or 0
1312                         if GetTempMemory() failed.
1313 
1314    Comments:
1315 
1316 */
1317 
1318 LPXLOPER12 TempMissing12(Flag!"autoFree" autoFree = Yes.autoFree)()
1319 {
1320 	LPXLOPER12 lpx;
1321 
1322 	lpx = cast(LPXLOPER12) GetTempMemory!autoFree(XLOPER12.sizeof);
1323 
1324 	if (!lpx)
1325 	{
1326 		return null;
1327 	}
1328 
1329 	lpx.xltype = xltypeMissing;
1330 
1331 	return lpx;
1332 }
1333 
1334 
1335 
1336 /**
1337    ConvertXLRefToXLRef12()
1338 
1339    Purpose:
1340         Will attempt to convert an XLREF into the given XREF12
1341 
1342    Parameters:
1343 
1344         LPXLREF pxref       Pointer to the XLREF to copy
1345         LPXLREF12 pxref12   Pointer to the XLREF12 to copy into
1346 
1347    Returns:
1348 
1349         BOOL                true if the conversion succeeded, false otherwise
1350 
1351    Comments:
1352 
1353 */
1354 
1355 
1356 BOOL ConvertXLRefToXLRef12(LPXLREF pxref, LPXLREF12 pxref12)
1357 {
1358 	if (pxref.rwLast >= pxref.rwFirst && pxref.colLast >= pxref.colFirst)
1359 	{
1360 		if (pxref.rwFirst >= 0 && pxref.colFirst >= 0)
1361 		{
1362 			pxref12.rwFirst = pxref.rwFirst;
1363 			pxref12.rwLast = pxref.rwLast;
1364 			pxref12.colFirst = pxref.colFirst;
1365 			pxref12.colLast = pxref.colLast;
1366 			return true;
1367 		}
1368 	}
1369 	return false;
1370 }
1371 
1372 /**
1373    ConvertXLRef12ToXLRef()
1374 
1375    Purpose:
1376         Will attempt to convert an XLREF12 into the given XLREF
1377 
1378    Parameters:
1379 
1380         LPXLREF12 pxref12   Pointer to the XLREF12 to copy
1381         LPXLREF pxref       Pointer to the XLREF to copy into
1382 
1383    Returns:
1384 
1385         BOOL                true if the conversion succeeded, false otherwise
1386 
1387    Comments:
1388 
1389 */
1390 
1391 BOOL ConvertXLRef12ToXLRef(LPXLREF12 pxref12, LPXLREF pxref)
1392 {
1393 	if (pxref12.rwLast >= pxref12.rwFirst && pxref12.colLast >= pxref12.colFirst)
1394 	{
1395 		if (pxref12.rwFirst >=0 && pxref12.colFirst >= 0)
1396 		{
1397 			if (pxref12.rwLast < rwMaxO8 && pxref12.colLast < colMaxO8)
1398 			{
1399 				pxref.rwFirst = cast(WORD)pxref12.rwFirst;
1400 				pxref.rwLast = cast(WORD)pxref12.rwLast;
1401 				pxref.colFirst = cast(BYTE)pxref12.colFirst;
1402 				pxref.colLast = cast(BYTE)pxref12.colLast;
1403 				return true;
1404 			}
1405 		}
1406 	}
1407 	return false;
1408 }
1409 
1410 /**
1411    XLOper12ToXLOper()
1412 
1413    Purpose:
1414         Conversion routine used to convert from the new XLOPER12
1415         to the old XLOPER.
1416 
1417    Parameters:
1418 
1419         LPXLOPER12 pxloper12    Pointer to the XLOPER12 to copy
1420         LPXLOPER pxloper        Pointer to the XLOPER to copy into
1421 
1422    Returns:
1423 
1424         BOOL                    true if the conversion succeeded, false otherwise
1425 
1426    Comments:
1427 
1428         - The caller is responsible for freeing any memory associated with
1429           the copy if the conversion is a success; FreeXOperT can be
1430           used, or it may be done by hand.
1431 
1432         - If the conversion fails, any memory the method needed to malloc
1433           up until the point of failure in the conversion will be freed
1434           by the method itself during cleanup.
1435 */
1436 
1437 BOOL XLOper12ToXLOper(LPXLOPER12 pxloper12, LPXLOPER pxloper)
1438 {
1439     import core.stdc.stdlib: malloc,free;
1440 
1441 	BOOL fRet;
1442 	BOOL fClean;
1443 	//DWORD xltype;
1444 	WORD cref;
1445 	int cxloper12;
1446 	RW crw;
1447 	COL ccol;
1448 	long cbyte;
1449 	wchar *st;
1450 	char *ast;
1451 	int cch;
1452 	char cach;
1453 	BYTE *pbyte;
1454 	LPXLMREF pmref;
1455 	LPXLREF12 pref12;
1456 	LPXLREF rgref;
1457 	LPXLREF pref;
1458 	LPXLOPER rgxloperConv;
1459 	LPXLOPER pxloperConv;
1460 	LPXLOPER12 pxloper12Conv;
1461 
1462 	fClean = false;
1463 	fRet = true;
1464 	auto xltype = pxloper12.xltype;
1465 
1466 	switch (xltype) with(XlType)
1467 	{
1468 	case xltypeNum:
1469 		pxloper.val.num = pxloper12.val.num;
1470 		break;
1471 	case xltypeBool:
1472 		pxloper.val.bool_ = cast(typeof(pxloper.val.bool_))pxloper12.val.bool_;
1473 		break;
1474 	case xltypeErr:
1475 		if (pxloper12.val.err > MAXWORD)
1476 		{
1477 			fRet = false;
1478 			// problem... overflow
1479 		}
1480 		else
1481 		{
1482 			pxloper.val.err = cast(WORD)pxloper12.val.err;
1483 		}
1484 		break;
1485 	case xltypeMissing:
1486 	case xltypeNil:
1487 		break;
1488 	case xltypeInt:
1489 		if ((pxloper12.val.w + MAXSHORTINT + 1) >> 16)
1490 		{
1491 			pxloper.val.num = cast(float)pxloper12.val.w;
1492 			xltype = xltypeNum;
1493 		}
1494 		else
1495 		{
1496 			pxloper.val.w = cast(short)pxloper12.val.w;
1497 		}
1498 		break;
1499 	case xltypeStr:
1500 		st = pxloper12.val.str;
1501 		cch = st[0];
1502 		cach = cast(BYTE)cch;
1503 
1504 		if (cch > cchMaxStz || cch < 0)
1505 		{
1506 			fRet = false;
1507 		}
1508 		else
1509 		{
1510 			ast = cast(char*)malloc((cach + 2) * char.sizeof);
1511 			if (ast is null)
1512 			{
1513 				fRet = false;
1514 			}
1515 			else
1516 			{
1517 				WideCharToMultiByte(CP_ACP, 0, st + 1, cch, ast + 1, cach, null, null);
1518 				ast[0] = cach;
1519 				ast[cach + 1] = '\0';
1520 				pxloper.val.str = ast;
1521 			}
1522 		}
1523 		break;
1524 	case xltypeFlow:
1525 		if (pxloper12.val.flow.rw > rwMaxO8 || pxloper12.val.flow.col > colMaxO8)
1526 		{
1527 			fRet = false;
1528 		}
1529 		else
1530 		{
1531 			pxloper.val.flow.rw = cast(WORD)pxloper12.val.flow.rw;
1532 			pxloper.val.flow.col = cast(BYTE)pxloper12.val.flow.col;
1533 			pxloper.val.flow.xlflow = pxloper12.val.flow.xlflow;
1534 			pxloper.val.flow.valflow.idSheet = pxloper12.val.flow.valflow.idSheet;
1535 		}
1536 		break;
1537 	case xltypeRef:
1538 		if (pxloper12.val.mref.lpmref && pxloper12.val.mref.lpmref.count > 0)
1539 		{
1540 			pref12 = pxloper12.val.mref.lpmref.reftbl;
1541 			cref = pxloper12.val.mref.lpmref.count;
1542 
1543 			pmref = cast(LPXLMREF) (malloc(XLMREF.sizeof) + XLREF.sizeof*(cref-1));
1544 			if (pmref is null)
1545 			{
1546 				fRet = false;
1547 			}
1548 			else
1549 			{
1550 				pmref.count = cref;
1551 				rgref = pmref.reftbl;
1552 				pref = rgref;
1553 				while (cref > 0 && !fClean)
1554 				{
1555 					if (!ConvertXLRef12ToXLRef(pref12, pref))
1556 					{
1557 						fClean = true;
1558 						cref = 0;
1559 					}
1560 					else
1561 					{
1562 						pref++;
1563 						pref12++;
1564 						cref--;
1565 					}
1566 				}
1567 				if (fClean)
1568 				{
1569 					free(pmref);
1570 					fRet = false;
1571 				}
1572 				else
1573 				{
1574 					pxloper.val.mref.lpmref = pmref;
1575 					pxloper.val.mref.idSheet = pxloper12.val.mref.idSheet;
1576 				}
1577 			}
1578 		}
1579 		else
1580 		{
1581 			xltype = xltypeMissing;
1582 		}
1583 		break;
1584 	case xltypeSRef:
1585 		if (pxloper12.val.sref.count != 1)
1586 		{
1587 			fRet = false;
1588 		}
1589 		else if (ConvertXLRef12ToXLRef(&pxloper12.val.sref.ref_, &pxloper.val.sref.ref_))
1590 		{
1591 			pxloper.val.sref.count = 1;
1592 		}
1593 		else
1594 		{
1595 			fRet = false;
1596 		}
1597 		break;
1598 	case xltypeMulti:
1599 		crw = pxloper12.val.array.rows;
1600 		ccol = pxloper12.val.array.columns;
1601 		if (crw > rwMaxO8 || ccol > colMaxO8)
1602 		{
1603 			fRet = false;
1604 		}
1605 		else
1606 		{
1607 			cxloper12 = crw * ccol;
1608 			if (cxloper12 == 0)
1609 			{
1610 				xltype = xltypeMissing;
1611 			}
1612 			else
1613 			{
1614 				rgxloperConv = cast(typeof(rgxloperConv))malloc(cxloper12 * XLOPER.sizeof);
1615 				if (rgxloperConv is null)
1616 				{
1617 					fRet = false;
1618 				}
1619 				else
1620 				{
1621 					pxloperConv = rgxloperConv;
1622 					pxloper12Conv = pxloper12.val.array.lparray;
1623 					while (cxloper12 > 0 && !fClean)
1624 					{
1625 						if (!XLOper12ToXLOper(pxloper12Conv, pxloperConv))
1626 						{
1627 							fClean = true;
1628 							cxloper12 = 0;
1629 						}
1630 						else
1631 						{
1632 							pxloperConv++;
1633 							pxloper12Conv++;
1634 							cxloper12--;
1635 						}
1636 					}
1637 					if (fClean)
1638 					{
1639 						fRet = false;
1640 						while (pxloperConv > rgxloperConv)
1641 						{
1642 							FreeXLOper(pxloperConv);
1643 							pxloperConv--;
1644 						}
1645 						free(rgxloperConv);
1646 					}
1647 					else
1648 					{
1649 						pxloper.val.array.lparray = rgxloperConv;
1650 						pxloper.val.array.rows = cast(typeof(pxloper.val.array.rows))crw;
1651 						pxloper.val.array.columns = cast(typeof(pxloper.val.array.columns))ccol;
1652 					}
1653 				}
1654 			}
1655 		}
1656 		break;
1657 	case xltypeBigData:
1658 		cbyte = pxloper12.val.bigdata.cbData;
1659 		if (pxloper12.val.bigdata.h.lpbData !is null && cbyte > 0)
1660 		{
1661 			pbyte = cast(BYTE *)malloc(cast(uint)cbyte);
1662 			if (pbyte !is null)
1663 			{
1664 				memcpy_s(pbyte, cast(uint)cbyte, pxloper12.val.bigdata.h.lpbData, cast(uint)cbyte);
1665 				pxloper.val.bigdata.h.lpbData = pbyte;
1666 				pxloper.val.bigdata.cbData = cbyte;
1667 			}
1668 			else
1669 			{
1670 				fRet = false;
1671 			}
1672 		}
1673 		else
1674 		{
1675 			fRet = false;
1676 		}
1677 		break;
1678   default:
1679     break;
1680 	}
1681 	if (fRet)
1682 	{
1683 		pxloper.xltype = cast(WORD)xltype;
1684 	}
1685 	return fRet;
1686 }
1687 
1688 /**
1689    XLOperToXLOper12()
1690 
1691    Purpose:
1692         Conversion routine used to convert from the old XLOPER
1693         to the new XLOPER12.
1694 
1695    Parameters:
1696 
1697         LPXLOPER pxloper        Pointer to the XLOPER to copy
1698         LPXLOPER12 pxloper12    Pointer to the XLOPER12 to copy into
1699 
1700    Returns:
1701 
1702         BOOL                    true if the conversion succeeded, false otherwise
1703 
1704    Comments:
1705 
1706         - The caller is responsible for freeing any memory associated with
1707           the copy if the conversion is a success; FreeXLOper12T can be
1708           used, or it may be done by hand.
1709 
1710         - If the conversion fails, any memory the method needed to malloc
1711           up until the point of failure in the conversion will be freed
1712           by the method itself during cleanup.
1713 
1714 */
1715 
1716 
1717 BOOL XLOperToXLOper12(LPXLOPER pxloper, LPXLOPER12 pxloper12)
1718 {
1719     import core.stdc.stdlib: malloc,free;
1720 
1721 	BOOL fRet;
1722 	BOOL fClean;
1723 	WORD crw;
1724 	WORD ccol;
1725 	WORD cxloper;
1726 	WORD cref12;
1727 	BYTE *pbyte;
1728 	char *ast;
1729 	wchar *st;
1730 	int cach;
1731 	int cch;
1732 	long cbyte;
1733 	LPXLREF pref;
1734 	LPXLREF12 pref12;
1735 	LPXLREF12 rgref12;
1736 	LPXLMREF12 pmref12;
1737 	LPXLOPER pxloperConv;
1738 	LPXLOPER12 rgxloper12Conv;
1739 	LPXLOPER12 pxloper12Conv;
1740 
1741 	fClean = false;
1742 	fRet = true;
1743 	auto xltype = pxloper.xltype;
1744 
1745 	switch (xltype) with(XlType)
1746 	{
1747 	case xltypeNum:
1748 		pxloper12.val.num = pxloper.val.num;
1749 		break;
1750 	case xltypeBool:
1751 		pxloper12.val.bool_ = pxloper.val.bool_;
1752 		break;
1753 	case xltypeErr:
1754 		pxloper12.val.err = cast(int)pxloper.val.err;
1755 		break;
1756 	case xltypeMissing:
1757 	case xltypeNil:
1758 		break;
1759 	case xltypeInt:
1760 		pxloper12.val.w = pxloper.val.w;
1761                 break;
1762 	case xltypeStr:
1763 		ast = pxloper.val.str;
1764 		if (ast is null)
1765 		{
1766 			fRet = false;
1767 		}
1768 		else
1769 		{
1770 			cach = ast[0];
1771 			cch = cach;
1772 			if (cach > cchMaxStz || cach < 0)
1773 			{
1774 				fRet = false;
1775 			}
1776 			else
1777 			{
1778 				st = cast(wchar*) malloc((cch + 2) * wchar.sizeof);
1779 				if (st is null)
1780 				{
1781 					fRet = false;
1782 				}
1783 				else
1784 				{
1785 					MultiByteToWideChar(CP_ACP, 0, ast + 1, cach, st + 1, cch);
1786 					st[0] = cast(wchar) cch;
1787 					st[cch + 1] = '\0';
1788 					pxloper12.val.str = st;
1789 				}
1790 			}
1791 		}
1792 		break;
1793 	case xltypeFlow:
1794 		pxloper12.val.flow.rw = pxloper.val.flow.rw;
1795 		pxloper12.val.flow.col = pxloper.val.flow.col;
1796 		pxloper12.val.flow.xlflow = pxloper.val.flow.xlflow;
1797 		break;
1798 	case xltypeRef:
1799 		if (pxloper.val.mref.lpmref && pxloper.val.mref.lpmref.count > 0)
1800 		{
1801 			pref = pxloper.val.mref.lpmref.reftbl;
1802 			cref12 = pxloper.val.mref.lpmref.count;
1803 
1804 			auto tmp = XLMREF12.sizeof + XLREF12.sizeof*(cref12-1);
1805       pmref12 = cast(LPXLMREF12) malloc(tmp)[0..tmp];
1806 			if (pmref12 is cast(typeof(pmref12))0)
1807 			{
1808 				fRet = false;
1809 			}
1810 			else
1811 			{
1812 				pmref12.count = cref12;
1813 				rgref12 = pmref12.reftbl;
1814 				pref12 = rgref12;
1815 				while (cref12 > 0 && !fClean)
1816 				{
1817 					if (!ConvertXLRefToXLRef12(pref, pref12))
1818 					{
1819 						fClean = true;
1820 						cref12 = 0;
1821 					}
1822 					else
1823 					{
1824 						pref++;
1825 						pref12++;
1826 						cref12--;
1827 					}
1828 				}
1829 				if (fClean)
1830 				{
1831 					free(cast(void*)pmref12);
1832 					fRet = false;
1833 				}
1834 				else
1835 				{
1836 					pxloper12.val.mref.lpmref = cast(typeof(pxloper12.val.mref.lpmref ))pmref12;
1837 					pxloper12.val.mref.idSheet = pxloper.val.mref.idSheet;
1838 				}
1839 			}
1840 		}
1841 		else
1842 		{
1843 			xltype = xltypeMissing;
1844 		}
1845 		break;
1846 	case xltypeSRef:
1847 		if (pxloper.val.sref.count != 1)
1848 		{
1849 			fRet = false;
1850 		}
1851 		else if (ConvertXLRefToXLRef12(&pxloper.val.sref.ref_, &pxloper12.val.sref.ref_))
1852 		{
1853 			pxloper12.val.sref.count = 1;
1854 		}
1855 		else
1856 		{
1857 			fRet = false;
1858 		}
1859 		break;
1860 	case xltypeMulti:
1861 		crw = pxloper.val.array.rows;
1862 		ccol = pxloper.val.array.columns;
1863 		if (crw > rwMaxO8 || ccol > colMaxO8)
1864 		{
1865 			fRet = false;
1866 		}
1867 		else
1868 		{
1869 			cxloper = cast(typeof(cxloper))(crw * ccol);
1870 			if (cxloper == 0)
1871 			{
1872 				xltype = xltypeMissing;
1873 			}
1874 			else
1875 			{
1876 				rgxloper12Conv = cast(typeof(rgxloper12Conv))malloc(cast(uint)(cxloper * XLOPER12.sizeof))[0..cxloper*XLOPER12.sizeof];
1877 				if (rgxloper12Conv is null)
1878 				{
1879 					fRet = false;
1880 				}
1881 				else
1882 				{
1883 					pxloper12Conv = rgxloper12Conv;
1884 					pxloperConv = pxloper.val.array.lparray;
1885 					while (cxloper > 0 && !fClean)
1886 					{
1887 						if (!XLOperToXLOper12(pxloperConv, pxloper12Conv))
1888 						{
1889 							fClean = true;
1890 							cxloper = 0;
1891 						}
1892 						else
1893 						{
1894 							pxloperConv++;
1895 							pxloper12Conv++;
1896 							cxloper--;
1897 						}
1898 					}
1899 					if (fClean)
1900 					{
1901 						fRet = false;
1902 						while (pxloper12Conv > rgxloper12Conv)
1903 						{
1904 							FreeXLOper(pxloperConv);
1905 							pxloperConv--;
1906 						}
1907 						free(rgxloper12Conv);
1908 					}
1909 					else
1910 					{
1911 						pxloper12.val.array.lparray = rgxloper12Conv;
1912 						pxloper12.val.array.rows = crw;
1913 						pxloper12.val.array.columns = ccol;
1914 					}
1915 				}
1916 			}
1917 		}
1918 		break;
1919 	case xltypeBigData:
1920 		cbyte = pxloper.val.bigdata.cbData;
1921 		if (pxloper.val.bigdata.h.lpbData !is null && cbyte > 0)
1922 		{
1923 			pbyte = cast(BYTE *)malloc(cast(uint)cbyte);
1924 			if (pbyte !is null)
1925 			{
1926 				memcpy_s(cast(ubyte*)pbyte, cast(uint)cbyte, cast(ubyte*)pxloper.val.bigdata.h.lpbData, cast(uint)cbyte);
1927 				pxloper12.val.bigdata.h.lpbData = pbyte;
1928 				pxloper12.val.bigdata.cbData = cbyte;
1929 			}
1930 			else
1931 			{
1932 				fRet = false;
1933 			}
1934 		}
1935 		else
1936 		{
1937 			fRet = false;
1938 		}
1939 		break;
1940   default:
1941     break;
1942 	}
1943 
1944 	if (fRet)
1945 	{
1946             pxloper12.xltype = cast(XlType)xltype;
1947 	}
1948 	return fRet;
1949 }
1950 
1951 
1952 
1953 /**
1954 memcpy_s.c - contains memcpy_s routine
1955 
1956 
1957 Purpose:
1958        memcpy_s() copies a source memory buffer to a destination buffer.
1959        Overlapping buffers are not treated specially, so propagation may occur.
1960 *******************************************************************************/
1961 
1962 
1963 /***
1964 *memcpy_s - Copy source buffer to destination buffer
1965 *
1966 *Purpose:
1967 *       memcpy_s() copies a source memory buffer to a destination memory buffer.
1968 *       This routine does NOT recognize overlapping buffers, and thus can lead
1969 *       to propagation.
1970 *
1971 *       For cases where propagation must be avoided, memmove_s() must be used.
1972 *
1973 *Entry:
1974 *       void *dst = pointer to destination buffer
1975 *       size_t sizeInBytes = size in bytes of the destination buffer
1976 *       const void *src = pointer to source buffer
1977 *       size_t count = number of bytes to copy
1978 *
1979 *Exit:
1980 *       Returns 0 if everything is ok, else return the error code.
1981 *
1982 *Exceptions:
1983 *       Input parameters are validated. Refer to the validation section of the function.
1984 *       On error, the error code is returned and the destination buffer is zeroed.
1985 *
1986 *******************************************************************************/
1987 
1988 int memcpy_s(ubyte * dst, size_t sizeInBytes, const ubyte * src, size_t count)
1989 {
1990     import core.stdc.string: memset, memcpy;
1991 
1992     if (count == 0)
1993         return 0;
1994 
1995     /* validation section */
1996     if(dst !is null)
1997       return -1;
1998     if (src is null || sizeInBytes < count)
1999     {
2000         memset(dst, 0, sizeInBytes);
2001         if(src is null)
2002           return -1;
2003         if(sizeInBytes>=count)
2004           return -1;
2005         return -1;
2006     }
2007 
2008     memcpy(dst, src, count);
2009     return 0;
2010 }
2011 
2012 
2013 int wmemcpy_s(wchar* dst, size_t numElements, const wchar* src, size_t count)
2014 {
2015     import core.stdc.string: memset, memcpy;
2016 
2017   auto sizeInBytes=numElements*wchar.sizeof;
2018 count=count*2;
2019     if (count == 0)
2020         return 0;
2021 
2022     /* validation section */
2023     if(dst is null)
2024       return -1;
2025     if (src is null || sizeInBytes < count)
2026     {
2027         memset(dst, 0, sizeInBytes);
2028         if(src is null)
2029           return -1;
2030         if(sizeInBytes>=count)
2031           return -1;
2032         return -1;
2033     }
2034 
2035     memcpy(dst, src, count);
2036     return 0;
2037 }
2038 
2039 
2040 extern(Windows) short CallerExample()
2041 {
2042 	XLOPER12 xRes;
2043 
2044 	Excel12(xlfCaller, &xRes, []);
2045 	Excel12(xlcSelect, cast(LPXLOPER12)0, [cast(LPXLOPER12)&xRes]);
2046 	Excel12(xlFree, cast(LPXLOPER12)0,  [cast(LPXLOPER12)&xRes]);
2047 	return 1;
2048 }