关键词:C++/CLR, .Net Core, .Net Famework, Opencv, C#
目录
什么是CLR类库
本文说明
创建Demo程序
调用dll
通过项目引用
通过dll文件引用
其他还没完全清楚的坑:
有关C++/CLI这块的资料真的很少而且都属于教程(新手找不到门的,和进了门才能懂的)
参考其他资料,以及微软官方说明,以及新建项目时的项目模板说明:
简单的说:
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
首先这是一个个人向,非专业的,入门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怎么办呢?
于是找到了这个
在VS2019新建项目中,搜索CLI或者CLR,找到这个项目模板
输入名称,以我这次【OpcvDllToNetCore】为例:
创建好后会得到如下项目结构(皆有VS自动生成):
像通常一样的方式配置opencv,参考:「图像处理」OpenCV的安装与配置
在【OpcvDllToNetCore.h】中,编写如下代码:
#pragma once
//以下代码使用非托管(opencv是非托管的)
#pragma unmanaged
//取消_M_CEE定义,否则会报很多 不兼容的错误
#undef _M_CEE
#include
//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文件。
再添加一个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复制过来,然后在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之后,也还是正常的,不是很理解