Mutable_Yunの業務改善ブログ

VBA勉強中の非エンジニア会社員向けのブログです。業務改善についても触れています。

VBA レジストリを利用して、エクセルブック外に値を保存する方法

エクセルVBAでツールを作る時に、エクセルマクロブックを閉じても、どこかに何かの設定を保存しておきたい時がありませんか?「本日〇回目のプログラムの実行します」の〇のところを変えたい、というイメージです。

エクセルシートに書き込んでしまうのではなく、レジストリというPC内の場所にデータを保存して操作する方法について解説します。

目次

レジストリとは何か

レジストリとは普段は見えないフォルダのような場所です。アプリケーションなどを動かす設定値などPCを動かす大事な値が入っています。間違って消すといけないので、ムリして開こうとしないほうがよいです。とはいえ、中が気になる人もいると思うので、ココで見た目だけ紹介しておきます。

レジストリエディタでレジストリの中身を見たところ。触ってはいけないファイルがたくさんある
レジストリエディタでレジストリの中身を見たところ。触ってはいけないファイルがたくさんある

今回はVBAを使ってレジストリの中に値を書き込んだりするのですが、そこはVBAさんの優しさで、絶対に大丈夫なところにしか値を書いたり消したりできません

VBAから使う分には安全なので、安心して利用しましょう。

今回やりたいこと

今回やりたいことは、そのマクロが本日何度目に実行されたのかを記録することです。エクセルマクロブックを閉じても、きょう実行した回数を覚えおいて欲しいと言うわけです。ついでに、最後に実行した日付も記録しておきましょう。

実務では、エクセルを開いたときに、前回実行した日次をメッセージボックスで表示して、前日処理漏れがなかったかチェックできるようにする、といった事が考えられます。

なぜエクセルシートに書き込まないほうが良いのか

まあ、ぶっちゃけどこかのシートのA1セルに書き込んでもいいです。でも、何か、ちょっと気が進まない感じです。(解説になっていない。。。)

レジストリにデータを保存して、取り出して使う

それでは、具体的にコードを記述していきましょう。

SaveSettingメソッド

レジストリに値を書き込むにはSaveSettingメソッドというのを使います。表示⇒オブジェクトブラウザで検索窓にsavesettingと打ち込んで調べたところ、下記の表示が出てきました。

InteractionクラスのSaveSettingメソッドをオブジェクトブラウザで調べた図
InteractionクラスのSaveSettingメソッド

4つ引数を取ります。見慣れない単語が多いですが、言い方が慣れないだけで、簡単です。何で見慣れない単語になっているかというとレジストリというのが、設定値を保存しておく場所なので、それにならっていると言うことです。順に解説します。

  • AppName

フォルダのことです。レジストリの中の何というフォルダに入れておくか。レジストリ内では他の設定は、アプリごとにフォルダにまとめられているので、「アプリの名前」という変な引数の名前になっています。

この名前は何でもいいです。レジストリを操作するエクセルマクロブックの名前やモジュールの名前にでもしておけば分かりやすくていいと思います。例えば、売上処理ブック、とかですね。

  • Section

フォルダの中のフォルダのことです。AppNameのフォルダの中にさらに細かくフォルダを作ってその中にファイルを置くイメージです。アプリごと(売上処理ブックのようなAppNameのフォルダごと)に、機能ごとのフォルダを用意する。その中にデータを書き込むファイルを置く作戦です。

  • Key

ファイル名のことです。この中にデータを書き込みます。

  • Setting

Key(=ファイル)に書き込むデータのことです。前述のように、アプリごとの設定を保存しておくのが前提なので、このような引数名になっています。単なるデータのことです。

念のためイメージを図示しておきます。こんな感じです。

レジストリの中身のイメージ図。単純な階層構造になっている
レジストリの中身のイメージ図。単純な階層構造になっている。

SaveSettingメソッドでレジストリ内にデータを作る

データを実際に書き込んでみます。データを書き込むと言うより、データを格納してあるファイルとフォルダとその上のフォルダを同時に作ります。

Sub 本日の処理回数と最終処理日を記録する()

    SaveSetting "本日の処理回数と最終処理日を記録するアプリ", "実行記録セクション", "処理回数", "1"
    SaveSetting "本日の処理回数と最終処理日を記録するアプリ", "実行記録セクション", "最終処理日", Date
    
End Sub

これで、レジストリの中にデータを格納することができました。注意すべきはSetting(=データ)の型はString型だと言うことです。

処理回数のKeyに格納する値が"1"になっています。文字列なので””をつけています*1。また、これは暫定処置で、後ほどデータを取得する方法を確認してから、本日の処理回数を格納するように書き換えます。

GetSettingメソッド

GetSettingメソッドでデータを取り出します。オブジェクトブラウザで調べると、このように表示されました。

InteractionクラスのSaveSettingメソッドをオブジェクトブラウザで調べた図
InteractionクラスのGetSettingメソッドをオブジェクトブラウザで調べた図

SaveSettingメソッドの時にはなかった、「Default」という引数が書かれています。[]と書いてあるので省略可能です。これはKey(=ファイル)が見つからなかったときに返す値を表しています。

GetSettingメソッドでレジストリ内のデータを取得する

それでは、早速使っていきましょう。先ほどのSaveSettingの上に変数の宣言、下にGetSettingを追記します。

Sub 本日の処理回数と最終処理日を記録する()
    
    Dim 処理回数_str As String
    Dim 最終処理日_str As String

    SaveSetting "本日の処理回数と最終処理日を記録するアプリ", "実行記録セクション", "処理回数", "1"
    SaveSetting "本日の処理回数と最終処理日を記録するアプリ", "実行記録セクション", "最終処理日", Date
    
    処理回数_str = GetSetting("本日の処理回数と最終処理日を記録するアプリ", "実行記録セクション", "処理回数", "0")
    最終処理日_str = GetSetting("本日の処理回数と最終処理日を記録するアプリ", "実行記録セクション", "最終処理日", "そんな日付ありません")
  
End Sub

これで書き込んだり取得したりすることができました。

本日の処理回数を実装して、実用的にする

あとは、レジストリの値を冒頭で1足してあげれば完成です。Val関数で数値に変換してから足しています*2

Sub 本日の処理回数と最終処理日を記録する()
    
    Dim 処理回数_long As Long
    Dim 処理回数_str As String
    Dim 最終処理日_str As String
    
    処理回数_long = Val(GetSetting("本日の処理回数と最終処理日を記録するアプリ", "実行記録セクション", "処理回数", "0"))
    処理回数_long = 処理回数_long + 1
    
    SaveSetting "本日の処理回数と最終処理日を記録するアプリ", "実行記録セクション", "処理回数", 処理回数_long
    SaveSetting "本日の処理回数と最終処理日を記録するアプリ", "実行記録セクション", "最終処理日", Date
    
    処理回数_str = GetSetting("本日の処理回数と最終処理日を記録するアプリ", "実行記録セクション", "処理回数", "0")
    最終処理日_str = GetSetting("本日の処理回数と最終処理日を記録するアプリ", "実行記録セクション", "最終処理日", "そんな日付ありません")
    
    MsgBox "本日の処理回数:" & 処理回数_str & "回" & vbCrLf & _
                "最終処理日:" & 最終処理日_str
                
End Sub

できました。

実行結果。レジストリを操作して、値が取得できた
実行結果実行結果。レジストリを操作して、値が取得できた

レジストリに書き込んでいる為、エクセルブックを閉じてもちゃんとカウントアップされます。エラーで処理ができなかったときやブックが存在しないときに、レジストリに書き込まないようにすれば、処理済みか処理済みでないかを判定する、最終処理日が変更されなければメールで通知するなど、工夫次第でいろんな事ができます。

いろいろと試してみましょう!

*1:本当はVBAの忖度機能により、文字列に自動で置き換えてくれますが、サンプルコードなのでちゃんと書いています

*2:1と同様です。他言語では文字列の”1”と”1”を足すと”11”になったりするので、きちんと数字に変換してから足すべきと考えます