VBA provides two basic procedure types: functions and subroutines.
You access a VBA function directly from a cell in a worksheet as a formula function. Use function procedures when the original MATLAB® function takes one or more inputs and returns zero outputs.
You access a subroutine as a general macro. Use a subroutine procedure when the original MATLAB function returns an array of values or multiple outputs because you need to map these outputs into multiple cells/ranges in the worksheet.
When you create a component, MATLAB
Compiler™ produces a
VBA module (.bas
file). This file contains simple
call wrappers, each implemented as a function procedure for each method
of the class.
Before you use any MATLAB Compiler component, initialize the supporting libraries with the current instance of Microsoft® Excel®. Do this once for an Excel session that uses the MATLAB Compiler components.
To
do this initialization, call the utility library function MWInitApplication
,
which is a member of the MWUtil
class. This class
is part of the MWComUtil
library. See Class MWUtil .
One way to add this initialization code into a VBA module is
to provide a subroutine that does the initialization once, and simply
exits for all subsequent calls. The following Microsoft
Visual Basic® code
sample initializes the libraries with the current instance of Excel.
A global variable of type Object
named MCLUtil
holds
an instance of the MWUtil
class, and another global
variable of type Boolean
named bModuleInitialized
stores
the status of the initialization process. The private subroutine InitModule()
creates
an instance of the MWComUtil
class and calls the MWInitApplication
method
with an argument of Application
. Once this function
succeeds, all subsequent calls exit without reinitializing.
Dim MCLUtil As Object Dim bModuleInitialized As Boolean Private Sub InitModule() If Not bModuleInitialized Then On Error GoTo Handle_Error If MCLUtil Is Nothing Then Set MCLUtil = CreateObject("MWComUtil.MWUtil") End If Call MCLUtil.MWInitApplication(Application) bModuleInitialized = True Exit Sub Handle_Error: bModuleInitialized = False End If End Sub
This code is similar to the default initialization code generated
in the VBA module created when the component is built. Each function
that uses MATLAB
Compiler components can include a call to InitModule
at
the beginning to ensure that the initialization always gets performed
as needed.
Before calling a class method (compiled MATLAB function), you must create an instance of the class that contains the method. VBA provides two techniques for doing this:
CreateObject
function
New
operator
This method uses the Microsoft
Visual Basic application programming
interface (API) CreateObject
function to create an instance of the class. Microsoft refers
to calling CreateObject as late binding and
using new
as early binding.
To use this method, declare a variable of type Object
using Dim
to
hold a reference to the class instance and call CreateObject
using
the class programmatic identifier (ProgID
) as an
argument, as shown in the next example:
Function foo(x1 As Variant, x2 As Variant) As Variant Dim aClass As Object On Error Goto Handle_Error Set aClass = CreateObject("mycomponent.myclass.1_0") ' (call some methods on aClass) Exit Function Handle_Error: foo = Err.Description End Function
This method uses the Visual Basic New
operator on a
variable explicitly dimensioned as the class to be created. Before
using this method, you must reference the type library containing
the class in the current VBA project. Do this by selecting the Tools menu from the Visual Basic Editor,
and then selecting References to
display the Available References list.
From this list, select the necessary type library.
The following example illustrates using the New
operator
to create a class instance. It assumes that you have selected mycomponent 1.0 Type Library from the Available References list
before calling this function.
Function foo(x1 As Variant, x2 As Variant) As Variant Dim aClass As mycomponent.myclass On Error Goto Handle_Error Set aClass = New mycomponent.myclass ' (call some methods on aClass) Exit Function Handle_Error: foo = Err.Description End Function
In this example, the class instance can be dimensioned as simply myclass
.
The full declaration in the form <component-name>.<class-name>
guards
against name collisions that can occur if other libraries in the current
project contain types named myclass
.
Using both CreateObject
and New
produce
a dimensioned class instance. The first method does not require a
reference to the type library in the VBA project; the second results
in faster code execution. The second method has the added advantage
of enabling the Auto-List-Members and Auto-Quick-Info capabilities of the Microsoft
Visual Basic editor
to work with your classes. The default function wrappers created with
each built component all use the first method for object creation.
In the previous two examples, the class instance used to make the method call was a local variable of the procedure. This creates and destroys a new class instance for each call. An alternative approach is to declare one single module-scoped class instance that is reused by all function calls, as in the initialization code of the previous example.
The following example illustrates this technique with the second method:
Dim aClass As mycomponent.myclass Function foo(x1 As Variant, x2 As Variant) As Variant On Error Goto Handle_Error If aClass Is Nothing Then Set aClass = New mycomponent.myclass End If ' (call some methods on aClass) Exit Function Handle_Error: foo = Err.Description End Function
MATLAB Compiler creates a single MATLAB Runtime when the first Microsoft COM class is instantiated in an application. This MATLAB Runtime is reused and shared among all subsequent class instances within the component, resulting in more efficient memory usage and eliminating the MATLAB Runtime startup cost in each subsequent class instantiation.
All class instances share a single MATLAB workspace and share global variables in the MATLAB files used to build the component. This makes properties of a COM class behave as static properties instead of instance-wise properties.
After you have created a class instance, you can call the class methods to access the compiled MATLAB functions. MATLAB Compiler applies a standard mapping from the original MATLAB function syntax to the method's argument list. See Reference Utility Classes for a detailed description of the mapping from MATLAB functions to COM class method calls.
When a method has output arguments, the first argument is always nargout
,
which is of type Long
. This input parameter passes
the normal MATLAB nargout
parameter to the
compiled function and specifies how many outputs are requested. Methods
that do not have output arguments do not pass a nargout
argument.
Following nargout
are the output parameters listed
in the same order as they appear on the left side of the original MATLAB function.
Next come the input parameters listed in the same order as they appear
on the right side of the original MATLAB function. All input
and output arguments are typed as Variant
, the
default Visual Basic data type.
The Variant
type can hold any of the basic
VBA types, arrays of any type, and object references. See Data Conversion Rules for a detailed description
of how to convert Variant
types of any basic type
to and from MATLAB data types. In general, you can supply any Visual Basic type
as an argument to a class method, with the exception of Visual Basic UDT
s.
You can also pass Microsoft
Excel Range
objects
directly as input and output arguments.
When you pass a simple Variant
type as an
output parameter, the called method allocates the received data and
frees the original contents of the Variant
. In
this case it is sufficient to dimension each output argument as a
single Variant
. When an object type (like an Excel Range
)
is passed as an output parameter, the object reference is passed in
both directions, and the object's Value
property
receives the data.
The following examples illustrate the process of passing input and output parameters from VBA to the MATLAB Compiler component class methods.
The first example is a formula function that takes two inputs
and returns one output. This function dispatches the call to a class
method that corresponds to a MATLAB function of the form function
y = foo(x1,x2)
.
Function foo(x1 As Variant, x2 As Variant) As Variant Dim aClass As Object Dim y As Variant On Error Goto Handle_Error Set aClass = New mycomponent.myclass aClass = CreateObject("mycomponent.myclass.1_0") Call aClass.foo(1,y,x1,x2) foo = y Exit Function Handle_Error: foo = Err.Description End Function
The second example rewrites the same function as a subroutine and uses Excel ranges for input and output.
Sub foo(Rout As Range, Rin1 As Range, Rin2 As Range) Dim aClass As Object On Error Goto Handle_Error aClass = CreateObject("mycomponent.myclass.1_0") Call aClass.foo(1,Rout,Rin1,Rin2) Exit Sub Handle_Error: MsgBox(Err.Description) End Sub
When varargin
and/or varargout
are
present in the MATLAB function that you are using for the Excel component,
these parameters are added to the argument list of the class method
as the last input/output parameters in the list. You can pass multiple
arguments as a varargin
array by creating a Variant
array,
assigning each element of the array to the respective input argument.
The following example creates a varargin
array
to call a method resulting from a MATLAB function of the form y = foo(varargin)
:
Function foo(x1 As Variant, x2 As Variant, x3 As Variant, _ x4 As Variant, x5 As Variant) As Variant Dim aClass As Object Dim v As Variant Dim y As Variant Dim MCLUtil As Object On Error GoTo Handle_Error set aClass = CreateObject("mycomponent.myclass.1_0") Set MCLUtil = CreateObject("MWComUtil.MWUtil") Call MCLUtil.MWPack(v, x1, x2, x3, x4, x5) Call aClass.foo(1, y, v) foo = y Exit Function Handle_Error: foo = Err.Description End Function
The MWUtil
class
included in the MWComUtil
utility library provides
the MWPack
helper function to create varargin
parameters.
See Class MWUtil for more details.
The next example processes a varargout
parameter
into three separate Excel Range
s. This function
uses the MWUnpack
function in the utility library.
The MATLAB function used is varargout = foo(x1,x2)
.
Sub foo(Rout1 As Range, Rout2 As Range, Rout3 As Range, _ Rin1 As Range, Rin2 As Range) Dim aClass As Object Dim aUtil As Object Dim v As Variant On Error Goto Handle_Error aUtil = CreateObject("MWComUtil.MWUtil") aClass = CreateObject("mycomponent.myclass.1_0") Call aClass.foo(3,v,Rin1,Rin2) Call aUtil.MWUnpack(v,0,True,Rout1,Rout2,Rout3) Exit Sub Handle_Error: MsgBox(Err.Description) End Sub
In MATLAB, varargin
inputs to functions
are optional, and may be present or omitted from the function call.
However, from Microsoft
Visual Basic, function signatures are more
strict—if varargin
is present among the MATLAB function
inputs, the VBA call must include varargin
, even
if you want it to be empty. To pass in an empty varargin
,
pass the Null
variant, which is converted to an
empty MATLAB cell array when passed.
Pass an Empty varargin from VBA Code. The following example illustrates how to pass the null variant
in order to pass an empty varargin
:
Function foo(x1 As Variant, x2 As Variant, x3 As Variant, _ x4 As Variant, x5 As Variant) As Variant Dim aClass As Object Dim v(1 To 5) As Variant Dim y As Variant On Error Goto Handle_Error v(1) = x1 v(2) = x2 v(3) = x3 v(4) = x4 v(5) = x5 aClass = CreateObject("mycomponent.myclass.1_0") 'Call aClass.foo(1,y,v) Call aClass.foo(1,y,Null) foo = y Exit Function Handle_Error: foo = Err.Description End Function
For more information about working with variable-length arguments, see Work with Variable-Length Inputs and Outputs.
Each MATLAB
Compiler component exposes a single read/write
property named MWFlags
of type MWFlags
.
The MWFlags
property consists of two sets of constants: array formatting flags and data conversion flags. Array
formatting flags affect the transformation of arrays,
whereas data conversion flags deal with type
conversions of individual array elements.
The data conversion flags change selected behaviors of the data
conversion process from Variant
s to MATLAB types
and vice versa. By default, the MATLAB
Compiler components allow
setting data conversion flags at the class level through the MWFlags
class
property. This holds true for all Visual Basic types, with the
exception of the MATLAB
Compiler MWStruct
, MWField
, MWComplex
, MWSparse
,
and MWArg
types. Each of these types exposes its
own MWFlags
property and ignores the properties
of the class whose method is being called. The MWArg
class
is supplied specifically for the case when a particular argument needs
different settings from the default class properties.
This section provides a general discussion of how to set these
flags and what they do. See Class MWFlags (MATLAB Compiler SDK) for
a detailed discussion of the MWFlags
type, as well
as additional code samples.
Array formatting flags guide the data conversion to produce
either a MATLAB cell array or matrix from general Variant
data
on input or to produce an array of Variant
s or
a single Variant
containing an array of a basic
type on output.
The following examples assume that you have referenced the MWComUtil
library
in the current project by selecting Tools >
References and selecting MWComUtil
7.5 Type Library from the list:
Sub foo( ) Dim aClass As mycomponent.myclass Dim var1(1 To 2, 1 To 2), var2 As Variant Dim x(1 To 2, 1 To 2) As Double Dim y1,y2 As Variant On Error Goto Handle_Error var1(1,1) = 11# var1(1,2) = 12# var1(2,1) = 21# var1(2,2) = 22# x(1,1) = 11 x(1,2) = 12 x(2,1) = 21 x(2,2) = 22 var2 = x Set aClass = New mycomponent.myclass Call aClass.foo(1,y1,var1) Call aClass.foo(1,y2,var2) Exit Sub Handle_Error: MsgBox(Err.Description) End Sub
In addition, these examples assume you have referenced the COM
object created with MATLAB
Compiler (mycomponent
)
as mentioned in New Operator.
Here, two Variant
variables, var1
and var2
are
constructed with the same numerical data, but internally they are
structured differently: var1
is a 2-by-2 array
of Variant
s with each element containing a 1-by-1 Double
,
while var2
is a 1-by-1 Variant
containing
a 2-by-2 array of Double
s.
In MATLAB
Compiler, when using the default settings, both
of these arrays will be converted to 2-by-2 arrays of double
s.
This does not follow the general convention listed in COM VARIANT
to the MATLAB Conversion Rules. According to these rules, var1
converts
to a 2-by-2 cell array with each cell occupied by a 1-by-1 double,
and var2
converts directly to a 2-by-2 double matrix.
The two arrays both convert to double matrices because the default
value for the InputArrayFormat
flag is mwArrayFormatMatrix
.
The InputArrayFormat
flag controls how arrays
of these two types are handled. This default is used because array
data originating from Excel ranges is always in the form of an
array of Variant
s (like var1
of
the previous example), and MATLAB functions most often deal with
matrix arguments.
But what if you want a cell array? In this case, you set the InputArrayFormat
flag
to mwArrayFormatCell
. Do this by adding the following
line after creating the class and before the method call:
aClass.MWFlags.ArrayFormatFlags.InputArrayFormat = mwArrayFormatCell
Setting this flag presents all array input to the compiled MATLAB function as cell arrays.
Similarly, you can manipulate the format of output arguments
using the OutputArrayFormat
flag. You can also
modify array output with the AutoResizeOutput
and TransposeOutput
flags.
AutoResizeOutput
is used for Excel Range
objects
passed directly as output parameters. When this flag is set, the target
range automatically resizes to fit the resulting array. If this flag
is not set, the target range must be at least as large as the output
array or the data is truncated.
The TransposeOutput
flag transposes all array
output. This flag is useful when dealing with MATLAB functions
that output one-dimensional arrays. By default, MATLAB realizes
one-dimensional arrays as 1-by-n matrices (row vectors) that become
rows in an Excel worksheet.
If your MATLAB function is specifically returning a row vector, for example, ensure you assign a similar row vector of cells in Excel.
You may prefer worksheet columns from row vector output. This example auto-resizes and transposes an output range:
Sub foo(Rout As Range, Rin As Range ) Dim aClass As mycomponent.myclass On Error Goto Handle_Error Set aClass = New mycomponent.myclass aClass.MWFlags.ArrayFormatFlags.AutoResizeOutput = True aClass.MWFlags.ArrayFormatFlags.TransposeOutput = True Call aClass.foo(1,Rout,Rin) Exit Sub Handle_Error: MsgBox(Err.Description) End Sub
Data conversion flags deal with type conversions of individual
array elements. The two data conversion flags, CoerceNumericToType
and InputDateFormat
,
govern how numeric and date types are converted from VBA to MATLAB.
Consider the example:
Sub foo( ) Dim aClass As mycomponent.myclass Dim var1, var2 As Variant Dim y As Variant On Error Goto Handle_Error var1 = 1 var2 = 2# Set aClass = New mycomponent.myclass Call aClass.foo(1,y,var1,var2) Exit Sub Handle_Error: MsgBox(Err.Description) End Sub
This example converts var1
of type Variant/Integer
to
an int16
and var2
of type Variant/Double
to
a double
.
If the original MATLAB function expects double
s
for both arguments, this code might cause an error. One solution is
to assign a double
to var1
,
but this may not be possible or desirable. In such a case set the CoerceNumericToType
flag
to mwTypeDouble
, causing the data converter to
convert all numeric input to double
. In the previous
example, place the following line after creating the class and before
calling the methods:
aClass.MWFlags.DataConversionFlags.CoerceNumericToType = mwTypeDouble
The InputDateFormat
flag controls how the
VBA Date
type is converted. This example sends
the current date and time as an input argument and converts it to
a string:
Sub foo( ) Dim aClass As mycomponent.myclass Dim today As Date Dim y As Variant On Error Goto Handle_Error today = Now Set aClass = New mycomponent.myclass aClass. MWFlags.DataConversionFlags.InputDateFormat = mwDateFormatString Call aClass.foo(1,y,today) Exit Sub Handle_Error: MsgBox(Err.Description) End Sub
Errors that occur while creating a class instance or during
a class method create an exception in the current procedure. Microsoft
Visual Basic provides
an exception handling capability through the On Error Goto
<label>
statement, in which the program execution
jumps to <label>
when an error occurs. (<label>
must
be located in the same procedure as the On Error Goto
statement).
All errors are handled this way, including errors within the original MATLAB code.
An exception creates a Visual Basic ErrObject
object
in the current context in a variable called Err
.
(See the Visual Basic for Applications documentation for a detailed
discussion on VBA error handling.) All of the examples in this section
illustrate the typical error trapping logic used in function call
wrappers for MATLAB
Compiler components.