如何从 C# 访问 C++/CLI 中的类?

Posted

技术标签:

【中文标题】如何从 C# 访问 C++/CLI 中的类?【英文标题】:How to access class in C++/CLI from C#? 【发布时间】:2013-10-10 10:13:07 【问题描述】:

我正在用 C# 编写一个 GUI 工具来解析和显示另一个用 C 编写的程序的数据输出。为了解析数据,我需要知道在许多 C 头文件中指定的数据结构。因此,我需要将这些 C 头文件合并到我的 C# 项目中。我的问题是:

1) 经过一番研究,我得出结论,最好的方法是在我的解决方案中创建一个新的 C++/CLI 项目,将 C 头文件导入这个新项目,编写一些充当瘦包装器的 C++/CLI 类对于 C 头文件中定义的数据结构,请从 C# 代码中引用 C++/CLI 包装类。这是最好的方法,还是有更好的方法?

2) 我遇到了参考问题。这是我的简化代码来说明问题:

C++/CLI 项目中的原始 C 头文件

#define ABC  0x12345

C++/CLI 项目中的包装类

#include "my_c_header.h"

namespace C_Wrappers 
    public ref class MyWrapper 
        public:
            property unsigned int C_ABC 
                unsigned int get()  return ABC; 
            
    
 

C#项目中的用户类

using C_Wrappers;
using System;

namespace DataViewer 
    public partial class MainForm : Form 
        private  MyWrapper myWrapper = new MyWrapper();
        public MainForm() 
            Console.WriteLine(myWrapper.C_ABC.ToString());
        
    
 

在 C# 项目中,我添加了对 C++/CLI 项目的引用(使用右键单击 > 添加引用)。在构建期间,我在 C# 项目中遇到错误:“找不到类型或命名空间 'C_Wrappers'(您是否缺少 using 指令或程序集引用?)。”

我以为我做了我应该做的一切。我应该怎么做才能修复这个错误?

【问题讨论】:

您是否确保首先编译 C++/CLI 项目(如在 C# 项目之前编译)?如果 C# 先编译并且没有为 CLI 项目生成 dll,它会这样说。 C++/CLI 命名空间是否在另一个命名空间中?使用对象浏览器进行查看。 你是否也在这两个项目之间放置了一个“项目依赖”...... @HansPassant C++/CLI项目中只有一个命名空间,如图所示。 @alexbuisson - 我检查了,C# 项目依赖于 C++/CLI 项目 【参考方案1】:

在我自己的解决方案中,我有 4 个项目:

    C++ 项目和测试代码 C++ DLL 项目,它只使用动态链接从第一个项目源中编译出 DLL 包装器项目,它只是一个使用 C++/CLI 的适配器,它包装了原始 C++ C# WPF 项目,这是我的图形界面。

这是我对上面提供的链接的翻译。

C++ DLL 项目

将您的 C++ 代码转换为 DLL 库。

    在 Visual Studio 中,转到 文件 > 新建 > 项目,从 Visual C++ 选项卡中选择 Win32 项目。 为项目和解决方案选择一个名称,解决方案将包含所有项目。 在 Win32 应用程序助手中,点击下一步,勾选DLL框,然后选择Empty project,然后点击Finish强>。

要添加的代码

这是我的 dll 的 C++ 头文件(减去很多东西)。

令牌.h

#pragma once
#define DLLEXP   __declspec( dllexport )

DLLEXP void pop_back(std::string& str);

DLLEXP std::string testReturnString();

DLLEXP int getRandomNumber();

CPP 内部没有什么可改变的。

构建项目,您应该有一个 DLL 和一个 LIB 文件以包含在 C# 项目调试目录中。

C++/CLI 包装器

此项目用作上一个项目的本机代码与 GUI 的托管代码之间的接口。

    向解决方案添加一个新项目(Visual C++ 中的类库)(在本例中称为“Wrapper”) 使用附加的包含目录添加本机项目的路径 添加原生项目作为新项目的参考(右右键单击 > 参考... > 添加新链接) 在 Properties > Linker > Input 中,将本机 dll 的名称放在延迟加载 DLL(本例中为 Computations.dll)字段中

C++/CLI 代码

我的包装器只是一个看起来像这样的类(减去我自己的代码)。

包装器.h

#include "Token.h" // include your C++ header

#include <string>
#include <iostream>

namespace Wrapper 

    // noticed the ref?
    public ref class TokenAnalyzer
    

    public:
        TokenAnalyzer()
        ;

        void Init();
            // use the C++/CLI type, like String^ (handles)
        System::String^ ProcessLine(int lineNbr, System::String^ line);
    ;

CPP 中没有什么特别之处,只是您必须包含 #include "stdafx.h"

它还应该构建到一个 DLL 中,您将把它包含在 C# 调试目录中。

只是我在 SO 某处找到的一个有用功能,但不记得您可能需要的位置。它将 C++/CLI 字符串句柄转换为 C++ 标准字符串。

std::string MarshalString (String ^ s) 
        using namespace Runtime::InteropServices;
        const char* chars = 
            (const char*)(Marshal::StringToHGlobalAnsi(s)).ToPointer();
        std::string os = chars;
        Marshal::FreeHGlobal(IntPtr((void*)chars));
        return os;
    

C# 项目

向解决方案添加一个新项目(C# Windows FormWPF 或任何你想要的!)并将其设置为启动项目(right-点击 > 设置为启动项目)。

    添加 C++/CLI 项目作为新项目的参考 以源代码形式添加指令using Wrapper;

像这样使用它:

/// Store the C++/CLI Wrapper object.</summary>
private Wrapper.TokenAnalyzer mTokenAnalyzer = new TokenAnalyzer();

2016/05/06 更新

Ashwin 花时间制作了sample project 和blog post tutorial,这可能会有所帮助。

【讨论】:

由于某种原因我的公司阻止了您的链接:( 我正在我的答案中写一个小教程,不会很长! 瞧!我希望这应该能让你开始。 哇,感谢您花时间写这么多。但不幸的是,它对我帮助不大。首先,我不需要做一个本地 DLL 项目,因为除了一堆可以直接放入 C++/CLI 项目的 C 头文件之外,我没有本地代码。其次,创建了从 C# 项目到 C++/CLI 项目的引用,并且依赖项正确(C++/CLI 项目在 C# 项目之前构建)并且 C++/CLI DLL 已成功创建,但 C# 代码无法引用 C++/CLI 中的任何类(错误表示 C++/CLI 中的命名空间不存在或找不到)。如何解决这个问题? 谢谢,我已编辑我的答案以指向您的示例项目。【参考方案2】:

对我来说,this 类似问题的答案解决了 C# 中的相同错误。

(即我的 C++\CLI 项目中有一个包装头文件,但也忘记包含一个 .cpp 文件(即使它只有两行:#include "stdafx.h" 和 #include " Wrapper.h"))

【讨论】:

以上是关于如何从 C# 访问 C++/CLI 中的类?的主要内容,如果未能解决你的问题,请参考以下文章

从 c# 访问 C++ .lib 库

如何通过 C++-CLI 回调和委托将字符串从 C++-CLI 传递到 C#

怎样创建C++/CLI程序

在 C++ 应用程序的另一个目录中使用 C# 库

如何从我的 C++/CLI 代码进入非托管 C++ 库

创建要在 C# 中使用的托管 C++ 接口