Excel (VBA)

Excel VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 10 Home : その他)
CALL関数でエラー
投稿日時: 21/06/06 13:42:19
投稿者: A太郎

下記のコードで、
エラー「オブジェクト変数または With ブロック変数が設定されていません。(エラー番号:91)」
が出てしまします。
一つめのプロシージャからCALLを除けばエラーはなくなりますが、この1行でエラーが出る意味が分かりません。
ご教示いただけると幸いです。
 
************************************************
 
Option Explicit
Private ws As Worksheet
 
Sub lesson1()
    Dim ws As Worksheet
    Set ws = ActiveSheet
    ws.Name = "11"
    Call lessonX
     
End Sub
 
Sub lessonX()
    Debug.Print ws.Name
    Set ws = Nothing
End Sub

回答
投稿日時: 21/06/06 14:06:46
投稿者: 半平太

>Private ws As Worksheet

>Sub lesson1()
> Dim ws As Worksheet
> Set ws = ActiveSheet
 
lesson1の中にある「ws」が余分じゃないですか?

回答
投稿日時: 21/06/06 15:11:39
投稿者: WinArrow
投稿者のウェブサイトに移動

VBAには、変数のスコープというルールがあります。
  
変数のスコープとは、その変数が参照できる範囲のことです。
  
逆にいうと、どこで定義した変数を使う(使われる)かが決まります。
  
今回の場合、
>ws
という変数が、2ヶ所で定義されています。
  
1つはモジュールレベル(Private だからモジュール内)
もう一つは、プロシジャレベル(プロシジャ内)
  
プロシジャ内で定義した変数は、他のプロシジャからは参照できません。
今回の場合、Call 元プロシジャでは、
自プロシジャ内で定義した「ws」が、優先されて使用されます。
  
このようなルール(変数のスコープ)を理解するようお勧めします。

回答
投稿日時: 21/06/07 09:44:25
投稿者: simple

既に解説のあったとおりです。
 
色分けするとこうなりますね。
Option Explicit
Private ws As Worksheet
Sub lesson1()
    Dim ws As Worksheet
    Set ws = ActiveSheet
    ws.Name = "11"
    Call lessonX
End Sub
Sub lessonX()
    Debug.Print ws.Name
    Set ws = Nothing
End Sub
 
wsはどこでも実体が与えられていないので、lessonXの中でwsを使おうとしてもエラーになります。
lesson1の中でSet ws = ActiveSheetとしたはずと思っても、
lesson1の中でプロシージャレベルの同一名の変数wsを宣言してしまうと、
モジュールレベルの変数wsは使われず、プロシージャレベルの変数wsが優先使用されるわけです。
 
また、ステップ実行して、ローカルウインドウを観察すると、変数の状況がよくわかると思いますよ。

回答
投稿日時: 21/06/07 13:54:25
投稿者: WinArrow
投稿者のウェブサイトに移動

対策案A
lesson1プロシジャ内の
Dim ws As worksheet
を削除する。
 
今回の場合、これが最も近道です。
 
 
対策B
 
モジュールレベルの
Private ws As Worksheet
を削除する。
代わりに
Sub lessonX()を引数付きのプロシジャに変更する。
Sub lessonX(ByRef ws As Worksheet)
 
※lessonXプロシジャから、他プロシジャ内の変数を参照しているが、
書き換えも出来てしまうので、効能をきちんと理解せずに使うと
問題発生時のトレースが難しいです。
 

投稿日時: 21/06/09 23:04:04
投稿者: A太郎

皆様
ご回答ありがとうございました。
宣言の優先順位があることを認識していませんでした。
理解できました。大変助かりました。