简体   繁体   中英

How to call C++ code, and the code it calls, from C#

TL;DR

I have legacy c++ code which does stuff (sometimes returns stuff), calls other cpp code, but is not a full class/obj. This code I cannot alter. I am making fresh c# code which I am looking to call the c++ code from. I don't understand whether to create a dll that calls the original legacy c++, or create a CLR?? which also calls the legacy cpp. Below I have example code that I have implemented (with problems).

Main

I have legacy.cpp and legacy.h which I can not alter.

This is not a class/object and only has public functions, values, and #defines. legacy.cpp and .h both #include other files and cpp libraries to do its job.

I have a new project where I can add C#, C++ code

I am having trouble understanding what I need to do/research in order to call any of the functions defined in legacy.cpp (or the values/defines) from within my new C# code.

Some of what I have looked at include

CLR

I have currently tried to create a CLR (thought I feel like it is not what I need in this situation), but I had problems in the clr_wrapper.cpp, it could not find the reference to foo()

//Wrapper.cpp

#include "Wrapper.h"

#include "abs\path\to\legacy\code\legacy.h"
#include "abs\path\to\legacy\code\legacy.cpp"

int foo_Wrapper()
{
    return foo(); //int foo() is declared in legacy.h and defined in legacy.cpp
}
#pragma once

#include "abs\path\to\legacy\code\legacy.h"
#include "abs\path\to\legacy\code\legacy.cpp"

using namespace System; //What things use this? 
                        //Can I just prepend System:: to whatever needs it?
namespace Wrapper {
    public ref class Wrapper
    {
    public:
        int foo_Wrapper();
    };
}

the foo_Wrapper() is not able to call foo().

My confusion with this method is that it looks like I would need to make the clr wrapper an object class with member functions that will be called as needed. Leading to a syntax of obj.foo() . Is this what needs to be done if I chose to do some sort of CLR wrapper?

DLL

I have also looked at making this all a dll like in ( How to call C++ DLL in C# )

However I am confused on setting this up. My current idea is to have a cpp dll call the original cpp (ie create legacyDll.dll which would make calls to foo(), then my main c# would call the __declspec(dllexport) functions defined within extern "C" {}

current setup (from "How to call c dll in c sharp") dllmain.cpp

// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include <iostream>
#include <Windows.h>

using namespace std;

extern "C"
{
    __declspec(dllexport) void bar_Dll()
    {
        cout << "calling bar() in legacy code" << endl;
    }

    __declspec(dllexport) int foo_Dll()
    {
        cout << "calling foo() in legacy code" << endl;
        //realistically I would have,
        //return foo()
    }
}

Class1.cs

using System;
using System.Runtime.InteropServices;

namespace Test_DLL_Calling
{
    class Class1
    {
        [DllImport("dllmain.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern void bar_Dll();

        [DllImport("dllmain.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern int foo_Dll();

        public static void Main(string[] arg)
        {
            bar_Dll(); //The specified module could not be found (Exception)

            Console.WriteLine(foo_Dll()); //Im guessing this will also ^^
        }
    }
}

This part I don't follow. What and why are the attributes done the way they are?

Alright, so you have a header and cpp which you need to use. In order to use it you have to have make the c++ into C code. This is pretty much what you see in the DLL example code that you showed. However, I do suggest that you remove the includes from the header as I'm unsure how that would translate to the C code. Put the includes in the cpp files instead.

I find it rather difficult to answer this questions other than just showing a whole bunch of example code. Full code in: https://github.com/ze413X/Cpp-Code-Gems/ Where "CSharpExampleUsingCpp" calls from MainWindow.xaml.cs the "DLLExample" which uses the file in the directory includes and source.

DLL:

The header which is exposing functions to be used:

#pragma once

#define DLLExport _declspec(dllexport)

extern "C" DLLExport void __cdecl GetCppText(char* str, int* strLength);

extern "C" DLLExport void __cdecl DLLPrint();

.cpp

#include "../includes/DLLExampleCode.h"

#include <string>
#include <iostream>

void __cdecl GetCppText(char* str, int* strLength)
{
    std::string text = "This is called from within the DLL.\0";
    if (*strLength < text.length() || str == nullptr)
    {
        return;
    }
    memset((void*)str, 0, (*strLength) * sizeof(char));
    strcpy_s(str, *strLength,text.c_str());
    *strLength = text.length();
}

void __cdecl DLLPrint()
{
    std::cout << "This is printed from inside DLLExample.dll.\n";
}

C#:

using System.Runtime.InteropServices;

namespace CSharpExampleUsingCpp
{
    public partial class MainWindow : Window
    {
const string PATH = "DLLExample.dll";

[DllImport(PATH, CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern void GetCppText(byte[] str, out System.Int32 strLength);

....

private void CppInteropButton_Click(object sender, RoutedEventArgs e)
        {
            System.Int32 size = 256;
            System.Byte[] str = new byte[size];
            for (int i = 0; i < size; i++)
            {
                str[i] = (byte)'1';
            }

            GetCppText(str, out size);
            string result = System.Text.Encoding.UTF8.GetString(str, 0, size);
            CppInteropButtonTextBox.Text = result;
}

Although, rereading my solution of obtaining a string might not be the best way of doing it. You could probably marshal that thing to avoid all this stupid char* conversions. I probably had some good reason at that point in time when I wrote it. That should be much easier to google though.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM