Oh, I should add that the usage in your case would be something like this:
%include cs_struct.i
cs_struct(CMyStruct, MyStruct)
struct CMyStruct {
int x;
double y;
long z;
};
bool getMyData(CMyStruct &cms);
You must also define a C# equivalent of the structure called “struct MyStruct”, and compile this definition along with the SWIG-generated files.
If you would like to use a C# class instead (“class MyStruct”), use the following macro:
////////////////////////////////////////////////////////////////////////////////
// %cs_class(TYPE, CSTYPE)
//
// Maps a C++ struct or class to a C# class that you have written yourself.
// The class should have [StructLayout(LayoutKind.Sequential)] in front of it.
// This macro should be used rather than cs_struct if the structure in question
// is always passed by reference (because it is large). Double pointers and
// references (**, *&) are not supported here, though I think it's possible to
// do so. I suspect that the .NET marshaller copies the class both on input and
// output, so function calls involving it are probably slow.
//
// It seems that if you pass a class to a C++ function as a parameter, any
// changes made by the C++ function will NOT be copied back to C#. So if that's
// what you need, there are two workarounds:
// 1. Pass a C# struct and use %cs_struct instead.
// 2. Change the C++ function to return a pointer to the same parameter that
// was passed in. Then your C# call will have to look like
// "a = Klass.Function(a)". Of course, if the function already returns a
// value then you're in a tough spot. Sorry.
%define %cs_class(TYPE, CSTYPE)
%ignore TYPE;
%typemap(ctype) TYPE*, TYPE& %{ TYPE* %}
%typemap(in) TYPE*, TYPE& %{ $1 = $input; %}
%typemap(varin) TYPE*, TYPE& %{ $1 = $input; %}
//%typemap(memberin) TYPE*, TYPE& %{ $1 = $input; %}
%typemap(out, null="NULL") TYPE*, TYPE& %{ $result = $1; %}
%typemap(imtype, out="IntPtr") TYPE*, TYPE& %{ CSTYPE %}
%typemap(cstype) TYPE*, TYPE& %{ CSTYPE %}
%typemap(csin) TYPE*, TYPE& %{ $csinput %}
%typemap(csout, excode=SWIGEXCODE) TYPE*, TYPE& {
IntPtr ptr = $imcall;$excode
if (ptr == IntPtr.Zero)
return null;
CSTYPE ret = (CSTYPE)Marshal.PtrToStructure(ptr, typeof(CSTYPE));
return ret;
}
%typemap(csvarin, excode=SWIGEXCODE2) TYPE*
%{
set { $imcall;$excode }
%}
%typemap(csvarout, excode=SWIGEXCODE2) TYPE*
%{
get {
IntPtr ptr = $imcall;$excode
if (ptr == IntPtr.Zero)
return null;
CSTYPE ret = (CSTYPE)Marshal.PtrToStructure(ptr, typeof(CSTYPE));
return ret;
}
%}
%enddef
Oh, I see the problem. Or at least the main problem. The macro is called %cs_struct, not cs_struct. Add a %.
%include "cs_struct.i"
cs_struct(CTypeData, TypeData);
Sorry, I don’t know what’s wrong. I suggest that you try something simple such as this:
%{
struct Point2D {
int X, Y;
};
%}
%cs_struct(Point2D, System.Drawing.Point)
%inline %{
void Test1(Point2D p) {}
void Test2(Point2D& p) {}
%}
If Test1 and Test2 are wrapped correctly, look for the differences between this code and your code.
Sergio... are you using the typemap for std::string? It comes with the swig distro & is called string.i i think... d.
------------------------------------------------------------------------------ Create and publish websites with WebMatrix Use the most popular FREE web apps or write code yourself; WebMatrix provides all the features you need to develop and publish your website. http://p.sf.net/sfu/ms-webmatrix-sf _______________________________________________ Swig-user mailing list Swig...@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/swig-user
Sergio...
You're having trouble wrapping a C++ class with an stl string as a member variable? Is that correct? sorry I've not been following this thread from the beginning...
d.
Hi Sergio...
i don't have experience wrapping structs - though i'd imagine that they'd behave just like public classes... i did notice in your sourceforge query that your getter function is getting the object by reference... if you want a copy of the struct in the target language why not return a copy? i believe swig handles such cases well - i do it all the time. Judging by the simplicity of my anwer, i'm guessing I'm not understanding your problem :-)
re wrapping for java as a target language - swig needs to know your target package name for it to work properly. not sure if you know this, i'm just mentioning it because it took me forever to figure this out for myself :-) if you're using anything other than the default package you MUST use the -package option with swig. run swig -help for a complete list of options ... I also find the - outdir super useful to put the resultant .java files right into your package.
good luck!
d.
When using %cs_struct, other typemaps such as std_wstring.i will have no effect. %cs_struct causes the structure to be passed *bitwise*, and the .NET marshaler is in charge of converting your C# structure to a C++ structure or vice versa. Therefore you can’t use std::string or std::wstring in your structure. You might be able to use wchar_t* in C++, and extract the string in C# using one of two methods:
1. Put “public IntPtr strPtr;” in the C# structure and use System.Runtime.InteropServices.Marshal.PtrToStringUni(strPtr); to extract the string
2. Put “[MarshalAs(UnmanagedType.LPWStr)] public string str;” in the C# structure. I haven’t tried this, but if you’re lucky it’ll make the marshaller extract the string automatically.
I don’t know who on this list would be an expert in SWIG for Java and JNI.
If you want to allocate the string on the C++ side and release it on the C# side, given that %cs_struct bypassed SWIG’s normal wrapping, I suppose the best option is BSTRs. On the C++ side you call SysAllocString or SysAllocStringLen to create a BSTR that you put in the structure. Then in C# call Marshal.PtrToStringBSTR to convert the IntPtr (which points to the BSTR) to System.String, and finally release the string with Marshal.FreeBSTR.
Well, you could also allocate the string with malloc() and wrap free() with SWIG:
%cs_struct(void*, IntPtr)
void free(void* ptr);
From: Sergio Gómez Villamor [mailto:sgo...@ac.upc.edu]
Sent: Friday, April 01, 2011 11:39 AM
To: David Piepgrass
Cc: swig...@lists.sourceforge.net
Subject: Re: [Swig-user] return a struct by reference without creating a handler wrapper class
OK, I will try this although I don't like it very much because if I have to allocate the string using SysAllocString, that means the allocation of the string will depend on the target language I'm compiling to.
Thanks,
Sergio
On Mar 29, 2011, at 11:59 AM, Sergio Gómez Villamor wrote:
> Thanks David for your fast response.
>
> But I still have problems:
>
> - This is how I defined my native library (dexlib.h)
In what way doesn’t it work? I haven’t actually tried %cs_struct(void*, IntPtr), but I do use %cs_struct(HWND, IntPtr), %cs_struct(HBITMAP, IntPtr), etc.
It is correct that there is no “ref” on TypeData using %cs_class. TypeData is supposed to be a class, so it is already passed by reference. “ref TypeData” would correspond to CTypeData** in C++.