1 /** 2 Necessary boilerplate for C#/.NET. 3 4 To wrap all functions/return/parameter types and struct/class definitions from 5 a list of modules, write this in a "main" module and generate mylib.{so,dll}: 6 7 ------ 8 mixin wrapCSharp("mylib", Modules("module1", "module2", ...)); 9 ------ 10 */ 11 module autowrap.csharp.boilerplate; 12 13 import autowrap.common; 14 import autowrap.reflection; 15 import autowrap.csharp; 16 17 public struct OutputFileName { 18 string value; 19 } 20 21 public string wrapCSharp(in Modules modules, OutputFileName outputFile, LibraryName libraryName, RootNamespace rootNamespace) @safe pure { 22 import std.format : format; 23 import std.algorithm: map; 24 import std.array: join; 25 26 if(!__ctfe) return null; 27 28 const modulesList = modules.value.map!(a => a.toString).join(", "); 29 30 return q{ 31 //Insert shared boilerplate code 32 %1$s 33 34 import std.typecons; 35 import autowrap.csharp.boilerplate; 36 import autowrap.csharp.dlang : wrapDLang; 37 38 immutable string t = wrapDLang!(%2$s); 39 mixin(t); 40 //pragma(msg, t); //Uncomment to see generated D interface code, useful for debugging. 41 42 //Insert DllMain for Windows only. 43 version(Windows) { 44 %3$s 45 } 46 47 void main() { 48 import std.stdio; 49 string generated = generateCSharp!(%2$s)(LibraryName("%4$s"), RootNamespace("%5$s")); 50 auto f = File("%6$s", "w"); 51 f.writeln(generated); 52 } 53 }.format(commonBoilerplate(), modulesList, dllMainMixinStr(), libraryName.value, rootNamespace.value, outputFile.value); 54 } 55 56 /** 57 Returns a string to be mixed in that defines the boilerplate code needed by all C# interfaces. 58 */ 59 private string commonBoilerplate() @safe pure { 60 return q{ 61 import core.memory; 62 import std.conv; 63 import std.string; 64 import std.traits; 65 import std.utf; 66 67 extern(C) export struct returnValue(T) { 68 T value; 69 wstring error; 70 71 this(T value) nothrow { 72 this.value = value; 73 static if (isArray!(T) || is(T == class) || is(T == interface)) { 74 if (this.value !is null) { 75 pinPointer(cast(void*)this.error.ptr); 76 } 77 } 78 this.error = null; 79 } 80 81 this(Exception error) nothrow { 82 this.value = T.init; 83 try { 84 this.error = to!wstring(error.toString()); 85 } catch(Exception ex) { 86 this.error = "Unhandled Exception while marshalling exception data. You should never see this error."; 87 } 88 pinPointer(cast(void*)this.error.ptr); 89 } 90 } 91 92 extern(C) export struct returnVoid { 93 wstring error = null; 94 95 this(Exception error) nothrow { 96 try { 97 this.error = to!wstring(error.toString()); 98 } catch(Exception ex) { 99 this.error = "Unhandled Exception while marshalling exception data. You should never see this error."; 100 } 101 pinPointer(cast(void*)this.error.ptr); 102 } 103 } 104 105 public void pinPointer(void* ptr) nothrow { 106 GC.setAttr(ptr, GC.BlkAttr.NO_MOVE); 107 GC.addRoot(ptr); 108 } 109 110 extern(C) export void autowrap_csharp_release(void* ptr) nothrow { 111 GC.clrAttr(ptr, GC.BlkAttr.NO_MOVE); 112 GC.removeRoot(ptr); 113 } 114 115 extern(C) export string autowrap_csharp_createString(wchar* str) nothrow { 116 string temp = toUTF8(to!wstring(str.fromStringz())); 117 pinPointer(cast(void*)temp.ptr); 118 return temp; 119 } 120 121 extern(C) export wstring autowrap_csharp_createWString(wchar* str) nothrow { 122 wstring temp = toUTF16(to!wstring(str.fromStringz())); 123 pinPointer(cast(void*)temp.ptr); 124 return temp; 125 } 126 127 extern(C) export dstring autowrap_csharp_createDString(wchar* str) nothrow { 128 dstring temp = toUTF32(to!wstring(str.fromStringz())); 129 pinPointer(cast(void*)temp.ptr); 130 return temp; 131 } 132 }; 133 }