C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

VBより今開いてるExcelのファイル名の取得

[トピック内 28 記事 (1 - 20 表示)]  << 0 | 1 >>

■94040 / inTopicNo.1)  VBより今開いてるExcelのファイル名の取得
  
□投稿者/ さき (13回)-(2020/03/06(Fri) 12:53:21)

分類:[VB.NET/VB2005 以降] 

タイトルの通り、
今開いてるExcelのファイル名を取得したいのですが、そのようなことは可能でしょうか?

Windows 10
Excel 2013
引用返信 編集キー/
■94041 / inTopicNo.2)  Re[1]: VBより今開いてるExcelのファイル名の取得
□投稿者/ 魔界の仮面弁士 (2589回)-(2020/03/06(Fri) 13:15:01)
No94040 (さき さん) に返信
> 今開いてるExcelのファイル名を取得したいのですが、

新規作成中で未保存の文書については、どうしますか?


> そのようなことは可能でしょうか?

Workbooks コレクションから、Workbook を列挙すれば、
FullName プロパティでファイルのフルパスを得られます。
https://docs.microsoft.com/ja-jp/office/vba/api/excel.workbook.fullname


Excel の起動済みインスタンスを拾う場合、
Application インスタンスが単一起動なら GetObject 関数を使えます。

Excel のバージョンが古く、複数の Excel インスタンスを個別に拾う必要が
ありそうなら、少し手間ですが IRunningObjectTable インターフェイス経由で列挙できます。
(
引用返信 編集キー/
■94042 / inTopicNo.3)  Re[2]: VBより今開いてるExcelのファイル名の取得
□投稿者/ 魔界の仮面弁士 (2590回)-(2020/03/06(Fri) 13:31:00)
No94041 (魔界の仮面弁士) に追記
> Excel の起動済みインスタンスを拾う場合、
> Application インスタンスが単一起動なら GetObject 関数を使えます。

手抜き実装ですが、たとえばこんな感じ。


Imports System.Runtime.InteropServices
Module Module1
 Public Sub Main()
  Dim files As String() = GetOpenedExcelFiles()
  Console.WriteLine("{0}個のファイルが開かれています。", files.Count)
  Array.ForEach(files, AddressOf Console.WriteLine)
  Console.ReadKey()
 End Sub

 Public Function GetOpenedExcelFiles() As String()
  Dim excel As Object
  Try
   excel = GetObject(, "Excel.Application")
  Catch
   'Excel は起動していない
   Return New String(-1) {}
  End Try

  Dim books = CallByName(excel, "Workbooks", CallType.Get)
  Dim files(CInt(CallByName(books, "Count", CallType.Get)) - 1) As String
  For n As Integer = 1 To files.Count
   Dim book = CallByName(books, "[DispId=0]", CallType.Get, n)
   files(n - 1) = CStr(CallByName(book, "FullName", CallType.Get))
   ReleaseComObject(book)
  Next
  ReleaseComObject(books)
  ReleaseComObject(excel)
  Return files
 End Function

 Private Sub ReleaseComObject(Of T)(ByRef o As T)
  If o IsNot Nothing AndAlso Marshal.IsComObject(o) Then
   Marshal.FinalReleaseComObject(o)
   o = Nothing
  End If
 End Sub
End Module
引用返信 編集キー/
■94043 / inTopicNo.4)  Re[2]: VBより今開いてるExcelのファイル名の取得
□投稿者/ さき (14回)-(2020/03/06(Fri) 13:51:46)
2020/03/06(Fri) 13:54:49 編集(投稿者)

No94041 (魔界の仮面弁士 さん) に返信

前後しました
ありがとうございます。



引用返信 編集キー/
■94044 / inTopicNo.5)  Re[3]: VBより今開いてるExcelのファイル名の取得
□投稿者/ さき (15回)-(2020/03/06(Fri) 14:49:51)
No94042 (魔界の仮面弁士 さん) に返信

作ってもいただきありがとうございます。

モジュールは初めてです。
Call Main()で呼び出せば良いのですね?

実行の結果、Console.ReadKey() で下記のエラーでました。

System.InvalidOperationException: 'アプリケーションにコンソールがないとき、またはコンソール入力がファイルからリダイレクトされているとき、キーを読み取ることはできません。Console.Read を使用してください。'
引用返信 編集キー/
■94045 / inTopicNo.6)  Re[4]: VBより今開いてるExcelのファイル名の取得
□投稿者/ 魔界の仮面弁士 (2591回)-(2020/03/06(Fri) 15:39:33)
2020/03/06(Fri) 16:18:56 編集(投稿者)

No94044 (さき さん) に返信
> モジュールは初めてです。

現状のプロジェクトは何でしょうか?
「Windows フォーム アプリケーション」でしょうか。
「WPF アプリ」でしょうか。

ASP.NET Web アプリケーションとかだと、前提条件から崩れてくる…。

※実際に作る際には、Module を Class に置き換えることもできます。


> Call Main()で呼び出せば良いのですね?
GetOpenedExcelFiles を呼び出せば、ファイル名の一覧が受け取れます。

先のコードを試す場合は、新規プロジェクトを作成して、
「コンソール アプリケーション (.NET Framework)」
を選択してください。Module と Sub Main が作られるので、
そこに貼り付ければ実行できます。

自アプリに組み込むのは、期待する結果が得られることを
確認出来てからの方が良いでしょう。


> 実行の結果、Console.ReadKey() で下記のエラーでました。
Windows フォームアプリケーションだと、Console.ReadKey() は使えません。
不要なら削ってください。

コンソール アプリの場合、処理が終わると自動終了してしまうため、
ReadKey メソッドでキー入力を待ち合わせることで、
画面を確認できるようにしているだけです。
Windows フォームでいえば、「MsgBox("終わり")」程度の意味であり、
それ自体に意味はありません。
引用返信 編集キー/
■94046 / inTopicNo.7)  Re[5]: VBより今開いてるExcelのファイル名の取得
□投稿者/ さき (16回)-(2020/03/06(Fri) 17:35:25)
No94045 (魔界の仮面弁士 さん) に返信

現状のプロジェクトは「Windows フォーム アプリケーション」です。

Moduleはプロジェクト、モジュールの追加を選び作成もしましたが、そもそもそこからして間違っていたようです。
そんな訳もあり出来ればClassが有り難いです。
お教えの方法で一応はModule と Sub Main は作られもしましたが。

それよりも予想より大層なので驚きです。
ご迷惑をお掛けしてそうです。

引用返信 編集キー/
■94047 / inTopicNo.8)  Re[6]: VBより今開いてるExcelのファイル名の取得
□投稿者/ 魔界の仮面弁士 (2592回)-(2020/03/06(Fri) 17:46:29)
No94046 (さき さん) に返信
> そんな訳もあり出来ればClassが有り難いです。
> お教えの方法で一応はModule と Sub Main は作られもしましたが。

今お使いのフォームの先頭に
 Imports System.Runtime.InteropServices
という記述を加えてください。

次に、先のコードの GetOpenedExcelFiles メソッドと ReleaseComObject メソッドの 2 つを
今お使いの Form にコピーしてください。


あとは、お好きな場所(たとえばボタンクリック時など)にて、
GetOpenedExcelFiles メソッドを呼び出すようにすれば、
このメソッドの戻り値から、Excel ファイルパスの一覧が得られます。
引用返信 編集キー/
■94049 / inTopicNo.9)  Re[7]: VBより今開いてるExcelのファイル名の取得
□投稿者/ さき (17回)-(2020/03/06(Fri) 19:31:30)
No94047 (魔界の仮面弁士 さん) に返信


> このメソッドの戻り値から、Excel ファイルパスの一覧が得られます。

ありがとうございます。
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Call GetOpenedExcelFiles()
    End Sub
これで良いかとは思うのですがGetOpenedExcelFilesの値はNothingのままでした。

また下記は Excel起動していない時にもこの行は実行されなかったです。
   'Excel は起動していない
   Return New String(-1) {}


引用返信 編集キー/
■94050 / inTopicNo.10)  Re[8]: VBより今開いてるExcelのファイル名の取得
□投稿者/ 魔界の仮面弁士 (2593回)-(2020/03/06(Fri) 21:41:43)
2020/03/06(Fri) 21:46:38 編集(投稿者)

No94049 (さき さん) に返信
> Call GetOpenedExcelFiles()

いや何で Call しちゃうんですか……(^^;

戻り値を読み捨てるのではなく、
配列変数に受けるなり、
For / For Each ステートメントで列挙するなり、
ListBox1.DataSource に渡すなり、
TextBox1.Lines にセットするなりして
戻り値の内容を確認してください。

> また下記は Excel起動していない時にもこの行は実行されなかったです。

非表示の Excel.exe プロセスが存在していませんか?
タスクマネージャーで確認してみてください。
引用返信 編集キー/
■94051 / inTopicNo.11)  Re[9]: VBより今開いてるExcelのファイル名の取得
□投稿者/ さき (18回)-(2020/03/06(Fri) 22:24:22)
No94050 (魔界の仮面弁士 さん) に返信


>>Call GetOpenedExcelFiles()
>
> いや何で Call しちゃうんですか……(^^;
すみません。
では、どうすればGetOpenedExcelFiles メソッドを呼び出せるのかが分かりません。


> 非表示の Excel.exe プロセスが存在していませんか?
> タスクマネージャーで確認してみてください。
確認もしましたが存在はしてました。
引用返信 編集キー/
■94058 / inTopicNo.12)  Re[10]: VBより今開いてるExcelのファイル名の取得
□投稿者/ kiku (168回)-(2020/03/09(Mon) 16:53:57)
> >>Call GetOpenedExcelFiles()
>>
>>いや何で Call しちゃうんですか……(^^;
> すみません。
> では、どうすればGetOpenedExcelFiles メソッドを呼び出せるのかが分かりません。

VB.NETなので間違っているかもしれませんが、
下記で戻り値を取得できませんか?

Dim result = GetOpenedExcelFiles()
引用返信 編集キー/
■94059 / inTopicNo.13)  Re[11]: VBより今開いてるExcelのファイル名の取得
□投稿者/ kiku (169回)-(2020/03/09(Mon) 16:54:59)
No94058 (kiku さん) に返信
>>>>Call GetOpenedExcelFiles()
> >>
> >>いや何で Call しちゃうんですか……(^^;
>>すみません。
>>では、どうすればGetOpenedExcelFiles メソッドを呼び出せるのかが分かりません。
>
> VB.NETなので間違っているかもしれませんが、
> 下記で戻り値を取得できませんか?
>
> Dim result = GetOpenedExcelFiles()

こっちかな。

Dim result() as string = GetOpenedExcelFiles()
引用返信 編集キー/
■94060 / inTopicNo.14)  Re[12]: VBより今開いてるExcelのファイル名の取得
□投稿者/ さき (19回)-(2020/03/09(Mon) 23:40:43)
No94059 (kiku さん) に返信

ありがとうございます。

> Dim result() as string = GetOpenedExcelFiles()
はエラーが出ました。

> Dim result = GetOpenedExcelFiles()
ですと、result の値は、Excelが開いてると{Length=1} 、閉じてると {Length=0} とはなります。
これをどのようにすれば Excelのファイル名の取得になるのでしょうか?

よろしくお願いします。

引用返信 編集キー/
■94061 / inTopicNo.15)  Re[13]: VBより今開いてるExcelのファイル名の取得
□投稿者/ 魔界の仮面弁士 (2597回)-(2020/03/10(Tue) 08:38:45)
2020/03/10(Tue) 16:27:50 編集(投稿者)

No94051 (さき さん) に返信
>>> また下記は Excel起動していない時にもこの行は実行されなかったです。
>>> 'Excel は起動していない
>>> Return New String(-1) {}
>>
>> 非表示の Excel.exe プロセスが存在していませんか?
>> タスクマネージャーで確認してみてください。
>
> 確認もしましたが存在はしてました。

「Return New String(-1) {}」の行が実行されなかったのは、
タスクマネージャー上に Excel.exe が「存在していた」ためです。


Excel.exe が起動していなかった場合には、
GetObject(, "Excel.Application") の呼び出しは失敗し、
Catch 句が実行されることになります。

Excel.exe が起動されていた場合には、
Excel が表示されていようといまいと、
GetObject(, "Excel.Application") の呼び出しが成功しますので、
その場合は Catch 句には到達せず、End Try 以降の行に進み、
そのまま Workbooks の Count を返すようになっています。


No94060 (さき さん) に返信
>>Dim result() as string = GetOpenedExcelFiles()
> はエラーが出ました。

エラーメッセージを蔑ろにせず、何というエラーになったのかを
示して頂けますでしょうか。同じ画面を見ながら操作しているわけでは
ないので、状況をきちんと説明して説明して頂かないと、
こちらからアドバイスしにくいです…。

たとえば誤って
 Dim result As String = GetOpenedExcelFiles() 'これはエラーになる
と書いてしまっていた…ということはありませんか?


想像だけでは答えにくいので、まずは状況を確認しておきたいのですが、 No94046 の段階で
> お教えの方法で一応はModule と Sub Main は作られもしましたが。
と書かれていましたが、実際に Sub Main() から動作することは確認済みでしょうか?

それが動作したのであれば、 No94042 における
>> Dim files As String() = GetOpenedExcelFiles()
と、 No94059 における
>> Dim result() as string = GetOpenedExcelFiles()
は、変数名が異なるだけであり、本質的には同一の内容ですから、
本来はエラーにはならないはずなのです。

というのも、Visual Basic における配列宣言においては、
『Dim a As String()』と『Dim a() As String』とでは
書き方が異なるだけであり、コンパイル結果は完全に同一だからです。

※もしも『配列』という言葉の意味が分からない状況だとしたら、
 前提知識が不足しているようなので、まずは入門書等で
 再学習されることをお奨めします。


> Dim result = GetOpenedExcelFiles()
これが実行できるなら、先のコードでも実行できるはずなのですけれどね…。

上記をデバッグして、変数 result のデータ型が
何になっているか確認しておいてください。

Dim result() As String = GetOpenedExcelFiles() 'パターン A
Dim result As String() = GetOpenedExcelFiles() 'パターン B
Dim result = GetOpenedExcelFiles() 'パターン C

上記 3 つは、変数のデータ型を指定する表現方法が異なるだけであり、
いずれの表現でも、変数が「String の一次元配列」な型となる仕様です。

※設定次第では、パターン C だけは別のデータ型になる可能性もあるのですが、
 通常の設定では、3 パターンとも同一の結果となります。


> Excelが開いてると{Length=1} 、閉じてると {Length=0} とはなります。
複数の Excel ファイルを同時に開いていた場合、さらにその数は増えるでしょう。

「ファイル名がまだつけられていない状態」すなわち
No94041 で指摘した『新規作成中で未保存の文書』がある場合、
それらもカウント対象となります。


> これをどのようにすれば Excelのファイル名の取得になるのでしょうか?
これは既に No94050 にて回答していますね。

>>> 戻り値を読み捨てるのではなく、
>>> 配列変数に受けるなり、
>>> For / For Each ステートメントで列挙するなり、
>>> ListBox1.DataSource に渡すなり、
>>> TextBox1.Lines にセットするなりして
>>> 戻り値の内容を確認してください。

GetOpenedExcelFiles は Sub ではなく Function として宣言されていますので、
結果は「戻り値」で返されます。

それなのに Call ステートメントを使っては、せっかくの戻り値が
読み捨てられてしまい、無意味になってしまいます。


ですから先の回答のように、
> 配列変数に受けるなり、
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
  Dim files() As String = GetOpenedExcelFiles() '配列変数で受け取る
  MsgBox(files.Length) '配列の個数を確認
  MsgBox(files(0)) ' 1 個めのファイルパスを表示(.Count が 0 の時はエラーになる)
  MsgBox(files(1)) ' 2 個めのファイルパスを表示(.Count が 0〜1 の時はエラーになる)
End Sub

> For / For Each ステートメントで列挙するなり、
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
  For file As String In GetOpenedExcelFiles()
    MsgBox(file)
  Next
End Sub

> ListBox1.DataSource に渡すなり、
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
  ListBox1.DataSource = GetOpenedExcelFiles()
End Sub


> ListBox1.DataSource に渡すなり、
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
  ' デザイン時に、TextBox1 のプロパティ設定で、
  ' Multiline = True、ScrollBars = Both、WordWrap = False に設定しておいてください
  TextBox1.Lines = GetOpenedExcelFiles()
End Sub


…などとして、GetOpenedExcelFiles という Function から得た
「戻り値」から Excel ファイル名の一覧を受け取ってください。


上記では、テキストボックスや MsgBox などに表示させていますが、
受け取った値をどこに表示するのかなどは、実際に作成されている
アプリケーションに合わせて、お好きなように書き換えてください。
引用返信 編集キー/
■94062 / inTopicNo.16)  Re[13]: VBより今開いてるExcelのファイル名の取得
□投稿者/ kiku (170回)-(2020/03/10(Tue) 08:43:55)
>>Dim result = GetOpenedExcelFiles()
> ですと、result の値は、Excelが開いてると{Length=1} 、閉じてると {Length=0} とはなります。
> これをどのようにすれば Excelのファイル名の取得になるのでしょうか?

戻り値resultはString型の配列になっています。
配列の中身を取得する必要があります。

配列についてぐぐってみてください。とりあえず下記貼っておきます。
https://itsakura.com/vbnet-array
引用返信 編集キー/
■94072 / inTopicNo.17)  Re[14]: VBより今開いてるExcelのファイル名の取得
□投稿者/ さき (20回)-(2020/03/10(Tue) 21:41:02)
No94061 (魔界の仮面弁士 さん) に返信

詳しい説明ありがとうございます。
一応は理解はできた積りですが何分初心者、おっしゃる通りまだまだ学習も足らないとこもあります。

>> 配列変数に受けるなり、
少し加工もしリストボックスに表示、選択も出来るようにし、これを使わせてもいただきました。
他はまた必要な節には使わせてもいただきます。

もう一件、調べても分かりませんでしたので恐縮です。
開いてるExcelをVBから閉じたいです。
可能であればお教えの程お願いします。
引用返信 編集キー/
■94073 / inTopicNo.18)  Re[15]: VBより今開いてるExcelのファイル名の取得
□投稿者/ 魔界の仮面弁士 (2602回)-(2020/03/11(Wed) 00:22:46)
No94072 (さき さん) に返信
> 一応は理解はできた積りですが何分初心者、

実行はできたようですが……結局のところ、
No94060 で発生したエラーは、何が原因だったのでしょうね?


その時に表示されていたエラーメッセージを教えてください。


> 開いてるExcelをVBから閉じたいです。

閉じるときに、現在開いている Excel 文書はどうしますか? 保存しますか?

保存するかどうかによって、たとえば下記のようなパターンが思い当たりますが、
どのパターンにするかによって、実装すべき処理内容も変わってくるでしょう。

1) 一つ一つ、保存するかどうかを問い合わせた上で閉じる
2) 保存確認等は行わせず、すべて保存せずに閉じる(未保存の内容は失われる)
3) 未保存のものがあれば、すべて上書き保存してから閉じる(まだ保存前の新規ファイルは、適当なファイル名をつけて保存)
4) 未保存のものがあれば、元のファイル名とは別の名前で保存してから閉じる(まだ保存前の新規ファイルは、適当なファイル名をつけて保存)
5) Excel そのものを閉じるのではなく、特定の Excel ワークブックだけを閉じる(すべてのブックが閉じられた時に限り、Excel 本体も閉じる)
6) 上記以外


> 可能であればお教えの程お願いします。

Excel そのものを閉じるなら、Application オブジェクトの Quit メソッドを呼び出します。
https://docs.microsoft.com/en-us/office/vba/api/excel.application.quit

Excel 全体ではなく、特定のワークブックを閉じたいのであれば、
Workbook オブジェクトの Close メソッドを呼び出します。
https://docs.microsoft.com/en-us/office/vba/api/excel.workbook.close


とりあえず、上記の 1) ならこんな感じ。

Public Sub CloseExcelApp()
  Dim excel As Object = Nothing
  Try
    '起動済みの Excel を取得します
    excel = GetObject(, "Excel.Application")

    '未保存のファイルを保存するかどうかが確認されるようにします
    CallByName(excel, "DisplayAlerts", CallType.Let, True)

    '確認画面が前面に表示されるよう、Excel をアクティブにしておきます
    Try
      AppActivate(CStr(CallByName(excel, "Caption", CallType.Get)))
    Catch
    End Try

    'Quit メソッドを呼び出して、Excel を終了させます
    CallByName(excel, "Quit", CallType.Method)
    '
    'この時、未保存のファイルがあれば、保存するかどうかを聞かれますが、
    'その画面で「キャンセル」が押された場合は、実際には閉じらずに残ります。
    '
  Catch
  Finally
    '下記メソッドの実装は No94042 を参照
    ReleaseComObject(excel)
  End Try
End Sub
引用返信 編集キー/
■94074 / inTopicNo.19)  Re[16]: VBより今開いてるExcelのファイル名の取得
□投稿者/ 魔界の仮面弁士 (2603回)-(2020/03/11(Wed) 08:20:28)
No94073 (魔界の仮面弁士) に追記
> その時に表示されていたエラーメッセージを教えてください。
>
> 閉じるときに、現在開いている Excel 文書はどうしますか? 保存しますか?

上記 2 点の逆質問への回答待ちですが、それはさておき。


> 1) 一つ一つ、保存するかどうかを問い合わせた上で閉じる
> 2) 保存確認等は行わせず、すべて保存せずに閉じる(未保存の内容は失われる)
> とりあえず、上記の 1) ならこんな感じ。

今度は 2) の実装例。

Public Sub CloseExcelApp()
  Dim excel As Object = Nothing
  Try
    excel = GetObject(, "Excel.Application")
    Dim books = CallByName(excel, "Workbooks", CallType.Get)
    For n = CInt(CallByName(books, "Count", CallType.Get)) To 1 Step -1
      Dim book = CallByName(books, "[DispId=0]", CallType.Get, n)
      ' ワークブックを保存せずに閉じる
      CallByName(book, "Close", CallType.Method, False)
      ReleaseComObject(book)
    Next
    ReleaseComObject(books)

    'Quit メソッドを呼び出して、Excel を終了させる
    CallByName(excel, "Quit", CallType.Method)
  Catch
  Finally
    ReleaseComObject(excel)
  End Try
End Sub



さて、Excel を操作するにあたって注意点があります。

開いている Excel が、「セルの編集作業中」「ファイル選択画面を開いている」
「メッセージボックス等を表示している」などといった状態にあった場合、
VB 等からの指示……今回のケースであれば、Workbook の Close メソッドや
Application の Quit メソッドなどによる終了操作は一切受け付けません。

メソッドを呼び出してもエラーとなってしまうため、
Try〜Catchで例外処理する必要があります。
引用返信 編集キー/
■94079 / inTopicNo.20)  Re[17]: VBより今開いてるExcelのファイル名の取得
 
□投稿者/ さき (21回)-(2020/03/11(Wed) 15:37:04)
No94074 (魔界の仮面弁士 さん) に返信

ありがとうございます。

>> その時に表示されていたエラーメッセージを教えてください。
>>
>> 閉じるときに、現在開いている Excel 文書はどうしますか? 保存しますか?
>
>上記 2 点の逆質問への回答待ちですが、それはさておき。

申し訳ありません。
何が原因でエラーになったのかは、今は分かってませんが、その後はエラーもなく正常に動いてはいます。
また、保存とかではなく、ファイル名のみを抽出、その内容を別途読み込みもし活用もしたかったのです。

またまた言葉足らずで恐縮です。
開いてるExcelをVBから閉じたいとは、上で抽出もしたそのExcelのことなのです。
閉じもせず読み込みもしょうとすれば、「System.IO.IOException 別のプロセスで使用されているため・・」とのエラーにもなるからです。
引用返信 編集キー/

このトピックをツリーで一括表示

次の20件>
トピック内ページ移動 / << 0 | 1 >>

管理者用

- Child Tree -