如何从C#调用C ++代码及其调用的代码

时间:2019-07-03 13:40:41

标签: c# c++ dll

TL; DR

我有遗留的c ++代码,可以执行填充(有时返回填充),调用其他cpp代码,但不是完整的类/ obj。我无法更改此代码。我正在制作新的C#代码,希望从中调用C ++代码。我不明白是创建一个调用原始旧版c ++的dll,还是创建CLR?这也称为旧版cpp。下面有我已实现的示例代码(有问题)。

主要

我有无法更改的legacy.cpp和legacy.h。

这不是类/对象,仅具有公共函数,值和#defines。 legacy.cpp和.h都#include其他文件和cpp库来完成其工作。

我有一个新项目,可以在其中添加C#,C ++代码

我无法理解要从我的新C#代码中调用legacy.cpp中定义的任何函数(或值/定义)需要做什么/研究。

我看过的一些内容包括

CLR

我目前正在尝试创建CLR(以为在这种情况下我不需要),但是clr_wrapper.cpp出现了问题,它找不到对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();
    };
}

foo_Wrapper()无法调用foo()。

我对此方法的困惑是,看起来我需要使clr包装器成为一个具有成员函数的对象类,该成员函数将根据需要被调用。导致语法为obj.foo()。如果我选择进行某种CLR包装,这是需要做的吗?

DLL

我还考虑过将其全部做成(How to call C++ DLL in C#)中的dll

但是我对此设置感到困惑。我目前的想法是让一个cpp dll调用原始cpp(即创建将对foo()进行调用的legacyDll.dll,然后我的主要c#将调用在extern“ C” {}中定义的__declspec(dllexport)函数。 >

当前设置(来自“如何在C Sharp中调用C dll”) 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 ^^
        }
    }
}

我不关注这部分。属性是什么以及为什么要按原样完成?

1 个答案:

答案 0 :(得分:0)

好的,因此您具有需要使用的标头和cpp。为了使用它,您必须将c ++转换为C代码。这几乎与您显示的DLL示例代码中看到的一样。但是,我确实建议您从标头中删除包含,因为我不确定这将如何转换为C代码。而是将include放入cpp文件中。

除了仅显示大量示例代码外,我很难回答这个问题。完整代码如下:https://github.com/ze413X/Cpp-Code-Gems/其中“ CSharpExampleUsingCpp”从MainWindow.xaml.cs调用,“ DLLExample”使用目录中的文件包括和源。

DLL:

公开要使用的功能的标头:

#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;
}

尽管,重新读取获取字符串的解决方案可能不是最好的方法。您可能会整理该东西以避免所有这些愚蠢的char *转换。当我写它的时候,我可能有一些很好的理由。谷歌应该更容易了。

相关问题