FSOオブジェクトで「オブジェクト変数またはWithブロック変数が設定されていません」と出る時は?

2020年3月18日

えー。どうしょうー。エラーが出ちゃったよぉ!
なんかオブジェクト変数とかWithブロック変数が設定されてないって出るけどどうしたらいいの?

おやおや・・どんなエラーなんだろう。ちょっと見てみよう。

エラーメッセージ

なるほど・・・オブジェクトでエラーが発生したのね。具体的にどこで発生したのか見てみましょう。

黄色の部分でエラー発生

なるほど、これは明らかにオブジェクト宣言でエラーが発生しているわね。

エラー発生の流れから考えよう

ではこれはどういうエラーで、解決方法は何があるかを考えてみる。

まず最初に、このメッセージが出た時私は真っ先に参照設定を疑った。
なぜなら過去にこういうことがあったからだ。

しかし、参照設定を見ても足りなさそうなものは見当たらず。
それでおかしいな?と思った時に、ふと、思い当たることがあった。

エラーが出た箇所

まず、コードを見てみよう。
今回エラーが出たのは、黄色の線の箇所である。
ということは、ファイルシステムオブジェクトでエラーが起きたことは明らか。

そして、ファイルシステムオブジェクトはどこで定義しているか?
この場合、直前のコードで定義していることが分かる。
つまり、この箇所。

Dim fso As FileSystemObject

ただし、実はこの宣言は「宣言になっていない」。
その理由をこれから書いていく。

変数宣言をしたらオブジェクト生成も必要!

まず、オブジェクトは宣言するだけでは足りない。
オブジェクトはインスタンス化して初めて使えるようになる、ということは頭に入れておくと分かりやすいと思う。

インスタンスとは

念のため、先にインスタンスについて説明しておく。
インスタンスとは、ざっくり言えば「実体」。

例えば

クラス・・・・概念(スマートフォン)
インスタンス・・・物体(iphone または Android)
オブジェクト・・・概念や物体を大まかに表したもの(携帯)

と書いたほうが分かりやすいだろうか?

そして、

インスタンスは、オブジェクト指向(携帯)に出てくる概念(iphoneまたはAndroid)の1つで、設計図(スマートフォン)を具現化した実態のこと

だとも言える。
そして、この「インスタンス」はただ定義するだけでなく、「インスタンス化」しなければならない。
では、このインスタンス化するとはどういうことなのか。それを次から説明する。

インスタンス化するということ

話を戻して、「インスタンス化する」ということは、
簡単に言えば【空っぽのオブジェクトに値を入れてあげる】ということでもある。

学校に例える。

誰もいない教室 = 定義しただけ(インスタンス化されていない)から
          何もできない
生徒がいる教室 = インスタンス化されているから名前を呼べば反応があるし、
          授業もできる

・・・ということである。
これが「インスタンス」であり、インスタンスを使うということは「インスタンス化する」必要がある、ということだ。

えっと・・なんかまだピンとこないんだけど、もしかしてこのエラーの原因って、定義しただけで終わっていて中身が与えられていないからエラーになってる、ってこと・・・?

そう!そういうことです。
先ほどのコード画像を見ると「インスタンス化されていない」ことが分かるわよね。これが今回のエラーの原因だと予想できるわね。

それでもまだピンと来ないかもしれない。
念のため、もう少し詳しく説明する。

FileSystemObjectの宣言の流れ

これまで説明した通りに書くと、Filesystemobjectの宣言の場合は

①定義する
②インスタンス化する

この2つを必ずセットにしないといけない。
従って、書き方としては

Dim fso as Filesystemobject
Set fso = New Filesystemobject 

というふうになる。

意外な落とし穴

そして、実は①と②を一緒にした書き方もある。
それが

Dim fso as New Filesystemobject

という書き方である。
また、こういう書き方でも特にエラーは起こらない。

でも、実はこれが落とし穴なのだ。

Microsoftは1行での書き方を薦めていない!

今までは先ほどの1行での書き方は認められていたし、
また個人でも1行の方がスッキリするということで親しまれていた。

しかし、Microsoftではこの書き方を2009年に禁じていることが分かった。
ソースはこちらである。(注:ソースではVB6.0のことを書いているが、VBAも同様なので同じである)

1行にするとNothingしてもその後またオブジェクトが作られてしまう!

これはどういうことかというと。

必ずオブジェクトが存在することが保証される (Nothing を設定してオブジェクトが破棄されたとしても、オブジェクトを再利用しようとすると、再作成される)

つまり、言い換えると、

変数宣言時にNewするとオブジェクト変数にNothingを設定しても、そのオブジェクト変数を再利用しようとすると自動でオブジェクトが生成されてしまう

要は、1行だけで変数とNewを同時にしてしまうと、処理の後にオブジェクト変数にNothingをかけてオブジェクト変数とのつながりを切ったとしても、
そのオブジェクト変数を再利用しようとすると自動でオブジェクトが作られてしまう。ということである。

参考記事

これについてはこちらの記事を読んだ方が分かりやすいかと思う。

そういうわけで、オブジェクトを作る時は今後は2行で書いたほうがいいわね。

結論

長くなったが、今回のエラーについてはどうすればいいのか、分かったと思う。

答えは、

Dim fso as Filesystemobject
Set fso = New Filesystemobject 

に直しておくのが正解である。

Filesystemobjectは必ず①定義②インスタンス化を忘れずに!