質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.60%

事前バインディングで「すでに開いているブック」を取得する方法は存在しますか?

解決済

回答 4

投稿

  • 評価
  • クリップ 1
  • VIEW 5,170

komugi3333

score 94

知りたいこと

事前バインディングにて、「すでに開いているブック」を取得する方法は存在するのでしょうか?
もし存在するなら、「New」キーワードや「Open」「Add」メソッドなどのほかに、何かがあるのでしょうか?

無ければ、やはりGetObject関数を使うしかなく、その際「特に問題は無い。トラブルは起こらない。2重のバインディングになる?とかは考えなくていい。」、という理解でよろしいのでしょうか?

どうかお教えください。

質問した理由

ExcelVBA初心者なので、まだ事前バインディングと実行時バインディングの細かい動きなどを理解できていないのですが、例えば、Word等からExcelファイルを操作したい場合で考えてみますと・・・、

(01)例えば事前バインディングをしたときには・・・、

a:新規ファイルを作る→NewやAddメソッドで。
b:既存ファイルを開く→NewやOpenメソッドで。

・・・といったような形でWordなどからExcelファイルを操作できると理解しています。

(02)それに対して、実行時バインディングにしたときは・・・

c:新規ファイルを作る→CreateObject関数で。
d:既存ファイルを開く→GetObject関数で。

・・・というような認識でいます。

実行時バインディングでしたら、既存ファイルのうち、「すでに開いているブック」は、「GetObject関数」で取得できます。

そこで、「そういえば、事前バインディングのほうで ”すでに開いているブックを取得する ” っていう話は聞かないな。なぜだろう? もしGetObject関数でしかやれないなら、事前バインディングと実行時バインディングで2重にバインディングする、みたいなことになるのかしら?特にトラブったりがないなら別にそれでもいいのだけど・・・」と、ふと思ったので質問させていただきました。

もし『事前バインディングで ” すでに開いているブックを取得する ” 方法』があるなら知りたいです。

Webを色々と調べたり、ヘルプを探したりもしてみたのですが、自分にはわかりませんでした。

WordとExcelのファイルを1つずつ開いて、Wordから・・・、

Dim bk01 As Object
Set bk01 = Excel.Application.Workbooks.Open("Book1")
bk01.Application.Visible = True

・・・のようにしてみましたら、マイドキュメントの「Book1.xlsx 」がさらに、開いただけでした。

よろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+1

「CreateObject、GetObject は実行時バインディング、New が実行時バインディング」という理解がそもそも勘違いだと思います。
また、参照設定がしてあるかどうかも、事前バインディングと実行時バインディングとは関係ありません。

変数宣言時にオブジェクトの型が決まっているか、なんでも代入できるObject型で宣言しているかの違いです。

例えば、Excelに参照設定してあった場合、下記は実行時バインディングです。

    Dim app As Object

    Set app = New Excel.Application
    app.Visible = True
    app.Workbooks.Open "C:\TEST\test.xlsx"

逆に、下記は事前バインディングです。(ただし、推奨できる書き方ではないらしい。)

    Dim app As Excel.Application

    Set app = CreateObject(,"Excel.Application")
    app.Visible = True
    app.Workbooks.Open "C:\TEST\test.xlsx"

下記を読まれるといいかと思います。

4.4 アーリーバインディングとレイトバインディング - EXCEL-VBA開発講座

既に開いている Excel あるいは、WorkBook を取得する場合は、GetObject しかないと思います。
ただし、複数の Excel が開かれている場合、どの Excel を取得するかは不確定なので、やはり、あまり推奨できません。

私は以上のように理解しているのですが、深いところまで理解しているわけではないので、外している部分があるかもしれません。その場合は、ご指摘ください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/22 22:57

    Office2013以降は複数バージョンの同時インストールはできませんが、それ以前のバージョンとは同時インストールできますね。
    以前は、Office2016 と Office2010 を同時インストールして使ってました。
    その場合、参照設定で2010の方にチェックをいれておいて、CreateObject("Excel.Application")したらどうなるのだろうか。CreateObjectが最新のものを取得するなら、参照設定とバージョンが合わないので、エラーになるのだろうか。
    どちらにしても事前バインディングの場合は、Newにしておけば安心ですね。

    キャンセル

  • 2019/04/23 07:56

    指摘ありがとうございます。
    少し前まで複数バージョンの同時インストール出来たのですね、最近の印象で間違ったことを書いてしまっていました。ありがとうございます。

    キャンセル

  • 2019/04/23 11:37

    teratailって解決済みでもコメントできるんですね!すごい。
    私もおふたりのやりとりが大変 勉強になりました。
    ありがとうございます。

    キャンセル

+1

事前バインディングとやらは何の話をしているのかはわかりませんが、Workbooksコレクションには開いているブックが含まれています。
例えば次のようなコードを実行すると、開いているブックの一覧が取得できます。

For Each wb In Workbooks
    Debug.Print wb.Name
Next


取得の仕方はSetです。
hoge.xlsxというブックが存在していたとしたら、

Set bk = Workbooks("hoge.xlsx")

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/22 15:03

    >Excelで直に開いているブックをWordで参照する

    すみません。ちょっと私がちゃんと ttyp03さんの書かれた意味を理解できていないかもしれませんが、このケースを想定しています。

    普通に
    ・Excelのファイルアイコンをダブルクリックして開いて、
    ・Wordもダブルクリックでファイルを開いて、
    ・そのWordのほうから、Excelのファイルをオブジェクトとして取得・操作する、
    というケースです。

    >Word内で同じExcelブックに対する処理が複数個所ある
    はい。「Word内で同じExcelブック」ということが、「ダブルクリックで開いたワードファイルから、ダブルクリックで開いたExcelファイルをオブジェクトとして取得・操作する」という意味でしたらそのとおりです。
    「すでに開かれているExcelファイルがあるなら、念のためにそれを先に全部閉じておく」、といった処理にも使えるなと思いました。

    また、少し前に「Excelブックに対する処理が複数個所あるという」ケースでなら、それをいっぺんに終わらせるコードを書くことになると思うのですが、それをやるのに、どうやらExcel(WordもAcceeも)には、「事前バインディング」と「実行時バインディング」というものがある・・・ということを学びました。

    それは以前から自分も「AccessからのExcelファイルを扱う操作」で(その言葉を知らないで)すでにやっていたのですが、その際に、『参照設定をしつつ、GetObject関数、も使っていたので、今はいいけどいつかどこかで異常終了しないか?』と心配になった、という次第です。

    でもそう心配することないようでしたら、問題が起こってから考えればいいかと、今は考えています。

    本当はWordではなくAccessからで使いたいと思っていたのですが、Wordでも同じかなと思って質問ではWordで・・・と書いてしまいました。

    一番気になったのは、バインディングということを2重に行ってしまって異常終了なので不具合が出ないか?というところでした。
    (今まで何の疑問も無くそうしてきてしまっていたので)

    もしほかに正しい方法があるなら、知りたいと思い質問をさせて頂きました。

    でも、ttyp03さんに「バインディング という言葉にとらわれなくてもよいのでは?」と言っていただき、そうしようと思っています。

    キャンセル

  • 2019/04/22 15:30

    Excelで開いているブックをWordからも操作する、ということですね。
    結局のところ、Word側でExcelオブジェクトを取得してもWorkbooksコレクションにはオープン済みのブックの情報は含まれてこないようです。
    なので、Word側でOpenしてあげないとダメみたいです。
    あくまでもそのオブジェクトごとに情報を持っているようです。
    こんな感じのコードで確認できます。
    Set xls1 = New Excel.Application
    Set xls2 = New Excel.Application
    xls1.Workbooks.Open "hoge.xlsx"
    Debug.Print "xls1"
    For Each wb In xls1.Workbooks
    Debug.Print wb.Name
    Next
    Debug.Print "xls2"
    For Each wb In xls2.Workbooks
    Debug.Print wb.Name
    Next
    Excelオブジェクトを2つ作って、1の方でオープンします。
    1の方のWorkbooksには入ってますが(当然)、2の方のworkbooksには入っていませんでした。

    キャンセル

  • 2019/04/22 16:06

    コードのご提示、ありがとうございます。
    一度、動かしてみまして、ローカルウィンドウでも見てみました結果、動きは理解できました。

    >Word側でOpenしてあげないとダメみたいです。
    はい。こちらも理解できます。
    いろいろと確認作業をして頂いてありがとうございます。

    例えば xls2 のほうに、既にダブルクリックして開いているExcelファイルを「CreateObject関数以外」で Setできないのかな、と思ったわかなのですが、そのようなメソッドなり関数なりなんなりが、今のところ見つからないので、ひとまずはこれまでどおり、CreateObject関数を使ってみようと思います。

    ほんとうにありがとうございます。

    キャンセル

+1

Option Explicit

'★ツール→参照設定でMicrosoft Excel *.* ObjectLibraryに
' チェックを入れておいて下さい。
Sub test()
    Dim AppExcel As Excel.Application
    Dim b As Excel.Workbook

    If GetExcel(AppExcel) = False Then
        MsgBox "エクセルが開いていません。"
        Exit Sub
    End If


    For Each b In AppExcel.Workbooks
        Debug.Print b.Name
    Next
End Sub

Function GetExcel(ByRef xlApp As Excel.Application) As Boolean
    On Error Resume Next
    Set xlApp = GetObject(, "Excel.Application")
    On Error GoTo 0
    If xlApp Is Nothing Then Exit Function
    GetExcel = True
End Function

こんな感じですかね?

----------<追記>------------

Sub test()
    Const cBName As String = "Book1"    '開いているブック名
    Dim wb As Excel.Workbook

    If Word.Application.Tasks.Exists(cBName) Then
        'Set wb = Excel.Workbooks(cBName)
        Set wb = GetObject(, "Excel.Application").Workbooks(cBName)
    End If
End Sub

Word VBA だと、指定のブックが開いているかどうかは簡単に確認出来ますが、
Set wb = Excel.Workbooks(cBName)
とやっても新しくエクセルが起動しますね^^;
WindowsのAPI関数でウィンドウのハンドルを探したらよさそうですが、
GetObject関数を使うのが簡単そうですかね。。。。。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/23 22:54

    > なんだかごっちゃに話をされてるのが気になります。

    これは大変申し訳ございませんでした。

    私が「そもそも事前バインディングと実行時バインディング」のことを間違って理解していたために、そのような「いろいろなことがごっちゃに」質問してしまいました。すみませんでした。


    >起動しているはずのエクセル君を捕まえるのが、今回のテーマでしょうか?

    「バインディング」のことを 以下のように誤って理解していたため、「起動しているはずのエクセルを捕まえるのがテーマ」であるかのような質問もしてしまいました。
    もしかしたらご迷惑をおかけしてしまったかもしれず、もしそうでしたら大変申し訳ございません。

    ●実行時バインディング
    =参照設定は必要なく、
    新規ブック作成はCreateObject関数+Addメソッドしか使えない。
    既存ファイルオープンはGetObject関数しか使えない。
    すでに開かれているファイルは「GetObject(,"××.Application")」で取得できる

    ●事前バインディング
    =参照設定を行い、
    新規ブック作成は New ××.Application+Addしか使えない。
    (=CreateObject関数は使えない。)
    既存ファイルオープンは New ××.Application+Openしか使えない。
    (=GetObject関数は使えない。)
    すでに開かれているファイルは何で開く?

    上記のように間違った理解をしていたため、「起動しているはずのエクセルを捕まえる」ということが「事前バインディング」の場合と、「実行時バインディング」の場合と、「別々に2つ、存在するのではないか?なら事前バインディングのほうは?」とまったく的外れな疑問を抱いてしまいました。

    なおかつ、「事前バインディング」と「実行時バインディング」を同時に行うと「2重になってエラーが出るのでは?」というこれもまったく的外れで無意味な疑問を抱いてしまいました。

    そしてその2つが気になっていたため、また、自分の勘違いが hatena19さんのご指摘を受けるまではなかなか抜けたかったため質問のテーマがごっちゃになってしまいました。


    >これは、ワードVBA限定の話でしょうか?
    >それとも一般論の話でしょうか?

    一般論での話となります。
    WordからExcelを起動することでテストしていましたが、AccessからExcel操作することも考えていましたので・・・。


    >WordVBAの話なら、も少し、なにか情報がないか突っ込んで探してみようかと

    そのように言ってくださってありがとうございます!!

    でも多分ですが、私の「バインディングに対する理解のし間違い・勘違い(恥)」が原因でしたのと、また、Word限定のお話でもないものですから、これ以上は mattuwanさんの貴重なお時間を奪うことになってしまうと思いますので、今回は、ここでいったん、ひと段落とさせていただければと思います。

    mattuwanさんに教えていただいたコードも、とても参考になり、今後も私も使えるので本当にありがたかったです。

    感謝しています。

    キャンセル

  • 2019/04/24 22:34

    趣味で掲示板を巡り、勉強するテーマを探しているだけですので、
    お気遣いなく。
    興味深い質問があれば勉強し、
    一応の結果あるいは結論が自分なりに得られれば、
    横槍を入れているだけです^^;
    なので、「知っておきたい。」とか、
    「知っておかなければいけない。」というような、
    一般論には興味がないのでご了承くださいませませ。

    キャンセル

  • 2019/04/25 01:14

    はい!承知いたしました!

    それで、早速ですがご提示いただいたコードですが・・・、

    > Tasks.

    で、なんだこれは?となって、

    「Exists」をヘルプを調べつつローカルウィンドウで Tasksの中身を見てみたら、「こんなことができるのかあ~」とびっくりしてしまいました。
    For EachでTaskを調べたらなんかいっぱい出てきました。
    すごいです!
    こんな風に何が起動してるのかも調べられるんですね。

    もう、私にとってはまったく未知の領域です・・・。

    >WindowsのAPI関数でウィンドウのハンドルを探したらよさそうですが、

    そういうことになるんですね。
    そちらもさらに、私にとっては未知の領域ですが・・・

    昔わけもわからずにAccessにて、WebからのコピペでプロセスID?かなにかを調べるようなことはしたことはありますが、多分それと似たようなことなんですよね?
    確かにそれを思いますと、GetObject関数を使うほうがやりやすいです。

    そこまで調べて頂いて本当にありがとうございました。

    自分の中で、「GetObject関数で行けばいい!」、と迷いが消えました。
    ありがとうございます!


    お恥ずかしい話ですが、

    >GetObject(, "Excel.Application").Workbooks(cBName)

    という書き方(.Workbooks(cBName)が)も、すごく参考になってしまいました!
    なるほど!今まで全然気が付かなかった・・・と・・・。
    VBAはAccessもExcelも初心者レベルから脱してないので、大変参考になります。

    本当に貴重なお時間をありがとうございました。
    大変勉強になりました。(^^)m( _ _ )m

    キャンセル

0

(01)オブジェクトの種類を明確に型の宣言をすると事前バインディング(=アーリーバインディング:ある意味、「コンパイル時」バインディング?)

(02)Object型で宣言すると実行時バインディング(=レイトバインディング:文字通り、実行時バインディング?)

バインディングの話は、別アプリケーションやそのオブジェクトの操作の話ではなく、変数の宣言の仕方やコンパイル時か実行時かの違いの話、ということで、『Web情報や書籍などの情報を、私が勝手に「勘違い」して理解していたことが、今回の疑問の原因というか、質問の答え 』という結論に達することができ、とてもすっきりしました。

まだ完全には理解できていないかもしれませんが「2重のバインディング」ということも考えずに済み、CreateObject関数なども今までどおり使えることがわかり、ありがたいです。

皆さんからたくさん、コードも教えていただき、全部、1行ずつ、実行して色々と考えることができました。ありがとうございました。

みなさん全員に、自分にとってはとってもよいことをたくさん教えていただいたので、全員にベストアンサーを送りたい気持ちですが、考え方の過ちを教えてくださった hatena19さんをベストアンサーにさせて頂きたいと思います。

皆さま、ほんとうにありがとうございました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.60%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る