From: William S F. <ws...@fu...> - 2015-07-04 22:52:39
|
On 18 June 2015 at 19:45, Prof. Christoph Müller <mc...@hs...> wrote: >> Date: Wed, 10 Jun 2015 22:38:59 +0100 >> From: William S Fulton <ws...@fu...> >> Subject: Re: [Swig-user] Swig C# NullException problem >> To: Linda Schey <lin...@gm...> >> Cc: swig-user <swi...@li...> >> Message-ID: >> <CAN...@ma...> >> Content-Type: text/plain; charset=UTF-8 >> >> On 8 June 2015 at 16:12, Linda Schey <lin...@gm...> wrote: >> > Hello, >> > >> > we have encountered a problem with swig for which we couln't find any >> > solution in the documentation nor in forum posts. >> > We are right now developing an universal plugin which will connect the >> > 3d program Blender with the 3d engine of our university. Blenders API >> > is written in c/c++ whereas our engine is developed in c#. >> > We need to swig a lot of classes which lead us to write typemaps that >> > won't address individual cases but set up rules for all custom types > etc. >> > >> > It's a huge learning process for us but right now we are having >> > troubles with the exception handling or at least it seems like this is >> > the error source. >> > Swig will always create a default exception in the generated c++ file >> > which results in zero as a return value. But this will create a >> > compile error with the method of our custom class, that can't have zero > as a return value. >> > >> > We've already gone through the documentation chapters about exception >> > handling and couldn't find a solution for our problem. >> > >> > How can we set up a custom exception that will result in a default >> > value if the object is null? Is there an obvious mistake we're just >> > too narrow minded to see? Can the error be fixed in another way? (The >> > object can never be null which means we really don't need this >> > exception.) >> > >> > Please find below our sample code which includes our typemaps (for the >> > exception handling and other custom types) and the generated c++ file. >> > >> > A huge thank you in advance for any clues and with best wishes, >> > >> > Linda Schey and Sarah Haefele >> > Computer Science in Media Master, Furtwangen University Germany >> > >> > -------------------------------------- >> > cpp_file.h >> > -------------------------------------- >> > std::array<float, 3> FooInArrayOut(Foo f); >> > >> > -------------------------------------- >> > cpp_file.i >> > -------------------------------------- >> > //Map std::array<float,3> To Fusee.Math.float3 >> > %typemap(ctype) std::array<float, 3> "std::array<float, 3> /* >> > std::array<float, 3>_ctype */" >> > %typemap(imtype) std::array<float, 3> "Fusee.Math.float3 /* >> > Fusee.Math.float3*_imtype */" >> > %typemap(cstype) std::array<float, 3> "Fusee.Math.float3 /* >> > iFusee.Math.float3_cstype */" >> > %typemap(csin) std::array<float, 3> "$csinput /* > Fusee.Math.float3_csin >> > */" >> > %typemap(in) std::array<float, 3> %{ $1 = $input /* > Fusee.Math.float3 >> > in*/; %} >> > %typemap(out) std::array<float, 3> %{ /* Fusee.Math.float3 > out*/$result = >> > $1/* Fusee.Math.float3 out*/; %} >> > %typemap(csout) std::array<float, 3> { return $imcall/* >> > Fusee.Math.float3 csout*/; } >> > >> > -------------------------------------- >> > cpp_file_wrap.cxx >> > -------------------------------------- >> > SWIGEXPORT std::array<float, 3> /* std::array<float, 3>_ctype */ >> > SWIGSTDCALL CSharp_cpp_file_FooInArrayOut(void * jarg1, void * jarg2) { >> > std::array<float, 3> /* std::array<float, 3>_ctype */ jresult ; >> > cpp_file *arg1 = (cpp_file *) 0 ; >> > Foo arg2 ; >> > Foo *argp2 ; >> > std::array< float,3 > result; >> > >> > arg1 = (cpp_file *)jarg1; >> > argp2 = (Foo *)jarg2; >> > if (!argp2) { >> > >> > SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullExceptio >> > n, "Attempt to dereference null Foo", 0); >> > return 0; >> > } >> > arg2 = *argp2; >> > result = (arg1)->FooInArrayOut(arg2); >> > /* Fusee.Math.float3 out*/jresult = result/* Fusee.Math.float3 out*/; >> > return jresult; >> > } >> > >> > -------------------------------------- >> > Error Msg >> > -------------------------------------- >> > error C2440: 'return' : cannot convert from 'int' to > 'std::array<float,3>' >> >> >> I don't think you can use std::array<float, 3> as a return type in wrapper > function. How is the CLI going to know how to marshal this type to > Fusee.Math.float3 ? >> >> The exception handling is written such that the return type return type > will be void or a type that will accept zero. I don't think any other type > will easily be handling without overriding quite a bit of default code > generation. >> >> William >> > > The CLI is capable of marshalling any C/C++ POD (plain-old-datatype - > classes or structs without methods, con- or destructors) to a respective C# > struct with the same memory layout. We are using this scheme to wrap c++ > methods returning instances (not pointers) to c# methods returning structs. > It works very well in a big project where we SWIGged the C++ API of Cinema4D > (currently more than 700 classes wrapped - http://fusee3d.org/c4dexporter/) > and we're very happy with it. The funny thing is: This only works because > just by chance none of the numerous C++methods returning a POD on the stack > takes a pointer to a class as an argument: > > A method like this works with the approach mentioned by Linda: > Vector TestReturnStructOnStack(); // (WORKS JUST FINE) > > And a method like that doesn't - because the SWIG-generated C++-Stub tries > to return 0 (which is not castable to Vector): > Vector TestReturnStructOnStack(Foo *foo); // (C++ COMPILE ERROR in > SWIG-C++-Stub - cannot cast int to Vector) > > I doubt that this is by design. There should be a customizable typemap-entry > for "Vector" allowing to change the default return value of any method > returning "Vector". > I tried to add a constructor taking an int to Vector. This cures the > compiler error but then Vector is not a POD anymore and the p/invoke will > crash. > Thanks for any help - we have been struggling with this for weeks now. Ah yes of course, marshalling of value types and std::array can be a POD. There is actually a solution. You'll notice that the SWIG exception code uses ' return $null' where $null is a special variable. SWIG expands $null into 0 unless the 'out' typemap has a 'null' attribute, in which case it uses the value of this attribute. This is used for void returns where the 'out' typemap in Lib/csharp/csharp.swg is: %typemap(out, null="") void "" so 'return' is generated instead of 'return 0'. So for your case, just modify the out typemap and add in the 'null' attribute as follows: %typemap(out, null="std::array<float, 3>()") std::array<float, 3> %{ /* Fusee.Math.float3 out*/$result = $1/* Fusee.Math.float3 out*/; %} The SWIG documentation ought to have some good examples of value types typemaps such as the std::array you show and it also ought to have this explained. A patch to the docs in Doc/Manual/CSharp.html would be much appreciated! William |