-Director support (virtual method callbacks into C#) has not yet been implemented and is the main missing feature compared to Java.
-Less of the STL is supported and there are also a few minor utility typemaps in the various.i library which are missing.
-
-
@@ -898,6 +894,399 @@ try {
+C# Directors
+
+
+The SWIG directors feature adds extra code to the generated C# proxy classes that enable these classes to be used in cross-language polymorphism.
+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.
+
+
+
+The following sections provide information on the C# director implementation and contain most of the information required to use the C# directors.
+However, the Java directors section should also be read in order to gain more insight into directors.
+
+
+Directors example
+
+
+Imagine we are wrapping a C++ base class, Base, from which we would like to inherit in C#.
+Such a class is shown below as well as another class, Caller, which calls the virtual method UIntMethod
+from pure unmanaged C++ code.
+
+
+
+
+
+// file: example.h
+class Base {
+public:
+ virtual ~Base() {}
+
+ virtual unsigned int UIntMethod(unsigned int x) {
+ std::cout << "Base - UIntMethod(" << x << ")" << std::endl;
+ return x;
+ }
+ virtual void BaseBoolMethod(const Base &b, bool flag) {}
+};
+
+class Caller {
+public:
+ Caller(): m_base(0) {}
+ ~Caller() { delBase(); }
+ void set(Base *b) { delBase(); m_base = b; }
+ void reset() { m_base = 0; }
+ unsigned int UIntMethodCall(unsigned int x) { return m_base->UIntMethod(x); }
+
+private:
+ Base *m_base;
+ void delBase() { delete m_base; m_base = 0; }
+};
+
+
+
+
+The director feature is turned off by default and the following simple interface file shows how directors are enabled
+for the class Base.
+
+
+
+
+/* File : example.i */
+%module(directors="1") example
+%{
+#include "example.h"
+%}
+
+%feature("director") Base;
+
+%include "example.h"
+
+
+
+
+The following is a C# class inheriting from Base:
+
+
+
+
+public class CSharpDerived : Base
+{
+ public override uint UIntMethod(uint x)
+ {
+ Console.WriteLine("CSharpDerived - UIntMethod({0})", x);
+ return x;
+ }
+}
+
+
+
+
+The Caller class can demonstrate the UIntMethod method being called from unmanaged code using the following C# code:
+
+
+
+
+public class runme
+{
+ static void Main()
+ {
+ Caller myCaller = new Caller();
+
+ // Test pure C++ class
+ using (Base myBase = new Base())
+ {
+ makeCalls(myCaller, myBase);
+ }
+
+ // Test director / C# derived class
+ using (Base myBase = new CSharpDerived())
+ {
+ makeCalls(myCaller, myBase);
+ }
+ }
+
+ static void makeCalls(Caller myCaller, Base myBase)
+ {
+ myCaller.set(myBase);
+ myCaller.UIntMethodCall(123);
+ myCaller.reset();
+ }
+}
+
+
+
+
+If the above is run, the output is then:
+
+
+
+
+Base - UIntMethod(123)
+CSharpDerived - UIntMethod(123)
+
+
+
+Directors implementation
+
+
+The previous section demonstrated a simple example where the virtual UIntMethod method was called from
+C++ code, even when the overridden method is implemented in C#.
+The intention of this section is to gain an insight into how the director feature works.
+It shows the generated code for the two virtual methods, UIntMethod and BaseBoolMethod,
+when the director feature is enabled for the Base class.
+
+
+
+Below is the generated C# Base director class.
+
+
+
+
+using System;
+using System.Runtime.InteropServices;
+
+public class Base : IDisposable {
+ private HandleRef swigCPtr;
+ protected bool swigCMemOwn;
+
+ internal Base(IntPtr cPtr, bool cMemoryOwn) {
+ swigCMemOwn = cMemoryOwn;
+ swigCPtr = new HandleRef(this, cPtr);
+ }
+
+ internal static HandleRef getCPtr(Base obj) {
+ return (obj == null) ? new HandleRef(null, IntPtr.Zero) : obj.swigCPtr;
+ }
+
+ ~Base() {
+ Dispose();
+ }
+
+ public virtual void Dispose() {
+ if(swigCPtr.Handle != IntPtr.Zero && swigCMemOwn) {
+ swigCMemOwn = false;
+ examplePINVOKE.delete_Base(swigCPtr);
+ }
+ swigCPtr = new HandleRef(null, IntPtr.Zero);
+ GC.SuppressFinalize(this);
+ }
+
+ public virtual uint UIntMethod(uint x) {
+ uint ret = examplePINVOKE.Base_UIntMethod(swigCPtr, x);
+ return ret;
+ }
+
+ public virtual void BaseBoolMethod(Base b, bool flag) {
+ examplePINVOKE.Base_BaseBoolMethod(swigCPtr, Base.getCPtr(b), flag);
+ if (examplePINVOKE.SWIGPendingException.Pending) throw examplePINVOKE.SWIGPendingException.Retrieve();
+ }
+
+ public Base() : this(examplePINVOKE.new_Base(), true) {
+ SwigDirectorConnect();
+ }
+
+ private void SwigDirectorConnect() {
+ if (SwigDerivedClassHasMethod("UIntMethod", swigMethodTypes0))
+ swigDelegate0 = new SwigDelegateBase_0(SwigDirectorUIntMethod);
+ if (SwigDerivedClassHasMethod("BaseBoolMethod", swigMethodTypes1))
+ swigDelegate1 = new SwigDelegateBase_1(SwigDirectorBaseBoolMethod);
+ examplePINVOKE.Base_director_connect(swigCPtr, swigDelegate0, swigDelegate1);
+ }
+
+ private bool SwigDerivedClassHasMethod(string methodName, Type[] methodTypes) {
+ System.Reflection.MethodInfo methodInfo = this.GetType().GetMethod(methodName, methodTypes);
+ bool hasDerivedMethod = methodInfo.DeclaringType.IsSubclassOf(typeof(Base));
+ return hasDerivedMethod;
+ }
+
+ private uint SwigDirectorUIntMethod(uint x) {
+ return UIntMethod(x);
+ }
+
+ private void SwigDirectorBaseBoolMethod(IntPtr b, bool flag) {
+ BaseBoolMethod(new Base(b, false), flag);
+ }
+
+ internal delegate uint SwigDelegateBase_0(uint x);
+ internal delegate void SwigDelegateBase_1(IntPtr b, bool flag);
+
+ private SwigDelegateBase_0 swigDelegate0;
+ private SwigDelegateBase_1 swigDelegate1;
+
+ private static Type[] swigMethodTypes0 = new Type[] { typeof(uint) };
+ private static Type[] swigMethodTypes1 = new Type[] { typeof(Base), typeof(bool) };
+}
+
+
+
+
+Everything from the SwigDirectorConnect() method and below is code that is only generated when
+directors are enabled.
+The design comprises a C# delegate being initialised for each virtual method on construction of the class.
+Let's examine the BaseBoolMethod.
+
+
+
+In the Base constructor a call is made to SwigDirectorConnect() which contains the initialisation code for all the virtual methods.
+It uses a support method, SwigDerivedClassHasMethod(), which simply uses reflection to determine if the named method,
+BaseBoolMethod, with the list of required parameter types, exists in a subclass.
+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.
+However, if there is an overridden method in any subclass, the delegate is required.
+It is then initialised to the SwigDirectorBaseBoolMethod which in turn will call BaseBoolMethod if invoked.
+The delegate is not initialised to the BaseBoolMethod directly as quite often types will need marshalling from the unmanaged type
+to the managed type in which case an intermediary method (SwigDirectorBaseBoolMethod) is required for the marshalling.
+In this case, the C# Base class needs to be created from the unmanaged IntPtr type.
+
+
+
+The last thing that SwigDirectorConnect() does is to pass the delegates to the unmanaged code.
+It calls the intermediary method Base_director_connect() which is really a call to the C function CSharp_Base_director_connect().
+This method simply maps each C# delegate onto a C function pointer.
+
+
+
+
+SWIGEXPORT void SWIGSTDCALL CSharp_Base_director_connect(void *objarg,
+ SwigDirector_Base::SWIG_Callback0_t callback0,
+ SwigDirector_Base::SWIG_Callback1_t callback1) {
+ Base *obj = (Base *)objarg;
+ SwigDirector_Base *director = dynamic_cast(obj);
+ if (director) {
+ director->swig_connect_director(callback0, callback1);
+ }
+}
+
+class SwigDirector_Base : public Base, public Swig::Director {
+public:
+ SwigDirector_Base();
+ virtual unsigned int UIntMethod(unsigned int x);
+ virtual ~SwigDirector_Base();
+ virtual void BaseBoolMethod(Base const &b, bool flag);
+
+ typedef unsigned int (SWIGSTDCALL* SWIG_Callback0_t)(unsigned int);
+ typedef void (SWIGSTDCALL* SWIG_Callback1_t)(void *, unsigned int);
+ void swig_connect_director(SWIG_Callback0_t callbackUIntMethod, SWIG_Callback1_t callbackBaseBoolMethod);
+
+private:
+ SWIG_Callback0_t swig_callbackUIntMethod;
+ SWIG_Callback1_t swig_callbackBaseBoolMethod;
+ void swig_init_callbacks();
+};
+
+void SwigDirector_Base::swig_connect_director(SWIG_Callback0_t callbackUIntMethod,
+ SWIG_Callback1_t callbackBaseBoolMethod) {
+ swig_callbackUIntMethod = callbackUIntMethod;
+ swig_callbackBaseBoolMethod = callbackBaseBoolMethod;
+}
+
+
+
+
+Note that for each director class SWIG creates an unmanaged director class for making the callbacks. For example Base has SwigDirector_Base and SwigDirector_Base
+is derived from Base.
+Should a C# class be derived from Base, the underlying C++ SwigDirector_Base is created rather than Base.
+The SwigDirector_Base class then implements all the virtual methods, redirecting calls up to managed code if the callback/delegate is non-zero.
+The implementation of SwigDirector_Base::BaseBoolMethod shows this - the callback is made by invoking the swig_callbackBaseBoolMethod function pointer:
+
+
+
+
+void SwigDirector_Base::BaseBoolMethod(Base const &b, bool flag) {
+ void * jb = 0 ;
+ unsigned int jflag ;
+
+ if (!swig_callbackBaseBoolMethod) {
+ Base::BaseBoolMethod(b,flag);
+ return;
+ } else {
+ jb = (Base *) &b;
+ jflag = flag;
+ swig_callbackBaseBoolMethod(jb, jflag);
+ }
+}
+
+
+
+Director caveats
+
+
+There are a few gotchas with directors.
+The first is that the base class virtual method should not be called directly otherwise a stack overflow will occur due to recursive calls.
+This might be fixed in a future version of SWIG, but is likely to slow down virtual methods calls.
+For example, given Base as a director enabled class:
+
+
+
+
+
+class Base {
+public:
+ virtual ~Base();
+ virtual unsigned int UIntMethod(unsigned int x);
+};
+
+
+
+
+Do not directly call the base method from a C# derived class:
+
+
+
+
+public class CSharpDerived : Base
+{
+ public override uint UIntMethod(uint x)
+ {
+ return base.UIntMethod(x);
+ }
+}
+
+
+
+
+Secondly, if default parameters are used, it is recommended to follow a pattern of always calling a single method in any C# derived class.
+An example will clarify this and the reasoning behind the recommendation. Consider the following C++ class wrapped as a director class:
+
+
+
+
+class Defaults {
+public:
+ virtual ~Defaults();
+ virtual void DefaultMethod(int a=-100);
+};
+
+
+
+
+Recall that C++ methods with default parameters generate overloaded methods for each defaulted parameter, so a C# derived class can be created
+with two DefaultMethod override methods:
+
+
+
+
+public class CSharpDefaults : Defaults
+{
+ public override void DefaultMethod()
+ {
+ DefaultMethod(-100); // note C++ default value used
+ }
+ public override void DefaultMethod(int x)
+ {
+ }
+}
+
+
+
+
+It may not be clear at first, but should a user intend to call CSharpDefaults.DefaultMethod() from C++, a call is actually made to CSharpDefaults.DefaultMethod(int).
+This is because the initial call is made in C++ and therefore the DefaultMethod(int) method will be called as is expected with C++ calls to methods with defaults,
+with the default being set to -100.
+The callback/delegate matching this method is of course the overloaded method DefaultMethod(int).
+However, a call from C# to CSharpDefaults.DefaultMethod() will of course call this exact method and in order for behaviour to be consistent with calls from C++, the implementation
+should pass the call on to CSharpDefaults.DefaultMethod(int)using the C++ default value, as shown above.
+
+
17.4 C# Typemap examples
diff --git a/Lib/csharp/csharp.swg b/Lib/csharp/csharp.swg
index 11eafdc33..9165d1324 100644
--- a/Lib/csharp/csharp.swg
+++ b/Lib/csharp/csharp.swg
@@ -85,7 +85,7 @@
%typemap(cstype) SWIGTYPE & "$csclassname"
/* pointer to a class member */
-%typemap(ctype) SWIGTYPE (CLASS::*) "int"
+%typemap(ctype) SWIGTYPE (CLASS::*) "void *"
%typemap(imtype, out="IntPtr") SWIGTYPE (CLASS::*) "HandleRef"
%typemap(cstype) SWIGTYPE (CLASS::*) "$csclassname"
@@ -95,6 +95,12 @@
%typemap(in) bool
%{ $1 = $input ? true : false; %}
+%typemap(directorout) bool
+%{ $1 = $input ? true : false; %}
+
+%typemap(csdirectorin) bool "$iminput"
+%typemap(csdirectorout) bool "$cscall"
+
%typemap(in) char,
signed char,
unsigned char,
@@ -110,6 +116,66 @@
double
%{ $1 = ($1_ltype)$input; %}
+%typemap(directorout) char,
+ signed char,
+ unsigned char,
+ short,
+ unsigned short,
+ int,
+ unsigned int,
+ long,
+ unsigned long,
+ long long,
+ unsigned long long,
+ float,
+ double
+%{ $1 = ($1_ltype)$input; %}
+
+%typemap(directorin) bool "$input = $1;"
+%typemap(directorin) char "$input = $1;"
+%typemap(directorin) signed char "$input = $1;"
+%typemap(directorin) unsigned char "$input = $1;"
+%typemap(directorin) short "$input = $1;"
+%typemap(directorin) unsigned short "$input = $1;"
+%typemap(directorin) int "$input = $1;"
+%typemap(directorin) unsigned int "$input = $1;"
+%typemap(directorin) long "$input = $1;"
+%typemap(directorin) unsigned long "$input = $1;"
+%typemap(directorin) long long "$input = $1;"
+%typemap(directorin) unsigned long long "$input = $1;"
+%typemap(directorin) float "$input = $1;"
+%typemap(directorin) double "$input = $1;"
+
+%typemap(csdirectorin) char,
+ signed char,
+ unsigned char,
+ short,
+ unsigned short,
+ int,
+ unsigned int,
+ long,
+ unsigned long,
+ long long,
+ unsigned long long,
+ float,
+ double
+ "$iminput"
+
+%typemap(csdirectorout) char,
+ signed char,
+ unsigned char,
+ short,
+ unsigned short,
+ int,
+ unsigned int,
+ long,
+ unsigned long,
+ long long,
+ unsigned long long,
+ float,
+ double
+ "$cscall"
+
%typemap(out) bool %{ $result = $1; %}
%typemap(out) char %{ $result = $1; %}
%typemap(out) signed char %{ $result = $1; %}
@@ -126,16 +192,31 @@
%typemap(out) double %{ $result = $1; %}
/* char * - treat as String */
-%typemap(in) char * %{ $1 = ($1_ltype)$input; %}
+%typemap(in) char * %{ $1 = $input; %}
%typemap(out) char * %{ $result = SWIG_csharp_string_callback((const char *)$1); %}
+%typemap(directorout) char * %{ $1 = $input; %}
+%typemap(directorin) char * %{ $input = SWIG_csharp_string_callback($1); %}
+%typemap(csdirectorin) char * "$iminput"
+%typemap(csdirectorout) char * "$cscall"
%typemap(out, null="") void ""
+%typemap(csdirectorin) void "$iminput"
+%typemap(csdirectorout) void "$cscall"
+%typemap(directorin) void ""
/* primitive types by const reference */
%typemap(in) const bool & ($*1_ltype temp)
%{ temp = $input ? true : false;
$1 = &temp; %}
+%typemap(directorout,warning=SWIGWARN_TYPEMAP_THREAD_UNSAFE_MSG) const bool &
+%{ static $*1_ltype temp;
+ temp = $input ? true : false;
+ $1 = &temp; %}
+
+%typemap(csdirectorin) const bool & "$iminput"
+%typemap(csdirectorout) const bool & "$cscall"
+
%typemap(in) const char & ($*1_ltype temp),
const signed char & ($*1_ltype temp),
const unsigned char & ($*1_ltype temp),
@@ -152,6 +233,65 @@
%{ temp = ($*1_ltype)$input;
$1 = &temp; %}
+%typemap(directorout,warning=SWIGWARN_TYPEMAP_THREAD_UNSAFE_MSG) const char &,
+ const signed char &,
+ const unsigned char &,
+ const short &,
+ const unsigned short &,
+ const int &,
+ const unsigned int &,
+ const long &,
+ const unsigned long &,
+ const long long &,
+ const float &,
+ const double &
+%{ static $*1_ltype temp;
+ temp = ($*1_ltype)$input;
+ $1 = &temp; %}
+
+%typemap(directorin) const bool & "$input = $1_name;"
+%typemap(directorin) const char & "$input = $1_name;"
+%typemap(directorin) const signed char & "$input = $1_name;"
+%typemap(directorin) const unsigned char & "$input = $1_name;"
+%typemap(directorin) const short & "$input = $1_name;"
+%typemap(directorin) const unsigned short & "$input = $1_name;"
+%typemap(directorin) const int & "$input = $1_name;"
+%typemap(directorin) const unsigned int & "$input = $1_name;"
+%typemap(directorin) const long & "$input = $1_name;"
+%typemap(directorin) const unsigned long & "$input = $1_name;"
+%typemap(directorin) const long long & "$input = $1_name;"
+%typemap(directorin) const float & "$input = $1_name;"
+%typemap(directorin) const double & "$input = $1_name;"
+
+%typemap(csdirectorin) const char & ($*1_ltype temp),
+ const signed char & ($*1_ltype temp),
+ const unsigned char & ($*1_ltype temp),
+ const short & ($*1_ltype temp),
+ const unsigned short & ($*1_ltype temp),
+ const int & ($*1_ltype temp),
+ const unsigned int & ($*1_ltype temp),
+ const long & ($*1_ltype temp),
+ const unsigned long & ($*1_ltype temp),
+ const long long & ($*1_ltype temp),
+ const float & ($*1_ltype temp),
+ const double & ($*1_ltype temp)
+ "$iminput"
+
+%typemap(csdirectorout) const char & ($*1_ltype temp),
+ const signed char & ($*1_ltype temp),
+ const unsigned char & ($*1_ltype temp),
+ const short & ($*1_ltype temp),
+ const unsigned short & ($*1_ltype temp),
+ const int & ($*1_ltype temp),
+ const unsigned int & ($*1_ltype temp),
+ const long & ($*1_ltype temp),
+ const unsigned long & ($*1_ltype temp),
+ const long long & ($*1_ltype temp),
+ const float & ($*1_ltype temp),
+ const double & ($*1_ltype temp)
+ "$cscall"
+
+
%typemap(out) const bool & %{ $result = *$1; %}
%typemap(out) const char & %{ $result = *$1; %}
%typemap(out) const signed char & %{ $result = *$1; %}
@@ -175,6 +315,14 @@
return $null;
}
$1 = *argp; %}
+
+%typemap(directorout) SWIGTYPE
+%{ if (!$input) {
+ SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "Unexpected null return for type $1_type", 0);
+ return $null;
+ }
+ $1 = *($&1_ltype)$input; %}
+
%typemap(out) SWIGTYPE
#ifdef __cplusplus
%{ $result = new $1_ltype(($1_ltype &)$1); %}
@@ -186,6 +334,11 @@
}
#endif
+%typemap(directorin) SWIGTYPE
+%{ $input = (void *)&$1; %}
+%typemap(csdirectorin) SWIGTYPE "new $&csclassname($iminput, false)"
+%typemap(csdirectorout) SWIGTYPE "$&csclassname.getCPtr($cscall).Handle"
+
/* Generic pointers and references */
%typemap(in) SWIGTYPE * %{ $1 = ($1_ltype)$input; %}
%typemap(in) SWIGTYPE (CLASS::*) %{ $1 = *($&1_ltype)&$input; %}
@@ -195,8 +348,23 @@
return $null;
} %}
%typemap(out) SWIGTYPE *, SWIGTYPE & %{ $result = (void *)$1; %}
-%typemap(out) SWIGTYPE (CLASS::*) %{ *($&1_ltype)&$result = $1; %}
+%typemap(out) SWIGTYPE (CLASS::*) %{ $result = (void *)&$1; %}
+%typemap(directorout) SWIGTYPE *, SWIGTYPE (CLASS::*)
+%{ $1 = ($1_ltype)$input; %}
+%typemap(directorin) SWIGTYPE *, SWIGTYPE (CLASS::*)
+%{ $input = ($1_ltype) $1; %}
+%typemap(directorout) SWIGTYPE &
+%{ if (!$input) {
+ SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "Unexpected null return for type $1_type", 0);
+ return $null;
+ }
+ $1 = ($1_ltype)$input; %}
+%typemap(directorin) SWIGTYPE &
+%{ $input = ($1_ltype) &$1; %}
+
+%typemap(csdirectorin) SWIGTYPE *, SWIGTYPE (CLASS::*), SWIGTYPE & "new $csclassname($iminput, false)"
+%typemap(csdirectorout) SWIGTYPE *, SWIGTYPE (CLASS::*), SWIGTYPE & "$csclassname.getCPtr($cscall).Handle"
/* Default array handling */
%typemap(in) SWIGTYPE [] %{ $1 = ($1_ltype)$input; %}
@@ -206,6 +374,12 @@
%typemap(in) char[ANY], char[] %{ $1 = $input; %}
%typemap(out) char[ANY], char[] %{ $result = SWIG_csharp_string_callback($1); %}
+%typemap(directorout) char[ANY], char[] %{ $1 = $input; %}
+%typemap(directorin) char[ANY], char[] %{ $input = SWIG_csharp_string_callback($1); %}
+
+%typemap(csdirectorin) char[ANY], char[] "$iminput"
+%typemap(csdirectorout) char[ANY], char[] "$cscall"
+
/* Typecheck typemaps - The purpose of these is merely to issue a warning for overloaded C++ functions
* that cannot be overloaded in C# as more than one C++ type maps to a single C# type */
@@ -609,7 +783,7 @@
}
%}
-%typemap(csconstruct, excode=SWIGEXCODE) SWIGTYPE %{: this($imcall, true) {$excode
+%typemap(csconstruct, excode=SWIGEXCODE,directorconnect="\n SwigDirectorConnect();") SWIGTYPE %{: this($imcall, true) {$excode$directorconnect
}
%}
@@ -632,6 +806,12 @@
base.Dispose();
}
+%typemap(directordisconnect, methodname="swigDirectorDisconnect") SWIGTYPE %{
+ protected void $methodname() {
+ swigCMemOwn = false;
+ $imcall;
+ }
+%}
/* C# specific directives */
#define %csconst(flag) %feature("cs:const","flag")
diff --git a/Lib/csharp/enums.swg b/Lib/csharp/enums.swg
index 9de377ca4..d2362ef48 100644
--- a/Lib/csharp/enums.swg
+++ b/Lib/csharp/enums.swg
@@ -18,6 +18,13 @@
$1 = &temp; %}
%typemap(out) const enum SWIGTYPE & %{ $result = *$1; %}
+%typemap(directorout,warning=SWIGWARN_TYPEMAP_THREAD_UNSAFE_MSG) const enum SWIGTYPE &
+%{ static $*1_ltype temp = ($*1_ltype)$input;
+ $1 = &temp; %}
+%typemap(directorin) const enum SWIGTYPE & "$input = $1_name;"
+%typemap(csdirectorin) const enum SWIGTYPE & "($*csclassname)$iminput"
+%typemap(csdirectorout) const enum SWIGTYPE & "(int)$cscall"
+
%typecheck(SWIG_TYPECHECK_POINTER) const enum SWIGTYPE & ""
%typemap(throws, canthrow=1) const enum SWIGTYPE &
@@ -46,6 +53,11 @@
%typemap(in) enum SWIGTYPE %{ $1 = ($1_ltype)$input; %}
%typemap(out) enum SWIGTYPE %{ $result = $1; %}
+%typemap(directorout) enum SWIGTYPE %{ $1 = ($1_ltype)$input; %}
+%typemap(directorin) enum SWIGTYPE "$input = $1;"
+%typemap(csdirectorin) enum SWIGTYPE "($csclassname)$iminput"
+%typemap(csdirectorout) enum SWIGTYPE "(int)$cscall"
+
%typecheck(SWIG_TYPECHECK_POINTER) enum SWIGTYPE ""
%typemap(throws, canthrow=1) enum SWIGTYPE
diff --git a/Lib/csharp/enumsimple.swg b/Lib/csharp/enumsimple.swg
index c93bcdd3f..43f1c4607 100644
--- a/Lib/csharp/enumsimple.swg
+++ b/Lib/csharp/enumsimple.swg
@@ -20,6 +20,13 @@
$1 = &temp; %}
%typemap(out) const enum SWIGTYPE & %{ $result = *$1; %}
+%typemap(directorout,warning=SWIGWARN_TYPEMAP_THREAD_UNSAFE_MSG) const enum SWIGTYPE &
+%{ static $*1_ltype temp = ($*1_ltype)$input;
+ $1 = &temp; %}
+%typemap(directorin) const enum SWIGTYPE & "$input = $1_name;"
+%typemap(csdirectorin) const enum SWIGTYPE & "$iminput"
+%typemap(csdirectorout) const enum SWIGTYPE & "$cscall"
+
%typecheck(SWIG_TYPECHECK_INT32) const enum SWIGTYPE & ""
%typemap(throws, canthrow=1) const enum SWIGTYPE &
@@ -48,6 +55,11 @@
%typemap(in) enum SWIGTYPE %{ $1 = ($1_ltype)$input; %}
%typemap(out) enum SWIGTYPE %{ $result = $1; %}
+%typemap(directorout) enum SWIGTYPE %{ $1 = ($1_ltype)$input; %}
+%typemap(directorin) enum SWIGTYPE "$input = $1;"
+%typemap(csdirectorin) enum SWIGTYPE "$iminput"
+%typemap(csdirectorout) enum SWIGTYPE "$cscall"
+
%typecheck(SWIG_TYPECHECK_INT32) enum SWIGTYPE ""
%typemap(throws, canthrow=1) enum SWIGTYPE
diff --git a/Lib/csharp/enumtypesafe.swg b/Lib/csharp/enumtypesafe.swg
index f06cd37e0..9822ad27d 100644
--- a/Lib/csharp/enumtypesafe.swg
+++ b/Lib/csharp/enumtypesafe.swg
@@ -19,6 +19,13 @@
$1 = &temp; %}
%typemap(out) const enum SWIGTYPE & %{ $result = *$1; %}
+%typemap(directorout,warning=SWIGWARN_TYPEMAP_THREAD_UNSAFE_MSG) const enum SWIGTYPE &
+%{ static $*1_ltype temp = ($*1_ltype)$input;
+ $1 = &temp; %}
+%typemap(directorin) const enum SWIGTYPE & "$input = $1_name;"
+%typemap(csdirectorin) const enum SWIGTYPE & "$*csclassname.swigToEnum($iminput)"
+%typemap(csdirectorout) const enum SWIGTYPE & "$cscall.swigValue"
+
%typecheck(SWIG_TYPECHECK_POINTER) const enum SWIGTYPE & ""
%typemap(throws, canthrow=1) const enum SWIGTYPE &
@@ -47,6 +54,11 @@
%typemap(in) enum SWIGTYPE %{ $1 = ($1_ltype)$input; %}
%typemap(out) enum SWIGTYPE %{ $result = $1; %}
+%typemap(directorout) enum SWIGTYPE %{ $1 = ($1_ltype)$input; %}
+%typemap(directorin) enum SWIGTYPE "$input = $1;"
+%typemap(csdirectorin) enum SWIGTYPE "$csclassname.swigToEnum($iminput)"
+%typemap(csdirectorout) enum SWIGTYPE "$cscall.swigValue"
+
%typecheck(SWIG_TYPECHECK_POINTER) enum SWIGTYPE ""
%typemap(throws, canthrow=1) enum SWIGTYPE
diff --git a/Lib/csharp/std_string.i b/Lib/csharp/std_string.i
index 7d554c925..b5c5c6f8b 100644
--- a/Lib/csharp/std_string.i
+++ b/Lib/csharp/std_string.i
@@ -6,7 +6,7 @@
*
* Typemaps for std::string and const std::string&
* These are mapped to a C# String and are passed around by value.
- *
+ *
* To use non-const std::string references use the following %apply. Note
* that they are passed by value.
* %apply const std::string & {std::string &};
@@ -26,6 +26,8 @@ class string;
%typemap(ctype) string "char *"
%typemap(imtype) string "string"
%typemap(cstype) string "string"
+%typemap(csdirectorin) string "$iminput"
+%typemap(csdirectorout) string "$cscall"
%typemap(in, canthrow=1) string
%{ if (!$input) {
@@ -35,6 +37,15 @@ class string;
$1 = std::string($input); %}
%typemap(out) string %{ $result = SWIG_csharp_string_callback($1.c_str()); %}
+%typemap(directorout, canthrow=1) string
+%{ if (!$input) {
+ SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "null string", 0);
+ return $null;
+ }
+ $1 = std::string($input); %}
+
+%typemap(directorin) string %{ $input = SWIG_csharp_string_callback($1.c_str()); %}
+
%typemap(csin) string "$csinput"
%typemap(csout, excode=SWIGEXCODE) string {
string ret = $imcall;$excode
@@ -61,6 +72,8 @@ class string;
%typemap(ctype) const string & "char *"
%typemap(imtype) const string & "string"
%typemap(cstype) const string & "string"
+%typemap(csdirectorin) const string & "$iminput"
+%typemap(csdirectorout) const string & "$cscall"
%typemap(in, canthrow=1) const string &
%{ if (!$input) {
@@ -77,6 +90,17 @@ class string;
return ret;
}
+%typemap(directorout, canthrow=1, warning=SWIGWARN_TYPEMAP_THREAD_UNSAFE_MSG) const string &
+%{ if (!$input) {
+ SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "null string", 0);
+ return $null;
+ }
+ /* possible thread/reentrant code problem */
+ static std::string $1_str($input);
+ $1 = &$1_str; %}
+
+%typemap(directorin) const string & %{ $input = SWIG_csharp_string_callback($1->c_str()); %}
+
%typemap(csvarin, excode=SWIGEXCODE2) const string & %{
set {
$imcall;$excode
diff --git a/Lib/csharp/typemaps.i b/Lib/csharp/typemaps.i
index 2ddd9d84d..7268188b9 100644
--- a/Lib/csharp/typemaps.i
+++ b/Lib/csharp/typemaps.i
@@ -15,7 +15,7 @@ INPUT typemaps
--------------
These typemaps are used for pointer/reference parameters that are input only
-are mapped to a C# input parameter.
+and are mapped to a C# input parameter.
The following typemaps can be applied to turn a pointer or reference into a simple
input value. That is, instead of passing a pointer or reference to an object,
@@ -62,10 +62,21 @@ In C# you could then use it like this:
%typemap(imtype) TYPE *INPUT, TYPE &INPUT "CSTYPE"
%typemap(cstype) TYPE *INPUT, TYPE &INPUT "CSTYPE"
%typemap(csin) TYPE *INPUT, TYPE &INPUT "$csinput"
+%typemap(csdirectorin) TYPE *INPUT, TYPE &INPUT "$iminput"
+%typemap(csdirectorout) TYPE *INPUT, TYPE &INPUT "$cscall"
%typemap(in) TYPE *INPUT, TYPE &INPUT
%{ $1 = ($1_ltype)&$input; %}
+%typemap(directorout) TYPE *INPUT, TYPE &INPUT
+%{ $1 = ($1_ltype)&$input; %}
+
+%typemap(directorin) TYPE &INPUT
+%{ $input = (CTYPE *)$1; %}
+
+%typemap(directorin) TYPE *INPUT
+%{ $input = (CTYPE *)$1; %}
+
%typemap(typecheck) TYPE *INPUT = TYPE;
%typemap(typecheck) TYPE &INPUT = TYPE;
%enddef
@@ -143,10 +154,24 @@ value returned in the second output parameter. In C# you would use it like this:
%typemap(imtype) TYPE *OUTPUT, TYPE &OUTPUT "out CSTYPE"
%typemap(cstype) TYPE *OUTPUT, TYPE &OUTPUT "out CSTYPE"
%typemap(csin) TYPE *OUTPUT, TYPE &OUTPUT "out $csinput"
+%typemap(csdirectorin) TYPE *OUTPUT, TYPE &OUTPUT "$iminput"
+%typemap(csdirectorout) TYPE *OUTPUT, TYPE &OUTPUT "$cscall"
+
%typemap(in) TYPE *OUTPUT, TYPE &OUTPUT
%{ $1 = ($1_ltype)$input; %}
+%typemap(directorout,warning="Need to provide TYPE *OUTPUT directorout typemap") TYPE *OUTPUT, TYPE &OUTPUT {
+}
+
+%typemap(directorin) TYPE &OUTPUT
+%{ $input = &$1; %}
+
+%typemap(directorin,warning="Need to provide TYPE *OUTPUT directorin typemap, TYPE array length is unknown") TYPE *OUTPUT
+{
+}
+
+
%typecheck(SWIG_TYPECHECK_##TYPECHECKPRECEDENCE) TYPE *OUTPUT, TYPE &OUTPUT ""
%enddef
@@ -228,10 +253,23 @@ of the function return value.
%typemap(imtype) TYPE *INOUT, TYPE &INOUT "ref CSTYPE"
%typemap(cstype) TYPE *INOUT, TYPE &INOUT "ref CSTYPE"
%typemap(csin) TYPE *INOUT, TYPE &INOUT "ref $csinput"
+%typemap(csdirectorin) TYPE *INOUT, TYPE &INOUT "$iminput"
+%typemap(csdirectorout) TYPE *INOUT, TYPE &INOUT "$cscall"
%typemap(in) TYPE *INOUT, TYPE &INOUT
%{ $1 = ($1_ltype)$input; %}
+%typemap(directorout,warning="Need to provide TYPE *INOUT directorout typemap") TYPE *INOUT, TYPE &INOUT {
+
+}
+
+%typemap(directorin) TYPE &INOUT
+%{ $input = &$1; %}
+
+%typemap(directorin,warning="Need to provide TYPE *INOUT directorin typemap, TYPE array length is unknown") TYPE *INOUT, TYPE &INOUT
+{
+}
+
%typecheck(SWIG_TYPECHECK_##TYPECHECKPRECEDENCE) TYPE *INOUT, TYPE &INOUT ""
%enddef