Excel (VBA)

Excel VBAに関するフォーラムです。
  • 掲示板への投稿には会員登録(無料)が必要です。会員登録がまだの方はこちら
  • 掲示板ご利用上のお願い」に反するご記入はご遠慮ください。
  • Q&A掲示板の使い方はこちらをご覧ください
トピックに返信
質問

 
(Windows 7 Professional : Excel 2013)
自動実行のマクロを含む複数のファイルを順次実行する方法
投稿日時: 17/12/14 03:43:09
投稿者: mbs

workbook openにマクロが記述されている、100ファイルがあります。
1つのファイルを開き、マクロが終了したら、ファイルを閉じて
次のファイルを開いて、、、という処理を実行したいのですが可能でしょうか?
 
各ファイルのマクロ処理時間は異なります。
 
調べてみたのですが、キーワードが悪いせいか欲しい情報を得られませんでした。
宜しくお願いします。

回答
投稿日時: 17/12/14 09:53:08
投稿者: WinArrow
投稿者のウェブサイトに移動

mbs さんの引用:
workbook openにマクロが記述されている、100ファイルがあります。
1つのファイルを開き、マクロが終了したら、ファイルを閉じて
次のファイルを開いて、、、という処理を実行したいのですが可能でしょうか?

可能か?
が質問趣旨ならば、可能です。
 
この制御をつかさどるマクロブックを別ブック(仮にMAIN)で作成します。
たぶん標準モジュールにコードを記述することになります。
コード記述前に若干の整理が必要です。、
(1)100ファイルの取得する方法を決めます。
(2)MAINとかのファイルの関係を整理します。
 MAINでは、各ファイルを開く〜閉じるだけでよいのか?
 その場合、各ファイルの中に自分を閉じるコードが存在しないことが重要
 または、各ファイルの中にシート画面操作が含まれていると、各ファイルのマクロが終了しても
 MAINに制御が返ってくるように作られているか?
 
など、単純ではない部分があり得るので、その点を充分チェックすること。
 
 
mbs さんの引用:

各ファイルのマクロ処理時間は異なります。

 
この部分は、どのような意味で書かれているかわかりません。
書士するデータ量が違えば、処理時間が異なるのは当たり前です。
 
mbs さんの引用:

宜しくお願いします。

 
最後に、何をお願いしているのですか?
 

回答
投稿日時: 17/12/14 09:59:10
投稿者: WinArrow
投稿者のウェブサイトに移動

文言入力ミスあり、訂正します
 
>書士するデータ量が違えば、処理時間が異なるのは当たり前です。

処理するデータ量が違えば、処理時間が異なるのは当たり前です。

回答
投稿日時: 17/12/14 15:25:59
投稿者: もこな2

WinArrowさんの回答とほぼかぶりますけど

引用:
1つのファイルを開き、マクロが終了したら、ファイルを閉じて次のファイルを開いて、、、という処理を実行したいのですが可能でしょうか?
可能不可能でいえば可能でしょう。ただし、開かれるそれぞれのブックのworkbook openにどのようなコードが書かれているかというのがポイントになりそうです。
 
引用:
各ファイルのマクロ処理時間は異なります。
呼び出す処理をするマクロ(メインルーチン)を一定時間待機させて、ということを考えたのでしょうか?アプローチを変えて呼び出すブックが開かれている間は待機ということもできそうです。
 
引用:
調べてみたのですが、キーワードが悪いせいか欲しい情報を得られませんでした。
宜しくお願いします。
ご質問からどのような情報が欲しかったのか読み取ることができませんでした。
どんなキーワードで検索したのかの提示があるとわかるかもしれません。

投稿日時: 17/12/15 01:09:36
投稿者: mbs

コメントありがとうございます。
 
まだ、ほとんど作成していませんが、
@マクロファイルを開く用のツールファイル
Aマクロファイル
 
@には、マクロファイル名がシートに一覧になっています。
ファイル名を元に、workbooks.openのループ処理を考えていたのですが
単純にループしただけでは、マクロファイルがどんどんOpenするだけになりますし
次のファイルを開くまで、waitさせるのは各マクロファイルの処理時間が異なるので
スマートじゃない。
マクロファイルの処理が終わったら、次のマクロファイルを開くような制御が
出来ないものかと思い投稿しました。
BAT書けば?と言われましたが、vb scriptは一から書いた事がありません。
 
マクロファイルには、処理の最後にマクロファイルを閉じるコードが書かれています。

回答
投稿日時: 17/12/15 18:40:53
投稿者: 細雪

複数ファイルを連続で処理する方法は
 http://www.moug.net/tech/exvba/0060003.html
辺りを参考に考えていただくとして・・
 
 
ひとまず。
Sub SamplE()
    Set wb = Workbooks.Open(Filename:="フルパス\????.xlsm")
    wb.Close savechanges:=False ' テストなので保存しなくても。
                 ' 保存までテストするならTrueに。
 
    MsgBox ""
End Sub
をお試しくださいませ。
「????.xlsm」を閉じた後にメッセージボックスが出るはずです。
 
開かれるブックに「_Open」イベントが書かれているのであれば、
開いて、処理して、閉じて、メッセージボックス表示、
と流れてくれますよ。
 
コレがスマートかどうか、私には分かりませんけど。
 
 

引用:
@マクロファイルを開く用のツールファイル
Aマクロファイル

この構成にこだわる理由も私には解りませんが、
Aは「xlsx(普通のエクセルブック)」
@は「xlsm(マクロ有効ブック)」にして、A達を連続で開いて加工(?)して閉じるマクロを仕込む
のが私にとってはスマートな作り方かなぁ、と思います。
だって、Aファイルの「_Open」イベントに仕込んでしまったら、
何かの拍子で単独で開きたいときにもマクロが動いてしまいますよね。
鬱陶しいことこの上ないと思うんですが、いかがでしょ?

回答
投稿日時: 17/12/15 18:43:43
投稿者: 細雪

連投すいません、書き忘れです。
どちらにしても
 

mbs さんの引用:
マクロファイルには、処理の最後にマクロファイルを閉じるコードが書かれています。

 
コレは無くて良いような気がします。
開いて〜閉じる までをメインのブックに書けば良いだけですから。

回答
投稿日時: 17/12/15 21:55:37
投稿者: WinArrow
投稿者のウェブサイトに移動

>マクロファイルには、処理の最後にマクロファイルを閉じるコードが書かれています。

>単純にループしただけでは、マクロファイルがどんどんOpenするだけになりますし
は、矛盾していませんか?
 
メイン側で制御するならば、マクロファイル(呼び出される側)には、閉じる命令は不要です。
どちらで制御するかを統一しないと、不具合が発生します。
 
基本的にVBAは、直列実行(並列ではない)ですから、1番目のマクロファイルの処理が終了しないうちに
2番目のマクロファイルの処理が始まることありません。
各々のマクロファイルの処理時間が異なっても何の問題もありません。

回答
投稿日時: 17/12/16 08:46:59
投稿者: simple

横入り失礼します。
 
質問者さんにお尋ねします。
 
Q1. Workbook_Openの中で自身を閉じる処理が書かれているのですね?
    それなら、普通の使い方をするときに支障はないのですか?
    開いたら直ぐに閉じるわけですよね。
 
Q2. 自身を閉じるコードが書かれているとして、
    2,3個のファイルを連続して処理するテストを実行していますか?
    最初のファイルでcloseが実行されたときに親の処理が止まってしまいませんか?
    ステップ実行してみて下さい。

回答
投稿日時: 17/12/16 11:44:55
投稿者: simple

対象ブックのなかで閉じる処理がなされていなければ、
開く・閉じる処理の繰り返しを実行すれば、自動的に同期処理されます。
(皆さんのご指摘のとおりです)
 
問題は各ブックの内部で閉じる処理が行われていたときです。
 
対応策として、Application.OnTimeを利用してみてはどうでしょうか。
 
(1)予約実行の対象プロシージャに引数を渡すこともできますから、
   ファイル名を引数で渡して開く処理を、一定の周期で実行する予約を入れればよいでしょう。
 
(2)Application.OnTimeは、時間が来たとき実行できない状況なら処理を待ってくれますから
  それを逆用すれば、対象ブックの処理時間の多様性を吸収してくれるのではないですか?

回答
投稿日時: 17/12/17 09:15:14
投稿者: simple

質問に対する回答がありませんが、テストコードを提供して
閲覧されているかたの参考に供したいと思います。
 
■まず、適当なフォルダに以下のテスト用ブックを複数作成しておきました。
 

テスト用マクロファイル
=== ThisWorkbookモジュール ===
Option Explicit
Private Sub Workbook_Open()
    Call test
End Sub

=== 標準モジュール ===
Option Explicit
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Sub test()
    Sleep 5000                  '5秒待つ
    ThisWorkbook.Close False
End Sub

 
■次に、繰り返し実行用のマクロです。
 
Sub test()
    Dim flder  As String
    Dim book   As String
    Dim myPath As String

    flder = "D:\MyDocuments\201712\test\"  ' 適宜修正のこと
    book = Dir(flder & "*.*")              ' 適宜修正のこと
    Do While book <> ""
        myPath = flder & book
        Application.OnTime Now(), "'open_book """ & myPath & """'"
        book = Dir()
    Loop
End Sub

Sub open_book(bookpath As String)
    Debug.Print Now()       '
    Workbooks.Open bookpath
    Debug.Print Now()       ' 対象ファイルで実行されるclose処理の影響で
                            ' これは実行されない。
End Sub

 
ポイント:
(1)こうした場面におけるOnTimeの使い方
(2)OnTimeの実行対象プロシージャに引数を渡すことができる(文字列に限定だが)。
 
# なお、あらゆることを想定してテスト検証を行っているわけではないので、
# 使用にあたっては自己責任でお願いします.

回答
投稿日時: 17/12/19 14:25:12
投稿者: もこな2

意外と難しいですね。これ。
当方で↓のようなテストを行ってみました。
 
1.以下を仕込んだブックを10ファイルほど用意
(わかりやすいように、TEST_01.xls、TEST_02.xls、、、というように連番にしてみました。)

Private Sub Workbook_Open()
With ThisWorkbook
    Open .Path & "\test.txt" For Append As #1
        Print #1, .Name
    Close #1
    .Close
End With
End Sub

2.制御するブック(メインブック.xlsmとします)のシート1のA列、1行目から〜
TEST_01.xls、TEST_02.xls、、、と入力
 
3.制御するブック(メインブック.xlsm)の標準モジュールに以下を記述
Sub 処理()
Dim i As Integer
With ThisWorkbook
    For i = 1 To 10 Step 1
        Workbooks.Open _
            Filename:=.Path & "\" & .Sheets(1).Cells(i, "A").Value
    Next i
End With
End Sub

4.制御するブック(メインブック.xlsm)の「処理」プロシージャを実行
 
すると、「TEST_01.xls」とだけ書かれたテキストファイルが完成します。
何回か、「処理」プロシージャを実行してみましたが、「TEST_01.xls」がどんどん追加されていくだけで、「TEST_02.xls」以降の処理に進んでいる様子がありませんでした。
 
ステップ実行をしてみると、ブックを開いて、テキストファイルに書き込むところまではちゃんといってるんですが、「Private Sub Workbook_Open」に移行した後「.Close」で実行が終わってしまうようです。(End Sub までいかず、「処理」プロシージャに戻らない)
 
とりあえず、回避方法として、Workbook_Openを無効にして、全部メインブック側で処理するという手は使えそうです。↓参照 
Sub 処理2()
Dim i As Integer
Application.EnableEvents = False 'イベントを無効化
With ThisWorkbook
For i = 1 To 10 Step 1
    Workbooks.Open _
        Filename:=.Path & "\" & .Sheets(1).Cells(i, "A").Value
    With Workbooks(Dir(.Path & "\" & .Sheets(1).Cells(i, "A").Value))
        Open .Path & "\test2.txt" For Append As #1
            Print #1, .Name
        Close #1
        .Close
    End With
Next i
End With
Application.EnableEvents = True 'イベントを有効化
End Sub

 
なので、mbsさんの100ファイルにどのようなコードが書かれているかわかりませんが、そう複雑でない処理であれば、思い切って「Workbook_Open」は無視して、新たに処理側のブックでなんやかんやするような設計にするってのもアリかと思います。

回答
投稿日時: 17/12/20 08:41:43
投稿者: mokutachi

もこな2 さんの引用:

With ThisWorkbook
For i = 1 To 10 Step 1
    Workbooks.Open _
        Filename:=.Path & "\" & .Sheets(1).Cells(i, "A").Value
    With Workbooks(Dir(.Path & "\" & .Sheets(1).Cells(i, "A").Value))
        Open .Path & "\test2.txt" For Append As #1
            Print #1, .Name
        Close #1
        .Close
    End With
Next i
End With

Openメソッドの戻り値を使えば、Workbooksプロパティや、Dir関数は必要なさそうですよ。
(ブック名を使うだけなら開く必要もなさそうですが?そこは置いておきます。)
 
例)
Dim wb As Workbook

Set wb = Workbooks.Open(・・・)
MsgBox wb.Sheets(1).Cells(1).Value
wb.Close False

回答
投稿日時: 17/12/20 10:15:09
投稿者: もこな2

引用:
Openメソッドの戻り値を使えば、Workbooksプロパティや、Dir関数は必要なさそうですよ。
なるほど、Openメソッドの戻り値は開かれたWorkbookオブジェクトが返るから、それをオブジェクト型変数で受けて使えばいいのですね.... 〆(._.=j
 
引用:
(ブック名を使うだけなら開く必要もなさそうですが?そこは置いておきます。)
そうですね。トピックの趣旨がたくさんのブックを連続して開いて処理するなので・・

トピックに返信