C#调用C++图像处理算法(OpenCV)
因为需要做一个图像处理的程序,后来决定采用C#写界面,C++写算法调用opencv的函数。关于opencv的使用之前已经学习过了,需要实现的是在C#中如何使用C++语言编写的DLL。
参考:
CSDN支持语法高亮的常用语言
本开发环境为win10+vs2010
C++编程笔记:dll的生成与使用
这个博客讲了dll是什么以及静态动态dll的区别还有dll的创建和使用,特别是隐式和显式链接方式加载dll。函数的名字自动改编导致错误的解决方案。
新建一个C++的dll(非托管类)
新建解决方案 =>【添加】【新建项目】=>【Visual C++】>【Win32 项目】> 输入名称:DllTest)> 完成 => 向导【下一步】>【DLL】> 【完成】
头文件夹中新建头文件 dllTest.h
// dllTest.h
#ifndef DllTest_H_
#define DllTest_H_
#ifdef MYLIBDLL
#define MYLIBDLL extern "C" _declspec(dllimport)
#else
#define MYLIBDLL extern "C" _declspec(dllexport)
#endif
MYLIBDLL int Add(int plus1, int plus2);
//You can also write like this:
//extern "C" {
//_declspec(dllexport) int Add(int plus1, int plus2);
//};
//also like this:
//extern "C" _declspec(dllexport) int Add(int plus1, int plus2);
#endif
// extern "C"外部声明,表示函数和变量是按照C语言的方式编译和链接的。
// _decspec(dllexport)的目的是为了将对应的函数放入到DLL动态库中。
// extern "C" _declspec(dllexport)的目的是为了使用DllImport调用非托管C++的DLL文件。
// 因为使用DllImport只能调用由C语言函数做的DLL。
源文件夹中新建cpp文件 dllTest.cpp
// DllTest.cpp : 定义 DLL 应用程序的导出函数。
#include "stdafx.h"
#include "dllTest.h"
#include <iostream>
using namespace std;
int Add(int plus1, int plus2)
{
int add_result = plus1 + plus2;
return add_result;
}
在资源文件夹中新建模板定义文件 dllTest.def
LIBRARY "DllTest" // 这个名字最好和项目名称相同 在我测试时不同会产生一个错误
EXPORTS
Add @1 // 这里是否改为 Add 不知道
在本项目中只写了一个Add函数,点击【启动调式】(Debug模式),将会在【解决方案】文件夹中的【Debug】文件夹中产生 DllTest.lib,和 DllTest.dll,在使用DLL时会需要这两个文件加 dllTest.h。
使用DLL时:【属性管理器】>【Microdoft.Cpp.Win32.user】>右键>【属性】>【链接器】>【输入】>【附加依赖项】要添加 DllTest.lib,【VC++目录】的【可执行文件项】添加 DllTest.dll 所在目录,【包含目录】添加 dllTest.h 所在目录即可。
在另一个c++项目中使用它
新建c++空项目Test,在源文件夹中新建 main.cpp
//== 依赖添加
//#include <opencv2/opencv.hpp>
//#include <opencv2/core/core.hpp>
//#include <opencv2/imgproc/imgproc.hpp> //opencv图像处理头文件
//#include <opencv2/highgui/highgui.hpp> //opencv highgui模块头文件
#include <iostream>
#include "dllTest.h"
//== 命名空间
//using namespace cv;
using namespace std;
//== 函数声明
//== 程序入口
int main(int argc, char* args)
{
int a,b;
while(1)
{
cin>>a>>b;
cout<<Add(a,b)<<endl;
}
// waitKey(0); // 好像是cv的函数
// system("pause")
return 0;
}
生成时出了一个错误,无法打开dllTest.def文件
1>------ 已启动生成: 项目: Test, 配置: Debug Win32 ------
1>生成启动时间为 2018/3/21 21:51:34。
1>InitializeBuildStatus:
1> 正在对“Debug\Test.unsuccessfulbuild”执行 Touch 任务。
1>ClCompile:
1> 所有输出均为最新。
1>LINK : fatal error LNK1104: 无法打开文件“dllTest.def”
1>
1>生成失败。
1>
1>已用时间 00:00:00.25
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========
原因是【属性管理器】中【链接器】【输入】【模块定义文件】中添加了文件 dllTest.def,删除后生成正确且没有任何警告报错等。
输入 12 35 得到结果 47 。
在C#中使用非托管类C++的dll
c++的(非托管类)dll(Release模式下) 生成后会在项目所在文件夹的Realease里面找到所生成的dll.
新建一个C#控制台应用程序,将上文所生成的DLL拷贝到C#应用程序的bin里面然后应用如下方式进行调用:
[DllImport(“ COM DLL path/file ”)]
extern static int FunctionName(byte param1, ushort param2)
具体调用的时候在参数传递的过程中会遇到问题,具体解决方式见这篇博客C#时常需要调用C++DLL。
在C#与C++之间常用的参数传递
将string转为IntPtr:IntPtr System.Runtime.InteropServices.Marshal.StringToCoTaskMemAuto(string)
将IntPtr转为string:string System.Runtime.InteropServices.MarshalPtrToStringAuto(IntPtr)
c++ <----------> c#
BSTR --------- StringBuilder
LPCTSTR --------- StringBuilder
LPCWSTR --------- IntPtr
handle---------IntPtr
hwnd-----------IntPtr
char *----------string
int * -----------ref int
int &-----------ref int
void *----------IntPtr
unsigned char *-----ref byte
Struct需要在C#里重新定义一个Struct
CallBack回调函数需要封装在一个委托里,delegate static extern int FunCallBack(string str);
注意在每个函数的前面加上public static extern +返回的数据类型,如果不加public ,函数默认为私有函数,调用就会出错。
C#中的代码 Test.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace Project1
{
class Test
{
[DllImport(@"D:\AppCache\Visual Studio 2010\Projects\DllLibs\DllTest.dll", EntryPoint = "Add")]
// 如果将DLL放进bin目录下就可以改为 [DllImport("DllTest.dll", EntryPoint = "Add")]
extern static int Add(int a, int b);
static void Main(String[] args)
{
//Console.WriteLine("Hello World");
int c = Add(1, 2);
Console.WriteLine(c);
Console.ReadKey();
}
}
}
很遗憾产生了一个错误,选择继续后会显示正确的结果。
新建托管类c++的dll
参考:C#C++混合编程
非托管类会存在一些问题,而这些问题的解决方式可能有点麻烦,就可以选择 C++函数=>托管类封装=>C#调用的形式进行。
所有参考:
CSDN支持语法高亮的常用语言在Markdown模式下在开头的三个反引号后加语言关键字
如何在写CSDN博客时插入代码
C++创建dll文件及使用方法
C#调用C++ dll 总结 内含(opencv)
C#时常需要调用C++DLL
C#C++混合编程
opencv的安装与环境配置
C#调用openCV函数及其移植
【开发日记】C#调用C++图像处理算法(opencv)
C#调用C++动态库(dll)
C#与C++ DLL的交互
在VS2015中用C++编写可被其它语言调用的动态库DLL
在VS2015中用C++创建DLL并用C#调用且同时实现对DLL的调试
利用C++制作dll并调用dll
C#调用 opencv cv::Mat 图像, 采用折中方法