Add Antti Karanta's documentation about the new c# array marshalling library plus some docs on the carrays library
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@10925 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
parent
087ae33b7c
commit
e4ef0a23d3
4 changed files with 334 additions and 24 deletions
|
|
@ -11,6 +11,12 @@
|
|||
<ul>
|
||||
<li><a href="#csharp_introduction">Introduction</a>
|
||||
<li><a href="#csharp_differences_java">Differences to the Java module</a>
|
||||
<li><a href="#CSharp_arrays">C# Arrays</a>
|
||||
<ul>
|
||||
<li><a href="#CSharp_arrays_swig_library">The SWIG C arrays library</a>
|
||||
<li><a href="#CSharp_arrays_pinvoke_default_array_marshalling">Managed arrays using P/Invoke default array marshalling</a>
|
||||
<li><a href="#CSharp_arrays_pinning">Managed arrays using pinning</a>
|
||||
</ul>
|
||||
<li><a href="#csharp_exceptions">C# Exceptions</a>
|
||||
<ul>
|
||||
<li><a href="#csharp_exception_example_check_typemap">C# exception example using "check" typemap</a>
|
||||
|
|
@ -402,7 +408,297 @@ Windows users can also get the examples working using a
|
|||
<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.
|
||||
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.
|
||||
|
||||
<H2><a name="csharp_exceptions"></a>17.3 C# Exceptions</H2>
|
||||
<H2><a name="CSharp_arrays"></a>17.3 C# Arrays</H2>
|
||||
|
||||
|
||||
<p>
|
||||
There are various ways to pass arrays from C# to C/C++.
|
||||
The default wrapping treats arrays as pointers and as such simple type wrapper classes are generated,
|
||||
eg <tt>SWIGTYPE_p_int</tt> when wrapping the C type <tt>int []</tt> or <tt>int *</tt>.
|
||||
This gives a rather restricted use of the underlying unmanaged code and the most practical way to use arrays is to enhance or customise
|
||||
with one of the following three approaches; namely the SWIG C arrays library, P/Invoke default array marshalling or
|
||||
pinned arrays.
|
||||
</p>
|
||||
|
||||
<H3><a name="CSharp_arrays_swig_library"></a>17.3.1 The SWIG C arrays library</H3>
|
||||
|
||||
|
||||
<p>
|
||||
The C arrays library keeps all the array memory in the unmanaged layer.
|
||||
The library is available to all language modules and is documented in the <a href="Library.html#Library_carrays">carrays.i library</a> section.
|
||||
Please refer to this section for details, but for convenience, the C# usage for the two examples outlined there is shown below.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For the <tt>%array_functions</tt> example, the equivalent usage would be:
|
||||
<p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
SWIGTYPE_p_double a = example.new_doubleArray(10); // Create an array
|
||||
for (int i=0; i<10; i++)
|
||||
example.doubleArray_setitem(a,i,2*i); // Set a value
|
||||
example.print_array(a); // Pass to C
|
||||
example.delete_doubleArray(a); // Destroy array
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
and for the <tt>%array_class</tt> example, the equivalent usage would be:
|
||||
<p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
doubleArray c = new doubleArray(10); // Create double[10]
|
||||
for (int i=0; i<10; i++)
|
||||
c.setitem(i, 2*i); // Assign values
|
||||
example.print_array(c.cast()); // Pass to C
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
|
||||
<H3><a name="CSharp_arrays_pinvoke_default_array_marshalling"></a>17.3.2 Managed arrays using P/Invoke default array marshalling</H3>
|
||||
|
||||
|
||||
<p>
|
||||
In the P/Invoke default marshalling scheme, one needs to designate whether the invoked function will treat a managed
|
||||
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,
|
||||
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
|
||||
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
|
||||
back into the managed array after the call returns. A pointer to to this buffer
|
||||
is passed to the native function.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The reason for allocating a separate buffer is to leave the CLR free to relocate the managed array object
|
||||
during garbage collection. If the overhead caused by the copying is causing a significant performance penalty, consider pinning the managed array and
|
||||
passing a direct reference as described in the next section.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For more information on the subject, see the
|
||||
<a href="http://msdn.microsoft.com/en-us/library/z6cfh6e6(VS.80).aspx">Default Marshaling for Arrays</a> article
|
||||
on MSDN.
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
The P/Invoke default marshalling is supported by the <tt>arrays_csharp.i</tt> library via the INPUT, OUTPUT and INOUT typemaps.
|
||||
Let's look at some example usage. Consider the following C function:
|
||||
<div class="code">
|
||||
<pre>
|
||||
void myArrayCopy(int *sourceArray, int *targetArray, int nitems);
|
||||
</pre>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
We can now instruct SWIG to use the default marshalling typemaps by
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
%include "arrays_csharp.i"
|
||||
|
||||
%apply int INPUT[] {int *sourceArray}
|
||||
%apply int OUTPUT[] {int *targetArray}
|
||||
</pre>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As a result, we get the following method in the module class:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
public static void myArrayCopy(int[] sourceArray, int[] targetArray, int nitems) {
|
||||
examplePINVOKE.myArrayCopy(sourceArray, targetArray, nitems);
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If we look beneath the surface at the corresponding intermediary class code, we see
|
||||
that SWIG has generated code that uses attributes
|
||||
(from the System.Runtime.InteropServices namespace) to tell the CLR to use default
|
||||
marshalling for the arrays:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
[DllImport("example", EntryPoint="CSharp_myArrayCopy")]
|
||||
public static extern void myArrayCopy([In, MarshalAs(UnmanagedType.LPArray)]int[] jarg1,
|
||||
[Out, MarshalAs(UnmanagedType.LPArray)]int[] jarg2, int jarg3);
|
||||
</pre>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As an example of passing an inout array (i.e. the target function will both read from and
|
||||
write to the array), consider this C function that swaps a given number of elements
|
||||
in the given arrays:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
void myArraySwap(int *array1, int *array2, int nitems);
|
||||
</pre>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Now, we can instruct SWIG to wrap this by
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
%include "arrays_csharp.i"
|
||||
|
||||
%apply int INOUT[] {int *array1}
|
||||
%apply int INOUT[] {int *array2}
|
||||
</pre>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This results in the module class method
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
public static void myArraySwap(int[] array1, int[] array2, int nitems) {
|
||||
examplePINVOKE.myArraySwap(array1, array2, nitems);
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
and intermediate class method
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
[DllImport("example", EntryPoint="CSharp_myArraySwap")]
|
||||
public static extern void myArraySwap([In, Out, MarshalAs(UnmanagedType.LPArray)]int[] jarg1,
|
||||
[In, Out, MarshalAs(UnmanagedType.LPArray)]int[] jarg2, int jarg3);
|
||||
</pre>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
|
||||
<H3><a name="CSharp_arrays_pinning"></a>17.3.3 Managed arrays using pinning</H3>
|
||||
|
||||
|
||||
<p>
|
||||
It is also possible to pin a given array in memory (i.e. fix its location in memory), obtain a
|
||||
direct pointer to it, and then pass this pointer to the wrapped C/C++ function. This approach
|
||||
involves no copying, but it makes the work of the garbage collector harder as
|
||||
the managed array object can not be relocated before the fix on the array is released. You should avoid
|
||||
fixing arrays in memory in cases where the control may re-enter the managed side via a callback and/or
|
||||
another thread may produce enough garbage to trigger garbage collection.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
Now let's look at an example using pinning, thus avoiding the CLR making copies
|
||||
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.
|
||||
Let's use the same function from the previous section:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
void myArrayCopy(int *sourceArray, int *targetArray, int nitems);
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
We now need to declare the module class method unsafe, as we are using pointers:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
%csmethodmodifiers myArrayCopy "public unsafe";
|
||||
</pre>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Apply the appropriate typemaps to the array parameters:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
%include "arrays_csharp.i"
|
||||
|
||||
%apply int FIXED[] {int *sourceArray}
|
||||
%apply int FIXED[] {int *targetArray}
|
||||
</pre>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Notice that there is no need for separate in, out or inout typemaps as is the
|
||||
case when using P/Invoke default marshalling.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As a result, we get the following method in the module class:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
public unsafe static void myArrayCopy(int[] sourceArray, int[] targetArray, int nitems) {
|
||||
fixed ( int *swig_ptrTo_sourceArray = sourceArray ) {
|
||||
fixed ( int *swig_ptrTo_targetArray = targetArray ) {
|
||||
{
|
||||
examplePINVOKE.myArrayCopy((IntPtr)swig_ptrTo_sourceArray, (IntPtr)swig_ptrTo_targetArray, nitems);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
On the method signature level the only difference to the version using P/Invoke default
|
||||
marshalling is the "unsafe" quantifier, which is required because we are handling pointers.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Also the intermediate class method looks a little different from the default marshalling
|
||||
example - the method is expecting an IntPtr as the parameter type.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
[DllImport("example", EntryPoint="CSharp_myArrayCopy")]
|
||||
public static extern void myArrayCopy(IntPtr jarg1, IntPtr jarg2, int jarg3);
|
||||
</pre>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
<H2><a name="csharp_exceptions"></a>17.4 C# Exceptions</H2>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
@ -499,7 +795,7 @@ set so should only be used when a C# exception is not created.
|
|||
</p>
|
||||
|
||||
|
||||
<H3><a name="csharp_exception_example_check_typemap"></a>17.3.1 C# exception example using "check" typemap</H3>
|
||||
<H3><a name="csharp_exception_example_check_typemap"></a>17.4.1 C# exception example using "check" typemap</H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
@ -681,7 +977,7 @@ method and C# code does not handle pending exceptions via the canthrow attribute
|
|||
Actually it will issue this warning for any function beginning with <tt>SWIG_CSharpSetPendingException</tt>.
|
||||
</P>
|
||||
|
||||
<H3><a name="csharp_exception_example_percent_exception"></a>17.3.2 C# exception example using %exception</H3>
|
||||
<H3><a name="csharp_exception_example_percent_exception"></a>17.4.2 C# exception example using %exception</H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
@ -746,7 +1042,7 @@ The managed code generated does check for the pending exception as mentioned ear
|
|||
</pre>
|
||||
</div>
|
||||
|
||||
<H3><a name="csharp_exception_example_exception_specifications"></a>17.3.3 C# exception example using exception specifications</H3>
|
||||
<H3><a name="csharp_exception_example_exception_specifications"></a>17.4.3 C# exception example using exception specifications</H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
@ -803,7 +1099,7 @@ SWIGEXPORT void SWIGSTDCALL CSharp_evensonly(int jarg1) {
|
|||
Multiple catch handlers are generated should there be more than one exception specifications declared.
|
||||
</p>
|
||||
|
||||
<H3><a name="csharp_custom_application_exception"></a>17.3.4 Custom C# ApplicationException example</H3>
|
||||
<H3><a name="csharp_custom_application_exception"></a>17.4.4 Custom C# ApplicationException example</H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
@ -937,7 +1233,7 @@ try {
|
|||
</pre>
|
||||
</div>
|
||||
|
||||
<H2><a name="csharp_directors"></a>17.4 C# Directors</H2>
|
||||
<H2><a name="csharp_directors"></a>17.5 C# Directors</H2>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
@ -950,7 +1246,7 @@ The following sections provide information on the C# director implementation and
|
|||
However, the <a href="Java.html#java_directors">Java directors</a> section should also be read in order to gain more insight into directors.
|
||||
</p>
|
||||
|
||||
<H3><a name="csharp_directors_example"></a>17.4.1 Directors example</H3>
|
||||
<H3><a name="csharp_directors_example"></a>17.5.1 Directors example</H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
@ -1071,7 +1367,7 @@ CSharpDerived - UIntMethod(123)
|
|||
</pre>
|
||||
</div>
|
||||
|
||||
<H3><a name="csharp_directors_implementation"></a>17.4.2 Directors implementation</H3>
|
||||
<H3><a name="csharp_directors_implementation"></a>17.5.2 Directors implementation</H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
@ -1257,7 +1553,7 @@ void SwigDirector_Base::BaseBoolMethod(Base const &b, bool flag) {
|
|||
</pre>
|
||||
</div>
|
||||
|
||||
<H3><a name="csharp_director_caveats"></a>17.4.3 Director caveats</H3>
|
||||
<H3><a name="csharp_director_caveats"></a>17.5.3 Director caveats</H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
@ -1305,7 +1601,7 @@ However, a call from C# to <tt>CSharpDefaults.DefaultMethod()</tt> will of cours
|
|||
should pass the call on to <tt>CSharpDefaults.DefaultMethod(int)</tt>using the C++ default value, as shown above.
|
||||
</p>
|
||||
|
||||
<H2><a name="csharp_typemap_examples"></a>17.5 C# Typemap examples</H2>
|
||||
<H2><a name="csharp_typemap_examples"></a>17.6 C# Typemap examples</H2>
|
||||
|
||||
|
||||
This section includes a few examples of typemaps. For more examples, you
|
||||
|
|
@ -1313,7 +1609,7 @@ might look at the files "<tt>csharp.swg</tt>" and "<tt>typemaps.i</tt>" in
|
|||
the SWIG library.
|
||||
|
||||
|
||||
<H3><a name="csharp_memory_management_member_variables"></a>17.5.1 Memory management when returning references to member variables</H3>
|
||||
<H3><a name="csharp_memory_management_member_variables"></a>17.6.1 Memory management when returning references to member variables</H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
@ -1437,7 +1733,7 @@ public class Bike : IDisposable {
|
|||
Note the <tt>addReference</tt> call.
|
||||
</p>
|
||||
|
||||
<H3><a name="csharp_memory_management_objects"></a>17.5.2 Memory management for objects passed to the C++ layer</H3>
|
||||
<H3><a name="csharp_memory_management_objects"></a>17.6.2 Memory management for objects passed to the C++ layer</H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
@ -1556,7 +1852,7 @@ The 'cscode' typemap simply adds in the specified code into the C# proxy class.
|
|||
</div>
|
||||
|
||||
|
||||
<H3><a name="csharp_date_marshalling"></a>17.5.3 Date marshalling using the csin typemap and associated attributes</H3>
|
||||
<H3><a name="csharp_date_marshalling"></a>17.6.3 Date marshalling using the csin typemap and associated attributes</H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
@ -1840,7 +2136,7 @@ public class example {
|
|||
</pre>
|
||||
</div>
|
||||
|
||||
<H3><a name="csharp_date_properties"></a>17.5.4 A date example demonstrating marshalling of C# properties</H3>
|
||||
<H3><a name="csharp_date_properties"></a>17.6.4 A date example demonstrating marshalling of C# properties</H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
@ -1941,7 +2237,7 @@ Some points to note:
|
|||
</ul>
|
||||
|
||||
|
||||
<H3><a name="csharp_partial_classes"></a>17.5.5 Turning wrapped classes into partial classes</H3>
|
||||
<H3><a name="csharp_partial_classes"></a>17.6.5 Turning wrapped classes into partial classes</H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
@ -2041,7 +2337,7 @@ demonstrating that the class contains methods calling both unmanaged code - <tt>
|
|||
The following example is an alternative approach to adding managed code to the generated proxy class.
|
||||
</p>
|
||||
|
||||
<H3><a name="csharp_extending_proxy_class"></a>17.5.6 Extending proxy classes with additional C# code</H3>
|
||||
<H3><a name="csharp_extending_proxy_class"></a>17.6.6 Extending proxy classes with additional C# code</H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue