Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

correctly convert C++ long to C# int

Tags:

I'm currently working on a .NET Framework 4.7.2 application using a business logic library written in unmanaged C++. I need to use unmanaged C++.

I need to use the logic from the C++ project, unfortunately I cannot correctly convert the input or output parameters of my program.

When I input 42, and simply want to return that value, I get 17582022 as a result. Which should actually be 42.

My C++ code looks like that:

MYCore header file:

#ifdef MYCORE_EXPORTS
#define MYCORE_API __declspec(dllexport)
#endif

#pragma once
#include <string>

using namespace std;

extern "C"
{
    class MYCORE_API TestClass
    {
    private:
        string name;
    public:
        TestClass(char*);
        long Iterate(long &n);
    };

    MYCORE_API TestClass* TestClass_Create(char* name);
}

MYCore source file:

#include "stdafx.h"

#include "MYCore.h"

TestClass::TestClass(char* n) 
{
    name = n;
}

long TestClass::Iterate(long &n) 
{
    return n;
}

extern "C"
{
    MYCORE_API TestClass * TestClass_Create(char* name)
    {
        return new TestClass(name);
    }
}

I'm using a .NET 4.7.2 Framework Interface project to export the C++ library functionality:

namespace MYCore.Interface
{
    public static class MYProxy
    {
        private const string coreDLL = "my.core.dll";

        [DllImport(coreDLL, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr TestClass_Create(string name);

        [DllImport(coreDLL, EntryPoint = "?Iterate@TestClass@@XXXXX@X", CallingConvention = CallingConvention.ThisCall)]
        public static extern int Iterate(int n);
    }
}

In my actual application I further import the dll and use the logic like that:

public static void Initialize()
{
    var test = MYProxy.WrapperIterator_Create("test");

    var result = MYProxy.Iterate(42); // as a result I'm getting sth. like 17582022 instead of 42   
}

Do you know how to correctly convert an int input from C# to C++ and vice versa?

Thank you!

like image 781
accordo777 Avatar asked Jan 07 '19 09:01

accordo777


2 Answers

What you're doing in C# does not work in C++ either:

auto result = Iterate(42l);

results in the compiler error

Cannot convert argument 1 from 'long' to 'long &'

I see two solutions:

a) Change the C++ code

long TestClass::Iterate(long n)

(without the reference)

b) Change the C# code

static extern int Iterate(ref int n);

(pass a reference) and call it like

int n = 42;
Console.WriteLine(Iterate(ref n));
like image 131
Thomas Weller Avatar answered Nov 07 '22 23:11

Thomas Weller


The problem is actually called "Marshal an unmanaged C++ Class to C#".

In my Proxy class I created a method to call an actual instance method:

[DllImport(coreDLL, EntryPoint = "?Iterate@TestClass@@XXX@X", CallingConvention = CallingConvention.ThisCall)]
public static extern int CallIterate(IntPtr instance, int n);

and the method in my C++ looks like that:

MYCORE_API int CallIterate(TestClass * instance, int n)
{
    if (instance!= NULL) 
    {
        return instance->Iterate(n);
    }
}

For further reading on how to marshal unmanaged C++ classes, I can suggest the following article:

https://www.codeproject.com/Articles/18032/How-to-Marshal-a-C-Class

My solution works fine now. Thanks for all the good input!

like image 21
accordo777 Avatar answered Nov 08 '22 00:11

accordo777