本贴目的: 64位编译,VS2015调用Matlab2016编译生成的DLL,搞定:各种运行错误,调试错误。
转载说明:
本贴内容仅仅用于软件代码的研究和学习,相关的转载和应用不得损害Microsoft和Mathworks公司的商业利益。
有条件的情况下,请稍微支持一下老美的正版软件,例如高校有经费买套正版或者买个学习版的,中国的开发者还是要参与到老外的开发体系中。如果版权所有者认定本贴已经发生侵权,请及时告知[email protected]。
各位老炮:对于比较有价值的题目还是要继续发帖和回帖,帮扶新人。只看贴不回不发,论坛的魔力就没了,各位年轻时候也是泡着坛子过来的。。。
本贴背景:
32位编译下,VC++(Visualstudio)调用Matlab编译生成的DLL本来是一件很容易的事情,现在转到64位了,编译环境设置不当,程序无法调通。另外,参照别人的帖子copy代码,不仔细思考,容易出现各种运行报错。
不想折腾的话,可以先用32位编译过渡一下:VS安装2010之前的版本,选用(x86) 32位编译,Matlab安装2011之前的版本,那个是支持32位编译的。这个路是通的,但是太保守,错过了新软件(个人认为VS2015的界面,好用而美腻)和新资源(OpenCV是个好东西,不安装最新的VS支持不了)。另外,OpenCV高版本只(直接)支持64位编译,所以还是要继续前进。。。
看到很多帖子有“杂交”的想法:安装高版本VS和低版本的Matlab。VS采用64位编译,编写主程序;VS采用32位编译,编写辅助程序调用Matlab 32位DLL。主程序和辅助程序采用进程间通信,例如:COM服务器,共享内存地址,发送消息。。。这个真的是很辛苦。其中,低版本的Matlab,mbuild选择高版本VS的编译器,也是比较麻烦,这里不展开。
另外,VC调用Matlab C++ Math Library也是一种混合编程的解决方案,我个人不推荐。理由:有些m文件不支持C文件编译输出。功能打包和调用编程没有DLL简便。
本贴内容:
[1]================扫清外围问题
VS和Matlab版本兼容的问题。Matlab的编译器只支持最近的VS版本,这个用mbuild –setup测试就知道了,一般建议Matlab版本稍高。本人建议:VS2015和Matlab2016,本人电脑win7 64。
首先,Matlab本身安装必须正点,安装后无需特别设置,直接mcc 编译一个图形显示+运算的exe运行OK。所以某论坛的破2017版本不建议安装。
其次,某些同志程序调不通,就各种VS和Matlab版本安装和卸载,这个没有必要。要相信老美大公司的产品。关键是,最终也没调通。
[2]=========== ====实例和过程
以下步骤描述简单,但是保证完整。
M文件定义。
function c =Test(a,b)
c = a+b;
--------------------------------------
Matlab命令生成库文件和头文件
mcc -W cpplib:TestMat64 -T link:lib Test
获得所需文件,拷贝到VS工程相应目录下。
电脑中添加Matlab运行环境: [ 注意:电脑重启生效!!!]
控制面板->所有控制面板项->系统->高级系统设置->高级->环境变量
Path一栏,后面追加:C:\ProgramFiles\MATLAB\R2016b\bin\win64
---------------------------------------------------------
VS编译环境设置:
添加include路径:C:\Program Files\MATLAB\R2016b\extern\include
添加lib路径:C:\Program Files\MATLAB\R2016b\extern\lib\win64\microsoft
添加附加lib:linker->input 追加
TestMat64.lib; libmx.lib; libmat.lib; mclmcr.lib;mclmcrrt.lib; 第1个是自己的M文件mcc生成的
库文件不能少,否则可以看到熟悉的编译报错:error LNK2019: 无法解析的外部符号
Matlab库文件的层次理解参考:
https://cn.mathworks.com/help/compiler_sdk/cxx/how-the-mclmcrrt-proxy-layer-handles-loading-of-libraries.html?searchHighlight=mclmcrrt&s_tid=doc_srchtitle&requestedDomain=true
VS编程调用:
学习细节可以参考官网:
https://cn.mathworks.com/help/compiler_sdk/cxx/integrate-a-cc-shared-library-into-an-application.html
https://cn.mathworks.com/help/compiler_sdk/shared-libraries.html
以下是VS原代码:完整
#include"TestMat64.h"// mcc DLL头文件
mclmcrInitialize();
if (!mclInitializeApplication(NULL, 0) return;
// 上两句初始化很重要,很多同志漏掉了,直接调用自己的DLL。
// 初始化可以鉴定Matlab外部调用环境设置是否正确,很多读者就是死在这里吧??后面有解答
if (!TestMat64Initialize()) return;
// mwArray输入变量这里是用数组间接赋值的,直接赋值报错!
mwArray a_ptr(1, 1, mxDOUBLE_CLASS, mxREAL);
mwArray b_ptr(1, 1, mxDOUBLE_CLASS, mxREAL);
double data1[] = { 1.0 };
double data2[] = { 2.0 };
a_ptr.SetData(data1, 1); // 间接赋值,不能直接赋值!!!
b_ptr.SetData(data2, 1);
mwArray c_ptr;
Test(1, c_ptr, a_ptr, b_ptr);
TestMat64Terminate();
mclTerminateApplication();
double Val; Val =c_ptr;
如果您到这里VS2015中按下F5一切正常,后面的就不用看了。我的电脑上不行。
[3] =================== 头文件包含的问题
除了Mcc生成的dll头文件TestMat64.h之外,还有几个库文件对应的头文件绕来绕去:mclmcrrt.h ,mclmcr.h ,mclcppclass.h 以及matrix.h。
头文件少了肯定不行,VS2015的代码里面可以看到函数没有定义。
但是头文件添加多了会出现以下报错:
errorC3861: 'mclmcrInitialize_proxy': identifier not found
errorC3861: 'mclInitializeApplication_860_proxy': identifier not found
看了下面mathworks社区的一个帖子,大概搞明白了里面有一个地方容易出问题:
MATLAB Compiler 4.8 (R2008a) or laterversions 已经在mcc生成的dll头文件中包含了mclmcrrt.h 和mclcppclass.h,
如果在VS代码中再include,会导致函数重定义,无法匹配lib,典型报错如上述error C3861.
https://cn.mathworks.com/matlabcentral/answers/100242-why-do-i-receive-a-linking-error-about-mclinitializeapplication_proxy-and-mclmcrinitialize_proxy-whe
该贴建议:将mcc生成的dll头文件放在最前,也就是顺序很重要。
我测试了一下,重复的头文件可以直接去掉,mclmcr.h和matrix.h也都没必要,也就是说一个头文件就搞定。
[4]=================调试debug错误
这个是比较挠头的问题,前面编译环境都搞定了,按下F5后,dubug output 窗口错误狂涌,一行接一行:
Exceptionthrown at 0x000007FEFCF6A06D in StartOpenCV.exe: Microsoft C++ exception:xsd_binder::MalformedDocumentError at memory location 0x00000000002887B0.
Exceptionthrown at 0x000007FEFCF6A06D in StartOpenCV.exe: Microsoft C++ exception:xsd_binder::MalformedDocumentError at memory location 0x000000000028AE30.
Exceptionthrown at 0x000007FEFCF6A06D in StartOpenCV.exe: Microsoft C++ exception:xsd_binder::MalformedDocumentError at memory location 0x00000000002887B0.
Exceptionthrown at 0x000007FEFCF6A06D in StartOpenCV.exe: Microsoft C++ exception:xsd_binder::MalformedDocumentError at memory location 0x000000000028AE30.
VS还会弹出如下对话框,提示 Frame not in module
和我一样受到困扰的人很多,最后在mathworks社区一个帖子的回复的最后面,找到了解答。
https://cn.mathworks.com/matlabcentral/answers/286624-matlab-c-shared-dll-library-initialization-problem
结论大概:VS自己debug有点管得太宽了。
Visual Studio 中Propertiesof Project -> Configuration Properties -> Debugging -> Debugger Type
原贴建议:将默认AUTO 改成 Managed Only,发现这样好像调试信息都没了,这还叫调试吗?
本人实际测试,Mixed 效果比较好。
----完毕----