C#调用matlab写的动态链接库(dll)

最近老师在做项目,有一个需求,就是他现在用matlab写了一些操作图像的代码,但是需要在C#环境下调用。基本上就是这样的需求吧。现在老师给我的文件是,如下图:


下面我分别解释一下这些文件,希望以后有这个需求的同学能少走一些弯路。

前八个一看就懂,.h和.c是源文件,.lib和.dll是生成的动态链接库,最后一个文件是:如果你的电脑上没有安装matlab,那么你需要下载并安装这个文件,如果你的电脑上安装了matlab,好像在matlab的安装目录下有这个文件,你找到,安装就行了,我是直接按的,并没有找,虽然我的电脑上也有matlab文件。

环境:

操作系统:win7  x64

环境:       vs2012

那个matlab我不知道,应该没有关系吧,我直接拿到手的就是matlab生成好的dll。

下面就按我的说了:

刚开始,用的网上的办法,总是出问题,因为网上说要在引用里面添加上这些dll,然后在using,但是这样的话总是出问题,弄了半天也没有弄好,只好想别的办法了。出现的问题如下:

未能添加对XXXX的引用,请确保此文件可访问,并且是一个有效的程序集或从com组件。

错误原因:应该是在生成matlab的dll的时候应该直接生成com组件才能用。

后来,我使用了和调用C++生成的动态链接库一样的办法,dllimport函数:

[DllImport("libFDS.dll", CharSet = CharSet.Ansi)]

public static extern MWNumericArray mlxFDS(int imglen, MWCharArray []imgFilename, int pathlen, MWCharArray []path);

但是这样的话又会出现这样的问题,在编译的时候:


未经处理的异常:  System.NotSupportedException: 无法从非托管句柄创建 SafeHandle
字段。
   在 System.StubHelpers.StubHelpers.FmtClassUpdateCLRInternal(Object obj, Byte*
 pNative)
   在 matlabconsoletest.Program.mlxFDS(Int32 imglen, MWCharArray[] imgFilename,
Int32 pathlen, MWCharArray[] path)
   在 matlabconsoletest.Program.Main(String[] args) 位置 d:\13liushuanpeng\matla
bconsoletest\matlabconsoletest\Program.cs:行号 34
请按任意键继续. . .

实在没有办法了后来,由于我原来做过用C#调用C++的动态链接库,而且成功了(参见我前面的一篇文章),所以想,能不能我先用C++调用matlab的dll,然后我在用C# 调用C++的动态链接库(事实证明可行)。

首先:我的原函数如下:就是.c文件中的函数

bool MW_CALL_CONV mlxFDS(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[])
{
  return mclFeval(_mcr_inst, "FDS", nlhs, plhs, nrhs, prhs);
}

LIB_libFDS_C_API 
bool MW_CALL_CONV mlfFDS(int nargout, mxArray** result, mxArray* imgFilename, mxArray* 
                         temPath)
{
  return mclMlfFeval(_mcr_inst, "FDS", nargout, 1, 2, result, imgFilename, temPath);
}
经过查资料,主要参考的是这篇文章:https://www.mathworks.com/matlabcentral/newsreader/view_thread/266426

http://blog.csdn.net/xiaowei_cqu/article/details/7346534这篇看着也对。

写出的如下代码:

int _tmain(int argc, char* argv[])
{<span style="white-space:pre">	</span>char fname[] = ".\\210103196303274887\\sy_20140728112957_210103196303274887_-859566652.jpg";
	char path[] = ".\\210103196303274887\\";

	libFDSInitialize();
	libFRSInitialize();

	mxArray *path_C[2];
	path_C[0] = mxCreateString(fname);
	path_C[1] = mxCreateString(path); 
	mxArray *output[1]; 
	mlxFDS(1,output,2,path_C);

	mxArray *y = NULL; //定义输出结果指针
	y = output[0]; 
	double res = mxGetScalar(y);

	return 0;
}
下面我们就用上面的代码来生成C++的dll了。生成办法,那个前面一篇文章有,可以参考。直接代码如下:

#include <tchar.h> 
#include "libFRS.h"
#include "libFDS.h"
#include "mclmcr.h"
#include "matrix.h"
#include "mclcppclass.h"
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <direct.h>
#include <windows.h>
using namespace std;

//#pragma comment(lib,"libFRS.dll")
//#pragma comment(lib,"libFDS.dll")
extern "C" __declspec(dllexport) double callMatlab(char fname[],char path[])
{
	
	mxArray *path_C[2];
	path_C[0] = mxCreateString(fname);
	path_C[1] = mxCreateString(path); 
	mxArray *output[1]; 
	mlxFDS(1,output,2,path_C);

	mxArray *y = NULL; //定义输出结果指针
	y = output[0]; 
	double res = mxGetScalar(y);
	return res;
}
当然,别忘记了把相应的dll和lib库包含尽量,需要在项目属性中,添加一些matlab的一些库,比如上面代码include的

#include "mclmcr.h"
#include "matrix.h"
#include "mclcppclass.h"
这三个,就是matlab库中的,在项目--属性--VC++目录--包含目录和库目录中分别包含

C:\Program Files\MATLAB\MATLAB Compiler Runtime\v81\extern\include

C:\Program Files\MATLAB\MATLAB Compiler Runtime\v81\extern\lib\win64\microsoft此为上面第八个文件MCR的安装路径下

之后把相应的lib库包含进来就行了

libFRS.lib
libFDS.lib
mclmcrrt.lib
libmx.lib
libmat.lib
mclmcr.lib
winmm.lib

运行,就可以生成两个文件,分别为.lib和.dll。。。

然后我们在在C#中调用这两个动态链接库。别忘记把相应的文件拷贝到对应的debug和release目录下。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using MathWorks.MATLAB.NET.Arrays;
using MathWorks.MATLAB.NET.Utility;

namespace matlabCons
{
    class Program
    {

        [DllImport("matlabDll.dll", CharSet = CharSet.Ansi)]
        public static extern double callMatlab(string fname,string path);
        [DllImport("libFRS.dll", CharSet = CharSet.Ansi)]
        public static extern bool libFRSInitialize();
        [DllImport("libFDS.dll", CharSet = CharSet.Ansi)]
        public static extern bool libFDSInitialize();

        [DllImport("libFRS.dll", CharSet = CharSet.Ansi)]
        public static extern bool libFRSTerminate();
        [DllImport("libFDS.dll", CharSet = CharSet.Ansi)]
        public static extern bool libFDSTerminate();

        static void Main(string[] args)
        {
            libFDSInitialize();
            libFRSInitialize();
            string fname = ".\\210103196303274887\\sy_20140728112957_210103196303274887_-859566652.jpg";
            string path = ".\\210103196303274887\\";
            int aa = System.Environment.TickCount;
            double ret = callMatlab(fname,path);
            Console.WriteLine(System.Environment.TickCount - aa); //单位毫秒
            Console.WriteLine(ret);
            libFRSTerminate();
            libFDSTerminate();
        }
    }
}
debug下的文件如下图:

最后两个文件,为C++生成的。

BTW:extern “C”的意义:

这就是连接规范的概念,由于C++的编译器在编译的时候会用到一种Name-Mangling技术,将函数进行重命名

机制。然而C++标准并没有规定一种统一的重命名方案,因此不同的编译器对重载函数可能产生不同风格的内部

标识符,这就是不同厂商的C++编译器和连接器不能兼容的一个主要原因。

所以我们这里用到了extern “C”,因为C的连接规范是通用连接规范。所以可以用来解决这个问题。














  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值