You cannot return C ++ objects for non-C ++ subscribers. (This does not even work when you try to export a C ++ object to the calling object if it is compiled with another C ++ compiler.) The reason is that the actual layout for the C ++ object is not standardized and can be executed by different compilers, it differently.
The .NET runtime has no idea how to deal with your object, and it does not know about the different types that make up your token . Likewise, std::string does not make sense for .NET, since it is a C ++ type that relies on unmanaged memory allocation and with a different internal string format and different semantics than C #.
You can try turning your C ++ objects into COM objects, and then you can return the COM interfaces to your C # caller. This will require some work, as COM types are again incompatible with C ++ types (for the same reasons as above).
You can also try serializing your C ++ object into an array of bytes, and then just return the buffer / length in C #, which first deserializes the object in the .NET view. You will have to duplicate the classes you are trying to handle in this way.
Another possibility is that you return all data as independent out parameters from your function calls, that is, you are not trying to return token , but return each of its properties as a separate out parameter from C ++. You still have to convert some of your data types into something that .NET recognizes. ( std::string cannot be returned, you will have to copy it to an array of bytes or select it as BSTR , etc.).
Finally, a pretty attractive option: you can return the token address as void* from your C ++ function, and then create some exported simple C functions to read various properties based on the input pointer. You will also need a function to free a C ++ object when you are done with it. Sort of:
__declspec(dllexport) TokenType WINAPI GetTokenType ( Kaleidoscope::Token* pToken ) { return ( pToken->Type ); }
Then you declare these functions in C # as follows:
[DllImport ( "MyDll.dll" )] public static extern int GetTokenType ( UIntPtr pObj );
The UIntPtr instance will be initialized from void* returned by your next_token function. Then you call each of the exported property reader functions to get individual token properties.
I would probably go with a special serializer, because this is the least amount of work (in my opinion), and I consider this to be the cleanest solution (in terms of readability and maintainability).
Note: using COM objects may be less, but you will have to move away from any type of C ++ (at least in the open interface).
Edit: I forgot to mention the somewhat obvious option earlier - using mixed code and C ++ / CLI. This way you can have unmanaged code and managed code in the same DLL at the same time, and you can perform all the transformations in C ++ code. If you define most of your classes in C ++ / CLI, you can simply pass the appropriate (managed) instances to your C # application without further conversion.
(Of course, you still have to convert between std:string and System.String if you use the first, but at least you can use all your conversion logic in the same project.)
This solution is simple, but the resulting DLL now requires the .NET runtime.