[英]How to call C++ code, and the code it calls, from C#
我有遗留的 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,如( 如何在 C# 中调用 C++ DLL )
但是我对设置这个感到困惑。 我目前的想法是让 cpp dll 调用原始 cpp(即创建 legacyDll.dll 它将调用 foo(),然后我的主 c# 将调用 extern "C" {} 中定义的 __declspec(dllexport) 函数
当前设置(来自“如何在 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/其中“CSharpExampleUsingCpp”从 MainWindow.xaml.cs 调用“DLLExample”,它使用目录包含和源中的文件。
动态链接库:
公开要使用的函数的标头:
#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* 转换。 在我写它的那个时候,我可能有一些很好的理由。 不过,谷歌应该更容易。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.