4

I'm calling C++ method from C# code. Everything works fine except returning multiple parameters back to C#.

In my case those parameters are: int x, y, width, height;

What I want to do is to return a class or struct from c++ code to c#.

I have provided an example so it would be much more clear what is on my mind. I know that one way to go is to use Marshal class, maybe the only way.

C# code

public class ImageMatch
{
    //method that is used to call pass string parameters and call c++ method
    [System.Runtime.InteropServices.DllImport("ImageComputingWrapper.dll", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)]
    static extern ImageComputingWrapper.ImageParams ComputeImage(string imgPath, string templPath);

    public  GetImgParams(string imgPath, string templPath)
    {
        //a class from C++ code
        ImageComputingWrapper.ImageParams imgParams;
        //retreive all the data
        imgParams = ComputeImage(imgPath, templPath);
    }
}

C++ code

//ImageComputingWrapper.cpp
extern "C" __declspec(dllexport) ImageComputingWrapper::ImageParams ComputeImage(const char* imgPath, const char* templPath)
{
    computeImage* compImage = new computeImage(imgPath, templPath);
    ImageComputingWrapper::ImageParams imageParams;

    imageParams.x = compImage->x;
    imageParams.y = compImage->y;
    imageParams.width = compImage->width;
    imageParams.height = compImage->height;

    return imageParams;
}

//ImageComputingWrapper.h
//class to return back to c#
public ref class ImageParams
{
    public:
        ImageParams(){}
        int x;
        int y;
        int width;
        int height;
};

I do know that it is not possible to return class from C++ code to C# as it's in this example. It is just to easily understand what I meant.

One thing to point out, I am a C# programmer so there may be something wrong in that C++ code (pointers).

2
  • possible duplicate stackoverflow.com/questions/315051/… Commented Feb 2, 2015 at 20:33
  • 1
    That's a System::Drawing::Rectangle. The point of using C++/CLI is to not have to use [DllImport] in your C# program. Simply add a reference to your C++/CLI project. You'll only see ImageParams now, you already know how to write a real ImageComputingWrapper Commented Feb 2, 2015 at 21:04

1 Answer 1

5

You cannot return a ref class using p/invoke. What you can do is declare a ref class in your C++/CLI assembly and simply consume that from C#.

First of all you need a C++/CLI class library. For instance:

// ClassLibrary1.h

#pragma once

using namespace System;

namespace ClassLibrary1 
{
    public ref class Class1
    {
    public:
        int x;
        int y;
        int width;
        int height;
    public:
        Class1() : x(42), y(666), width(24), height(13) {}
    };
}

You can then consume this class library like any other managed assembly:

using System;
using ClassLibrary1;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Class1 instance = new Class1();
            Console.WriteLine(instance.x);
            Console.WriteLine(instance.y);
            Console.WriteLine(instance.width);
            Console.WriteLine(instance.height);
        }
    }
}

And that's all there is to it.


You ask in comments how to pass string arguments to the C++/CLI code. Use System::String^ on the C++/CLI side. That's the C++/CLI way of referring to the .net string type. So your constructor might become:

public ref class Class1
{
....
public:
    Class1(System::String^ imgPath, System::String^ tempPath)
    {
        ....
    }
};

On the C# side you would create the instance like this:

string imgPath = "...";
string tempPath = "...";
Class1 instance = new Class1(imgPath, tempPath);
Sign up to request clarification or add additional context in comments.

4 Comments

Yes this is really nice solution +1 @David Heffernan. But one reason why I'didn't chose the class constructor is because I couldn't figure out how to pass string parameters imgPath and templPath from c# to c++. The only way that I found was using dllimport. I should highligh this issue more.
In C++/CLI use System::String^, in C# use string. Both of those refer to the same type, the .net string type. I'll show you in an update.
You are dam right man! I always like to make things more complicated than they are, But I searched for this some time and couldn't find. Maybe this post will help someone else to not do the same mistake that I did.
Thanks. Sometimes it is hard to see the wood for the trees!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.