VBA を使用したコンポーネントの統合
数式関数またはサブルーチンを使用する場合
VBA では、関数およびサブルーチンという 2 つの基本プロシージャ タイプが提供されています。
VBA 関数にはワークシートのセル内から数式関数として直接アクセスします。元の MATLAB® 関数の出力が 1 つ、または出力がない場合には、関数プロシージャを使用します。
サブルーチンには一般的なマクロとしてアクセスします。元の MATLAB 関数が値の配列または複数の出力を返す場合には、これらの出力をワークシート内の複数のセル/範囲にマップしなければならないため、サブルーチン プロシージャを使用します。
コンポーネントを作成するときに、MATLAB Compiler™ は VBA モジュール (.bas
ファイル) を作成します。このファイルには単純な呼び出しラッパーが含まれており、クラスのメソッドごとに関数プロシージャとしてそれぞれが実装されています。詳細については、Excel アドインのコンパイルの仕組みを参照してください。
MATLAB Compiler ライブラリを Microsoft Excel で初期化
任意の MATLAB Compiler コンポーネントを使用する前に、サポートするライブラリを Microsoft® Excel® の現在のインスタンスで初期化します。MATLAB Compiler コンポーネントを使用する Excel セッションについて、これを 1 回実行します。
この初期化を実行するには、MWUtil
クラスのメンバーであるユーティリティ ライブラリ関数 MWInitApplication
を呼び出します。このクラスは MWComUtil
ライブラリの一部です。詳細については、クラス MWUtilを参照してください。
この初期化コードを VBA モジュールに追加する方法の 1 つは、初期化を 1 回実行し、それ以降のすべての呼び出しを単純に終了するサブルーチンを指定することです。次の Microsoft Visual Basic® コード サンプルでは、ライブラリを Excel の現在のインスタンスで初期化しています。Object
型の MCLUtil
という名前のグローバル変数は、MWUtil
クラスのインスタンスを保持し、Boolean
型の bModuleInitialized
という名前の別のグローバル変数は、初期化プロセスの状態を格納します。プライベート サブルーチン InitModule()
は MWComUtil
クラスのインスタンスを作成し、MWInitApplication
メソッドを引数 Application
で呼び出します。この関数が正常に終了すると、その後のすべての呼び出しは再び初期化されることなく終了します。
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
このコードはコンポーネントのビルド時に作成される VBA モジュール内で生成される既定の初期化コードに似ています。MATLAB Compiler コンポーネントを使用する各関数では、必要な場合は常に初期化されるように InitModule
の呼び出しを先頭に含めることができます。
クラスのインスタンスの作成
クラス メソッド (コンパイルされた MATLAB 関数) を呼び出す前に、そのメソッドを含むクラスのインスタンスを作成する必要があります。VBA にはこれを行うための 2 つの手法が用意されています。
関数
CreateObject
New
演算子
関数 CreateObject
この方法では、Microsoft Visual Basic アプリケーション プログラミング インターフェイス (API) の関数 CreateObject
を使用してクラスのインスタンスを作成します。Microsoft では CreateObject の呼び出しを "遅延バインド"、new
の使用を "事前バインド" と呼んでいます。
この方法を使用するには、次の例に示すように、クラス インスタンスへの参照を保持するために Object
型の変数を Dim
を使用して宣言し、CreateObject
をクラス プログラム識別子 (ProgID
) を引数として使用して呼び出します。
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
New 演算子
この方法では、作成するクラスとして明示的に設定された変数に Visual Basic の New
演算子を使用します。この方法を使用する前に、現在の VBA プロジェクトのクラスを含むタイプ ライブラリを参照しなければなりません。これを実行するには、Visual Basic エディターの [ツール] メニューを選択し、[参照設定] を選択して [参照可能なライブラリファイル] リストを表示します。このリストから、必要なタイプ ライブラリを選択します。
以下の例では、New
演算子を使用してクラス インスタンスを作成する方法を説明します。この関数を呼び出す前に [参照可能なライブラリファイル] リストから [mycomponent 1.0 Type Library] を選択していることを前提にしています。
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
この例では、クラス インスタンスは単純に myclass
として設定できます。<component-name>.<class-name>
の形式で完全に宣言すると、現在のプロジェクトの他のライブラリに myclass
という名前の型がある場合に発生する可能性がある名前の競合が回避されます。
CreateObject
と New
のどちらを使用しても、設定されたクラス インスタンスが生成されます。最初の方法では VBA プロジェクト内のタイプ ライブラリへの参照を必要としません。2 番目の方法ではコード実行が速くなります。2 番目の方法には、Microsoft Visual Basic Editor の自動メンバー表示機能と自動クイック ヒント機能でクラスを操作できるという追加の利点があります。ビルドされた各コンポーネントと共に作成されるすべての既定の関数ラッパーでは、オブジェクトの作成に最初のメソッドが使用されます。
前の 2 つの例では、メソッドの呼び出しに使用されたクラス インスタンスはプロシージャのローカル変数でした。これにより、呼び出しのたびに、新しいクラス インスタンスが作成され廃棄されます。代替の手法は、前の例の初期化コードのように、すべての関数呼び出しで再利用される、単一のモジュールをスコープとしたクラス インスタンスを宣言することです。
次の例では、2 番目の方法でこの手法を使用しています。
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 Runtime を共有する方法
MATLAB Compiler は、最初の Microsoft COM クラスがアプリケーション内でインスタンス化されるときに単一の MATLAB Runtime インスタンスを作成します。この MATLAB Runtime はコンポーネント内で後続のすべてのクラス インスタンス間で再利用されて共有されるため、メモリの使用効率が向上し、後続の各クラスのインスタンス化で MATLAB Runtime の起動コストが抑えられます。
すべてのクラス インスタンスが、単一の MATLAB ワークスペースを共有し、コンポーネントのビルドで使用された MATLAB ファイル内のグローバル変数を共有します。これにより COM クラスのプロパティはインスタンス単位のプロパティではなく静的プロパティとして動作します。
クラス インスタンスのメソッドの呼び出し
クラス インスタンスを作成した後、コンパイルされた MATLAB 関数にアクセスするためにクラス メソッドを呼び出すことができます。MATLAB Compiler は、元の MATLAB 関数構文からメソッドの引数リストへの標準マッピングを適用します。MATLAB 関数から COM クラス メソッド呼び出しへのマッピングの詳細な説明は、ユーティリティ クラスの参照を参照してください。
メソッドに出力引数がある場合、最初の引数は常に Long
型の nargout
です。この入力パラメーターは通常の MATLAB nargout
パラメーターをコンパイルされた関数に渡し、必要な出力の数を指定します。出力引数をもたないメソッドは nargout
引数を渡しません。nargout
の後には、元の MATLAB 関数の左辺と同じ順序でリストされた出力パラメーターが続きます。次に元の MATLAB 関数の右辺と同じ順序でリストされた入力パラメーターが続きます。すべての入力引数および出力引数は Visual Basic の既定のデータ型である Variant
型になります。
Variant
型は VBA の任意の基本型、任意の型の配列およびオブジェクト参照を保持できます。任意の基本型の Variant
型と MATLAB データ型間の変換方法の詳細な説明は、データ変換ルールを参照してください。一般的に、Visual Basic UDT
を例外として、任意の Visual Basic 型をクラス メソッドの引数として指定することができます。Microsoft Excel の Range
オブジェクトを入力引数および出力引数として直接渡すこともできます。
単純な Variant
型を出力パラメーターとして渡すと、呼び出されたメソッドは受け取ったデータを割り当て、Variant
の元の内容を解放します。この場合、それぞれの出力引数を単一の Variant
として設定すれば十分です。オブジェクト型 (Excel Range
など) が出力パラメーターとして渡される場合、オブジェクト参照が双方向に渡され、オブジェクトの Value
プロパティがデータを受け取ります。
以下の例では、VBA からの入力パラメーターおよび出力パラメーターが MATLAB Compiler コンポーネントのクラス メソッドに渡されるプロセスを説明します。
最初の例は 2 つの入力を取り、出力を 1 つ返す数式関数です。この関数は、function y = foo(x1,x2)
という形式の MATLAB 関数に対応するクラス メソッドの呼び出しをディスパッチします。
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
2 番目の例では、同じ関数をサブルーチンとして書き換え、Excel の範囲を入力および出力として使用しています。
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
可変引数をもつプログラム
varargin 引数と varargout 引数の処理
varargin
または varargout
、あるいはその両方が、Excel コンポーネントのために使用する MATLAB 関数内にあるとき、これらのパラメーターはクラス メソッドの引数リストにリストの最後の入力/出力パラメーターとして追加されます。Variant
配列を作成し、配列の各要素をそれぞれの入力引数に代入することで、複数の引数を varargin
配列として渡せます。
次の例では、y = foo(varargin)
という形式の MATLAB 関数から得られたメソッドを呼び出すために、配列 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
MWComUtil
ユーティリティ ライブラリに含まれる MWUtil
クラスは varargin
パラメーターを作成するための補助関数 MWPack
を提供します。詳細は、クラス MWUtilを参照してください。
次の例では、varargout
パラメーターを処理して 3 つの別々の Excel Range
にします。この関数はユーティリティ ライブラリ内の関数 MWUnpack
を使用します。使用されている MATLAB 関数は 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
Microsoft Visual Basic コードから空の varargin を渡す
MATLAB では、関数への varargin
入力はオプションであり、関数呼び出しで含まれる、あるいは省略される可能性があります。ただし、Microsoft Visual Basic からの関数シグネチャはより厳格であり、varargin
が MATLAB 関数入力の間に存在する場合は、空にする場合でも VBA 呼び出しには varargin
を含めなければなりません。空の varargin
を渡すためには、Null
バリアントを渡します。渡された後、空の MATLAB cell 配列に変換されます。
VBA コードから空の varargin を渡す. 次の例では、空の varargin
を渡すために null のバリアントを渡す方法を示しています。
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
詳細情報
可変長引数の取り扱いの詳細については、複数の MATLAB 関数を使用するマクロの作成を参照してください。
フラグの変更
各 MATLAB Compiler コンポーネントは、MWFlags
型で MWFlags
という名前をもつ単一の読み取り/書き込みプロパティを公開します。MWFlags
プロパティは、配列形式フラグとデータ変換フラグという 2 セットの定数で構成されています。"配列形式フラグ" が配列の変換に影響するのに対し、"データ変換フラグ" は個々の配列要素の型変換を処理します。
データ変換フラグは、Variant
から MATLAB 型へのデータ変換とその逆のプロセスで選択された動作を変更します。既定で、MATLAB Compiler コンポーネントは MWFlags
クラス プロパティを介してクラス レベルでデータ変換フラグの設定を許可します。これは MATLAB Compiler の MWStruct
型、MWField
型、MWComplex
型、MWSparse
型、および MWArg
型を例外として、すべての Visual Basic の型に当てはまります。これらの各型は自身の MWFlags
プロパティを公開し、メソッドが呼び出されているクラスのプロパティを無視します。MWArg
クラスは、特に特定の引数が既定のクラス プロパティとは異なる設定を必要とする場合に指定されます。
この節では、これらのフラグの設定方法とその動作についての一般的な説明を記載しています。MWFlags
型の詳細および追加のコード サンプルについては、クラス MWFlags (MATLAB Compiler SDK)を参照してください。
配列形式フラグ
配列形式フラグによるデータ変換の指示は、入力において一般的な Variant
データから MATLAB cell 配列または行列を生成するか、出力において Variant
の単一の配列か、基本型の配列を含む単一の Variant
を生成します。
以下の例では、[ツール]、[参照設定] を選択した後、リストから [MWComUtil 7.5 Type Library] を選択して、現在のプロジェクトの MWComUtil
ライブラリを参照したことを前提としています。
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
さらに、これらの例では、New 演算子で説明されているように、MATLAB Compiler で作成された COM オブジェクト (DLL ファイル) (mycomponent
) が参照されていることを前提としています。
ここで、2 つの Variant
変数 var1
および var2
は同じ数値データで作成されていますが、内部の構造は異なります。var1
は、各要素に 1 行 1 列の Double
を含む Variant
の 2 行 2 列の配列であり、var2
は 2 行 2 列の Double
の配列を含む 1 行 1 列の Variant
です。
MATLAB Compiler で既定の設定を使用する場合、これらの配列は両方とも 2 行 2 列の double
の配列に変換されます。これは COM バリアントから MATLAB への変換ルールにリストされた一般的な規則に従っていません。これらのルールによれば、var1
は 2 行 2 列の cell 配列に変換され、各セルには 1 行 1 列の double が入り、var2
は 2 行 2 列の double 行列に直接変換されます。
2 つの配列は InputArrayFormat
フラグの既定値が mwArrayFormatMatrix
なので、両方とも double 行列に変換されます。InputArrayFormat
フラグはこれら 2 つの型の配列の処理方法を制御します。Excel の範囲から発生する配列データは常に (前の例の var1
のように) Variant
の配列の形式であり、MATLAB 関数はほとんどの場合、行列引数を処理するため、この既定が使用されます。
しかし、 cell 配列が必要な場合もあります。この場合は、InputArrayFormat
フラグを mwArrayFormatCell
に設定します。このようにするには、クラス作成の後、メソッドを呼び出す前に以下の行を追加します。
aClass.MWFlags.ArrayFormatFlags.InputArrayFormat = mwArrayFormatCell
このフラグを設定すると、コンパイルされた MATLAB 関数のすべての配列入力が cell 配列として表されます。
同様に、出力引数の形式を OutputArrayFormat
フラグを使用して操作できます。配列出力を AutoResizeOutput
フラグおよび TransposeOutput
フラグを使用して変更することもできます。
AutoResizeOutput
は出力パラメーターとして直接渡される Excel Range
オブジェクトに使用されます。このフラグが設定されると、ターゲット範囲は結果の配列に合うように自動的にサイズ変更されます。このフラグが設定されない場合、ターゲット範囲は少なくとも出力配列と同じ大きさでなければなりません。そうでない場合、データは打ち切られます。
TransposeOutput
フラグはすべての配列出力を転置します。このフラグは 1 次元配列を出力する MATLAB 関数を処理するときに役に立ちます。既定では、MATLAB は 1 次元配列を Excel ワークシートでは行となる 1 行 n 列の行列 (行ベクトル) にします。
ヒント
たとえば、MATLAB 関数が厳密に行ベクトルを返す場合、Excel では必ずセルで構成された同様の行ベクトルを割り当てるようにしてください。
行ベクトル出力からワークシートの列にする場合もあります。この例では、出力範囲を自動でサイズ変更し転置しています。
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
データ変換フラグ
データ変換フラグは個々の配列要素の型変換を処理します。2 つのデータ変換フラグ CoerceNumericToType
および InputDateFormat
は、VBA から MATLAB への数値型および日付型の変換方法を制御します。以下の例を考えてみましょう。
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
この例では、Variant/Integer
型の var1
が int16
に、そして Variant/Double
型の var2
が double
に変換されます。
元の MATLAB 関数が両方の引数に対して double
を想定している場合、このコードはエラーとなる可能性があります。1 つの解決方法は double
を var1
に割り当てることですが、これは可能ではない、あるいは望ましくない場合があります。そのような場合、CoerceNumericToType
フラグを mwTypeDouble
に設定し、データ コンバーターによりすべての数値入力を double
に変換します。前の例では、以下の行をクラス作成の後、メソッドの呼び出しの前に置きます。
aClass.MWFlags.DataConversionFlags.CoerceNumericToType = mwTypeDouble
InputDateFormat
フラグは VBA Date
型の変換方法を制御します。この例では、現在の日付と時刻を入力引数として送り、文字列に変換しています。
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
メソッド呼び出し中のエラー処理
クラス インスタンスの作成中またはクラス メソッド中に発生するエラーは、現在のプロシージャで例外を生成します。Microsoft Visual Basic は On Error Goto <label>
ステートメントを介した例外処理機能を提供しています。このステートメントでは、エラーが発生すると、プログラムの実行は <label>
にジャンプします (<label>
は On Error Goto
ステートメントと同じプロシージャ内になければなりません)。すべてのエラーは元の MATLAB コード内のエラーも含め、この方法で処理されます。例外によって、Err
と呼ばれる変数内の現在のコンテキストには、Visual Basic の ErrObject
オブジェクトが作成されます (VBA エラー処理についての詳細は、Visual Basic for Applications のドキュメンテーションを参照してください)。この節のすべての例では、MATLAB Compiler コンポーネント用の関数呼び出しラッパーで使用される一般的なエラー トラップ ロジックを説明します。