「C++学习笔记」面向.Net Core的(C++)CLR类库非专业入门(+使用Opencv)

关键词:C++/CLR, .Net Core, .Net Famework, Opencv, C#

目录

什么是CLR类库

本文说明

创建Demo程序

调用dll

通过项目引用

通过dll文件引用

其他还没完全清楚的坑:


有关C++/CLI这块的资料真的很少而且都属于翻墙教程(新手找不到门的,和进了门才能懂的)

参考其他资料,以及微软官方说明,以及新建项目时的项目模板说明:

扫描二维码关注公众号,回复: 10111272 查看本文章

什么是CLR类库

简单的说:

CLR类库,是C++语言的一种扩充,目的是面向C#(.NET)的,

一方面,可以在C++中调用.Net中的方法,让很多原本在C++上很痛苦的工作变简单,并扩大C++的战斗范围。

另一方面,让类库的接口变得.Net友好化,不用每个方法都[dllimport……]了。

抓重点:面向.Net的,带有.Net扩展的C++项目

一定注意,它归根结底是C++项目,我一开始总是会想歪了(总觉得是C#中能使用C++)

------------------------------------------------------------------------

网上有很多这方面的讲解,都比较旧了(那会叫C++/CLI)

其实写这篇文展的几个月之前,VS2019创建项目时,也还是叫“C++/CLI”的,应该时最近才改了名字吧。

大概需要先了解下托管和非托管的区别。原本的C++项目一般都是非托管的代码,而C#是托管代码。

C++/CLI就像一种胶水,或者说桥梁一样,让这两种代码相连

所以也就能看到在同一文件中,"using namespace xx"和"#include <xx.h>"齐飞,"std::cout"和"Console::WriteLine"并存的壮观景象。看起来着实木乱。

本文说明

首先这是一个个人向非专业的入门Demo说明。

需求是这样的,按照原本的方式,我们创建一个C++的dll,在C#中调用的时候,每个方法都需要"[DllImport ....]"先在dll中找到方法,再赋给一个函数指针。具体可以参考我之前的博客:「C++学习笔记」动态链接库(Dll):C++动/静态调用C++的dll

真的是超级头疼,所以有没有一种办法能减缓这种痛苦呢

我找到了C++/CLI

此时我需要C++&OpenCV做一些图像处理相关的工作,封装成dll供.Net Core使用

如果仅仅是.Net Framework平台,可以直接使用OpencvSharp:「图像处理」OpenCV在C#中使用基础(OpenCVSharp)

OpenCV + .Net Core怎么办呢?

于是找到了这个

创建Demo程序

在VS2019新建项目中,搜索CLI或者CLR,找到这个项目模板

输入名称,以我这次【OpcvDllToNetCore】为例:

创建好后会得到如下项目结构(皆有VS自动生成):

像通常一样的方式配置opencv,参考:「图像处理」OpenCV的安装与配置

在【OpcvDllToNetCore.h】中,编写如下代码:

#pragma once

//以下代码使用非托管(opencv是非托管的)
#pragma unmanaged
//取消_M_CEE定义,否则会报很多 不兼容的错误
#undef _M_CEE
#include <opencv2/opencv.hpp>
//opencv包含完了之后,再恢复_M_CEE的定义以及托管声明
#define _M_CEE
#pragma managed

//带上命名空间
namespace OpcvDllToNetCore 
{
	public ref class Opcv
	{
		
	public:
		//调用opencv显示一张图像
		void showImg()
		{
			cv::Mat img = cv::imread("D:\\Demo\\1000\\0001.jpg", cv::IMREAD_COLOR);
			cv::namedWindow("show", cv::WINDOW_NORMAL);
			cv::imshow("show", img);
			cv::waitKey(0);
		}
	};
}

这里说明

1、#pragma unmanaged和#pragma managed

即该行以后按所声明方式编译,即#pragma unmanaged下面的按非托管,#pragma managed按照托管方式

2、#undef _M_CEE 和 #define _M_CEE

这一点不是特别清楚,貌似和windows sdk相关,因为如果不加这一句,会有很多如下报错

“链接规范与前面的xxx不兼容”

这些报错都是windows 10 sdk中的,定位进去就能看到

为了解决这些错误,我把opencv.h的包含放在了_M_CEE定义之外(见前面代码),目前未见其他异常。

然后编译就会生成dll文件。

调用dll

通过项目引用

再添加一个C# 的控制台项目,起名【ConsoleDebug】,注意,这是一个C#项目了

在依赖项中,添加引用,选择前面的【OpcvDllToNetCore】项目。

接着在主函数中引用命名空间,并编写简单调用代码:

using OpcvDllToNetCore;

namespace ConsoleDebug
{
    class Program
    {
        static void Main(string[] args)
        {
            Opcv opcv = new Opcv();
            opcv.showImg();
        }
    }
}

编译运行,会报一些错误,因为缺少opencv的dll,复制到生成的exe的同目录下就好了。

通过dll文件引用

引用项目比较傻瓜式,适合个人开发,多人开发这种可能不方便,一般都是一个人负责dll开发,另一个人使用。

其实方法很简单,把生成的dll复制过来,然后在C#的项目依赖中添加这个dll就好,添加完之后就像使用C#类库一样,引用命名空间,就可以直接使用了,代码和上面的一样。

但是运行起来后报错了,这里有一点要注意!

复制dll过来时,一个时生成的主dll,另一个是所依赖的第三方dll,比如我的opencv_world420.dll,还有个容易被忽略的,就是【Ijwhost.dll】,这个文件是CLR类库生成时一并产生的,从修改时间上看,貌似是一个早就存在的东西,没有这个,就没法正确加载。(其实去研究“引用项目”方式的话可以看到,VS会自动复制这个到exe同目录下的)

其他还没完全清楚的坑:

还遇到了一些坑,但是也稀里糊涂解决的,记录一下,方便有遇到相同问题的

1、总是出现“无法解析的外部命令/符号”

这种一般都是lib没加载对,opencv我习惯用单独的属性配置文件来配置,但是确实写对的,右键项目名,点击属性,重写配一遍就好了,但是再删掉这些,也莫名其妙还是好的,无法理解。

2、总是“试图加载格式不正确的文件”

一般是加的dll依赖的其他dll不全,把前文说的都复制全了,还是会报,删掉重编译,把类库生成的其他文件,包括.pdb、config.json等,一股脑全复制过来就好了,接着再删掉.pdb、.runtimeconfig.json、.deps.json之后,也还是正常的,不是很理解

发布了21 篇原创文章 · 获赞 5 · 访问量 3659

猜你喜欢

转载自blog.csdn.net/Raink_LH/article/details/105052656