1 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
4 <title>SWIG and C#</title>
5 <link rel="stylesheet" type="text/css" href="style.css">
7 <body bgcolor="#FFFFFF">
8 <H1><a name="CSharp"></a>18 SWIG and C#</H1>
10 <div class="sectiontoc">
12 <li><a href="#csharp_introduction">Introduction</a>
13 <li><a href="#csharp_differences_java">Differences to the Java module</a>
14 <li><a href="#CSharp_arrays">C# Arrays</a>
16 <li><a href="#CSharp_arrays_swig_library">The SWIG C arrays library</a>
17 <li><a href="#CSharp_arrays_pinvoke_default_array_marshalling">Managed arrays using P/Invoke default array marshalling</a>
18 <li><a href="#CSharp_arrays_pinning">Managed arrays using pinning</a>
20 <li><a href="#csharp_exceptions">C# Exceptions</a>
22 <li><a href="#csharp_exception_example_check_typemap">C# exception example using "check" typemap</a>
23 <li><a href="#csharp_exception_example_percent_exception">C# exception example using %exception</a>
24 <li><a href="#csharp_exception_example_exception_specifications">C# exception example using exception specifications</a>
25 <li><a href="#csharp_custom_application_exception">Custom C# ApplicationException example</a>
27 <li><a href="#csharp_directors">C# Directors</a>
29 <li><a href="#csharp_directors_example">Directors example</a>
30 <li><a href="#csharp_directors_implementation">Directors implementation</a>
31 <li><a href="#csharp_director_caveats">Director caveats</a>
33 <li><a href="#csharp_typemap_examples">C# Typemap examples</a>
35 <li><a href="#csharp_memory_management_member_variables">Memory management when returning references to member variables</a>
36 <li><a href="#csharp_memory_management_objects">Memory management for objects passed to the C++ layer</a>
37 <li><a href="#csharp_date_marshalling">Date marshalling using the csin typemap and associated attributes</a>
38 <li><a href="#csharp_date_properties">A date example demonstrating marshalling of C# properties</a>
39 <li><a href="#csharp_partial_classes">Turning wrapped classes into partial classes</a>
40 <li><a href="#csharp_extending_proxy_class">Extending proxy classes with additional C# code</a>
48 <H2><a name="csharp_introduction"></a>18.1 Introduction</H2>
52 The purpose of the C# module is to offer an automated way of accessing existing C/C++ code from .NET languages.
53 The wrapper code implementation uses C# and the Platform Invoke (PInvoke) interface to access natively compiled C/C++ code.
54 The PInvoke interface has been chosen over Microsoft's Managed C++ interface as it is portable to both Microsoft Windows and non-Microsoft platforms.
55 PInvoke is part of the ECMA/ISO C# specification.
56 It is also better suited for robust production environments due to the Managed C++ flaw called the
57 <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vstechart/html/vcconMixedDLLLoadingProblem.asp">Mixed DLL Loading Problem</a>.
58 Swig C# works equally well on non-Microsoft operating systems such as Linux, Solaris and Apple Mac using
59 <a href="http://www.mono-project.com/">Mono</a> and <a href="http://www.dotgnu.org/pnet.html">Portable.NET</a>.
63 To get the most out of this chapter an understanding of interop is required.
64 The <a href="http://msdn.microsoft.com">Microsoft Developer Network (MSDN)</a> has a good reference guide in a section titled "Interop Marshaling".
65 Monodoc, available from the Mono project, has a very useful section titled <a href="http://www.mono-project.com/Interop_with_Native_Libraries">Interop with native libraries</a>.
68 <H2><a name="csharp_differences_java"></a>18.2 Differences to the Java module</H2>
72 The C# module is very similar to the Java module, so until some more complete documentation has been written,
73 please use the <a href="Java.html#Java">Java documentation</a> as a guide to using SWIG with C#.
74 The C# module has the same major SWIG features as the Java module.
75 The rest of this section should be read in conjunction with the Java documentation as it lists the main differences.
77 The most notable differences to Java are the following:
81 When invoking SWIG use the <tt>-csharp</tt> command line option instead of <tt>-java</tt>.
85 The <tt>-nopgcpp</tt> command line option does not exist.
89 The <tt>-package</tt> command line option does not exist.
93 The <tt>-namespace <name></tt> commandline option will generate all code into the namespace specified by <tt><name></tt>.
94 C# supports nested namespaces that are not lexically nested, so nested namespaces will of course also work. For example:
95 <tt>-namespace com.bloggs.widget</tt>, will generate code into C# namespaces:
97 <div class="code"><pre>
98 namespace com.bloggs.widget {
102 Note that by default, the generated C# classes have no namespace and the module name is unrelated to namespaces. The module name is just like in Java and is merely used to name some of the generated classes.
106 The <tt>-dllimport <name></tt> commandline option specifies the name of the DLL for the <tt>DllImport</tt> attribute for every PInvoke method. If this commandline option is not given, the <tt>DllImport</tt> DLL name is the same as the module name. This option is useful for when one wants to invoke SWIG multiple times on different modules, yet compile all the resulting code into a single DLL.
110 C/C++ variables are wrapped with C# properties and not JavaBean style getters and setters.
114 Global constants are generated into the module class. There is no constants interface.
118 There is no implementation for type unsafe enums - not deemed necessary.
122 The default enum wrapping approach is proper C# enums, not typesafe enums.
124 Note that %csconst(0) will be ignored when wrapping C/C++ enums with proper C# enums.
125 This is because C# enum items must be initialised from a compile time constant.
126 If an enum item has an initialiser and the initialiser doesn't compile as C# code,
127 then the %csconstvalue directive must be used as %csconst(0) will have no effect.
128 If it was used, it would generate an illegal runtime initialisation via a PInvoke call.
132 C# doesn't support the notion of throws clauses.
133 Therefore there is no 'throws' typemap attribute support for adding exception classes to a throws clause.
134 Likewise there is no need for an equivalent to <tt>%javaexception</tt>.
135 In fact, throwing C# exceptions works quite differently, see <a href="CSharp.html#csharp_exceptions">C# Exceptions</a> below.
139 The majority of the typemaps are in csharp.swg, not java.swg.
143 <p>Typemap equivalent names:</p>
145 <div class="code"><pre>
151 javadirectorin -> csdirectorin
152 javadirectorout -> csdirectorout
153 javainterfaces -> csinterfaces and csinterfaces_derived
154 javabase -> csbase
155 javaclassmodifiers -> csclassmodifiers
156 javacode -> cscode
157 javaimports -> csimports
158 javabody -> csbody
159 javafinalize -> csfinalize
160 javadestruct -> csdestruct
161 javadestruct_derived -> csdestruct_derived
167 <p>Additional typemaps:</p>
169 <div class="code"><pre>
170 csvarin C# code property set typemap
171 csvarout C# code property get typemap
172 csattributes C# attributes for attaching to proxy classes/enums
178 <p>Feature equivalent names:</p>
179 <div class="code"><pre>
180 %javaconst -> %csconst
181 %javaconstvalue -> %csconstvalue
182 %javamethodmodifiers -> %csmethodmodifiers
187 <p>Pragma equivalent names:</p>
188 <div class="code"><pre>
189 %pragma(java) -> %pragma(csharp)
190 jniclassbase -> imclassbase
191 jniclassclassmodifiers -> imclassclassmodifiers
192 jniclasscode -> imclasscode
193 jniclassimports -> imclassimports
194 jniclassinterfaces -> imclassinterfaces
199 <p>Special variable equivalent names:</p>
200 <div class="code"><pre>
201 $javaclassname -> $csclassname
202 $&javaclassname -> $&csclassname
203 $*javaclassname -> $*csclassname
204 $javainput -> $csinput
205 $jnicall -> $imcall
211 Unlike the "javain" typemap, the "csin" typemap does not support the 'pgcpp' attribute as the C# module does not have a premature garbage collection prevention parameter.
212 The "csin" typemap supports additional optional attributes called 'cshin' and 'terminator'.
213 The 'cshin' attribute should contain the parameter type and name whenever a <a href="Java.html#java_constructor_helper_function">constructor helper function</a> is generated due to the 'pre' or 'post' attributes.
214 The 'terminator' attribute normally just contains a closing brace for when the 'pre' attribute contains an opening brace, such as when a C# <tt>using</tt> or <tt>fixed</tt> block is started.
215 Note that 'pre', 'post', 'terminator' and 'cshin' attributes are not used for marshalling the property set.
216 Please see the <a href="#csharp_date_marshalling">Date marshalling example</a> and <a href="#csharp_date_properties">Date marshalling of properties example</a> for further understanding of these "csin" applicable attributes.
222 Support for asymmetric type marshalling. The 'ctype', 'imtype' and 'cstype' typemaps support an optional <tt>out</tt> attribute which is used for output types.
223 If this typemap attribute is specified, then the type specified in the attribute is used for output types and
224 the type specified in the typemap itself is used for the input type.
225 If this typemap attribute is not specified, then the type used for both input and output is the type specified in the typemap.
226 An example shows that <tt>char *</tt> could be marshalled in different ways,
231 %typemap(imtype, out="IntPtr") char * "string"
232 char * function(char *);
237 The output type is thus IntPtr and the input type is string. The resulting intermediary C# code is:
242 public static extern IntPtr function(string jarg1);
250 Support for type attributes.
251 The 'imtype' and 'cstype' typemaps can have an optional <tt>inattributes</tt> and <tt>outattributes</tt> typemap attribute.
252 There are C# attributes and typemap attributes, don't get confused!!
253 The C# attributes specified in these typemap attributes are generated wherever the type is used in the C# wrappers.
254 These can be used to specify any C# attribute associated with a C/C++ type, but are more typically used for the C# <tt>MarshalAs</tt> attribute.
261 inattributes="[MarshalAs(UnmanagedType.LPStr)]",
262 outattributes="[return: MarshalAs(UnmanagedType.LPStr)]") const char * "String"
264 const char * GetMsg() {}
265 void SetMsg(const char *msg) {}
270 The intermediary class will then have the marshalling as specified by everything in the 'imtype' typemap:
275 class examplePINVOKE {
277 [DllImport("example", EntryPoint="CSharp_GetMsg")]
278 [return: MarshalAs(UnmanagedType.LPStr)]
279 public static extern String GetMsg();
281 [DllImport("example", EntryPoint="CSharp_SetMsg")]
282 public static extern void SetMsg([MarshalAs(UnmanagedType.LPStr)]String jarg1);
288 Note that the <tt>DllImport</tt> attribute is always generated, irrespective of any additional attributes specified.
292 These attributes are associated with the C/C++ parameter type or return type, which is subtly different to
293 the attribute features and typemaps covered next.
294 Note that all these different C# attributes can be combined so that a method has more than one attribute.
300 Support for attaching C# attributes to wrapped methods and variables.
301 This is done using the <tt>%csattributes</tt> feature, see <a href="Customization.html#features">%feature directives</a>.
302 Note that C# attributes are attached to proxy classes and enums using the <tt>csattributes</tt> typemap.
303 For example, imagine we have a custom attribute class, <tt>ThreadSafeAttribute</tt>, for labelling thread safety.
304 The following SWIG code shows how to attach this C# attribute to some methods and the class declaration itself:
309 %typemap(csattributes) AClass "[ThreadSafe]"
310 %csattributes AClass::AClass(double d) "[ThreadSafe(false)]"
311 %csattributes AClass::AMethod() "[ThreadSafe(true)]"
324 will generate a C# proxy class:
330 public class AClass : IDisposable {
333 public AClass(double a) ...
336 public void AMethod() ...
342 If C# attributes need adding to the <tt>set</tt> or <tt>get</tt> part of C# properties, when wrapping C/C++ variables,
343 they can be added using the 'csvarin' and 'csvarout' typemaps respectively.
344 Note that the type used for the property is specified in the 'cstype' typemap.
345 If the 'out' attribute exists in this typemap, then the type used is from the 'out' attribute.
351 The intermediary classname has <tt>PINVOKE</tt> appended after the module name instead of <tt>JNI</tt>, for example <tt>modulenamePINVOKE</tt>.
357 The <tt>%csmethodmodifiers</tt> feature can also be applied to variables as well as methods.
358 In addition to the default <tt>public</tt> modifier that SWIG generates when <tt>%csmethodmodifiers</tt> is not
359 specified, the feature will also replace the <tt>virtual</tt>/<tt>new</tt>/<tt>override</tt> modifiers that SWIG thinks is appropriate.
360 This feature is useful for some obscure cases where SWIG might get the <tt>virtual</tt>/<tt>new</tt>/<tt>override</tt> modifiers incorrect, for example with multiple inheritance.
365 <a name="csharp_module_directive"></a>
367 The name of the intermediary class can be changed from its default, that is, the module name with PINVOKE appended after it.
368 The module directive attribute <tt>imclassname</tt> is used to achieve this:
373 %module (imclassname="name") modulename
378 If <tt>name</tt> is the same as <tt>modulename</tt> then the module class name gets changed
379 from <tt>modulename</tt> to <tt>modulenameModule</tt>.
384 There is no additional 'premature garbage collection prevention parameter' as the marshalling of the <tt>HandleRef</tt> object
385 takes care of ensuring a reference to the proxy class is held until the unmanaged call completed.
391 <b><tt>$dllimport</tt></b><br>
392 This is a C# only special variable that can be used in typemaps, pragmas, features etc.
393 The special variable will get translated into the value specified by the <tt>-dllimport</tt> commandline option
394 if specified, otherwise it is equivalent to the <b>$module</b> special variable.
398 <b><tt>$imclassname</tt></b><br>
399 This special variable expands to the intermediary class name. For C# this is usually the same as '$modulePINVOKE' ('$moduleJNI' for Java),
400 unless the imclassname attribute is specified in the <a href="CSharp.html#csharp_module_directive">%module directive</a>.
404 The directory <tt>Examples/csharp</tt> has a number of simple examples.
405 Visual Studio .NET 2003 solution and project files are available for compiling with the Microsoft .NET C# compiler on Windows.
406 If your SWIG installation went well on a Unix environment and your C# compiler was detected, you should be able to type <tt>make</tt> in each example directory,
407 then <tt>ilrun runme.exe</tt> (Portable.NET C# compiler) or <tt>mono runme.exe</tt> (Mono C# compiler) to run the examples.
408 Windows users can also get the examples working using a
409 <a href="http://www.cygwin.com">Cygwin</a> or <a href="http://www.mingw.org">MinGW</a> environment for automatic configuration of the example makefiles.
410 Any one of the three C# compilers (Portable.NET, Mono or Microsoft) can be detected from within a Cygwin or Mingw environment if installed in your path.
412 <H2><a name="CSharp_arrays"></a>18.3 C# Arrays</H2>
416 There are various ways to pass arrays from C# to C/C++.
417 The default wrapping treats arrays as pointers and as such simple type wrapper classes are generated,
418 eg <tt>SWIGTYPE_p_int</tt> when wrapping the C type <tt>int []</tt> or <tt>int *</tt>.
419 This gives a rather restricted use of the underlying unmanaged code and the most practical way to use arrays is to enhance or customise
420 with one of the following three approaches; namely the SWIG C arrays library, P/Invoke default array marshalling or
424 <H3><a name="CSharp_arrays_swig_library"></a>18.3.1 The SWIG C arrays library</H3>
428 The C arrays library keeps all the array memory in the unmanaged layer.
429 The library is available to all language modules and is documented in the <a href="Library.html#Library_carrays">carrays.i library</a> section.
430 Please refer to this section for details, but for convenience, the C# usage for the two examples outlined there is shown below.
434 For the <tt>%array_functions</tt> example, the equivalent usage would be:
439 SWIGTYPE_p_double a = example.new_doubleArray(10); // Create an array
440 for (int i=0; i<10; i++)
441 example.doubleArray_setitem(a,i,2*i); // Set a value
442 example.print_array(a); // Pass to C
443 example.delete_doubleArray(a); // Destroy array
448 and for the <tt>%array_class</tt> example, the equivalent usage would be:
453 doubleArray c = new doubleArray(10); // Create double[10]
454 for (int i=0; i<10; i++)
455 c.setitem(i, 2*i); // Assign values
456 example.print_array(c.cast()); // Pass to C
461 <H3><a name="CSharp_arrays_pinvoke_default_array_marshalling"></a>18.3.2 Managed arrays using P/Invoke default array marshalling</H3>
465 In the P/Invoke default marshalling scheme, one needs to designate whether the invoked function will treat a managed
466 array parameter as input, output, or both. When the function is invoked, the CLR allocates a separate chunk of memory as big as the given managed array,
467 which is automatically released at the end of the function call. If the array parameter is marked as being input, the content of the managed array is copied
468 into this buffer when the call is made. Correspondingly, if the array parameter is marked as being output, the contents of the reserved buffer are copied
469 back into the managed array after the call returns. A pointer to to this buffer
470 is passed to the native function.
474 The reason for allocating a separate buffer is to leave the CLR free to relocate the managed array object
475 during garbage collection. If the overhead caused by the copying is causing a significant performance penalty, consider pinning the managed array and
476 passing a direct reference as described in the next section.
480 For more information on the subject, see the
481 <a href="http://msdn.microsoft.com/en-us/library/z6cfh6e6(VS.80).aspx">Default Marshaling for Arrays</a> article
487 The P/Invoke default marshalling is supported by the <tt>arrays_csharp.i</tt> library via the INPUT, OUTPUT and INOUT typemaps.
488 Let's look at some example usage. Consider the following C function:
492 void myArrayCopy(int *sourceArray, int *targetArray, int nitems);
497 We can now instruct SWIG to use the default marshalling typemaps by
502 %include "arrays_csharp.i"
504 %apply int INPUT[] {int *sourceArray}
505 %apply int OUTPUT[] {int *targetArray}
510 As a result, we get the following method in the module class:
515 public static void myArrayCopy(int[] sourceArray, int[] targetArray, int nitems) {
516 examplePINVOKE.myArrayCopy(sourceArray, targetArray, nitems);
522 If we look beneath the surface at the corresponding intermediary class code, we see
523 that SWIG has generated code that uses attributes
524 (from the System.Runtime.InteropServices namespace) to tell the CLR to use default
525 marshalling for the arrays:
530 [DllImport("example", EntryPoint="CSharp_myArrayCopy")]
531 public static extern void myArrayCopy([In, MarshalAs(UnmanagedType.LPArray)]int[] jarg1,
532 [Out, MarshalAs(UnmanagedType.LPArray)]int[] jarg2, int jarg3);
537 As an example of passing an inout array (i.e. the target function will both read from and
538 write to the array), consider this C function that swaps a given number of elements
544 void myArraySwap(int *array1, int *array2, int nitems);
549 Now, we can instruct SWIG to wrap this by
554 %include "arrays_csharp.i"
556 %apply int INOUT[] {int *array1}
557 %apply int INOUT[] {int *array2}
562 This results in the module class method
567 public static void myArraySwap(int[] array1, int[] array2, int nitems) {
568 examplePINVOKE.myArraySwap(array1, array2, nitems);
574 and intermediate class method
579 [DllImport("example", EntryPoint="CSharp_myArraySwap")]
580 public static extern void myArraySwap([In, Out, MarshalAs(UnmanagedType.LPArray)]int[] jarg1,
581 [In, Out, MarshalAs(UnmanagedType.LPArray)]int[] jarg2, int jarg3);
586 <H3><a name="CSharp_arrays_pinning"></a>18.3.3 Managed arrays using pinning</H3>
590 It is also possible to pin a given array in memory (i.e. fix its location in memory), obtain a
591 direct pointer to it, and then pass this pointer to the wrapped C/C++ function. This approach
592 involves no copying, but it makes the work of the garbage collector harder as
593 the managed array object can not be relocated before the fix on the array is released. You should avoid
594 fixing arrays in memory in cases where the control may re-enter the managed side via a callback and/or
595 another thread may produce enough garbage to trigger garbage collection.
599 For more information, see the <a href="http://msdn.microsoft.com/en-us/library/f58wzh21(VS.80).aspx">fixed statement</a> in the C# language reference.
604 Now let's look at an example using pinning, thus avoiding the CLR making copies
605 of the arrays passed as parameters. The <tt>arrays_csharp.i</tt> library file again provides the required support via the <tt>FIXED</tt> typemaps.
606 Let's use the same function from the previous section:
611 void myArrayCopy(int *sourceArray, int *targetArray, int nitems);
616 We now need to declare the module class method unsafe, as we are using pointers:
621 %csmethodmodifiers myArrayCopy "public unsafe";
626 Apply the appropriate typemaps to the array parameters:
631 %include "arrays_csharp.i"
633 %apply int FIXED[] {int *sourceArray}
634 %apply int FIXED[] {int *targetArray}
639 Notice that there is no need for separate in, out or inout typemaps as is the
640 case when using P/Invoke default marshalling.
644 As a result, we get the following method in the module class:
649 public unsafe static void myArrayCopy(int[] sourceArray, int[] targetArray, int nitems) {
650 fixed ( int *swig_ptrTo_sourceArray = sourceArray ) {
651 fixed ( int *swig_ptrTo_targetArray = targetArray ) {
653 examplePINVOKE.myArrayCopy((IntPtr)swig_ptrTo_sourceArray, (IntPtr)swig_ptrTo_targetArray, nitems);
662 On the method signature level the only difference to the version using P/Invoke default
663 marshalling is the "unsafe" quantifier, which is required because we are handling pointers.
667 Also the intermediate class method looks a little different from the default marshalling
668 example - the method is expecting an IntPtr as the parameter type.
673 [DllImport("example", EntryPoint="CSharp_myArrayCopy")]
674 public static extern void myArrayCopy(IntPtr jarg1, IntPtr jarg2, int jarg3);
680 <H2><a name="csharp_exceptions"></a>18.4 C# Exceptions</H2>
684 It is possible to throw a C# Exception from C/C++ code.
685 SWIG already provides the framework for throwing C# exceptions if it is able to detect that a C++ exception could be thrown.
686 Automatically detecting that a C++ exception could be thrown is only possible when a C++ exception specification is used,
687 see <a href="SWIGPlus.html#SWIGPlus_exception_specifications">Exception specifications</a>.
688 The <a href="Customization.html#exception">Exception handling with %exception</a> section details the <tt>%exception</tt> feature.
689 Customised code for handling exceptions with or without a C++ exception specification is possible and the details follow.
690 However anyone wishing to do this should be familiar with the contents of the sections referred to above.
694 Unfortunately a C# exception cannot simply be thrown from unmanaged code for a variety of reasons.
695 Most notably being that throwing a C# exception results in exceptions being thrown across the C PInvoke interface and C does not understand exceptions.
696 The design revolves around a C# exception being constructed and stored as a pending exception, to be thrown only when the unmanaged code has completed.
697 Implementing this is a tad involved and there are thus some unusual typemap constructs.
698 Some practical examples follow and they should be read in conjunction with the rest of this section.
702 First some details about the design that must be followed.
703 Each typemap or feature that generates <b>unmanaged code</b> supports an attribute called <tt>canthrow</tt>.
704 This is simply a flag which when set indicates that the code in the typemap/feature has code which might want to throw a C# exception.
705 The code in the typemap/feature can then raise a C# exception by calling one of the C functions,
706 <tt>SWIG_CSharpSetPendingException()</tt> or <tt>SWIG_CSharpSetPendingExceptionArgument()</tt>.
707 When called, the function makes a callback into the managed world via a delegate.
708 The callback creates and stores an exception ready for throwing when the unmanaged code has finished.
709 The typemap/feature unmanaged code is then expected to force an immediate return from the unmanaged wrapper function,
710 so that the pending managed exception can then be thrown.
711 The support code has been carefully designed to be efficient as well as thread-safe.
712 However to achieve the goal of efficiency requires some optional code generation in the <b>managed code</b> typemaps.
713 Code to check for pending exceptions is generated if and only if the unmanaged code has code to set a pending exception,
714 that is if the <tt>canthrow</tt> attribute is set.
715 The optional managed code is generated using the <tt>excode</tt> typemap attribute and <tt>$excode</tt> special variable in the relevant managed code typemaps.
716 Simply, if any relevant unmanaged code has the <tt>canthrow</tt> attribute set, then any occurrences of <tt>$excode</tt>
717 is replaced with the code in the <tt>excode</tt> attribute.
718 If the <tt>canthrow</tt> attribute is not set, then any occurrences of <tt>$excode</tt> are replaced with nothing.
722 The prototypes for the <tt>SWIG_CSharpSetPendingException()</tt> and <tt>SWIG_CSharpSetPendingExceptionArgument()</tt> functions are
727 static void SWIG_CSharpSetPendingException(SWIG_CSharpExceptionCodes code,
730 static void SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpExceptionArgumentCodes code,
732 const char *param_name);
737 The first parameter defines which .NET exceptions can be thrown:
743 SWIG_CSharpApplicationException,
744 SWIG_CSharpArithmeticException,
745 SWIG_CSharpDivideByZeroException,
746 SWIG_CSharpIndexOutOfRangeException,
747 SWIG_CSharpInvalidCastException,
748 SWIG_CSharpInvalidOperationException,
749 SWIG_CSharpIOException,
750 SWIG_CSharpNullReferenceException,
751 SWIG_CSharpOutOfMemoryException,
752 SWIG_CSharpOverflowException,
753 SWIG_CSharpSystemException
754 } SWIG_CSharpExceptionCodes;
757 SWIG_CSharpArgumentException,
758 SWIG_CSharpArgumentNullException,
759 SWIG_CSharpArgumentOutOfRangeException,
760 } SWIG_CSharpExceptionArgumentCodes;
765 where, for example, <tt>SWIG_CSharpApplicationException</tt> corresponds to the .NET exception, <tt>ApplicationException</tt>.
766 The <tt>msg</tt> and <tt>param_name</tt> parameters contain the C# exception message and parameter name associated with the exception.
771 The <tt>%exception</tt> feature in C# has the <tt>canthrow</tt> attribute set.
772 The <tt>%csnothrowexception</tt> feature is like <tt>%exception</tt>, but it does not have the <tt>canthrow</tt> attribute
773 set so should only be used when a C# exception is not created.
777 <H3><a name="csharp_exception_example_check_typemap"></a>18.4.1 C# exception example using "check" typemap</H3>
781 Lets say we have the following simple C++ method:
787 void positivesonly(int number);
792 and we want to check that the input <tt>number</tt> is always positive and if not throw a C# <tt>ArgumentOutOfRangeException</tt>.
793 The "check" typemap is designed for checking input parameters. Below you will see the <tt>canthrow</tt> attribute is set because
794 the code contains a call to <tt>SWIG_CSharpSetPendingExceptionArgument()</tt>. The full example follows:
801 %typemap(check, canthrow=1) int number %{
803 SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentOutOfRangeException,
804 "only positive numbers accepted", "number");
807 // SWIGEXCODE is a macro used by many other csout typemaps
809 "\n if ($modulePINVOKE.SWIGPendingException.Pending)"
810 "\n throw $modulePINVOKE.SWIGPendingException.Retrieve();"
812 %typemap(csout, excode=SWIGEXCODE) void {
819 void positivesonly(int number) {
827 When the following C# code is executed:
834 example.positivesonly(-1);
841 The exception is thrown:
846 Unhandled Exception: System.ArgumentOutOfRangeException: only positive numbers accepted
847 Parameter name: number
848 in <0x00034> example:positivesonly (int)
849 in <0x0000c> runme:Main ()
854 Now let's analyse the generated code to gain a fuller understanding of the typemaps. The generated unmanaged C++ code is:
860 SWIGEXPORT void SWIGSTDCALL CSharp_positivesonly(int jarg1) {
866 SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentOutOfRangeException,
867 "only positive numbers accepted", "number");
878 This largely comes from the "check" typemap. The managed code in the module class is:
883 public class example {
884 public static void positivesonly(int number) {
885 examplePINVOKE.positivesonly(number);
886 if (examplePINVOKE.SWIGPendingException.Pending)
887 throw examplePINVOKE.SWIGPendingException.Retrieve();
895 This comes largely from the "csout" typemap.
899 The "csout" typemap is the same as the default void "csout" typemap so is not strictly necessary for the example.
900 However, it is shown to demonstrate what managed output code typemaps should contain,
901 that is, a <tt>$excode</tt> special variable and an <tt>excode</tt> attribute.
902 Also note that <tt>$excode</tt> is expanded into the code held in the <tt>excode</tt> attribute.
903 The <tt>$imcall</tt> as always expands into <tt>examplePINVOKE.positivesonly(number)</tt>.
904 The exception support code in the intermediary class, <tt>examplePINVOKE</tt>, is not shown, but is contained within the inner classes,
905 <tt>SWIGPendingException</tt> and <tt>SWIGExceptionHelper</tt> and is always generated.
906 These classes can be seen in any of the generated wrappers.
907 However, all that is required of a user is as demonstrated in the "csin" typemap above.
908 That is, is to check <tt>SWIGPendingException.Pending</tt> and to throw the exception returned by <tt>SWIGPendingException.Retrieve()</tt>.
912 If the "check" typemap did not exist, then
913 the following module class would instead be generated:
918 public class example {
919 public static void positivesonly(int number) {
920 examplePINVOKE.positivesonly(number);
928 Here we see the pending exception checking code is omitted.
929 In fact, the code above would be generated if the <tt>canthrow</tt> attribute was not in the "check" typemap, such as:
934 %typemap(check) int number %{
936 SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentOutOfRangeException,
937 "only positive numbers accepted", "number");
945 Note that if SWIG detects you have used <tt>SWIG_CSharpSetPendingException()</tt> or <tt>SWIG_CSharpSetPendingExceptionArgument()</tt>
946 without setting the <tt>canthrow</tt> attribute you will get a warning message similar to
951 example.i:21: Warning(845): Unmanaged code contains a call to a SWIG_CSharpSetPendingException
952 method and C# code does not handle pending exceptions via the canthrow attribute.
956 Actually it will issue this warning for any function beginning with <tt>SWIG_CSharpSetPendingException</tt>.
959 <H3><a name="csharp_exception_example_percent_exception"></a>18.4.2 C# exception example using %exception</H3>
963 Let's consider a similar, but more common example that throws a C++ exception from within a wrapped function.
964 We can use <tt>%exception</tt> as mentioned in <a href="Customization.html#exception">Exception handling with %exception</a>.
969 %exception negativesonly(int value) %{
972 } catch (std::out_of_range e) {
973 SWIG_CSharpSetPendingException(SWIG_CSharpApplicationException, e.what());
978 #include <stdexcept>
979 void negativesonly(int value) {
981 throw std::out_of_range("number should be negative");
988 The generated unmanaged code this time catches the C++ exception and converts it into a C# <tt>ApplicationException</tt>.
993 SWIGEXPORT void SWIGSTDCALL CSharp_negativesonly(int jarg1) {
1001 } catch (std::out_of_range e) {
1002 SWIG_CSharpSetPendingException(SWIG_CSharpApplicationException, e.what());
1011 The managed code generated does check for the pending exception as mentioned earlier as the C# version of <tt>%exception</tt> has the <tt>canthrow</tt> attribute set by default:
1016 public static void negativesonly(int value) {
1017 examplePINVOKE.negativesonly(value);
1018 if (examplePINVOKE.SWIGPendingException.Pending)
1019 throw examplePINVOKE.SWIGPendingException.Retrieve();
1024 <H3><a name="csharp_exception_example_exception_specifications"></a>18.4.3 C# exception example using exception specifications</H3>
1028 When C++ exception specifications are used, SWIG is able to detect that the method might throw an exception.
1029 By default SWIG will automatically generate code to catch the exception and convert it into a managed <tt>ApplicationException</tt>,
1030 as defined by the default "throws" typemaps.
1031 The following example has a user supplied "throws" typemap which is used whenever an exception specification contains a <tt>std::out_of_range</tt>,
1032 such as the <tt>evensonly</tt> method below.
1037 %typemap(throws, canthrow=1) std::out_of_range {
1038 SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentException, $1.what(), NULL);
1043 #include <stdexcept>
1044 void evensonly(int input) throw (std::out_of_range) {
1046 throw std::out_of_range("number is not even");
1053 Note that the type for the throws typemap is the type in the exception specification.
1054 SWIG generates a try catch block with the throws typemap code in the catch handler.
1059 SWIGEXPORT void SWIGSTDCALL CSharp_evensonly(int jarg1) {
1066 catch(std::out_of_range &_e) {
1068 SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentException, (&_e)->what(), NULL);
1078 Multiple catch handlers are generated should there be more than one exception specifications declared.
1081 <H3><a name="csharp_custom_application_exception"></a>18.4.4 Custom C# ApplicationException example</H3>
1085 This example involves a user defined exception.
1086 The conventional .NET exception handling approach is to create a custom <tt>ApplicationException</tt> and throw it in your application.
1087 The goal in this example is to convert the STL <tt>std::out_of_range</tt> exception into one of these custom .NET exceptions.
1092 The default exception handling is quite easy to use as the <tt>SWIG_CSharpSetPendingException()</tt> and <tt>SWIG_CSharpSetPendingExceptionArgument()</tt>
1093 methods are provided by SWIG.
1094 However, for a custom C# exception, the boiler plate code that supports these functions needs replicating.
1095 In essence this consists of some C/C++ code and C# code.
1096 The C/C++ code can be generated into the wrapper file using the <tt>%insert(runtime)</tt> directive and
1097 the C# code can be generated into the intermediary class using the <tt>imclasscode</tt> pragma as follows:
1104 // Code to handle throwing of C# CustomApplicationException from C/C++ code.
1105 // The equivalent delegate to the callback, CSharpExceptionCallback_t, is CustomExceptionDelegate
1106 // and the equivalent customExceptionCallback instance is customDelegate
1107 typedef void (SWIGSTDCALL* CSharpExceptionCallback_t)(const char *);
1108 CSharpExceptionCallback_t customExceptionCallback = NULL;
1110 extern "C" SWIGEXPORT
1111 void SWIGSTDCALL CustomExceptionRegisterCallback(CSharpExceptionCallback_t customCallback) {
1112 customExceptionCallback = customCallback;
1115 // Note that SWIG detects any method calls named starting with
1116 // SWIG_CSharpSetPendingException for warning 845
1117 static void SWIG_CSharpSetPendingExceptionCustom(const char *msg) {
1118 customExceptionCallback(msg);
1122 %pragma(csharp) imclasscode=%{
1123 class CustomExceptionHelper {
1124 // C# delegate for the C/C++ customExceptionCallback
1125 public delegate void CustomExceptionDelegate(string message);
1126 static CustomExceptionDelegate customDelegate =
1127 new CustomExceptionDelegate(SetPendingCustomException);
1129 [DllImport("$dllimport", EntryPoint="CustomExceptionRegisterCallback")]
1130 public static extern
1131 void CustomExceptionRegisterCallback(CustomExceptionDelegate customCallback);
1133 static void SetPendingCustomException(string message) {
1134 SWIGPendingException.Set(new CustomApplicationException(message));
1137 static CustomExceptionHelper() {
1138 CustomExceptionRegisterCallback(customDelegate);
1141 static CustomExceptionHelper exceptionHelper = new CustomExceptionHelper();
1147 The method stored in the C# delegate instance, <tt>customDelegate</tt> is what gets called by the C/C++ callback.
1148 However, the equivalent to the C# delegate, that is the C/C++ callback, needs to be assigned before any unmanaged code is executed.
1149 This is achieved by putting the initialisation code in the intermediary class.
1150 Recall that the intermediary class contains all the PInvoke methods, so the static variables in the intermediary class will be initialised
1151 before any of the PInvoke methods in this class are called.
1152 The <tt>exceptionHelper</tt> static variable ensures the C/C++ callback is initialised with the value in <tt>customDelegate</tt> by calling
1153 the <tt>CustomExceptionRegisterCallback</tt> method in the <tt>CustomExceptionHelper</tt> static constructor.
1154 Once this has been done, unmanaged code can make callbacks into the managed world as <tt>customExceptionCallback</tt> will be initialised with a valid callback/delegate.
1155 Any calls to <tt>SWIG_CSharpSetPendingExceptionCustom()</tt> will make the callback to create the pending exception in the same way that
1156 <tt>SWIG_CSharpSetPendingException()</tt> and <tt>SWIG_CSharpSetPendingExceptionArgument()</tt> does.
1157 In fact the method has been similarly named so that SWIG can issue the warning about missing <tt>canthrow</tt> attributes as discussed earlier.
1158 It is an invaluable warning as it is easy to forget the <tt>canthrow</tt> attribute when writing typemaps/features.
1162 The <tt>SWIGPendingException</tt> helper class is not shown, but is generated as an inner class into the intermediary class.
1163 It stores the pending exception in Thread Local Storage so that the exception handling mechanism is thread safe.
1167 The boiler plate code above must be used in addition to a handcrafted <tt>CustomApplicationException</tt>:
1172 // Custom C# Exception
1173 class CustomApplicationException : System.ApplicationException {
1174 public CustomApplicationException(string message)
1182 and the SWIG interface code:
1187 %typemap(throws, canthrow=1) std::out_of_range {
1188 SWIG_CSharpSetPendingExceptionCustom($1.what());
1193 void oddsonly(int input) throw (std::out_of_range) {
1195 throw std::out_of_range("number is not odd");
1202 The "throws" typemap now simply calls our new <tt>SWIG_CSharpSetPendingExceptionCustom()</tt> function so that the exception can be caught, as such:
1208 example.oddsonly(2);
1209 } catch (CustomApplicationException e) {
1215 <H2><a name="csharp_directors"></a>18.5 C# Directors</H2>
1219 The SWIG directors feature adds extra code to the generated C# proxy classes that enable these classes to be used in cross-language polymorphism.
1220 Essentially, it enables unmanaged C++ code to call back into managed code for virtual methods so that a C# class can derive from a wrapped C++ class.
1224 The following sections provide information on the C# director implementation and contain most of the information required to use the C# directors.
1225 However, the <a href="Java.html#java_directors">Java directors</a> section should also be read in order to gain more insight into directors.
1228 <H3><a name="csharp_directors_example"></a>18.5.1 Directors example</H3>
1232 Imagine we are wrapping a C++ base class, <tt>Base</tt>, from which we would like to inherit in C#.
1233 Such a class is shown below as well as another class, <tt>Caller</tt>, which calls the virtual method <tt>UIntMethod</tt>
1234 from pure unmanaged C++ code.
1245 virtual unsigned int UIntMethod(unsigned int x) {
1246 std::cout << "Base - UIntMethod(" << x << ")" << std::endl;
1249 virtual void BaseBoolMethod(const Base &b, bool flag) {}
1254 Caller(): m_base(0) {}
1255 ~Caller() { delBase(); }
1256 void set(Base *b) { delBase(); m_base = b; }
1257 void reset() { m_base = 0; }
1258 unsigned int UIntMethodCall(unsigned int x) { return m_base->UIntMethod(x); }
1262 void delBase() { delete m_base; m_base = 0; }
1268 The director feature is turned off by default and the following simple interface file shows how directors are enabled
1269 for the class <tt>Base</tt>.
1274 /* File : example.i */
1275 %module(directors="1") example
1277 #include "example.h"
1280 %feature("director") Base;
1282 %include "example.h"
1287 The following is a C# class inheriting from <tt>Base</tt>:
1292 public class CSharpDerived : Base
1294 public override uint UIntMethod(uint x)
1296 Console.WriteLine("CSharpDerived - UIntMethod({0})", x);
1304 The <tt>Caller</tt> class can demonstrate the <tt>UIntMethod</tt> method being called from unmanaged code using the following C# code:
1307 <div class="targetlang">
1313 Caller myCaller = new Caller();
1315 // Test pure C++ class
1316 using (Base myBase = new Base())
1318 makeCalls(myCaller, myBase);
1321 // Test director / C# derived class
1322 using (Base myBase = new CSharpDerived())
1324 makeCalls(myCaller, myBase);
1328 static void makeCalls(Caller myCaller, Base myBase)
1330 myCaller.set(myBase);
1331 myCaller.UIntMethodCall(123);
1339 If the above is run, the output is then:
1344 Base - UIntMethod(123)
1345 CSharpDerived - UIntMethod(123)
1349 <H3><a name="csharp_directors_implementation"></a>18.5.2 Directors implementation</H3>
1353 The previous section demonstrated a simple example where the virtual <tt>UIntMethod</tt> method was called from
1354 C++ code, even when the overridden method is implemented in C#.
1355 The intention of this section is to gain an insight into how the director feature works.
1356 It shows the generated code for the two virtual methods, <tt>UIntMethod</tt> and <tt>BaseBoolMethod</tt>,
1357 when the director feature is enabled for the <tt>Base</tt> class.
1361 Below is the generated C# <tt>Base</tt> director class.
1367 using System.Runtime.InteropServices;
1369 public class Base : IDisposable {
1370 private HandleRef swigCPtr;
1371 protected bool swigCMemOwn;
1373 internal Base(IntPtr cPtr, bool cMemoryOwn) {
1374 swigCMemOwn = cMemoryOwn;
1375 swigCPtr = new HandleRef(this, cPtr);
1378 internal static HandleRef getCPtr(Base obj) {
1379 return (obj == null) ? new HandleRef(null, IntPtr.Zero) : obj.swigCPtr;
1386 public virtual void Dispose() {
1388 if(swigCPtr.Handle != IntPtr.Zero && swigCMemOwn) {
1389 swigCMemOwn = false;
1390 examplePINVOKE.delete_Base(swigCPtr);
1392 swigCPtr = new HandleRef(null, IntPtr.Zero);
1393 GC.SuppressFinalize(this);
1397 public virtual uint UIntMethod(uint x) {
1398 uint ret = examplePINVOKE.Base_UIntMethod(swigCPtr, x);
1402 public virtual void BaseBoolMethod(Base b, bool flag) {
1403 examplePINVOKE.Base_BaseBoolMethod(swigCPtr, Base.getCPtr(b), flag);
1404 if (examplePINVOKE.SWIGPendingException.Pending)
1405 throw examplePINVOKE.SWIGPendingException.Retrieve();
1408 public Base() : this(examplePINVOKE.new_Base(), true) {
1409 SwigDirectorConnect();
1412 private void SwigDirectorConnect() {
1413 if (SwigDerivedClassHasMethod("UIntMethod", swigMethodTypes0))
1414 swigDelegate0 = new SwigDelegateBase_0(SwigDirectorUIntMethod);
1415 if (SwigDerivedClassHasMethod("BaseBoolMethod", swigMethodTypes1))
1416 swigDelegate1 = new SwigDelegateBase_1(SwigDirectorBaseBoolMethod);
1417 examplePINVOKE.Base_director_connect(swigCPtr, swigDelegate0, swigDelegate1);
1420 private bool SwigDerivedClassHasMethod(string methodName, Type[] methodTypes) {
1421 System.Reflection.MethodInfo methodInfo = this.GetType().GetMethod(methodName, methodTypes);
1422 bool hasDerivedMethod = methodInfo.DeclaringType.IsSubclassOf(typeof(Base));
1423 return hasDerivedMethod;
1426 private uint SwigDirectorUIntMethod(uint x) {
1427 return UIntMethod(x);
1430 private void SwigDirectorBaseBoolMethod(IntPtr b, bool flag) {
1431 BaseBoolMethod(new Base(b, false), flag);
1434 internal delegate uint SwigDelegateBase_0(uint x);
1435 internal delegate void SwigDelegateBase_1(IntPtr b, bool flag);
1437 private SwigDelegateBase_0 swigDelegate0;
1438 private SwigDelegateBase_1 swigDelegate1;
1440 private static Type[] swigMethodTypes0 = new Type[] { typeof(uint) };
1441 private static Type[] swigMethodTypes1 = new Type[] { typeof(Base), typeof(bool) };
1447 Everything from the <tt>SwigDirectorConnect()</tt> method and below is code that is only generated when
1448 directors are enabled.
1449 The design comprises a C# delegate being initialised for each virtual method on construction of the class.
1450 Let's examine the <tt>BaseBoolMethod</tt>.
1454 In the <tt>Base</tt> constructor a call is made to <tt>SwigDirectorConnect()</tt> which contains the initialisation code for all the virtual methods.
1455 It uses a support method, <tt>SwigDerivedClassHasMethod()</tt>, which simply uses reflection to determine if the named method,
1456 BaseBoolMethod, with the list of required parameter types, exists in a subclass.
1457 If it does not exist, the delegate is not initialised as there is no need for unmanaged code to call back into managed C# code.
1458 However, if there is an overridden method in any subclass, the delegate is required.
1459 It is then initialised to the <tt>SwigDirectorBaseBoolMethod</tt> which in turn will call <tt>BaseBoolMethod</tt> if invoked.
1460 The delegate is not initialised to the <tt>BaseBoolMethod</tt> directly as quite often types will need marshalling from the unmanaged type
1461 to the managed type in which case an intermediary method (<tt>SwigDirectorBaseBoolMethod</tt>) is required for the marshalling.
1462 In this case, the C# <tt>Base</tt> class needs to be created from the unmanaged <tt>IntPtr</tt> type.
1466 The last thing that <tt>SwigDirectorConnect()</tt> does is to pass the delegates to the unmanaged code.
1467 It calls the intermediary method <tt>Base_director_connect()</tt> which is really a call to the C function <tt>CSharp_Base_director_connect()</tt>.
1468 This method simply maps each C# delegate onto a C function pointer.
1473 SWIGEXPORT void SWIGSTDCALL CSharp_Base_director_connect(void *objarg,
1474 SwigDirector_Base::SWIG_Callback0_t callback0,
1475 SwigDirector_Base::SWIG_Callback1_t callback1) {
1476 Base *obj = (Base *)objarg;
1477 SwigDirector_Base *director = dynamic_cast<SwigDirector_Base *>(obj);
1479 director->swig_connect_director(callback0, callback1);
1483 class SwigDirector_Base : public Base, public Swig::Director {
1485 SwigDirector_Base();
1486 virtual unsigned int UIntMethod(unsigned int x);
1487 virtual ~SwigDirector_Base();
1488 virtual void BaseBoolMethod(Base const &b, bool flag);
1490 typedef unsigned int (SWIGSTDCALL* SWIG_Callback0_t)(unsigned int);
1491 typedef void (SWIGSTDCALL* SWIG_Callback1_t)(void *, unsigned int);
1492 void swig_connect_director(SWIG_Callback0_t callbackUIntMethod,
1493 SWIG_Callback1_t callbackBaseBoolMethod);
1496 SWIG_Callback0_t swig_callbackUIntMethod;
1497 SWIG_Callback1_t swig_callbackBaseBoolMethod;
1498 void swig_init_callbacks();
1501 void SwigDirector_Base::swig_connect_director(SWIG_Callback0_t callbackUIntMethod,
1502 SWIG_Callback1_t callbackBaseBoolMethod) {
1503 swig_callbackUIntMethod = callbackUIntMethod;
1504 swig_callbackBaseBoolMethod = callbackBaseBoolMethod;
1510 Note that for each director class SWIG creates an unmanaged director class for making the callbacks. For example <tt>Base</tt> has <tt>SwigDirector_Base</tt> and <tt>SwigDirector_Base</tt>
1511 is derived from <tt>Base</tt>.
1512 Should a C# class be derived from <tt>Base</tt>, the underlying C++ <tt>SwigDirector_Base</tt> is created rather than <tt>Base</tt>.
1513 The <tt>SwigDirector_Base</tt> class then implements all the virtual methods, redirecting calls up to managed code if the callback/delegate is non-zero.
1514 The implementation of <tt>SwigDirector_Base::BaseBoolMethod</tt> shows this - the callback is made by invoking the <tt>swig_callbackBaseBoolMethod</tt> function pointer:
1519 void SwigDirector_Base::BaseBoolMethod(Base const &b, bool flag) {
1521 unsigned int jflag ;
1523 if (!swig_callbackBaseBoolMethod) {
1524 Base::BaseBoolMethod(b,flag);
1527 jb = (Base *) &b;
1529 swig_callbackBaseBoolMethod(jb, jflag);
1535 <H3><a name="csharp_director_caveats"></a>18.5.3 Director caveats</H3>
1539 There is a subtle gotcha with directors.
1540 If default parameters are used, it is recommended to follow a pattern of always calling a single method in any C# derived class.
1541 An example will clarify this and the reasoning behind the recommendation. Consider the following C++ class wrapped as a director class:
1548 virtual ~Defaults();
1549 virtual void DefaultMethod(int a=-100);
1555 Recall that C++ methods with default parameters generate overloaded methods for each defaulted parameter, so a C# derived class can be created
1556 with two <tt>DefaultMethod</tt> override methods:
1561 public class CSharpDefaults : Defaults
1563 public override void DefaultMethod()
1565 DefaultMethod(-100); // note C++ default value used
1567 public override void DefaultMethod(int x)
1575 It may not be clear at first, but should a user intend to call <tt>CSharpDefaults.DefaultMethod()</tt> from C++, a call is actually made to <tt>CSharpDefaults.DefaultMethod(int)</tt>.
1576 This is because the initial call is made in C++ and therefore the <tt>DefaultMethod(int)</tt> method will be called as is expected with C++ calls to methods with defaults,
1577 with the default being set to -100.
1578 The callback/delegate matching this method is of course the overloaded method <tt>DefaultMethod(int)</tt>.
1579 However, a call from C# to <tt>CSharpDefaults.DefaultMethod()</tt> will of course call this exact method and in order for behaviour to be consistent with calls from C++, the implementation
1580 should pass the call on to <tt>CSharpDefaults.DefaultMethod(int)</tt>using the C++ default value, as shown above.
1583 <H2><a name="csharp_typemap_examples"></a>18.6 C# Typemap examples</H2>
1586 This section includes a few examples of typemaps. For more examples, you
1587 might look at the files "<tt>csharp.swg</tt>" and "<tt>typemaps.i</tt>" in
1591 <H3><a name="csharp_memory_management_member_variables"></a>18.6.1 Memory management when returning references to member variables</H3>
1595 This example shows how to prevent premature garbage collection of objects when the underlying C++ class returns a pointer or reference to a member variable.
1596 The example is a direct equivalent to this <a href="Java.html#java_memory_management_objects">Java equivalent</a>.
1600 Consider the following C++ code:
1607 Wheel(int sz) : size(sz) {}
1613 Bike(int val) : wheel(val) {}
1614 Wheel& getWheel() { return wheel; }
1620 and the following usage from C# after running the code through SWIG:
1626 Wheel wheel = new Bike(10).getWheel();
1627 Console.WriteLine("wheel size: " + wheel.size);
1628 // Simulate a garbage collection
1629 System.GC.Collect();
1630 System.GC.WaitForPendingFinalizers();
1631 Console.WriteLine("wheel size: " + wheel.size);
1636 Don't be surprised that if the resulting output gives strange results such as...
1642 wheel size: 135019664
1647 What has happened here is the garbage collector has collected the <tt>Bike</tt> instance as it doesn't think it is needed any more.
1648 The proxy instance, <tt>wheel</tt>, contains a reference to memory that was deleted when the <tt>Bike</tt> instance was collected.
1649 In order to prevent the garbage collector from collecting the <tt>Bike</tt> instance a reference to the <tt>Bike</tt> must
1650 be added to the <tt>wheel</tt> instance. You can do this by adding the reference when the <tt>getWheel()</tt> method
1651 is called using the following typemaps.
1657 %typemap(cscode) Wheel %{
1658 // Ensure that the GC doesn't collect any Bike instance set from C#
1659 private Bike bikeReference;
1660 internal void addReference(Bike bike) {
1661 bikeReference = bike;
1665 // Add a C# reference to prevent premature garbage collection and resulting use
1666 // of dangling C++ pointer. Intended for methods that return pointers or
1667 // references to a member variable.
1668 %typemap(csout, excode=SWIGEXCODE) Wheel& getWheel {
1669 IntPtr cPtr = $imcall;$excode
1670 $csclassname ret = null;
1671 if (cPtr != IntPtr.Zero) {
1672 ret = new $csclassname(cPtr, $owner);
1673 ret.addReference(this);
1681 The code in the first typemap gets added to the <tt>Wheel</tt> proxy class.
1682 The code in the second typemap constitutes the bulk of the code in the generated <tt>getWheel()</tt> function:
1687 public class Wheel : IDisposable {
1689 // Ensure that the GC doesn't collect any Bike instance set from C#
1690 private Bike bikeReference;
1691 internal void addReference(Bike bike) {
1692 bikeReference = bike;
1696 public class Bike : IDisposable {
1698 public Wheel getWheel() {
1699 IntPtr cPtr = examplePINVOKE.Bike_getWheel(swigCPtr);
1701 if (cPtr != IntPtr.Zero) {
1702 ret = new Wheel(cPtr, false);
1703 ret.addReference(this);
1712 Note the <tt>addReference</tt> call.
1715 <H3><a name="csharp_memory_management_objects"></a>18.6.2 Memory management for objects passed to the C++ layer</H3>
1719 The example is a direct equivalent to this <a href="Java.html#java_memory_management_objects">Java equivalent</a>.
1720 Managing memory can be tricky when using C++ and C# proxy classes.
1721 The previous example shows one such case and this example looks at memory management for a class passed to a C++ method which expects the object to remain in scope
1722 after the function has returned. Consider the following two C++ classes:
1729 Element(int val) : value(val) {}
1734 Container() : element(0) {}
1735 void setElement(Element* e) { element = e; }
1736 Element* getElement() { return element; }
1747 Container container;
1748 Element element(20);
1749 container.setElement(&element);
1750 cout << "element.value: " << container.getElement()->value << endl;
1755 and more or less equivalent usage from C#
1760 Container container = new Container();
1761 Element element = new Element(20);
1762 container.setElement(element);
1767 The C++ code will always print out 20, but the value printed out may not be this in the C# equivalent code.
1768 In order to understand why, consider a garbage collection occuring...
1773 Container container = new Container();
1774 Element element = new Element(20);
1775 container.setElement(element);
1776 Console.WriteLine("element.value: " + container.getElement().value);
1777 // Simulate a garbage collection
1778 System.GC.Collect();
1779 System.GC.WaitForPendingFinalizers();
1780 Console.WriteLine("element.value: " + container.getElement().value);
1785 The temporary element created with <tt>new Element(20)</tt> could get garbage collected
1786 which ultimately means the <tt>container</tt> variable is holding a dangling pointer, thereby printing out any old random value instead of the expected value of 20.
1787 One solution is to add in the appropriate references in the C# layer...
1792 public class Container : IDisposable {
1796 // Ensure that the GC doesn't collect any Element set from C#
1797 // as the underlying C++ class stores a shallow copy
1798 private Element elementReference;
1799 private HandleRef getCPtrAndAddReference(Element element) {
1800 elementReference = element;
1801 return Element.getCPtr(element);
1804 public void setElement(Element e) {
1805 examplePINVOKE.Container_setElement(swigCPtr, getCPtrAndAddReference(e));
1812 The following typemaps will generate the desired code.
1813 The 'csin' typemap matches the input parameter type for the <tt>setElement</tt> method.
1814 The 'cscode' typemap simply adds in the specified code into the C# proxy class.
1819 %typemap(csin) Element *e "getCPtrAndAddReference($csinput)"
1821 %typemap(cscode) Container %{
1822 // Ensure that the GC doesn't collect any Element set from C#
1823 // as the underlying C++ class stores a shallow copy
1824 private Element elementReference;
1825 private HandleRef getCPtrAndAddReference(Element element) {
1826 elementReference = element;
1827 return Element.getCPtr(element);
1834 <H3><a name="csharp_date_marshalling"></a>18.6.3 Date marshalling using the csin typemap and associated attributes</H3>
1838 The <a href="Java.html#nan_exception_typemap">NaN Exception example</a> is a simple example of the "javain" typemap and its 'pre' attribute.
1839 This example demonstrates how a C++ date class, say <tt>CDate</tt>, can be mapped onto the standard .NET date class,
1840 <tt>System.DateTime</tt> by using the 'pre', 'post' and 'pgcppname' attributes of the "csin" typemap (the C# equivalent to the "javain" typemap).
1841 The example is an equivalent to the <a href="Java.html#java_date_marshalling">Java Date marshalling example</a>.
1842 The idea is that the <tt>System.DateTime</tt> is used wherever the C++ API uses a <tt>CDate</tt>.
1843 Let's assume the code being wrapped is as follows:
1851 CDate(int year, int month, int day);
1858 static int doSomething(const CDate &dateIn, CDate &dateOut);
1859 Action(const CDate &date, CDate &dateOut);
1865 Note that <tt>dateIn</tt> is const and therefore read only and <tt>dateOut</tt> is a non-const output type.
1869 First let's look at the code that is generated by default, where the C# proxy class <tt>CDate</tt> is used in the proxy interface:
1874 public class Action : IDisposable {
1876 public Action(CDate dateIn, CDate dateOut)
1877 : this(examplePINVOKE.new_Action(CDate.getCPtr(dateIn), CDate.getCPtr(dateOut)), true) {
1878 if (examplePINVOKE.SWIGPendingException.Pending)
1879 throw examplePINVOKE.SWIGPendingException.Retrieve();
1882 public int doSomething(CDate dateIn, CDate dateOut) {
1883 int ret = examplePINVOKE.Action_doSomething(swigCPtr,
1884 CDate.getCPtr(dateIn),
1885 CDate.getCPtr(dateOut));
1886 if (examplePINVOKE.SWIGPendingException.Pending)
1887 throw examplePINVOKE.SWIGPendingException.Retrieve();
1895 The <tt>CDate &</tt> and <tt>const CDate &</tt> C# code is generated from the following two default typemaps:
1900 %typemap(cstype) SWIGTYPE & "$csclassname"
1901 %typemap(csin) SWIGTYPE & "$csclassname.getCPtr($csinput)"
1906 where '$csclassname' is translated into the proxy class name, <tt>CDate</tt> and '$csinput' is translated into the name of the parameter, eg <tt>dateIn</tt>.
1907 From C#, the intention is then to call into a modifed API with something like:
1912 System.DateTime dateIn = new System.DateTime(2011, 4, 13);
1913 System.DateTime dateOut = new System.DateTime();
1915 // Note in calls below, dateIn remains unchanged and dateOut
1916 // is set to a new value by the C++ call
1917 Action action = new Action(dateIn, out dateOut);
1918 dateIn = new System.DateTime(2012, 7, 14);
1923 To achieve this mapping, we need to alter the default code generation slightly so that at the C# layer,
1924 a <tt>System.DateTime</tt> is converted into a <tt>CDate</tt>.
1925 The intermediary layer will still take a pointer to the underlying <tt>CDate</tt> class.
1926 The typemaps to achieve this are shown below.
1931 %typemap(cstype) const CDate& "System.DateTime"
1933 pre=" CDate temp$csinput = new CDate($csinput.Year, $csinput.Month, $csinput.Day);"
1935 "$csclassname.getCPtr(temp$csinput)"
1937 %typemap(cstype) CDate& "out System.DateTime"
1939 pre=" CDate temp$csinput = new CDate();",
1940 post=" $csinput = new System.DateTime(temp$csinput.getYear(),"
1941 " temp$csinput.getMonth(), temp$csinput.getDay(), 0, 0, 0);",
1942 cshin="out $csinput"
1944 "$csclassname.getCPtr(temp$csinput)"
1950 The resulting generated proxy code in the <tt>Action</tt> class follows:
1955 public class Action : IDisposable {
1957 public int doSomething(System.DateTime dateIn, out System.DateTime dateOut) {
1958 CDate tempdateIn = new CDate(dateIn.Year, dateIn.Month, dateIn.Day);
1959 CDate tempdateOut = new CDate();
1961 int ret = examplePINVOKE.Action_doSomething(swigCPtr,
1962 CDate.getCPtr(tempdateIn),
1963 CDate.getCPtr(tempdateOut));
1964 if (examplePINVOKE.SWIGPendingException.Pending)
1965 throw examplePINVOKE.SWIGPendingException.Retrieve();
1968 dateOut = new System.DateTime(tempdateOut.getYear(),
1969 tempdateOut.getMonth(), tempdateOut.getDay(), 0, 0, 0);
1973 static private IntPtr SwigConstructAction(System.DateTime dateIn, out System.DateTime dateOut) {
1974 CDate tempdateIn = new CDate(dateIn.Year, dateIn.Month, dateIn.Day);
1975 CDate tempdateOut = new CDate();
1977 return examplePINVOKE.new_Action(CDate.getCPtr(tempdateIn), CDate.getCPtr(tempdateOut));
1979 dateOut = new System.DateTime(tempdateOut.getYear(),
1980 tempdateOut.getMonth(), tempdateOut.getDay(), 0, 0, 0);
1984 public Action(System.DateTime dateIn, out System.DateTime dateOut)
1985 : this(Action.SwigConstructAction(dateIn, out dateOut), true) {
1986 if (examplePINVOKE.SWIGPendingException.Pending)
1987 throw examplePINVOKE.SWIGPendingException.Retrieve();
1994 A few things to note:
1997 <li> The "cstype" typemap has changed the parameter type to <tt>System.DateTime</tt> instead of the default generated <tt>CDate</tt> proxy.
1998 <li> The non-const <tt>CDate &</tt> type is marshalled as a reference parameter in C# as the date cannot be explicitly set once the object has been created, so a new object is created instead.
1999 <li> The code in the 'pre' attribute appears before the intermediary call (<tt>examplePINVOKE.new_Action</tt> / <tt>examplePINVOKE.Action_doSomething</tt>).
2000 <li> The code in the 'post' attribute appears after the intermediary call.
2001 <li> A try .. finally block is generated with the intermediary call in the try block and 'post' code in the finally block.
2002 The alternative of just using a temporary variable for the return value from the intermediary call and the 'post' code being inserted before the
2003 return statement is not possible given that the intermediary call and method return comes from a single source (the "csout" typemap).
2004 <li> The temporary variables in the "csin" typemaps are called <tt>temp$csin</tt>, where "$csin" is replaced with the parameter name.
2005 "$csin" is used to mangle the variable name so that more than one <tt>CDate &</tt> type can be used as a parameter in a method, otherwise two or
2006 more local variables with the same name would be generated.
2007 <li> The use of the "csin" typemap causes a constructor helper function (<tt>SwigConstructAction</tt>) to be generated.
2008 This allows C# code to be called before the intermediary call made in the constructor initialization list.
2009 <li> The 'cshin' attribute is required for the <tt>SwigConstructAction</tt> constructor helper function so that the 2nd parameter is declared as <tt>out dateOut</tt> instead of just <tt>dateOut</tt>.
2013 So far we have considered the date as an input only and an output only type.
2014 Now let's consider <tt>CDate *</tt> used as an input/output type. Consider the following C++ function which modifies the date passed in:
2019 void addYears(CDate *pDate, int years) {
2020 *pDate = CDate(pDate->getYear() + years, pDate->getMonth(), pDate->getDay());
2026 If usage of <tt>CDate *</tt> commonly follows this input/output pattern, usage from C# like the following
2031 System.DateTime christmasEve = new System.DateTime(2000, 12, 24);
2032 example.addYears(ref christmasEve, 10); // christmasEve now contains 2010-12-24
2037 will be possible with the following <tt>CDate *</tt> typemaps
2042 %typemap(cstype, out="System.DateTime") CDate * "ref System.DateTime"
2045 pre=" CDate temp$csinput = new CDate($csinput.Year, $csinput.Month, $csinput.Day);",
2046 post=" $csinput = new System.DateTime(temp$csinput.getYear(),"
2047 " temp$csinput.getMonth(), temp$csinput.getDay(), 0, 0, 0);",
2048 cshin="ref $csinput"
2050 "$csclassname.getCPtr(temp$csinput)"
2055 Globals are wrapped by the module class and for a module called example, the typemaps result in the following code:
2060 public class example {
2061 public static void addYears(ref System.DateTime pDate, int years) {
2062 CDate temppDate = new CDate(pDate.Year, pDate.Month, pDate.Day);
2064 examplePINVOKE.addYears(CDate.getCPtr(temppDate), years);
2066 pDate = new System.DateTime(temppDate.getYear(), temppDate.getMonth(), temppDate.getDay(), 0, 0, 0);
2075 The following typemap is the same as the previous but demonstrates how a using block can be used for the temporary variable.
2076 The only change to the previous typemap is the introduction of the 'terminator' attribute to terminate the <tt>using</tt> block.
2077 The <tt>subtractYears</tt> method is nearly identical to the above <tt>addYears</tt> method.
2083 pre=" using (CDate temp$csinput = new CDate($csinput.Year, $csinput.Month, $csinput.Day)) {",
2084 post=" $csinput = new System.DateTime(temp$csinput.getYear(),"
2085 " temp$csinput.getMonth(), temp$csinput.getDay(), 0, 0, 0);",
2086 terminator=" } // terminate temp$csinput using block",
2087 cshin="ref $csinput"
2089 "$csclassname.getCPtr(temp$csinput)"
2091 void subtractYears(CDate *pDate, int years) {
2092 *pDate = CDate(pDate->getYear() - years, pDate->getMonth(), pDate->getDay());
2098 The resulting generated code shows the termination of the <tt>using</tt> block:
2103 public class example {
2104 public static void subtractYears(ref System.DateTime pDate, int years) {
2105 using (CDate temppDate = new CDate(pDate.Year, pDate.Month, pDate.Day)) {
2107 examplePINVOKE.subtractYears(CDate.getCPtr(temppDate), years);
2109 pDate = new System.DateTime(temppDate.getYear(), temppDate.getMonth(), temppDate.getDay(), 0, 0, 0);
2111 } // terminate temppDate using block
2118 <H3><a name="csharp_date_properties"></a>18.6.4 A date example demonstrating marshalling of C# properties</H3>
2122 The previous section looked at converting a C++ date class to <tt>System.DateTime</tt> for parameters.
2123 This section extends this idea so that the correct marshalling is obtained when wrapping C++ variables.
2124 Consider the same <tt>CDate</tt> class from the previous section and a global variable:
2129 CDate ImportantDate = CDate(1999, 12, 31);
2134 The aim is to use <tt>System.DateTime</tt> from C# when accessing this date as shown in the following usage where the module name is 'example':
2139 example.ImportantDate = new System.DateTime(2000, 11, 22);
2140 System.DateTime importantDate = example.ImportantDate;
2141 Console.WriteLine("Important date: " + importantDate);
2146 When SWIG wraps a variable that is a class/struct/union, it is wrapped using a pointer to the type for the reasons given in <a href="SWIG.html#SWIG_structure_data_members">Stucture data members</a>.
2147 The typemap type required is thus <tt>CDate *</tt>. Given that the previous section already designed <tt>CDate *</tt> typemaps, we'll use those same typemaps plus the 'csvarin' and 'csvarout' typemaps.
2151 %typemap(cstype, out="System.DateTime") CDate * "ref System.DateTime"
2154 pre=" CDate temp$csinput = new CDate($csinput.Year, $csinput.Month, $csinput.Day);",
2155 post=" $csinput = new System.DateTime(temp$csinput.getYear(),"
2156 " temp$csinput.getMonth(), temp$csinput.getDay(), 0, 0, 0);",
2157 cshin="ref $csinput"
2159 "$csclassname.getCPtr(temp$csinput)"
2161 %typemap(csvarin, excode=SWIGEXCODE2) CDate * %{
2162 /* csvarin typemap code */
2164 CDate temp$csinput = new CDate($csinput.Year, $csinput.Month, $csinput.Day);
2168 %typemap(csvarout, excode=SWIGEXCODE2) CDate * %{
2169 /* csvarout typemap code */
2171 IntPtr cPtr = $imcall;
2172 CDate tempDate = (cPtr == IntPtr.Zero) ? null : new CDate(cPtr, $owner);$excode
2173 return new System.DateTime(tempDate.getYear(), tempDate.getMonth(), tempDate.getDay(),
2180 For a module called example, the typemaps result in the following code:
2185 public class example {
2186 public static System.DateTime ImportantDate {
2187 /* csvarin typemap code */
2189 CDate tempvalue = new CDate(value.Year, value.Month, value.Day);
2190 examplePINVOKE.ImportantDate_set(CDate.getCPtr(tempvalue));
2192 /* csvarout typemap code */
2194 IntPtr cPtr = examplePINVOKE.ImportantDate_get();
2195 CDate tempDate = (cPtr == IntPtr.Zero) ? null : new CDate(cPtr, false);
2196 return new System.DateTime(tempDate.getYear(), tempDate.getMonth(), tempDate.getDay(),
2206 Some points to note:
2210 <li>The property set comes from the 'csvarin' typemap and the property get comes from the 'csvarout' typemap.
2211 <li>The type used for the property comes from the 'cstype' typemap. This particular example has the 'out' attribute set in the typemap and as it is specified, it is used in preference to the type in the typemap body. This is because the type in the 'out' attribute can never include modifiers such as 'ref', thereby avoiding code such as <tt>public static ref System.DateTime ImportantDate { ...</tt>, which would of course not compile.
2212 <li>The <tt>$excode</tt> special variable expands to nothing as there are no exception handlers specified in any of the unmanaged code typemaps (in fact the marshalling was done using the default unmanaged code typemaps.)
2213 <li>The <tt>$imcall</tt> typemap expands to the appropriate intermediary method call in the <tt>examplePINVOKE</tt> class.
2214 <li>The <tt>$csinput</tt> special variable in the 'csin' typemap always expands to <tt>value</tt> for properties. In this case <tt>$csclassname.getCPtr(temp$csinput)</tt> expands to <tt>CDate.getCPtr(tempvalue)</tt>.
2215 <li>The 'csin' typemap has 'pre', 'post' and 'cshin' attributes, and these are all ignored in the property set. The code in these attributes must instead be replicated within the 'csvarin' typemap. The line creating the <tt>temp$csinput</tt> variable is such an example; it is identical to what is in the 'pre' attribute.
2219 <H3><a name="csharp_partial_classes"></a>18.6.5 Turning wrapped classes into partial classes</H3>
2223 C# supports the notion of partial classes whereby a class definition can be split into more than one file.
2224 It is possible to turn the wrapped C++ class into a partial C# class using the <tt>csclassmodifiers</tt> typemap.
2225 Consider a C++ class called <tt>ExtendMe</tt>:
2232 int Part1() { return 1; }
2238 The default C# proxy class generated is:
2243 public class ExtendMe : IDisposable {
2245 public int Part1() {
2253 The default csclassmodifiers typemap shipped with SWIG is
2258 %typemap(csclassmodifiers) SWIGTYPE "public class"
2263 Note that the type used is the special catch all type <tt>SWIGTYPE</tt>.
2264 If instead we use the following typemap to override this for just the <tt>ExtendMe</tt> class:
2269 %typemap(csclassmodifiers) ExtendMe "public partial class"
2274 The C# proxy class becomes a partial class:
2279 public partial class ExtendMe : IDisposable {
2281 public int Part1() {
2289 You can then of course declare another part of the partial class elsewhere, for example:
2294 public partial class ExtendMe : IDisposable {
2295 public int Part2() {
2303 and compile the following code:
2308 ExtendMe em = new ExtendMe();
2309 Console.WriteLine("part1: {0}", em.Part1());
2310 Console.WriteLine("part2: {0}", em.Part2());
2315 demonstrating that the class contains methods calling both unmanaged code - <tt>Part1()</tt> and managed code - <tt>Part2()</tt>.
2316 The following example is an alternative approach to adding managed code to the generated proxy class.
2319 <H3><a name="csharp_extending_proxy_class"></a>18.6.6 Extending proxy classes with additional C# code</H3>
2323 The previous example showed how to use partial classes to add functionality to a generated C# proxy class.
2324 It is also possible to extend a wrapped struct/class with C/C++ code by using the <a href="SWIGPlus.html#SWIGPlus_class_extension">%extend directive</a>.
2325 A third approach is to add some C# methods into the generated proxy class with the <tt>cscode</tt> typemap.
2326 If we declare the following typemap before SWIG parses the <tt>ExtendMe</tt> class used in the previous example
2331 %typemap(cscode) ExtendMe %{
2332 public int Part3() {
2341 The generated C# proxy class will instead be:
2346 public class ExtendMe : IDisposable {
2348 public int Part3() {
2351 public int Part1() {