0
votes

I am creating a C++/CLI DLL which should be used as a wrapper. The purpose of it, is to wrap a C# SDK and present functions to native C++ Code. I always get errors that I am mixing types and my using statements in the managed classes are marked red, so here is what I have so far:

#pragma once

#include <iostream>
#include <memory>
#include <string>

namespace TPInterface
{
class ITPFactory
{
public:
  static __declspec(dllexport) std::shared_ptr<ITPFactory> CreateTPFactory();
};
}

Which creates a instance of TPFactory.

#pragma once

#include "ITPSSITotalStation.h"
#include "TPSSITotalStation.h"
#include "ITPFactory.h"
#include <iostream>
#include <memory>
#include <string>

namespace TPInterface
{
class TPFactory : public ITPFactory
{
public:
  static std::shared_ptr<SensorSoftwareInterface::TotalStation::ITPSSITotalStation> CreateTPSSITotalStation(std::string pathToDriver);
};
}

And this creates a TPSSITotalStation object that is a ITPSSITotalStation interface.

TPSSITotalStation -> TPSSIBase -> TPBase

both TPSSIBase and TPBase contain classes (gcroot and header) which are written in managed code (ref classes).

Now the compiler tells me, that those ref classes are mixed, not allowed and so on. I don't get the problem here... What am I doing wrong?

Sorry for being dumb, I am a complete newbie to C++, comin from C#.

Errors:

Error   7   error C4368: cannot define 'm_selectedPath' as a member of managed 'TPInterface::Driver': mixed types are not supported

Error   8   error C4368: cannot define 'm_assemblyNameAndVersion' as a member of managed 'TPInterface::Driver': mixed types are not supported   

Error   9   error C2678: binary '=' : no operator found which takes a left-hand operand of type 'std::string' (or there is no acceptable conversion)    

Error   28  error C3265: cannot declare a managed '_Ptr' in an unmanaged 'std::tr1::_Ptr_base<_Ty>'

Error   51  error C3699: '*' : cannot use this indirection on type 'TPInterface::Sensor'    

Error   65  error C3642: 'TPInterface::Sensor msclr::gcroot<T>::operator ->(void) const' : cannot call a function with __clrcall calling convention from native code

Small example for understanding purpose:

ref class Driver // Contains errors in using (C#) statements
{
  // Does something managed
    private:
  std::string m_selectedPath;
  std::string m_assemblyNameAndVersion;
}
ref class Sensor // Contains errors in using (C#) statements
{
  // Does something managed
}

class TPBase
{
  // includes Driver class and holds it also inside msclr::gcroot<Driver^> 
}
class TPSSIBase : TPBase
{
  // includes Sensor and Driver class and holds sensor also inside msclr::gcroot<Sensor^> 
}
class TPSSITotalStation : TPSSIBase, public ITPSSITotalStation
{
  // contains functions which should be exported to native C++ 
}

The rest is already stated above.

2
"Now the compiler tells me, that those ref classes are mixed, not allowed and so on." - Please do share the actual error message!hlt
I thought it might be missleading, because those error messages contain names of classes/types and so on which I did not show. Either way, I will add error messages.Anon
__declspec(dllexport) - That's not how you do c++/CLIMickyD
"[T]hose error messages contain names of classes/types and so on which I did not show." Try creating a minimal reproducible example and showing the error messages of that insteadhlt
@hlt I tried. Sorry that I cannot express myself good enough.. I lack a lot of C++ knowledge.Anon

2 Answers

7
votes
  1. You can't derive an unmanaged class from a managed class.
  2. You can't derive a managed class from an unmanaged class.
  3. You can't add managed members to umanaged classes
  4. You can't add unmanaged data members (except pointers) to a managed class.
  5. In an unmanaged class you may write functions that return managed types.
  6. In a managed class you can only form functions that use the allowed managed types.

So what to do, to create a wrapper:

  1. Create a unmanaged class that contain gcroot<..> pointer/objects for all managed objects you need to create create and hold. Look in the documentation for gcroot<..> template.
  2. In the managed class you are free to hold pointers to the unmanaged world.

As long as you use gcroot and normal pointers you can easily access the .NET world from the unmanaged world and vice versa.

3
votes

Because std::string is an unmanaged type but ref class Driver is a managed class, you cannot define a field with unmanaged type inside a managed class.

If you want to define a string field, use System.String^ instead.