DLL関数を作成する(戻り値あり)|C++でDLLを自作してExcelVBAで呼び出す方法④
第2回、第3回で引数のありと引数なしの2パターンの関数の作成しました。
関数としては入力となる「引数」と出力となる「戻り値」が設定ができれば、基本的な関数としての機能は満たせます。
という訳で今回は「戻り値あり」パターンの関数を作成していきます。
第1~3回と第4回となる今回を合わせてVBAで呼び出すことのできるDLL関数を作成する方法は一区切りです。あとはDLL内のコードつまりはC++の内容に入るので、作成したい関数を実現できるようC++を学習すれば実現できる機能の幅が広がっていきます。
DLLファイルを作成(引数なし)
今回はVBAから引数として渡されたファイルパスをもとに、そのファイルのサイズを取得してVBA側に返す「GetFileSize1」関数を作成していきます。C++にはすでに「GetFileSize」という関数が存在しており、同じ関数名は使用できないため「GetFileSize1」という関数名にしています。
本関数はこれまでと同じく「VBA_DLL.dll」内に追加していきます。
VisualStudioを閉じてしまった場合は「VBA_DLL.sln」を開いて追記していって下さい。
ヘッダーファイル (VBA_DLL.h)
まずは「GetFileSize1」関数を宣言します。
今回の引数はファイルパスということで文字列となります。
引数を文字列(VBA側はString)として受け取る場合はconst char*型を使います。
また、今回は取得したファイルサイズを戻り値としてVBA側に返すため、これまで「void」としていた部分は戻り値の型となる「long」を指定し、下記のように宣言します。
extern “C” VBADLL_API long GetFileSize1(const char* sFilePath);
今回は文字列の受け取りに「const char*型」を使いましたがそのほかの型を使った受け渡し方法もあります。またこの型はVBAからString型を受け取ることはできますが、DLL側からVBAのString型に返すことはできない一方通行のものなので注意して下さい。
ソースファイル (VBA_DLL.cpp)
ヘッダーファイルに新たな関数「GetFileSize1」の宣言をしたので、ソースファイル(.cpp)側では関数の処理内容を書いていきます。コードは下記の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include "VBA_DLL.h" #include "windows.h" #include "sys/stat.h" //ファイル状態を取得するstat関数が含まれている //void EmptyProcess() は表示の関係上省略 //void HelloWorld() は表示の関係上省略 //void AddNumber(long a, long b) は表示の関係上省略 long GetFileSize1(const char* sFilePath) { struct _stat buf; int result = _stat(sFilePath, &buf); if (result == 0) { return buf.st_size; } else { return 0; } } |
このコードにより引数として入力されたファイルパスのファイルサイズを取得し、Long型でVBAに値を返すことができます。また、入力されたパスのファイルが存在しない場合は「0」という値を返すような処理となっています。
C++でファイルサイズの取得方法はいくつかありますが、今回は「stat関数」を使って取得するようにしているため「#include “sys/stat.h”」を忘れず記載しておきましょう。
VBAで作成したDLLファイルを呼び出す
上記のコードでDLLファイルを出力したら、VBAで呼び出してみます。コードは下記の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
'DLLファイルの関数定義 Private Declare PtrSafe Function GetFileSize1 _ Lib "C:\programming\cpp\VBA_DLL\x64\Release\VBA_DLL.dll" (ByVal sFilePath As String) As Long Sub Test() Dim iFileSize As Long Dim sFilePath As String sFilePath = Application.GetOpenFilename() If sFilePath = "False" Then Exit Sub iFileSize = GetFileSize1(sFilePath) MsgBox "選択したファイルのサイズは" & iFileSize / 1024 & "kbです" End Sub |
今回のDLLの関数は戻り値ありなので、VBA側でも戻り値を受け取る設定をします。
DLL内で宣言した戻り値の型と対応するようにVBA側の戻り値の型を下記のように設定します。
Private Declare PtrSafe Function 関数名 Lib “DLLファイル” () As 戻り値の型
戻り値ありの場合は関数名の前を「Function」にする必要があるので注意して下さい。
また、引数はDLL側では文字列の型として「const char*型」を指定しましたが、VBAでの文字列の型はString型なので関数の宣言では「ByVal sFilePath As String」とすればOKです。
上記コードを実行することで、選択したファイルのサイズをメッセージボックスで表示することができます。DLLから返ってくる値の単位は「Byte」なのでVBA側で「KByte」に変換するような処理もしています。(1KByte = 1024Byte)
選択ファイルを変えることで、しっかりとDLL側とVBA側でやり取りできていることがわかります。
まとめ
今回はDLLの関数として引数と戻り値のある関数を新たに追加しました。
内容をまとめると下記の通りです。
C++側:extern “C” VBADLL_API 戻り値の型 関数名();
VBA側:Private Declare PtrSafe Function 関数名 Lib “DLLファイル” () As 戻り値の型
※このときC++とVBAで同じ型(もしくは対応する型)を指定する必要あり
戻り値はC++とVBAで型が対応していないと受け渡せない
今回で関数の基本となる引数と戻り値の設定方法の解説は終了です。
これらの方法が理解できれば基本的な関数は何でもDLLファイルとして作成できるはずです。
VBAとDLL(C++)のやり取りができるようになれば、あとは単純にC++のスキルによって作成できる関数の幅が広がっていくので、これを機にC++をがっつり学習することをオススメします。
【次回】VBAで自作DLLファイルを動的に呼び出す
【前回】DLL関数を作成する(戻り値あり)
目次へ戻る