Click here to Skip to main content
15,887,958 members
Articles / Programming Languages / C++
Article

A class wrapper for Matlab(c) ActiveX Control

Rate me:
Please Sign up or sign in to vote.
4.42/5 (18 votes)
21 Oct 20023 min read 306.2K   3.9K   65   76
Eases up the use of the Matlab(c) COM server...

Sample Image - matlabengine.png

Introduction

Matlab(c) is a well-known scientific software covering a wide range of engineering and mathematicals fields. It contains also a set of complete and powerfull visualization tools.

Matlab(c) contains it's own language and you can easily develop applications on it. However, sometimes you will want to run it from a C/C++ application and that's where everything get's tricky. In fact, although Matlab(c) comes with a C API, it is complicated to use: linking problems, compiler special flags and other mysterious bugs (maybe I did it all wrong).

Another solution is to use the COM interface of the ActiveX control. The sad thing about this interface is that... it's COM and you end up with dozens of lines of code... That's where the CMatlabEngine gets in the play. It hides all the COM code (getting CLSID, getting IDispatch, allocating variants, setting function arguments and many others) and enables you to focus on the main part of the job: use Matlab(c).

This article will discuss the main features the class, for further details check the Doxygen documentation that is shipped with the demo project. Note that you can also generate it by running Doxygen on MatlabEngine.h

Initializing the engine

All the initialization code is contained in the constructor of CMatlabEngine. You can check that the server has been correctly initialized by calling IsInitialized:

// Initializing COM
CoInitialize(NULL);

...
// Hooking matlab engine
CMatlabEngine mt;
if (!mt.IsInitialized())
   // could not initialize matlab engine, do something about it

Do not forget to uninitialize COM when quitting the application:

CoUninitialize();

Engine main methods

The matlab engine contains 5 main methods: Execute, PutMatrix, GetMatrix, PutString and GetString

Executing Matlab(c) code:

You can execute Matlab(c) code by calling Execute( LPCTSTR szMatlabCode ):

// this code will show the classic Matlab(c) demo
mt.Execute(_T("surf(peaks)"));
mt.Execute(_T("title('demo')"));

Sending arrays to Matlab(c)

You can send array, real or complex, in the form of vector<double> to Matlab(c) by using PutMatrix.Note that the vector in PutMatrix have to be ordered line by lines: for a matrix M of size (mxn), M(i,j) is equivalent to M[i* n + j].

UINT nRows=10; // number of rows
UINT nCols=2;  // number of columns
vector<double> v( nRows * nCols );
// filling up v
...
// sending v to Matlab(c) with name "Mv"
mt.PutMatrix( _T("M"), v, nRows, nCols);
// M is now a matrix in the Matlab(c) workspace

Retreiving arrays from matlab

You can retreive arrays (real or complex) by calling GetMatrix( It is the dual of PutMatrix):

mt.Execute(_T("v=[1 2 3; 4 5 6]';"));
vector<double> vReal;
UINT nRows, nCols;
mt.GetMatrix(_T("v"), nRows, nCols, vReal);	

nRows and nCols now contains the dimension of the array and vReal the data.

Sending string to Matlab(c)

Piece of cake using PutString:

mt.PutString("text", "Inserting a string named text");

Getting string from Matlab(c)

Use the method GetString:

LPTSTR szText;
// we suppose that myText is a string variable in Matlab
mt.GetString("myText",szText);
Note that szText is allocated on the heap by GetString, the memory cleaning is left to the user.

Workspace

You can modify the workspace you are working on by using SetWorkspace. By default, the workspace is "base". If you want to declare global variables, use "global" workspace.

Handling the Matlab Window state

  • Minimize the command window,
    mt.MinimizeWindow();
  • Maximize the command window,
    mt.MaximizeWindow();
  • Show, hide the command window,
    mt.Show( true /* true to make it visible, false to hide it*/);
  • Get the visibility state the command window,
    if(mt.IsVisivle())
        // Matlab is server is visible...
  • Quit the command window,
    mt.Quit();

Known bugs and limitations

Matlab 5.3 and earlier

Some function interface from the Matlab engine have been introduced only with the version 6.0 therefore user with version earlier than 6.0 would have faced problem with the class.

If you have a Matlab earlier than v6.0, undefine the MATLAB_VERSION_6 constant that is at the beginning of MatlabEngine.h, it will disable the following functions: IsVisible, Show, PutString, GetString

Further developments

  • Write PutCellArray and GetCellArray to write and read cell arrays.

Reference and further reading

Revision History

21-10-2002Added references
10-09-2002
  • GetString is now working! At last !
  • Fixed bugs in GetResult, GetMatrix thanks to Juan Carlos Cobas.
09-25-2002
  • GetMatrix is now working! At last !
09-23-2002
  • Added PutString method
  • Added MATLAB_VERSION_6 string for Matlab version < 6. Thanks for ZHANG Yan for finding the workaround.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Engineer
United States United States
Jonathan de Halleux is Civil Engineer in Applied Mathematics. He finished his PhD in 2004 in the rainy country of Belgium. After 2 years in the Common Language Runtime (i.e. .net), he is now working at Microsoft Research on Pex (http://research.microsoft.com/pex).

Comments and Discussions

 
GeneralThanks! Pin
arnonm22-May-03 0:39
arnonm22-May-03 0:39 
GeneralRe: Thanks! Pin
arnonm22-May-03 0:44
arnonm22-May-03 0:44 
GeneralRe: Thanks! Pin
Jonathan de Halleux22-May-03 1:04
Jonathan de Halleux22-May-03 1:04 
GeneralThe sample in C# Pin
sragner19-May-03 3:39
sragner19-May-03 3:39 
GeneralRe: The sample in C# Pin
Jonathan de Halleux19-May-03 4:28
Jonathan de Halleux19-May-03 4:28 
GeneralDetails Pin
flora_k7-Apr-03 1:07
flora_k7-Apr-03 1:07 
GeneralRe: Details Pin
Jonathan de Halleux7-Apr-03 1:20
Jonathan de Halleux7-Apr-03 1:20 
GeneralRe: Details Pin
flora_k7-Apr-03 1:57
flora_k7-Apr-03 1:57 
I put the code on the previous message. i just copy/paste it.
All the parameters have been initialized. i think it's a good idea i give you the insight of the whole thing. There we go

// CPPAnalyzerTestModule.cpp : Implementation of CPPAnalyzerTestModule
#include "stdafx.h"
#include "PPAnalyzerTestModule.h"
#include "CPPAnalyzerTestModule.h"
#include "StrDef.h"

// for filter function
#include <stdio.h>
#include <math.h>

//for matlab interfacing
#include <engine.h>
#include "myfunctions.h"
#define BUFSIZE 256

Engine*ep;
mxArray *A_ptr;
double *A;



/////////////////////////////////////////////////////////////////////////////
// CPPAnalyzerTestModule

// handlers used by this module
PPHANDLER_IMPLEMENT_USAGE(PPLogHandler)
PPHANDLER_IMPLEMENT_USAGE(PPErrorHandler)

// imported command id's from other module classes to use PPCMD() macros
#define IMPORT_MODULECOMMANDS
#include "PPChainLib\CmdMap.h"
#include "PPProxyLib\CmdMap.h"
/* TODO: Add #includes for other module classes used:
#include "PPSomeModule\CmdMap.h"
#include "PPOtherModule\CmdMap.h"
... or delete the entire IMPORT_MODULECOMMANDS section if not needed */
#undef IMPORT_MODULECOMMANDS


// function prototypes
void Filter(long amount, unsigned char* pData);
unsigned char bessel(unsigned char x);

// -------------------------------------------------------
// CONSTRUCTOR/DESTRUCTOR

//##ModelId=3B6171AE006E
CPPAnalyzerTestModule::CPPAnalyzerTestModule()
{
PPHANDLER_START_USAGE(PPLogHandler)
PPHANDLER_START_USAGE(PPErrorHandler)
PPLOG2(COARSE, CHAINMODULES, INF, STR_STARTUP, GetModuleClassName())
InitMatlab();
}

//##ModelId=3B6171AE006F
CPPAnalyzerTestModule::~CPPAnalyzerTestModule()
{
PPLOG2(COARSE, CHAINMODULES, INF, STR_SHUTDOWN, GetModuleClassName())
PPHANDLER_STOP_USAGE(PPErrorHandler)
PPHANDLER_STOP_USAGE(PPLogHandler)
CloseMatlab();
}


// -------------------------------------------------------
// PUBLIC COM INTERFACE METHODS

STDMETHODIMP CPPAnalyzerTestModule::Reset(int *result)
{
// keep functionality of baseclass
return CPPChainModuleBase::Reset(result);
}

//##ModelId=3B6171AE007A
STDMETHODIMP CPPAnalyzerTestModule::SetChainModuleId(long idModule, int *result)
{
// keep functionality of baseclass
return CPPChainModuleBase::SetChainModuleId(idModule, result);
}

//##ModelId=3B6171AE007E
STDMETHODIMP CPPAnalyzerTestModule::Connect(unsigned inputNr, IPPChainModule* pPrevModule, unsigned prevOutputNr, int *result)
{
// keep functionality of baseclass
return CPPChainModuleBase::Connect(inputNr, pPrevModule, prevOutputNr, result);
}

//##ModelId=3B6171AE008C
STDMETHODIMP CPPAnalyzerTestModule::SetParameter(IUnknown* pIUnk, int* result)
{
// extend functionality of baseclass
// following file implements the moduleparameter dispatch switch
#include "ParMap.h"
}

//##ModelId=3B6171AE0091
STDMETHODIMP CPPAnalyzerTestModule::SetCommand(long idDest, long idCmd, __int64 offset, const unsigned char* pData, long amount, int* result)
{
// keep functionality of baseclass
return CPPChainModuleBase::SetCommand(idDest, idCmd, offset, pData, amount, result);
}

//##ModelId=3C6D24A501D3
STDMETHODIMP CPPAnalyzerTestModule::IsEnabled(int *IsEnabled, int *ModuleName, int *result)
{
// keep functionality of baseclass
return CPPChainModuleBase::IsEnabled(IsEnabled, ModuleName, result);
}

//##ModelId=3B6171AE009F
STDMETHODIMP CPPAnalyzerTestModule::Validate(int* result)
{
// extend functionality of base class
*result = PP_OK;
HRESULT hr = CPPChainModuleBase::Validate(result);
if (SUCCEEDED(hr) && (*result == PP_OK))
{
// TODO: Add code here for further validation
}
return hr;
}

//##ModelId=3B6171AE00A9
STDMETHODIMP CPPAnalyzerTestModule::Prepare(int* result)
{
// extend functionality of base class
*result = PP_OK;
HRESULT hr = CPPChainModuleBase::Prepare(result);
if (SUCCEEDED(hr) && (*result == PP_OK))
{

}
return hr;
}

//##ModelId=3B6171AE00AC
STDMETHODIMP CPPAnalyzerTestModule::Run(int* result)
{
// keep functionality of baseclass
return CPPChainModuleBase::Run(result);
}

//##ModelId=3C8F773300EF
STDMETHODIMP CPPAnalyzerTestModule::HandleEvent(eModuleEventType eventType, int * result)
{
// keep functionality of baseclass
return CPPChainModuleBase::HandleEvent(eventType, result);
}

//##ModelId=3B6171AE00AF
STDMETHODIMP CPPAnalyzerTestModule::Pull(unsigned outputNr, long amount, long *amountActual, unsigned char* pData, unsigned char * ppCmds, int *more, int *result)
{
HRESULT hr = S_OK;

// replace functionality of baseclass
PullEntry(outputNr, amount, amountActual, pData, ppCmds, more, result);
if (*result == PP_OK)
{
// the main thing: read from previous module
hr = PullPrevModule(0, amount, amountActual, pData, ppCmds, more, result);

if (SUCCEEDED(hr) && (*result == PP_OK))
{
// command preprocessing
PullTransposeCmds(ppCmds, amountActual, pData); // TODO: override if necessary
PullInsertCmds(ppCmds, amountActual, pData);

// a basic loop for command processing
CCmdIterator iter(ppCmds);
CCommand *pCmd;
while (!iter.Ready() && (*result == PP_OK) && *more)
{
if ((pCmd = iter.GetNextCmdForMe(GetChainModuleId())) != NULL)
{
HandleCommand(pCmd, amountActual, pData, more, result);
if (!pCmd->IsBroadcastCmd())
delete pCmd;
}
}
}

/*
Process the data in this block
*/

// call your function
// use number of samples (amount actual)
// use buffer :
// yourfunc(long samples, unsigned char* pData);
//DisplayMatlab(*amountActual, pData, 0);
//FilterInMatlab(*amountActual, pData);
//either
//Filter(*amountActual, pData);

DisplayMatlab(*amountActual, pData, 1);

/*
Process the data in this block
*/


}
PullExit(outputNr, amount, amountActual, pData, ppCmds, more, result);
return hr;
}

//##ModelId=3BB850280291
STDMETHODIMP CPPAnalyzerTestModule::GetRunTimeInfo(const char* name, char* value, int maxlen, int* result)
{
// extend functionality of baseclass
// following file implements the runtimeinfo dispatch switch
#include "RtiMap.h"
}

STDMETHODIMP CPPAnalyzerTestModule::LogDumpRunTimeInfo(int* result)
{
// extend functionality of baseclass
// following lines implement the logdump of all runtimeinfo
#define LOGDUMP_MODULERUNTIMEINFO
#include "RtiMap.h"
#undef LOGDUMP_MODULERUNTIMEINFO
}

//##ModelId=3B61838B030A
STDMETHODIMP CPPAnalyzerTestModule::Abort(int* result)
{
// keep functionality of baseclass
return CPPChainModuleBase::Abort(result);
}


// -------------------------------------------------------
// OVERRIDEABLE METHODS

//##ModelId=3B6171AE0070
const char *CPPAnalyzerTestModule::GetModuleClassName() const
{
// override functionality of baseclass
return STR_MODULECLASSNAME;
}

//##ModelId=3BF1480F01AA
void CPPAnalyzerTestModule::HandleCommand(CCommand *pCmd, long *amountActual, unsigned char *pData, int* more, int *result)
{
// extend functionality of baseclass
// following file implements the commandhandler dispatch switch
#include "CmdMap.h"
}


// -------------------------------------------------------
// MODULEPARAMETER METHODS

// TODO: replace with your own module parameters
//##ModelId=3B6171AE00C9
int CPPAnalyzerTestModule::SetExampleParam(long value)
{
if (value < 0) // is just an example
{
PPERROR2(STR_ERR_EXAMPLEPARAM, GetModuleClassName())
PPLOG2(COARSE, CHAINMODULES, ERR, STR_ERR_EXAMPLEPARAM, GetModuleClassName())
return PP_NOT_OK;
}
m_ExampleParam = value;
return PP_OK;
}

// -------------------------------------------------------
// MODULERUNTIMEINFO METHODS

// TODO: replace with your own module runtime info
//##ModelId=3BF1480F00DF
int CPPAnalyzerTestModule::GetExampleInfo(char* value, int maxlen) const
{
// return example info
static long exampleInfo = 0;
_snprintf(value, maxlen, "ExampleInfo: %ld", exampleInfo++); // is just an example
return PP_OK;
}

// -------------------------------------------------------
// MODULECOMMAND METHODS

// TODO: replace with your own module commands
//##ModelId=3BF1480F01D9
int CPPAnalyzerTestModule::HandleSetByteExample(CCommand *pCmd, long *amountActual, unsigned char *pData, int* more)
{
// set byte to 0xee on offset location
pData[pCmd->GetOffset()] = 0xee; // is just an example
return PP_OK;
}




/*******************************************************************************************

Transfer function:

10395
---------------------------------------------------
6.045e-045 s^6 + 2.974e-036 s^5 + 6.968e-028 s^4

+ 9.796e-020 s^3 + 8.607e-012 s^2

+ 0.0004437 s + 10395



Transfer function:

0.02651 z^6 + 0.1591 z^5 + 0.3977 z^4 + 0.5302 z^3

+ 0.3977 z^2 + 0.1591 z + 0.02651

---------------------------------------------------
z^6 + 0.1852 z^5 + 0.4568 z^4 + 0.01633 z^3

+ 0.03876 z^2 - 0.0007527 z + 0.0003637


Sampling time: 1.9113e-008
********************************************************************************************/


unsigned char bessel(unsigned char x) // Function accessible only from this file
{
double b0=0.02651,b1=0.1591,b2=0.3977, b3=0.5302, b4=0.3977, b5=0.1591, b6=0.02651;
double a1= -0.1852, a2= -0.4568, a3= -0.01633, a4= -0.03876, a5= 0.0007527, a6= -0.0003637;
double temp_x1,temp_x2,temp_x3,temp_x4,temp_x5,temp_x6,temp_x7;
double temp_y1,temp_y2,temp_y3,temp_y4,temp_y5,temp_y6;
double y;
unsigned char y_unsigned;
double static xn_1,xn_2,xn_3,xn_4,xn_5,xn_6;
double static yn_1,yn_2,yn_3,yn_4,yn_5,yn_6;


temp_x1 = x * b0;
temp_x2 = xn_1* b1;
temp_x3 = xn_2 * b2;
temp_x4 = xn_3 * b3 ;
temp_x5 = xn_4 * b4;
temp_x6 = xn_5 * b5;
temp_x7 = xn_6 * b6;


temp_y1 = yn_1 * a1;
temp_y2 = yn_2* a2;
temp_y3 = yn_3 * a3;
temp_y4 = yn_4 * a4 ;
temp_y5 = yn_5 * a5;
temp_y6 = yn_6 * a6;




y = temp_x1 + temp_x2 + temp_x3 + temp_x4 + temp_x5 + temp_x6 + temp_x7 + temp_y1 + temp_y2 + temp_y3 + temp_y4 + temp_y5 + temp_y6 ;

xn_6 = xn_5;
xn_5 = xn_4;
xn_4 = xn_3;
xn_3 = xn_2;
xn_2 = xn_1;
xn_1 = (double) x;

yn_6 = yn_5;
yn_5 = yn_4;
yn_4 = yn_3;
yn_3 = yn_2;
yn_2 = yn_1;
yn_1 = y;

y_unsigned = (unsigned char) y;
return y_unsigned;

}



void Filter (long amount, unsigned char* pData)
{
long n;
unsigned char y;
for (n=0; n
General??? Pin
Jonathan de Halleux19-May-03 4:26
Jonathan de Halleux19-May-03 4:26 
Generalmy problem Pin
flora_k7-Apr-03 0:15
flora_k7-Apr-03 0:15 
GeneralRe: my problem Pin
Jonathan de Halleux7-Apr-03 0:24
Jonathan de Halleux7-Apr-03 0:24 
GeneralLibraries and header files Pin
flora_k7-Apr-03 0:02
flora_k7-Apr-03 0:02 
GeneralRe: Libraries and header files Pin
Jonathan de Halleux7-Apr-03 0:05
Jonathan de Halleux7-Apr-03 0:05 
Generalmatlab engine Pin
flora_k6-Apr-03 23:57
flora_k6-Apr-03 23:57 
GeneralRe: matlab engine Pin
Jonathan de Halleux7-Apr-03 0:04
Jonathan de Halleux7-Apr-03 0:04 
GeneralmxCreateCharArray Pin
flora_k6-Apr-03 23:02
flora_k6-Apr-03 23:02 
GeneralRe: mxCreateCharArray Pin
Jonathan de Halleux6-Apr-03 23:09
Jonathan de Halleux6-Apr-03 23:09 
GeneralRe: mxCreateCharArray Pin
Abbas_Riazi27-May-03 23:59
professionalAbbas_Riazi27-May-03 23:59 
Questiongetstring? Pin
mansour_ahmadian9-Jan-03 3:57
mansour_ahmadian9-Jan-03 3:57 
AnswerLook deeper... Pin
Jonathan de Halleux27-Jan-03 1:50
Jonathan de Halleux27-Jan-03 1:50 
Generali hope you can help me!!!!! Pin
Sunnygirl8-Jan-03 8:28
Sunnygirl8-Jan-03 8:28 
GeneralRe: i hope you can help me!!!!! Pin
Mo Hossny30-Jan-03 4:22
Mo Hossny30-Jan-03 4:22 
Questionwhy use the ActiveX interfcae? Pin
keller22-Oct-02 0:04
keller22-Oct-02 0:04 
AnswerAn answer Pin
Jonathan de Halleux22-Oct-02 1:08
Jonathan de Halleux22-Oct-02 1:08 
GeneralRe: An answer Pin
Mo Hossny30-Jan-03 4:26
Mo Hossny30-Jan-03 4:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.