#0 环境
- win7 32bit
- vs2008
- matlab r2013b
#1 准备工作
确保vs与matlab均已正确安装
添加环境变量
PATH
:D:\Program Files\MATLAB\R2013b\bin\win32
,(我的matlab安装在D:\Program Files\MATLAB\
,如果不是这个路径则做相应修改,64bit系统路径最后则为win64,下同)vs设置,工具 -> 选项 -> 项目和解决方案 -> VC++ 路径,Platform选择Win32,然后
Include files中添加D:\Program Files\MATLAB\R2013b\extern\include
Library files中添加D:\Program Files\MATLAB\R2013b\extern\lib\win32\microsoft
注意高版本的VS如2013已经将该设置迁移到项目属性中。附加依赖项设置,项目属性 -> 配置属性 -> 链接器 -> 输入 -> 附加依赖项,编辑加入
libeng.lib
。(也可直接在代码中加入#pragma comment(lib, "libeng.lib")
语句)关于以上路径设置的说明
环境变量Path:指定系统搜索路径(此处用于查找libeng.dll
等dll文件),也可不设置而是将该路径下所有用到的dll文件拷贝到当前路径中
头文件路径:指定头文件的搜索路径(此处为engine.h
文件以及该文件中包含的其他头文件),也可不设置,但包含头文件时需要使用完整路径,这样头文件较多时会比较麻烦
库文件路径:指定库文件的搜索路径(此处为libeng.lib
文件),可以不设置,但#pragma comment
时需要使用lib文件的完整路径,或者将该文件拷贝到当前路径下
#2 引擎函数介绍
下表列出了本文用到的所有引擎函数
函数 | 说明 |
---|---|
engOpen | 启动matlab计算引擎(创建了一个matlab进程并建立联系) |
engClose | 关闭引擎(关闭创建的matlab进程) |
engSetVisible | 设置引擎窗口是否可见 |
engOutputBuffer | 设置引擎文本输出缓冲区(每次使用engEvalString 执行新命令都会使缓冲区清空并填入新的结果),执行代码engOutputBuffer(ep, NULL, 0) 可停用缓冲区 |
engEvalString | 执行matlab命令 |
- engOpen
- [函数原型]
Engine* engOpen(const char* startcmd)
- [参数说明] 用于启动matlab的字符串命令,Windows中为
NULL
- [返回值] 引擎指针
- [函数原型]
- engClose
- [函数原型]
int engClose(Engine* ep)
- [参数说明] 引擎指针,即
engClose
函数的返回值 - [返回值] 0成功,1失败
- [函数原型]
- engSetVisible
- [函数原型]
int engSetVisible(Engine* ep, bool newVal)
- [参数说明]
ep
为引擎指针;newVal
为true
表示显示引擎窗口,false
表示隐藏引擎窗口 - [返回值] 0成功,1失败
- [函数原型]
- engOutputBuffer
- [函数原型]
int engOutputBuffer(Engine* ep, char* buffer, int buflen)
- [参数说明]
ep
为引擎指针;buffer
为文本输出缓冲区指针;buflen
为缓冲区大小 - [返回值] 0成功,1失败
- [函数原型]
- engEvalString
- [函数原型]
int engEvalString(Engine* ep, const char* string)
- [参数说明]
ep
为引擎指针;string
为要执行的命令文本 - [返回值] 0成功,1失败
- [函数原型]
#3 引擎使用
包括打开与设置引擎、执行命令、关闭引擎三个部分
打开引擎并设置。包括打开引擎、设置不可见、设置输出缓冲区以及设置工作空间为当前路径,代码如下
// 打开并设置Matlab引擎 int MatlabOpen(Engine** ep, const char* sPath, char* sBuffer, int nBufLen) { // 启动matlab引擎 if (!(*ep = engOpen(NULL))) // 启动引擎 { return 1; // 启动失败 } // 设置 engSetVisible(*ep, false); // 设置窗口不可视 engOutputBuffer(*ep, sBuffer, nBufLen); // 设置Matlab输出缓冲区 // 修改工作路径 char sWorkPath[MAX_PATH]; sprintf_s(sWorkPath, MAX_PATH, "cd '%s'", sPath); engEvalString(*ep, sWorkPath); return 0; }
关闭引擎。代码如下
// 关闭Matlab引擎 int MatlabClose(Engine* ep) { return engClose(ep); }
执行命令。执行命令获取文本结果,如果有画图命令则将Figure保存为图片
// 执行Matlab命令 // 返回图片个数 int MatlabExec(Engine* ep, const char* mCmd) { int nFig = 0; // 图片个数 engOutputBuffer(ep, matbuf, MATBUFSIZE); // 恢复输出缓冲区 engEvalString(ep, mCmd); // 执行命令 engOutputBuffer(ep, matbuffig, MATBUFFIGSIZE); // 临时缓冲区,保存检测是否有Figure的结果 // 判断是否有figure并处理 engEvalString(ep, "isempty(findall(0,'Type','Figure'))"); if (strlen(matbuffig) > 13 && '0' == matbuffig[13]) // 有Figure { char savefig[100] = {0}; char gettype[20] = {0}; int i = 1; sprintf_s(gettype, 20, "get(1,'Type');"); engEvalString(ep, gettype); while(matbuffig[0] == 0) // 空 { // 将Figure保存为图片 sprintf_s(savefig, 100, "set(%d,'color','white');f=getframe(%d);imwrite(f.cdata,'figure%d.png');", i, i, i); engEvalString(ep, savefig); nFig++; // 下一个 sprintf_s(gettype, 20, "get(%d,'Type');", ++i); engEvalString(ep, gettype); } engEvalString(ep, "close all"); // 关闭所有Figure } return nFig; // 返回图片个数 }
#4 示例
由于关于Matlab计算引擎的操作都要在同一个线程内执行,而项目需要在其他多个线程中执行matlab命令,因此考虑采用线程消息的方式实现。即在主线程中启用计算引擎,其他线程通过向主线程发送消息来请求计算,命令通过消息参数传递。完整代码如下
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include "engine.h"
#pragma comment(lib, "libeng.lib")
#define WM_CALC WM_USER+200 // 请求计算消息
// 全局变量
#define MATBUFSIZE 10240
#define MATBUFFIGSIZE 256
char matbuf[MATBUFSIZE] = {0}; // Matlab输出缓冲区
char matbuffig[MATBUFFIGSIZE] = {0}; // 临时输出缓冲区
DWORD dwMainThreadId = 0; // 主线程ID
// 函数声明
DWORD WINAPI ThreadTest(LPVOID lpParam); // 测试线程
int MatlabOpen(Engine** ep, const char* sPath, char* sBuffer, int nBufLen);
int MatlabClose(Engine* ep);
int MatlabExec(Engine* ep, const char* mCmd);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
// 获取线程ID
dwMainThreadId = GetCurrentThreadId();
// 启动matlab引擎
Engine* ep = NULL; // matlab引擎
char path[MAX_PATH]; // 当前路径
strcpy_s(path, MAX_PATH, __argv[0]);
(_tcsrchr(path, '\\'))[1] = 0; // 只保留路径部分
if (MatlabOpen(&ep, path, matbuf, MATBUFSIZE))
{
return 0;
}
// 创建测试线程
CreateThread(NULL, 0, ThreadTest, 0, 0, NULL);
// 线程消息循环
MSG msg;
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
while(GetMessage(&msg, NULL, 0, 0))
{
if (msg.message == WM_CALC) // 请求计算消息
{
MatlabExec(ep, (char*)msg.wParam); // 执行matlab命令
}
}
// 关闭matlab引擎
MatlabClose(ep);
return (int) msg.wParam;
}
// 测试线程
DWORD WINAPI ThreadTest(LPVOID lpParam)
{
Sleep(1000);
PostThreadMessage(dwMainThreadId, WM_CALC, WPARAM("pi"), 0); // 输出pi
Sleep(1000);
PostThreadMessage(dwMainThreadId, WM_CALC, WPARAM("plot(sin(0:0.1:10))"), 0); // 画正弦曲线
Sleep(5000);
PostThreadMessage(dwMainThreadId, WM_QUIT, 0, 0); // 退出程序
return 0;
}
// MatlabOpen、MatlabClose、MatlabExec三个函数的实现分别见3.1、3.2、3.3,此处不再列出
// ……
测试结果:
- 第一次计算后matbuf值为
"ans = 3.1416"
- exe路径下生成文件
figure1.png
,如下图
本文原文链接 http://blog.csdn.net/yanglx2022/article/details/46477025