Maybe I'm the only one dealing with this issue, but I'll post it anyway
for the record.
I'd just like to add a new wrinkle to this old thread. It seems that if
the structure you return has a constructor, then the C++ compiler
decides to add 4 to the number at the end of the exported name, and thus
the C++ and C# exported names match. See, in the example below I suggest
declaring an alias in your .def file:
_CSharp_CreateSquareBox@16 = _CSharp_CreateSquareBox@12
BUT if the Box structure is given a constructor, the C++ compiler will
(or at least might) decide to use the name _CSharp_CreateSquareBox@16 in
the first place. Consequently the line in the .def file is not only
unnecessary but illegal and you get this linker output:
warning LNK4197: export '_CSharp_CreateSquareBox@16' specified multiple
times; using first specification
error LNK2001: unresolved external symbol _CSharp_CreateSquareBox@12
Gee whiz, Microsoft does weird things. Also, when you give your
structure a constructor, the C++ compiler will give you a warning
'CSharp_CreateSquareBox' has C-linkage specified, but returns UDT 'Box'
which is incompatible with C
I'm not sure whether this warning is anything to be concerned about.
> To recap a previous thread: Somebody might want to export a function
> that returns a structure:
>
> typedef struct {
> int width;
> int height;
> int length;
> } Box;
> Box CreateSquareBox(int width, int height, int length) {
> Box b;
> b.width = width;
> b.height = height;
> b.length = length;
> return b;
> }
>
> (Typemaps are listed below)
>
> Now the compiler exports the wrapper as _CSharp_CreateSquareBox@12,
> where 12 refers to the size (in bytes) of the 3 arguments.
>
> SWIG correctly imports into C# like this:
>
> [DllImport("NaviMapping", EntryPoint="CSharp_CreateSquareBox")]
> public static extern Box CreateSquareBox(int jarg1, int jarg2, int
> jarg3);
>
> It doesn't work and I have now confirmed the reason why. My
> understanding is that structures returned by value are automatically
> transformed into pass by reference, something like this (I have not
> found any documentation on it, so this is just a guess):
>
> void CreateSquareBox(Box* box, int width, int height, int length);
>
> Now when you tell the .NET framework that the entry point is
> CSharp_CreateSquareBox, it searches the DLL for two names: (1) it
looks
> for CSharp_CreateSquareBox and doesn't find it. (2) It computes the
size
> of the arguments to form the alternate name
_CSharp_CreateSquareBox@16.
> It looks for this and doesn't find it, so
> 'System.EntryPointNotFoundException' is thrown. The C++ compiler is
much
> older so it is likely that _CSharp_CreateSquareBox@12 is the correct
> name, and the .NET framework just has a bug in it. It must be hard to
> get right given that there seems to be no documentation anywhere on
the
> subject... for example if you look at
>
>
http://msdn2.microsoft.com/EN-US/library/awbckfbz.aspx>
> You'll notice that Microsoft only considers passing structures as
> arguments, not as return values.
>
> There is an important exception: there is no problem if the structure
> being returned is only 4 or 8 bytes. I assume that this is because a 4
> or 8-byte structure can be returned in registers, so the hidden
argument
> is not required and the but in .NET doesn't show up.
>
> I know of three solutions that let you call the function from C#.
>
> 1. Don't return structures; pass by reference.
>
> 2. Create a .def file in your C++ project in which you alias the
> function:
>
> LIBRARY "Example"
>
> EXPORTS
> CSharp_CreateSquareBox
> _CSharp_CreateSquareBox@16 = CSharp_CreateSquareBox@12
>
> 3. Somehow tell SWIG to tell P/Invoke the correct name (not sure how):
>
> DllImport("NaviMapping", EntryPoint="_CSharp_CreateSquareBox@12")]
> public static extern Box CreateSquareBox(int jarg1, int jarg2, int
> jarg3);
>
> P.S. When using SWIG with C#, you need to redefine the same struct in
C#
> (manually) and you need typemaps like this:
>
> %ignore Box;
> %typemap(in) Box %{ $1 = $input; %}
> %typemap(out, null="Box()", outattribute="return:
> MarshalAs(ValueStruct)") Box %{ $result = $1; %}
> // TODO, need a better null attribute, also do it in C
> %typemap(cstype) Box "Box"
> %typemap(imtype) Box "Box"
> %typemap(ctype) Box "Box"
> %typemap(csout, excode=SWIGEXCODE) Box {
> Box ret = $imcall;$excode
> return ret;
> }
> %typemap(csin) Box "$csinput"
>
> // In C#:
> [StructLayout(LayoutKind.Sequential)]
> public struct Box
> {
> public int width;
> public int height;
> public int length;
> }
>
> Bonus: here's how to marshall System.Drawing.Point, an 8-byte
structure
> which does not exhibit the problem:
>
> %ignore Point;
> %typemap(in) Point %{ $1 = $input; %}
> %typemap(out, null="System.Drawing.Point()",
> outattribute="return: MarshalAs(ValueStruct)") Point
> %{ $result = $1; %}
> %typemap(cstype) Point "System.Drawing.Point"
> %typemap(imtype) Point "System.Drawing.Point"
> %typemap(ctype) Point "Point"
> %typemap(csout, excode=SWIGEXCODE) Point {
> System.Drawing.Point ret = $imcall;$excode
> return ret;
> }
> %typemap(csin) Point "$csinput"
>
> %inline
> %{
> typedef struct {
> int x,y;
> } Point;
> Point CreatePoint(int x, int y) {
> Point p = {x,y};
> return p;
> }
> %}
>
> // Later, in C#...
> System.Drawing.Point p = Example.CreatePoint(2, 3);
> Debug.WriteLine(string.Format("Point: {0}, {1}", p.X, p.Y));
>
> ------------------------------
>
> One little thing I forgot to mention:
>
> EXPORTS
> ; Either of these two lines will work; you don't need both.
> CSharp_CreateSquareBox
> _CSharp_CreateSquareBox@16 = CSharp_CreateSquareBox@12
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/_______________________________________________
Swig-user mailing list
Swig-user@...
https://lists.sourceforge.net/lists/listinfo/swig-user