1 /** 2 Code from generic.h and generic.d 3 Ported to the D Programming Language by Laeeth Isharc (2015) 4 This module provides the ceremony that must be done for every XLL. 5 At least one module must be linked to this one implementing the 6 getWorkSheetFunctions function so that they can be registered 7 with Excel. 8 */ 9 10 module xlld.sdk.xll; 11 12 import xlld: WorksheetFunction, LPXLOPER12; 13 version(testingExcelD) import unit_threaded; 14 15 16 alias AutoCloseFunc = void delegate() nothrow; 17 18 private AutoCloseFunc[] gAutoCloseFuncs; 19 20 /** 21 Registers a delegate to be called when the XLL is unloaded 22 */ 23 void registerAutoCloseFunc(AutoCloseFunc func) nothrow { 24 gAutoCloseFuncs ~= func; 25 } 26 27 /** 28 Registers a function to be called when the XLL is unloaded 29 */ 30 void registerAutoCloseFunc(void function() nothrow func) nothrow { 31 gAutoCloseFuncs ~= { func(); }; 32 } 33 34 void callRegisteredAutoCloseFuncs() nothrow { 35 foreach(func; gAutoCloseFuncs) func(); 36 } 37 38 39 version(Windows) { 40 version(exceldDef) 41 enum dllMain = false; 42 else version(unittest) 43 enum dllMain = false; 44 else 45 enum dllMain = true; 46 } else 47 enum dllMain = false; 48 49 50 static if(dllMain) { 51 52 import core.sys.windows.windows; 53 54 extern(Windows) BOOL DllMain( HANDLE hDLL, DWORD dwReason, LPVOID lpReserved ) 55 { 56 import core.runtime; 57 import std.c.windows.windows; 58 import core.sys.windows.dll; 59 switch (dwReason) 60 { 61 case DLL_PROCESS_ATTACH: 62 Runtime.initialize(); 63 dll_process_attach( hDLL, true ); 64 break; 65 case DLL_PROCESS_DETACH: 66 Runtime.terminate(); 67 dll_process_detach( hDLL, true ); 68 break; 69 case DLL_THREAD_ATTACH: 70 dll_thread_attach( true, true ); 71 break; 72 case DLL_THREAD_DETACH: 73 dll_thread_detach( true, true ); 74 break; 75 default: 76 break; 77 } 78 return true; 79 } 80 } 81 82 // this function must be defined in a module compiled with 83 // the current module 84 // It's extern(C) so that it can be defined in any module 85 extern(C) WorksheetFunction[] getWorksheetFunctions() @safe pure nothrow; 86 87 extern(Windows) int xlAutoOpen() { 88 import core.runtime:rt_init; 89 90 rt_init(); // move to DllOpen? 91 registerAllWorkSheetFunctions; 92 93 return 1; 94 } 95 96 private void registerAllWorkSheetFunctions() { 97 import xlld.memorymanager: allocator; 98 import xlld.sdk.framework: Excel12f, freeXLOper; 99 import xlld.sdk.xlcall: xlGetName, xlfRegister, XLOPER12; 100 import xlld.conv: toXlOper; 101 import std.algorithm: map; 102 import std.array: array; 103 104 // get name of this XLL, needed to pass to xlfRegister 105 static XLOPER12 dllName; 106 Excel12f(xlGetName, &dllName); 107 108 foreach(strings; getWorksheetFunctions.map!(a => a.toStringArray)) { 109 auto opers = strings.map!(a => a.toXlOper(allocator)).array; 110 scope(exit) foreach(ref oper; opers) freeXLOper(&oper, allocator); 111 112 auto args = new LPXLOPER12[opers.length + 1]; 113 args[0] = &dllName; 114 foreach(i; 0 .. opers.length) 115 args[i + 1] = &opers[i]; 116 117 Excel12f(xlfRegister, cast(LPXLOPER12)null, args); 118 } 119 } 120 121 extern(Windows) int xlAutoClose() { 122 import core.runtime: rt_term; 123 124 callRegisteredAutoCloseFuncs; 125 126 rt_term; 127 return 1; 128 } 129 130 extern(Windows) int xlAutoFree12(LPXLOPER12 arg) nothrow { 131 import xlld.memorymanager: autoFree; 132 import xlld.sdk.xlcall: xlbitDLLFree; 133 134 if(!(arg.xltype & xlbitDLLFree)) { 135 log("[ERROR]: Trying to free XLOPER12 without xlbitDLLFree, ignoring"); 136 return 0; 137 } 138 139 autoFree(arg); 140 return 1; 141 } 142 143 extern(Windows) LPXLOPER12 xlAddInManagerInfo12(LPXLOPER12 xAction) { 144 import xlld.sdk.xlcall: XLOPER12, XlType, xltypeInt, xlCoerce, xlerrValue; 145 import xlld.sdk.framework: Excel12f; 146 import xlld.conv: toAutoFreeOper; 147 148 static XLOPER12 xInfo, xIntAction; 149 150 // 151 // This code coerces the passed-in value to an integer. This is how the 152 // code determines what is being requested. If it receives a 1, 153 // it returns a string representing the long name. If it receives 154 // anything else, it returns a #VALUE! error. 155 // 156 157 //we need an XLOPER12 with a _value_ of xltypeInt 158 XLOPER12 arg; 159 arg.xltype = XlType.xltypeInt; 160 arg.val.w = xltypeInt; 161 162 Excel12f(xlCoerce, &xIntAction, [xAction, &arg]); 163 164 if (xIntAction.val.w == 1) { 165 xInfo = "My XLL".toAutoFreeOper; 166 } else { 167 xInfo.xltype = XlType.xltypeErr; 168 xInfo.val.err = xlerrValue; 169 } 170 171 return &xInfo; 172 } 173 174 version(Windows) { 175 extern(Windows) void OutputDebugStringW(const wchar* fmt) nothrow @nogc; 176 177 const(wchar)* toWStringz(in wstring str) @safe nothrow { 178 return &(str ~ '\0')[0]; 179 } 180 181 void log(T...)(T args) { 182 import std.conv: text, to; 183 try 184 OutputDebugStringW(text(args).to!wstring.toWStringz); 185 catch(Exception) 186 OutputDebugStringW("[DataServer] outputDebug itself failed"w.toWStringz); 187 } 188 } else version(unittest) { 189 void log(T...)(T args) { 190 } 191 } else { 192 void log(T...)(T args) { 193 import std.experimental.logger: trace; 194 try 195 trace(args); 196 catch(Exception ex) {} 197 } 198 }