Excel (VBA)

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

 
(指定なし : 指定なし)
オブジェクトモジュールと変数
投稿日時: 18/07/15 14:33:02
投稿者: オムライス

純粋な疑問です。
 
次のコードでエラーが発生する原因をおわかりの方、ご教示いただけないでしょうか。
 
まず、Sheet1オブジェクトモジュールに次のコードを記述します。
 

Public Sub ShowMessage()
    MsgBox "OK"
End Sub

 
 
そして、このプロシージャを標準モジュールから呼び出します。
 
このとき、TestプロシージャのようにSheet1オブジェクトを直接指定いたときは動作しますが、Test2プロシージャのように、一旦オブジェクト変数に参照を代入してからShowMessageプロシージャを呼び出そうとすると、コンパイルエラーが発生し、「メソッドまたはデータメンバーが見つかりません」というメッセージが表示されます。
 
Public Sub Test()
    Sheet1.ShowMessage
End Sub

 
Public Sub Test2()
    Dim sh As Worksheet
    Set sh = Sheet1
    sh.ShowMessage    '←コンパイルエラーになる
End Sub

 
まぁ、「こんなことしないよ」と言われてしまえばそれまでなのですが、オブジェクト変数を使用した場合のエラーが気になります。
推測含めで結構です。どのように解釈したら良いかご教示いただけると幸いです。
 
何卒宜しくお願いします。

回答
投稿日時: 18/07/15 15:13:55
投稿者: simple

■オブジェクトブラウザーでSheet1を検索すると
Class Sheet1
    VBAProject のメンバー
とあります。
実際にShowMessageというメンバーを持っていることが表示されていると思います。
 
■一方、Worksheetは、
Class Worksheet
    Excel のメンバー
となっています。
元々別のものなんですね。
 
そして、後者のWorksheetオブジェクトは、
プロシージャをメンバー(プロパティやメソッド)に持つなどということはありません。
 
これらは、それぞれそのような仕組みとして作成されたものなので、そう了解するよりありません。
 
ちなみに、例えば Sheet1.Selectなどとできるのは、
Excel.Worksheetのメンバーをラップしているからではないでしょうか。(想像)

回答
投稿日時: 18/07/15 15:18:51
投稿者: WinArrow
投稿者のウェブサイトに移動

>エラーの解釈
は、Excel君(正確には、VBA君)が解釈できない・・・って言っているんだから
 
シートモジュールに共通処理を記述すること自体がおかしい、

投稿日時: 18/07/15 15:35:34
投稿者: オムライス

simple様
WinArrow様
 
コメントありがとうございます。
 
>simple様

引用:
ちなみに、例えば Sheet1.Selectなどとできるのは、
Excel.Worksheetのメンバーをラップしているからではないでしょうか。(想像)

なるほど。そういうことであれば理解できます(もちろん、おっしゃる通りあくまで想像ですけど)。
ありがとうございます。
 
>WinArrow様
引用:
シートモジュールに共通処理を記述すること自体がおかしい、

ごもっともです。
でも、だったら「Sheet1.ShowMessage」もエラーになってくれたほうがわかりやすいな、なんて思ってしまいます。
もちろん、「仕様」でしょうからそんなこと言っても仕方ないのでしょうけれど。
 
もう少し開けておきたいと思います。
よろしくお願いいたします。

回答
投稿日時: 18/07/15 16:47:34
投稿者: Abyss2

「Worksheet」クラスと「Sheet1」クラスは別ものですから。
 
シートモジュール記載メソッドは、「当シートオブジェクト」の部品になります。
ご提示のShowMessageメソッドは、Sheet1クラスのメンバーであり、
Worksheetクラスのメンバーではないです。
 
  Dim sh As Worksheet
  Set sh = Sheet1
  'ここでSheet1オブジェクトに対して_Worksheetインタフェース抽出作業が行われます。
  'Sheet1.QueryInterface(IID__Worksheet, **sh)
 
「Sheet1型」変数以外のなんらかの変数経由でメソッドを呼びたいなら、
Object型(IDispatch)を使うといいでしょう。QueryInterface作業が行われないですので。
 
'標準モジュール

Public Sub Test3()
    Dim sh As Object    'IDispatch
    Set sh = Sheet1
    sh.ShowMessage
End Sub

 

回答
投稿日時: 18/07/15 17:01:23
投稿者: 半平太

私の推測
 
Worksheet型にセットした場合、Sheet1オブジェクトの情報自体は持っている。
しかし、Worksheet型に列挙されたメソッドの中にないので、コンパイルエラーにする。
 
Variant型とオブジェクト型は、どんなメソッドがあるか分からないので、コンパイル時にはエラーにはしない。
けど、実際にそんなメソッドが無かったら、実行時にエラーを起こさせる。
 
現実に「obj.でたらめ」なんて書いても、コンパイルエラーにはならなかったです。
 

Public Sub Test2ver()
    Dim sh As Worksheet
    Set sh = Sheet1
    
    Dim var 'バリアントに入れてみる
    Set var = sh
    var.ShowMessage
    
    Dim obj As Object  'オブジェクトに入れてみる
    Set obj = sh
    obj.ShowMessage
    obj.でたらめ
    
    Dim Wsh As Sheet1  '元のSheet1に入れてみる
    Set Wsh = sh
    Wsh.ShowMessage
End Sub

回答
投稿日時: 18/07/15 17:27:04
投稿者: WinArrow
投稿者のウェブサイトに移動

他の回答者と重複しますが
 

引用:
Public Sub Test2()
    Dim sh As Worksheet
    Set sh = Sheet1
    sh.ShowMessage '←コンパイルエラーになる
End Sub

 
の中の
> Dim sh As Worksheet

    Dim sh As Sheet1
に変更するだけでコンパイルエラーは解決します。

投稿日時: 18/07/15 19:23:30
投稿者: オムライス

Abyss2様
半平太様
WinArrow様
 
コメントありがとうございます。
 
Abyss2様の以下のコメントで理解できたと思います。

引用:
「Worksheet」クラスと「Sheet1」クラスは別ものですから。
  
シートモジュール記載メソッドは、「当シートオブジェクト」の部品になります。
ご提示のShowMessageメソッドは、Sheet1クラスのメンバーであり、
Worksheetクラスのメンバーではないです。

 
でも、Abyss2様のコメントにある
 
引用:
'ここでSheet1オブジェクトに対して_Worksheetインタフェース抽出作業が行われます。
  'Sheet1.QueryInterface(IID__Worksheet, **sh)

こういった知識を身につけるには、どんな勉強をすればいいのでしょうか?
VBAに関するサイトを見ても巡り合ったことがありません。
 
合わせてご教示いただけると幸いです。
 
何卒よろしくお願いいたします。

回答
投稿日時: 18/07/15 21:48:46
投稿者: WinArrow
投稿者のウェブサイトに移動

オブジェクトブラウザ
は、ご存知ですか?
 
 
左上の「すべてのライブラリ」というコンボボックスがあります。
このドロップダウンリストの中に、いくつかのライブらるがあります。
例えば
「WorkSheet」は「Excel」のメンバーです。
この中には、「Sheet1」というメンバーは存在せず
メンバーの一つである「Name」というプロパティの「値」として「Sheet1」が格納されています。
ですから、「Sheet1」でなくても「シート01」でもなんでもよいことになります。
 
「Sheet1」は、「VBAProject」のメンバーです。
Sheet1モジュールの中に記述したプロシジャは、「Sheet1」のメンバーとして表示(参照)されます。
これは、プロパテイではなくオブジェクトそのものですから、
シート名が変わってもオブジェクト名は変更されません。
 
 
 

投稿日時: 18/07/15 21:57:10
投稿者: オムライス

WinArrow様
 
コメントありがとうございます。
 

引用:
オブジェクトブラウザ
は、ご存知ですか?

 
はい。一応存じております。もっとも、ちゃんと使いこなせているかはなんとも言えませんけど。
 
でも、オブジェクトブラウザで検索しても「QueryInterface」って出てこないですよね。
どうすればいいんでしょう?
 
頼りっぱなしの質問で申し訳ありませんが、よろしくお願いいたします。
 

回答
投稿日時: 18/07/15 22:39:39
投稿者: WinArrow
投稿者のウェブサイトに移動

>オブジェクトブラウザで検索しても「QueryInterface」って出てこないですよね。
 
すべてのラブラリのドロップダウンリストで示すライブラリには入っていないのでしょう・・・
どのような名前なのか私は知らないのですが、
当該ライブラりをVBEにの「ツール」ー「参照設定」で追加すればよいのではないかと思います。
 
だんだん変な方向にそれていくような気がします。
初期の目的から逸脱するようなら、別なトピでお願いします。

投稿日時: 18/07/16 09:00:44
投稿者: オムライス

WinArrow様
 
コメントありがとうございます。
おっしゃる通りですね。
勉強方法については、改めてスレ立てるようにします。
 
最後に1点確認させてください。
 
いろいろ試している中で、以下のコードはエラーにななりませんでした。
 

ThisWorkbook.Worksheets("Sheet1").ShowMessage

「ThisWorkbook.Worksheets("Sheet1")」で取得できるのは、Worksheetオブジェクトですけどエラーにならないのは、Abyss2様がおっしゃる
 
引用:
Dim sh As Worksheet 
Set sh = Sheet1 

  'ここでSheet1オブジェクトに対して_Worksheetインタフェース抽出作業が行われます。
  'Sheet1.QueryInterface(IID__Worksheet, **sh)

 
の処理がこの場合は発生しないから、という解釈でよろしいでしょうか。
 
いろいろ、細かいところをしつこくて申し訳ありませんが、何卒宜しくお願いします。

回答
投稿日時: 18/07/16 10:36:51
投稿者: simple

オブジェクトブラウザーで調べて下さい。
 
Worksheetsの Itemプロパティも _Defaultプロパティも
いずれもObject型を返すPropertyとされています。
決して、Worksheet型を返すものではないからです。
もし、Worksheet型を返すのであればエラーになりますが。
 
なお、単に
Worksheets("Sheet1").ShowMessage
としても同じようにエラーにはなりません。

投稿日時: 18/07/16 11:15:06
投稿者: オムライス

simple様
 
コメントありがとうございます。
 

引用:
Worksheetsの Itemプロパティも _Defaultプロパティも
いずれもObject型を返すPropertyとされています。
決して、Worksheet型を返すものではないからです。

ありがとうございます。理解しました。
オブジェクトブラウザも理解が浅いためきちんと使えていませんでした。
勉強になりました。
 
おかげさまでいろいろと勉強になりました。
 
simple様始め、コメント頂いた皆様ありがとうございました。
 
閉じさせていただきます。