空DLLファイルの作成と呼び出し|C++でDLLを自作してExcelVBAで呼び出す方法①

今回はVBAで呼び出し可能なDLLファイルをVisual Studioを使って作成していきます。
まずは単純にVBAで”自作したDLLファイルを呼び出せるのか”を確認するため、作成するDLLの中身の処理は空の処理として作成していきます。

作成したDLLをVBAで呼び出すことが出来たらDLLの作成自体はできているということなので、あとはDLL側で行いたい処理を書いていくだけです。という訳で、まずは”空DLLファイルをVBAで呼び出す”というところまでは確実にできるようにしておきましょう。

 

C++開発環境の準備(Visual Studio Community 2022)

DLLの作成にはVisual Studio Community 2022という統合開発環境(通称:IDE)を使います。
はじめのうちはVBAでいうところの「Visual Basic Editor」にあたる存在と思っておけば大丈夫です。
(※Visual Studioは初回起動時にMicrosoftアカウントにサインインする必要があるので注意)

下記ページ(Microsoftページ)でインストーラーのダウンロードが可能です。

 
インストーラーがダウンロード出来たら、流れに従ってインストールしてください。
Visual Studioは様々な言語で開発することができるため、インストールする際にはどの環境をインストールするかを指定する必要があります。(インストール後でも追加や削除といった変更は可能です)

DLL作成には「C++によるデスクトップ開発」の環境だけあれば作成することができます。
インストールの詳細(下画像でいう右側の項目)はデフォルトのままでOKです。

インストールは結構時間がかかるので気長に待ちましょう。

もしインストール方法がわからなければ他サイトに飛びますが下記ページを参照下さい。
画像付きで1つ1つ紹介されているので非常にわかりやすいです。
【初心者向け】Visual Studio 2022(正式リリース版) インストール手順

 

DLLファイルを作成

Visual Studio(以下:VS)の準備が整ったら実際にVBAで呼び出し可能なDLLファイルを作成していきます。まずは「処理を何も行わない”空”の関数だけのDLLファイル」を作成してVBA側で呼び出すということをやっていきます。(VBAでいうところの「Sub Sample(): End Sub」だけのイメージ)

というのもいきなりがっつりコードを書いてDLLを作成してしまうと、もしうまくDLLが使えなかった場合に何が原因なのかが判明しづらくなるためです。まずは「自作したDLLがVBAの処理で呼び出せるのか」ということを調べるためにDLL側は空の処理(関数)としておきます。
 

1.プロジェクト作成

まずはDLL作成用のプロジェクトを作成します。
メニューバーの[ファイル]>[新規作成]>[プロジェクト]をクリックします。
(VS起動時に表示されるメニューの「新しいプロジェクトの作成」でもOK)

 
「ダイナミック リンク ライブラリ(DLL)」を選択してウィンドウ右下の[次へ]をクリックします。
 見つからない場合はウィンドウ上部の「テンプレートの検索」で「DLL」と検索してもいいですし、下画像のように「C++」「Windows」「ライブラリ」とフィルターをかけて表示されるプロジェクトの種類を減らせばすぐに見つけることができます。

 
プロジェクト名と保存場所を指定してウィンドウ右下の[作成]をクリックします。
ここではプロジェクト名を「VBA_DLL」保存場所を「C:\programming\cpp」としています。
ソリューション名は自動でプロジェクト名と同じになるのでそのままでOKです。
最下にある「ソリューションとプロジェクトを同じディレクトリに配置する」はそのままの意味です。チェックを付けてもつけなくてもどちらでもいいですが、ここでは付けないで進めます。

 
最終的に下画像のようなテンプレートが呼び出されていれば完了です。

 

2. 初期設定変更

テンプレートでいくつかのファイルが作成されましたが、必要最低限のファイル以外はすべて削除します。もちろんテンプレートで用意されているファイルなのであってもいいのですが、ここではファイルの構成を単純化するために削除していきます。
 

 icon-gear プリコンパイル済みヘッダーの設定変更

まずはメニューバーの[プロジェクト]>[プロパティ]を選択します。
(※ソリューションエクスプローラー上でプロジェクト「VBA_DLL」を事前に選択しておくこと)

 
プロパティページが表示されたらまず上部の[構成(C):]を[すべての構成], [プラットフォーム(P):]を[すべてのプラットフォーム]に変更してください。

その後、[構成プロパティ]>[C/C++]>[プリコンパイル済みヘッダー]を選択し、[プリコンパイル済みヘッダーを使用しない]に変更します。(デフォルトでは[使用]になっているはずです)

設定を変更したらウィンドウ右下の[適用]をクリックして[OK]で閉じます
 

プログラミング言語は通常、人間のわかる(認識できる)言語で書かれていますが、実際にコンピュータに読み込ませる際にはコンピュータが読めるような機械語に翻訳する必要があります。
この翻訳作業の手法はプログラミング言語によって違いますが主に「コンパイラ方式」と「インタプリンタ方式」という2種類の方法があります。
 
 
「コンパイラ方式」は翻訳作業をコード実行前に一括で行い後で一気に実行する
のに対して「インタプリタ方式」はコードを1行ずつ翻訳しては実行を繰り返すというような違いがあります。

このうちC++はコンパイラ方式となっており、コードが作成できたら実行前に毎回コンパイル作業をする必要があります。ただ、プロジェクトの規模が大きくなってくるとこのコンパイルにも時間がかかってしまいます。

そこで「プリコンパイル」という、毎回読み込んでいるファイル(#include)を事前にコンパイルして別ファイルとして残しておき、実際にメインコードをコンパイルする時にそのファイルから情報を読み取ることで全体のコンパイル時間を短縮するという手法が用いられます。

「pch.h 」はプリコンパイル済みヘッダーというもので、このファイル内に事前にコンパイルしておきたい内容を書いておくことでプリコンパイルしてくれる便利なヘッダーファイルです。ただ、本ページで紹介するDLLの作成はそこまで大規模なものにはならない、かつ初めのうちはファイル数が少ない方がわかりやすいという理由から削除していきます。

ちなみにVBAはインタプリタのように感じますが、実際はコンパイラの要素も含んでいるようです。


 

 

 icon-files-o ファイルの削除

上記設定が完了したら「pch.h」「framework.h」「dllmain.cpp」「pch.cpp」の4つのファイルをすべて削除します。右クリックしてコンテキストメニューの中から[削除]をします。

[削除]を選択すると、下画像のようなメッセージが表示されます。
どちらでもいいですが、一応再度呼び込めるようにここではすべて[除外]にしておきましょう。

[削除]:ファイルごと完全に削除される
[除外]:プロジェクトからは切り離されるがファイルとしては削除されない  
    除外したファイルはディレクトリにあり再度読み込むことが可能

 

ヘッダーファイル(.h)の作成

DLL作成の準備が整ったので実際にファイルを作成していきます。
まずはDLLがVBAから呼び出せるようにするための設定、およびVBAで呼び出す関数の宣言を行うためのヘッダーファイルを作成していきます。

icon-files-o ヘッダーファイル新規作成

ソリューションエクスプローラー内の「ヘッダーファイル」を右クリックし、コンテキストメニューから[追加]>[新しい項目]をクリックします。

 
[新しい項目の追加]ウィンドウが立ち上がるので「ヘッダーファイル(.h)」を選択します。
ウィンドウ下側で作成するファイルの名前と保存場所が指定できます。
ファイル名はプロジェクト名に合わせて「VBA_DLL」、保存場所はデフォルトのままにします。
ファイル名を入力したらウィンドウ右下の[追加]をクリックします。

 

icon-code  ヘッダーファイルのコード作成

ヘッダーファイルが作成できたら、下記のコードを入力します。

「#ifdef」部分では外部参照設定つまりはVBAからでもアクセスできるようにする設定をしています。
今回の方法とは別に「defファイル」を使った設定方法もありますが、その場合はこの部分を書く必要がなくなります。(その場合はdefファイルを作成して別のコードを書く必要があります)

上記コードの場合は「VBADLL_EXPORTS」のアンダーバーより前側の「VBADLL」部分はプロジェクト名と合わせておく必要があります。(※ハイフン[-]やアンダーバー[_]は省略します)

また「VBADLL_API」に関しては統一しておけば好きな文字列に変更して大丈夫です。それ以外の部分は定型文なので初めのうちは”おまじない”だと思っておいてください。

また「extern “C”」始まりの1行ではこれから作成する関数を宣言しています。

 icon-code 関数宣言 

extern “C” VBADLL_API void EmptyProcess();

このコードでいうEmptyProcess」の部分が関数名void」部分が戻り値となります。
1つのDLLファイル内に複数の関数を作る場合はこの行を増やしていけばいいだけです。

現状ではEmptyProcess関数について何も定義していないのでVS上で見ると緑の波線(警告)がついていますが、以降で関数のコードを書いていけば勝手に消えるので今は無視して進みましょう。

 

ソースファイル(.cpp)の作成

ヘッダーファイルの作成が完了したら次はソースファイルを作成します。
ここでは先ほどヘッダーファイルで宣言した関数の中身を書いていきます。

 icon-files-o ソースファイル新規作成

ヘッダーファイルのときと同じようにソリューションエクスプローラー内の「ソースファイル」を右クリックし、コンテキストメニューから[追加]>[新しい項目]をクリックします。

 
[新しい項目の追加]ウィンドウが立ち上がるので「C++ファイル(.cpp)」を選択します。
ウィンドウ下側で作成するファイルの名前と保存場所が指定できます。
ファイル名はプロジェクト名に合わせて「VBA_DLL」、保存場所はデフォルトのままにします。
ファイル名を入力したらウィンドウ右下の[追加]をクリックします。

 

icon-code  ソースファイルのコード作成

C++ファイルが作成できたら、下記のコードを入力します。
ここでは処理を何も行わない空コードとして作成していきます。

このコードはVBAでいうところの「Sub EmptyProcess(): End Sub」と全く同じです。
実際はこの部分にVBAで呼び出して利用したい処理(関数)を書きます。

コードの初めには「#include “VBA_DLL.h” 」のようにして先ほど作ったヘッダーファイルを読み込む処理を書いておく必要があるので注意して下さい。

 

DLLファイル作成

必要なソースファイル(.cpp)とヘッダーファイル(.h)の作成が完了したので実際にDLLファイル(.dll)として書き出していきます。最終的にはここで作成したDLLファイルをVBAで呼び出して使用します。
 

icon-files-o DLLファイル出力

まずはVSウィンドウ上部にあるソリューションの構成を「Release」, ソリューションのプラットフォームを「x64」にします。(項目によって出力場所が変化します)

 
上記設定が完了したら、メニューバーの[ビルド]>[ソリューションのビルド]をクリックします。

 
ビルドすると出力ウィンドウに下画像のように表示されます。
最下行の「===ビルド: 成功 1、失敗 0、最新の状態 0、スキップ 0 ===」がビルド結果です。
成功が「1」になっていればDLLファイルの作成が正常に完了したことを表します

※出力ウィンドウがない場合はメニューバーの[表示]>[出力]を選択すれば表示されます。
 

icon-files-o DLLファイルの確認

DLLファイルの出力が完了したので実際にファイルを確認してみましょう。
ファイルパスは下記の場所です。(※プロジェクトディレクトリは一番初めに指定した場所です)

icon-file DLLファイルパス 

(※プロジェクトディレクトリ)\VBA_DLL\x64\Release\VBA_DLL.dll”

DLLファイル以外にもいくつかのファイルが作成されていると思いますがVBAで呼び出すのはDLLファイルだけです。一度書き出しているのでDLLのファイル名は変更しても呼び出すことが可能です。

 

VBAで作成したDLLファイルを呼び出す

最終確認として、作成したDLLファイルがVBAで実行できるか確認します。
VBAで下記のコードを実行してみましょう。(※DLLのパスは自身の環境に書き換えて下さい)

基本的に呼び出し方はWinAPIと同じで下記のように書きます。

 icon-code DLLファイルの関数の宣言 

Private Declare PtrSafe Sub 関数名 Lib “DLLファイル” ()

WinAPIの場合、Windowsに標準で用意されているDLLファイルのため保存してある場所のパスがすでに通されています。そのためDLLのファイル名(kearnel32のように)を書くだけでファイルを認識してくれますが、自作DLLは基本的にはパスが通っていないためフルパスで指定する必要があります

※「VBAで自作DLLファイルを動的に呼び出す」ページでフルパスではなく動的にDLLファイルを指定できる方法を紹介します。この方法を使うことで、たとえばExcelファイルと同階層にあるDLLファイルを取得することが可能になります。

上記コードを実行してエラーが起きなければDLLファイルの呼び出しは成功しています。
DLLは空の処理をしているため何も起きていないように見えますが、DLLの呼び出しに失敗した場合は必ずエラーメッセージが表示されるのでエラーが出なければ呼び出しには成功していると思っていて大丈夫です。

 

まとめ

今回は自作DLLファイルを作成してVBAで呼び出すまでの方法を紹介しました。
内容を噛み砕いてまとめると下記の通りです。

icon-check-square DLLファイル作成にはVSのダイナミック リンク ライブラリ(DLL)テンプレートを使用する
icon-check-square テンプレに初めから用意されているファイルは使わないため削除する
  「プリコンパイル済みヘッダーを使わない」設定にする必要がある
icon-check-square ヘッダーファイル(.h)には外部参照を可能にするコードと関数宣言のコードを書く
icon-check-square ソースファイル(.cpp)には関数の処理内容を書く
  ヘッダーファイルのインクルード(#include)が必要

今回やった空DLLファイルの呼び出しがうまくできれば、あとは関数の内容を書くだけです。
空のDLLファイルを呼び出しただけでは実感がわかないと思うので、次回はDLLファイル側で実際に目に見える処理を作成してその結果を見ていきます。
 

【次回】DLL関数を作成する(引数なし)
目次へ戻る

 icon-book  C++初心者オススメ書籍

2022年8月21日C++, DLL, Excel, VBA

Posted by Lic