VBAをVBに変換2017.11.04
VBAから扱えるDLLを作成したいと思い、Visual Studio 2017を利用し、試しにつくってみました。VBAから扱えるDLLを作成
無事に動作したので、次にVBAで書いた大がかりな関数をDLLにすることにしました。
今回取り組むのは、数独を解析する関数です。VBAコード:Excelで数独解析 Ver.2.3.0
Visual Studio はVBやC#等なので、最も変換しやすいVB(2017)に、VBAコードを変換してみました。
何点か気を付ける点があったので、そのまとめとコードのメモです。
これらの情報はVB2017を前提としています。
ポイント
・変数
・配列
・構造体
・ラベル
・Function
変数
32ビット符号付き整数
32ビット符号付き整数は、VBではInteger型であるのに対し、VBA(32ビット)ではLong型になる。型が違うとエラーになる。引数の引き渡しの際に注意が必要。
[ VB ]で次のように、Integer型を引数の型に指定する。(画像クリックで拡大↓)
[ VBA ]でInteger型を引数に指定すると、エラーになる。
[ VBA ]でLong型にすると、正常に実行される。
Variant型は使えない
VBは.NET以降、Variant型が非対応。VBAで、セルの値を代入したVariant型の変数は、対応する型に変換する必要がある。次のサイトには代替案が載っている。
連載! とことん VB: 第 2 回 VB.NET における Variant 型の代替案
尚、Excelで数独解析 Ver.2.3.0のVBAコードでは、引数にセルの値を代入したVariant型の2次元配列を渡していた。VBではそれができないので、Variant型配列に代入したセルの値を、Long型の変数に代入しなおし、引数として渡すことにした。
[ VBA ]元のコード
[ VBA ] VBに対応させるため、Variant型に格納されている値をLong型に代入したコード
配列
配列のインデックス
VB(2017) で配列のインデックスの下限に設定できるのは0のみである。3つの要素を持つ配列を宣言する際、VBAでは、次のようにインデックスの下限が0でなくとも設定できる。
Dim i(1 To 3) As Long ' 1,2,3
もちろん、次の書き方だと下限は0になる(Option Base 1 を設定していなければ)。
Dim i(2) As Long ' 0,1,2
一方、VBでは次の形でしか宣言できない。
下限は0で決まっておりOption Baseステートメントもない。
Dim i(2) As Integer ' 0,1,2
では、VBAで Dim i(1 To 3) As Long ' 1,2,3 このようにインデックスの下限が0でない設定で、配列を用いていた場合はどのように修正すればよいのか。
それは Dim i(3) As Long ' 0,1,2,3 のようにするのである(もちろん状況によるが)。
そしてVBも同様に Dim i(3) As Integer ' 0,1,2,3 このように宣言すれば良い。
使用しない(0)の部分の要素数は増えるが、コードを書き換える手間は省ける。
数独を解析するコードでは、9行×9列のセル範囲をVariant型変数に代入しているため、2次元配列の下限はそれぞれ1になる。Variant型をLong型に変換する際、Dim lngRangeS(9, 9) As Longを宣言し、配列要素の0は使わずに、値を代入し、それをVBに引き渡している。もちろん、VB側もDim intRangeS(9, 9) As Integerで受け取るよう設定する。
動的配列の宣言と引き渡し
VBAでの動的配列の宣言は、次元数に関係なく 変数名() で行う。Redimで要素数や次元数を設定する。
サブルーチンや関数の引数で配列を受け取る時も、次元数に関係なく 変数名() でよい。
'VBAサンプル Public Sub TEST() Dim i() As Long ReDim i(1) Call test1(i) MsgBox i(1) ReDim i(1, 1) Call test2(i) MsgBox i(1, 1) End Sub
Private Sub test1(ByRef i() As Long) i(1) = 100 End Sub
Private Sub test2(ByRef i() As Long) i(1, 1) = 200 End Sub
一方VBでは、動的配列を宣言する際に次元数を指定する必要がある。2次元だと 変数名(,) になる。そしてRedimで設定できるのは要素数のみになる。つまり、1次元配列と2次元配列は、別々に宣言する必要がある。
サブルーチンや関数の引数で配列を受け取る時も、次元数を指定する必要がある。
'VBサンプル Public Sub TEST() Dim i() As Integer ReDim i(1) Call test1(i) MsgBox(i(1)) Dim ii(,) As Integer ReDim ii(1, 1) Call test2(ii) MsgBox(ii(1, 1)) End Sub
Private Sub test1(ByRef i() As Integer) i(1) = 100 End Sub
Private Sub test2(ByRef i(,) As Integer) i(1, 1) = 200 End Sub
ユーザー定義型(構造体)
VBAのユーザー定義型を宣言するTypeステートメントはVBにない。それに代わるのがStructureステートメント。
数独を解析するプログラムでは構造体を利用している。以下、その宣言部分。
'VBA Type Separation Value() As Long Count(1 To 9, 1 To 9) As Long End Type Private typSep(1 To 52) As Separation
上記をVB変換すると、次のようになる。
'VB Structure Separation Dim Value(,) As Integer Dim Count(9,9) As Integer End Structure Private typSep(52) As Separation
ラベル
VBAでも、VBでも ERR: のようなラベルは使えるが、VBではGoSubは使えない。
GoToで対応。
'VBA Sub test() Call Sample(0) End Sub
Sub Sample(ByVal n As Long) If n = 0 Then GoSub ERR Exit Sub ERR: MsgBox "Error" End Sub
'VB Sub test() Call Sample(0) End Sub
Sub Sample(ByVal n As Long) If n = 0 Then GoTo ERR Exit Sub ERR: MsgBox("Error") End Sub
Function(関数)
Functionの戻り値に関して、VBAでは関数名が戻り値になるのに対し、VBは、Returnステートメントを使い戻り値を設定する。
'VBA Public Function VBA_Sample(ByVal c As Long) As Long Dim i As Long For i = 0 To c VBA_Sample = VBA_Sample + i Next End Function
'VB Public Function VB_Sample(ByVal c As Integer) As Integer Dim i As Integer For i = 0 To c VB_Sample = VB_Sample + i Next Return VB_Sample End Function
VB・VBAコード比較
少し時間がかかったが、Excelで数独解析 Ver.2.3.0のVBAコードを、VB(2017)コードに変換できた。
VBとVBAのコード比較ページを準備した。
ページの左側が、実際にVisual Studio 2017に入力したVBコード、右側が、元のVBAのコードである。
比較ページ
Excelマクロ管理ツール