0

I'm force to expose some methods in a C# library so that they can be used from an external program written in C++ (VC++ 6.0). I thus created a mixed assembly which works quite ok so far but I have some troubles with a method that returns an array of .NET objects.

The .NET signature of the method is:

public Results[] Measure(String model, String identifier);

Where Results itself is:

public class Results
{
    public String[] ElementType;
    public bool[] HasError;
}

To provide entry point from C++, I started to write a C++/CLI wrapper method like this:

std::vector<ResultsWrapper> Measure(char* model, char* identifier)
{
    // Call .NET code
    String^ gcmodel = gcnew System::String(model);
    String^ gcidentifier = gcnew System::String(identifier);
    cli::array<Results^>^ gcres = myNetInstance->Measure(gcmodel, gcidentifier);

    // Convert results to C++ vector
    std::vector<ResultsWrapper> ret;
    for (int ki = 0; ki < res->Length; ki++)
    {
        ResultsWrapper r = ResultsWrapper(res[ki]->...., );
        ret.push_back(r);
    }

    return ret;
}

but I must admit I'm a bit lost, this is very long time I haven't wrote a single line of C++ and very long time I haven't deal with by hand memory management...

What is the best solution to create ResultsWrapper class so that there will be no much need to care for memory management from C++ side. Maybe something like the following ?

class ResultsWrapper
{
   public:
      ResultsWrapper(vector<std::String> elementType, vector<bool> hasError)
      {
         this.ElementType = elementType;
         this.HasError = hasError;
      }

   public:
     vector<std:String> ElementType;
     vector<bool> HasError; 
}

NB: I don't think team on VC++ 6.0 side are aware of boost library or share_ptr types (and I'm not very knowledgable about them either). All C++ code is very classic C++ code style, not even using stdlib.

CitizenInsane
  • 4,755
  • 1
  • 25
  • 56
  • I think you must serialize array first and next deserialize – pedrofernandes May 23 '16 at 17:28
  • @pho3nix You are right. At least if you ignore all the C++/CLI featuers and are ignorant what the language offers. Otherwise you are totally doing unnecessary things. GREAT programming. – TomTom May 23 '16 at 17:49
  • 2
    You cannot use std::vector, the compiler is far too old. Memory management is a problem as well for the same reason so allocating the array with *new* is not possible either. Use LocalAlloc() or SafeArrayCreate() to get somewhere. – Hans Passant May 23 '16 at 18:07
  • Yeah, for the exposure part FORGET C++ - your exports need to stick to either the standard C level function exports, OR you go "all the way" (quite easy with the .NET side) and make COM objects... COM goes back really way back. And COM is supported as export from .NET - BUT: you rather need to know what you do in COM... – TomTom May 24 '16 at 07:16
  • Thanks @TomTom ... yes COM was another way I thought of even if I fear that customer knows nothing about COM / .tlb, etc... still using VC++ 6.0 in 2016 :/ ... I have pushed so much to provide a simple .exe with results stored in files instead of an API but I'm not in the papers of those who decide for so crazy/useless/stupid/time-consuming backward support ;) – CitizenInsane May 24 '16 at 08:17

2 Answers2

0

I could not pass safely/easily STL types across dll boundaries so I get back to old char**, and manual allocation/deallocation and It Just Worked...

IJW for a while only ... then I tried to check for when throwing exception from .NET back to the calling C++ application and then patatra ... need conversion to native exceptions ... that again cannot safely cross dll boundaries ...

Mixed mode assemblies sounded appealing to go from .NET to native but was an IJS experience in my case... I give up and will go through COM instead.

CitizenInsane
  • 4,755
  • 1
  • 25
  • 56
-1

In C++/CLI I started to write a wrapper method like this:

No, you did not

public Results[] Measure(String model, String identifier);

has no resemblance in

std::vector Measure(char* model, char* identifier)

None.

There is no marshalling required in a C++/CLI reference class. Use String^ as pointer to string (instead of char*) and use array<ResultsWrapper>^ as pointer to a managed array.

There is no need to use a wrapper at all. Declare a class as managed reference (ref class) and you can call it from the .NET side because it is a .NET class.

halfer
  • 19,824
  • 17
  • 99
  • 186
TomTom
  • 61,059
  • 10
  • 88
  • 148
  • Yup. C++/CLI definitely deserves more love from MS - the docs are arcane, you get all the quirks of C++, the quirks of .NET, and quirky behavior resulting from trying to mix the two together. That's a recipe for a headache. But your're right on the RTFM part - 3/4 of the questions in this tag are about string marshaling :-\ – Lucas Trzesniewski May 23 '16 at 18:00
  • 3
    @TomTom The question that the OP asked was not "How do I use a C++/CLI class from C#", but instead "I need to expose some methods in a C# library so that they can be used from an external program written with VC++ 6.0." How exactly does your answer address any of that? – Chris Hannon May 23 '16 at 18:08