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

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

本文关键字:代码 调用      更新时间:2023-10-16

tl; dr

我有旧版C 代码可以做东西(有时会返回内容(,调用其他CPP代码,但不是完整的类/obj。这个代码我无法更改。我正在制作新的C#代码,我希望从中调用C 代码。我不明白是创建称为原始旧版C 的DLL,还是创建CLR?这也称为传统CPP。在下面,我拥有已实施的示例代码(有问题(。

MAIN

我有传统和遗产。

这不是类/对象,仅具有公共功能,值和#Defines。lagacy.cpp和.h均#include其他文件和CPP库可以完成工作。

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

我很难理解我需要做的/研究,以调用legacy.cpp(或从我的新C#代码中的值/定义(中定义的任何功能。

我看过的一些包括

  • 托管CLR包装器

    • https://drthitirat.wordpress.com/2013/06/03/use-c-codes-in-codes-in-c-project-wrapping-native-native-c-with-a-a-man-maned-clr-wrapper/
    • https://web.archive.org/web/20140806022309/http://blogs.msdn.com/b/borisj/archive/2006/09/28/28/769708.aspx
  • dlls ??
    • 如何在C#
    • 中调用C DLL
  • clr

    我目前已经尝试创建一个CLR(以为我觉得这不是我在这种情况下需要的(,但是我在clr_wrapper.cpp中遇到了问题,它找不到对foo((

    //Wrapper.cpp
    #include "Wrapper.h"
    #include "abspathtolegacycodelegacy.h"
    #include "abspathtolegacycodelegacy.cpp"
    int foo_Wrapper()
    {
        return foo(); //int foo() is declared in legacy.h and defined in legacy.cpp
    }
    
    #pragma once
    #include "abspathtolegacycodelegacy.h"
    #include "abspathtolegacycodelegacy.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

    我还考虑使所有dll都喜欢(如何在C#中调用C DLL(

    但是,我对设置这个问题感到困惑。我目前的想法是让CPP DLL调用原始CPP(即创建Legacydll.dll,它将调用FOO((,然后我的主C#将调用__declspec(dllexport(函数,在extern" c" {}

    当前设置(从"如何在c尖锐中调用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 ^^
            }
        }
    }
    

    我不遵循这部分。属性是什么以及为什么按照其方式完成的?

    好吧,因此您需要使用一个标题和CPP。为了使用它,您必须将C 变成C代码。这几乎是您在显示的DLL示例代码中看到的。但是,我确实建议您从标题中删除包含的内容,因为我不确定如何转化为C代码。将包含在CPP文件中。

    我发现除了显示一大堆示例代码外,很难回答这个问题。完整代码在:https://github.com/ze413x/cpp-code-gems/其中,其中" csharpexamplescpp"呼叫来自mainwindow.xaml.cs的" csharpexlamecpp"呼叫" dllex amplame",该" dllex amplame"使用目录中的文件包含和源。

    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.";
        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;
    }
    

    尽管重读我获得字符串的解决方案可能不是最好的方法。您可能会围攻那件事,以避免所有这些愚蠢的chr*转换。当时我写它时,我可能有一些充分的理由。对于Google来说应该容易得多。