C# 使用 CLI 包装器调用非托管 C++
Posted
技术标签:
【中文标题】C# 使用 CLI 包装器调用非托管 C++【英文标题】:C# calling unmanaged C++ using CLI wrapper 【发布时间】:2020-11-18 15:50:17 【问题描述】:我一直在阅读此处的多个示例以及有关如何完成此操作的其他来源。最近,我关注了这个在多个其他类似问题中已链接到的具体示例。
https://dorodnic.com/blog/2014/12/10/calling-cpp-by-example/
但是,即使直接从 github 导入此项目,它仍然会在 C# 项目中出现错误,无法引用 C++ CLI 代码。 “找不到类型或命名空间(您是否缺少 using 指令或程序集引用)”。这是我在自己遵循其他示例时发现的相同错误。谁能向我解释为什么这会失败和/或建议修复它的步骤?
编辑:在此处添加代码以节省时间。
//Logic.h
#pragma once
namespace MeaningOfLife
namespace Cpp
// This is our native implementation
// It's marked with __declspec(dllexport)
// to be visible from outside the DLL boundaries
class __declspec(dllexport) Logic
public:
int Get() const; // That's where our code goes
;
//Logic.cpp
#include "Logic.h"
int MeaningOfLife::Cpp::Logic::Get() const
return 42; // Really, what else did you expect?
//Logic.h CLI
#pragma once
namespace MeaningOfLife
namespace Cpp
// First a Forward Declaration to Cpp::Logic class:
class Logic; // This allows us to mention it in this header file
// without actually including the native version of Logic.h
namespace CLI
// Next is the managed wrapper of Logic:
public ref class Logic
public:
// Managed wrappers are generally less concerned
// with copy constructors and operators, since .NET will
// not call them most of the time.
// The methods that do actually matter are:
// The constructor, the "destructor" and the finalizer
Logic();
~Logic();
!Logic();
int Get();
void Destroy();
static void InitializeLibrary(System::String^ path);
private:
// Pointer to our implementation
Cpp::Logic* _impl;
;
//Logic.cpp CLI
#include "Logic.h"
#include "..\MeaningOfLife.Cpp\Logic.h"
#include <string>
#include <Windows.h>
using namespace std;
MeaningOfLife::Cpp::CLI::Logic::Logic()
: _impl(new Cpp::Logic())
// Allocate some memory for the native implementation
int MeaningOfLife::Cpp::CLI::Logic::Get()
return _impl->Get(); // Call native Get
void MeaningOfLife::Cpp::CLI::Logic::Destroy()
if (_impl != nullptr)
delete _impl;
_impl = nullptr;
MeaningOfLife::Cpp::CLI::Logic::~Logic()
// C++ CLI compiler will automaticly make all ref classes implement IDisposable.
// The default implementation will invoke this method + call GC.SuspendFinalize.
Destroy(); // Clean-up any native resources
MeaningOfLife::Cpp::CLI::Logic::!Logic()
// This is the finalizer
// It's essentially a fail-safe, and will get called
// in case Logic was not used inside a using block.
Destroy(); // Clean-up any native resources
string ManagedStringToStdString(System::String^ str)
cli::array<unsigned char>^ bytes = System::Text::Encoding::ASCII->GetBytes(str);
pin_ptr<unsigned char> pinned = &bytes[0];
std::string nativeString((char*)pinned, bytes->Length);
return nativeString;
void MeaningOfLife::Cpp::CLI::Logic::InitializeLibrary(System::String^ path)
string nativePath = ManagedStringToStdString(path);
LoadLibrary(nativePath.c_str()); // Actually load the delayed library from specific location
//C#
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace MeaningOfLife.WPF
using Cpp.CLI;
using Microsoft.Win32;
public partial class MainWindow : Window
public MainWindow()
InitializeComponent();
private void Button_Click(object sender, RoutedEventArgs e)
var fileOpenDialog = new OpenFileDialog
CheckFileExists = true,
Filter = "Native Library|MeaningOfLife.Cpp.dll",
InitialDirectory = Environment.CurrentDirectory
;
var result = fileOpenDialog.ShowDialog(this);
if (result.HasValue && result.Value)
Logic.InitializeLibrary(fileOpenDialog.FileName);
using (var wrapper = new Logic())
MessageBox.Show("The answer is " + wrapper.Get());
错误发生在使用 Cpp.CLI 时,然后在调用 Logic 时发生。
作为跟进,我也尝试了这个示例,并在代码的可比较位置收到了相同的错误。
https://www.red-gate.com/simple-talk/dotnet/net-development/creating-ccli-wrapper/
【问题讨论】:
您的 CLI 包装类将输出您需要在托管 C# 类中引用的程序集。根据错误,您似乎没有引用程序集。 对,我认为我做得对。我会用一些代码更新它以节省时间。谢谢。 您缺少 using 指令或程序集引用。前者是该网页最明显的原因,MainWindow.cs 缺少让编译器识别 Logic 类所需的 using 指令。它需要using MeaningOfLife.Cpp.CLI;
才能正确编译。或者其他方式,拼写全名:var wrapper = new MeaningOfLife.Cpp.CLI.Logic()
MeaningOfLife 只给了我MeaningOfLife.WPF
的选项。 MeaningOfLife.Cpp
无法识别。 C# 有 CLI 作为参考,我认为这会更正,但情况似乎并非如此。
您可能会更轻松地使用#pragma unmanaged
,而不是为 cpp/cli 类使用两个单独的程序集:docs.microsoft.com/en-us/cpp/preprocessor/…
【参考方案1】:
这已通过以下方式解决: A) 删除并添加回应用程序的 WPF 部分 B) 将 CLI 引用的“复制本地”属性设置为 true。
我之所以遵循这些示例,是因为缺乏相关知识,因此想进一步了解这个过程。我不认为这是真正的答案,但它确实解决了我的直接问题。
【讨论】:
以上是关于C# 使用 CLI 包装器调用非托管 C++的主要内容,如果未能解决你的问题,请参考以下文章