Main Content

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

この方法では、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 という名前の型がある場合に発生する可能性がある名前の競合が回避されます。

CreateObjectNew のどちらを使用しても、設定されたクラス インスタンスが生成されます。最初の方法では 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 ExcelRange オブジェクトを入力引数および出力引数として直接渡すこともできます。

単純な 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 CompilerMWStruct 型、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 型の var1int16 に、そして Variant/Double 型の var2double に変換されます。

元の MATLAB 関数が両方の引数に対して double を想定している場合、このコードはエラーとなる可能性があります。1 つの解決方法は doublevar1 に割り当てることですが、これは可能ではない、あるいは望ましくない場合があります。そのような場合、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 BasicOn Error Goto <label> ステートメントを介した例外処理機能を提供しています。このステートメントでは、エラーが発生すると、プログラムの実行は <label> にジャンプします (<label>On Error Goto ステートメントと同じプロシージャ内になければなりません)。すべてのエラーは元の MATLAB コード内のエラーも含め、この方法で処理されます。例外によって、Err と呼ばれる変数内の現在のコンテキストには、Visual Basic の ErrObject オブジェクトが作成されます (VBA エラー処理についての詳細は、Visual Basic for Applications のドキュメンテーションを参照してください)。この節のすべての例では、MATLAB Compiler コンポーネント用の関数呼び出しラッパーで使用される一般的なエラー トラップ ロジックを説明します。