ブック | Excel作業をVBAで効率化 https://vbabeginner.net いつものExcel作業はVBAを使えば数秒で終わるかもしれませんよ Sat, 09 Nov 2024 05:46:03 +0000 ja hourly 1 https://wordpress.org/?v=6.6.2 https://vbabeginner.net/wp-content/uploads/2019/02/favicon-150x150.png ブック | Excel作業をVBAで効率化 https://vbabeginner.net 32 32 VBAのWorkbooks.Openでリンク更新ダイアログを消す https://vbabeginner.net/prevent-link-update-dialog-workbooks-open/ Wed, 02 Aug 2023 15:52:19 +0000 https://vbabeginner.net/?p=6867 Workbooks.OpenでApplication.DisplayAlartが効かない?

VBAを使ってブックを開いて処理する場合、Workbooks.Openメソッドを利用します。

Workbooks.Open("C:\test\abc.xlsx")

ただ、このときに以下のリンク更新ダイアログが表示されることがあります。

「このブックには、安全ではない可能性のある外部ソースへのリンクが1つ以上含まれています。リンクを信頼できる場合、リンクを更新して最新データを取り込みます。信頼できない場合は、データをそのまま手元で処理してもかまいません。」

相変わらず意味が分かりにくいメッセージです。ボタンを押すこと自体が恐怖です。これをユーザーに見せて理解できると本当にMicrosoftは思ってるのか謎です。

分かりやすく書くと、「他のブックのセルにハイパーリンク貼ってるけど、値変わってるかもしれんよ。確認して値を最新にする?」って話です。

で、このようなメッセージダイアログを出さないようにする仕組みとして「Applicationo.DisplayAlart = False」がありますが、このメッセージの場合はこの方法が効きません。

というのも、「Applicationo.DisplayAlart = False」は全てのダイアログを消すことはできず、セキュリティ上問題がある場合にはダイアログの表示が優先されてしまいます。

リンク更新ダイアログを出さない方法

では、どうやってリンク更新ダイアログの表示を回避するかというと、Workbooks.Openメソッドの引数でUpdateLinksに0を指定します。

Sub UpdateLinksZero()
    Dim wb      As Workbook                 '// ワークブック
    Dim sPath                               '// ブックファイルパス
    
    '// 開くブックを指定
    sPath = "C:\test\abc.xlsx"
    
    '// Filename:開くブック
    '// UpdateLinks:0=リンク更新しない
    '// ReadOnly:True=読み取り専用で開く
    '// IgnoreReadOnlyRecommended:True=読み取り専用推奨ダイアログを非表示
    Set wb = Workbooks.Open(Filename:=sPath, UpdateLinks:=0, ReadOnly:=True, IgnoreReadOnlyRecommended:=True)
    
    '// ブックを閉じる
    Call wb.Close
End Sub

0を指定するとリンク更新は「更新しない」扱いになります。リンク更新ダイアログで「更新しない」ボタンを押したときと同じ挙動になります。

上のコードではUpdateLinks以外にReadOnly、IgnoreReadOnlyRecommendedも引数で設定していますが、リンク更新ダイアログを非表示にしたい場合は、ブックをとにかく参照したい場合が多いため、これらの引数は大体セットで設定します。

Workbooks.Openの詳細については「VBAでExcelブックを開く方法(Workbooks.Open)」をご参照ください。

そもそもリンク更新ダイアログが出るような状態が問題

リンク更新ダイアログが出る原因は、他ブックのセルを参照していることがほとんどですが、意図せずこの状況になっていることが多々あります。

この状況になるとVBAのWorkbooks.Openメソッドだけでなく、普通にブックを開くときにも以下のセキュリティの警告が表示されます。

ハイパーリンクで他のブックのセルを参照するのは便利な機能ではありますが、ほとんどの場合は別シートにリンクを貼ったシートを、別のブックにコピーすることが原因です。

再現方法は、Book1.xlsxにSheet1とSheet2があり、Sheet2のA1セルで「=Sheet1!A1」として、そのSheet2を別ブックにコピーすると、元の「=Sheet1!A1」が「=’C:\test\[Book1.xlsx]Sheet1′!A1」のように外部ブックを指すようになります。

これが、別ブックを参照していることになってしまう原因です。

これを解消するには、Ctrl+Fキーで検索ダイアログで「.xls」を検索すると、外部ブックへのハイパーリンクが見つかります。ごくまれにですが、オートシェイプをボタンのようにハイパーリンクを貼っていることもありますので、セルの検索で見つからない場合はオートシェイプを探してみてください。

あとは見つかった外部ブックのリンクを書き換えると、リンク更新ダイアログやセキュリティ警告は出なくなります。

]]>
VBAで複数のブックに対して同じ処理を行う https://vbabeginner.net/do-same-process-for-multiple-workbooks/ Tue, 04 Apr 2023 16:14:43 +0000 https://vbabeginner.net/?p=6665 複数のブックに対して同じ処理を行うには

作業で扱うブックが複数ある場合で、それら全てのブックに対して同じ処理として内容の確認や修正をしなければならない、なんてことがよくあります。

例えば、どのセルに「aaa」と書いてあるか調べたい場合や、背景色が付いているセルを「塗りつぶしなし」にしたい場合や、シート名の西暦を和暦に変えたい場合などが挙げられますが、他にもいろいろあります。

どのような参照や修正を行うのかは本当にいろいろありますが、それらの処理を行うために必要な「複数のブックに対して同じ処理をする」という処理の書き方はいずれも大体同じような書き方になります。

そこで以下で、その大体同じような書き方になる、複数のブックに対して同じ処理を行いたい場合のコードの書き方を紹介します。

複数のブックの参照を行うコード

以下のコードは、事前にブックの一覧をシートに書いてあることが前提になります。

ここでは、A1セルからブックのフルパスを書いておき、列挙された各ブックのフルパスに対してそれぞれ同じ処理を行う、というコードの書き方になります。

マクロを実行する際には、ブックのフルパスが書いてあるブックをアクティブにしていることが前提になります。

コードの内容ですが、ブックの参照のみを行い、保存はしない場合の書き方になります。

Doループの中で1ブックずつ開いて、なんか処理して、閉じる、ということを繰り返しています。

関数の先頭でエラー発生時のラベル「ERR_LABEL」を付けています。これは、ブックが存在しない場合にWorkbooks.Openでエラーが発生して処理が止まってしまうためそれを防ぐためです。ブックが存在しなかった場合はイミディエイトウィンドウにエラー情報を出力しています。

「Application.DisplayAlerts = False」はブックのループ処理を行う場合は入れておいた方がよいです。ブックによっては開くたびに自動計算が実行されるようなものがあります。例えばTODAY関数を入れていたりなどです。そのようなブックは開く度にセルの内容が変わるため、ブックを閉じるときに「保存しますか?」と聞かれることになります。マクロで実行した場合も同様で、保存確認ダイアログを表示してそこでマクロ処理が中断されてしまいます。それを避けるために「Application.DisplayAlerts = False」を入れています。

Doループの中でブックを開く「Workbooks.Open」の引数で、「ReadOnly:=True」と「IgnoreReadOnlyRecommended:=True」を指定していますが、これはどういう処理を行うかによってTrueではなくFalseを設定することもあります。

各ブックで行う処理のサンプルとして「なんか参照処理」を用意していますが、ここではブックの一番左のシートの名前をイミディエイトウィンドウに出力しています。この部分を、個別の処理に書き換えることで、複数のブックに対して同じ処理を行うことができます

Sub BooksLoopRefer()
    On Error GoTo ERR_LABEL
    
    Dim r   As Range                    '// セル(ループ中に1セルずつ下にずれる)
    Dim wb  As Workbook                 '// ブック
    
    '// ブックの一覧の基点セルを指定
    Set r = Range("A1")
    
    '// ブックを閉じる際の保存確認ダイアログを出さないようにする
    Application.DisplayAlerts = False
    
    '// シートのA列に書かれている全てのブックパスをループ
    Do
        '// 現在ループのセルにブックパスが書いていない場合はここでループを抜ける
        If r.Value = "" Then
            Exit Do
        End If
        
        '// ブックを開く。
        '// Filename:=r.Value:現在ループのセルに書いてあるブックパスを開く。
        '// ReadOnly:=True:読み取り専用で開く
        '// IgnoreReadOnlyRecommended:=True:読み取り専用推奨ダイアログを非表示にする
        Set wb = Workbooks.Open(Filename:=r.Value, ReadOnly:=True, IgnoreReadOnlyRecommended:=True)
        
        Call なんか参照処理(wb)
        
        '// ブックを閉じる
        Call wb.Close
        
        '// 現在ループのA列のセルの1つ下のセルを参照する
        Set r = r.Offset(1, 0)
    Loop
    
    Application.DisplayAlerts = True
    
ERR_LABEL:
    If (Err.Number <> 0) Then
        '// エラーが発生したブックパスとエラー内容を出力
        Debug.Print r.Value & " " & Err.Number & " " & Err.Description
    End If
End Sub

Sub なんか参照処理(wb As Workbook)
    Debug.Print wb.Worksheets(1).Name
End Sub

複数のブックの更新を行うコード

上のコードはブックを参照する場合の書き方でしたが、以下のコードはブックの内容を書き換えて上書き保存をしたい場合の書き方です。

といっても、ほとんどの部分は上のコードと同じです。違うのはブックを開くWorkbooks.Openメソッドの引数で読み取り専用で開かないようにしていることと、ブックを閉じる前にSaveメソッドで上書き保存をしている点です。他の部分は上のコードと違いはありません。

例として、「なんか更新処理」という関数を用意しています。この関数は一番左のシートのC10セルに「aaaa」を入力します。この部分を、個別の処理に書き換えることで、複数のブックに対して同じ処理を行うことができます

Sub BooksLoopUpdate()
    On Error GoTo ERR_LABEL
    
    Dim r   As Range                    '// セル(ループ中に1セルずつ下にずれる)
    Dim wb  As Workbook                 '// ブック
    
    '// ブックの一覧の基点セルを指定
    Set r = Range("A1")
    
    '// ブックを閉じる際の保存確認ダイアログを出さないようにする
    Application.DisplayAlerts = False
    
    '// シートのA列に書かれている全てのブックパスをループ
    Do
        '// 現在ループのセルにブックパスが書いていない場合はここでループを抜ける
        If r.Value = "" Then
            Exit Do
        End If
        
        '// ブックを開く。
        '// Filename:=r.Value:現在ループのセルに書いてあるブックパスを開く。
        '// IgnoreReadOnlyRecommended:=True:読み取り専用推奨ダイアログを非表示にする
        Set wb = Workbooks.Open(Filename:=r.Value, IgnoreReadOnlyRecommended:=True)
        
        Call なんか更新処理(wb)
        
        '// 上書き保存
        Call wb.Save
        
        '// ブックを閉じる
        Call wb.Close
        
        '// 現在ループのA列のセルの1つ下のセルを参照する
        Set r = r.Offset(1, 0)
    Loop
    
    Application.DisplayAlerts = True
    
ERR_LABEL:
    If (Err.Number <> 0) Then
        '// エラーが発生したブックパスとエラー内容を出力
        Debug.Print r.Value & " " & Err.Number & " " & Err.Description
    End If
End Sub

Sub なんか更新処理(wb As Workbook)
    wb.Worksheets(1).Range("C10").Value = "aaaa"
End Sub

]]>
VBAで新規ブックにシートをコピーする https://vbabeginner.net/copy-sheet-to-new-workbook/ Thu, 03 Nov 2022 17:50:23 +0000 https://vbabeginner.net/?p=6531 シートを新規ブックにコピーする手順

Excel上でシートを新規ブックにコピーする場合、シートを右クリックして「移動またはコピー」ダイアログで、「新しいブック」を選択して、「コピーを作成する」にチェックしてOKを押せば、新規ブックにシートがコピーされた状態で作成されます。

これをVBAで実施する場合には、「新規ブックの作成」と「作成した新規ブックへのシートのコピー」の2つの処理が必要です。

VBAでブックの新規作成を行う(Workbooks.Add)
VBAでシートのコピーを行う(Worksheet.Copy)

それぞれの詳細については上記に書いていますが、以下では「新規ブックの作成」と「新規ブックへのシートのコピー」の2つの処理を合わせて書く場合はどう書いたらについて順を追って説明します。

新規ブックの操作はWorkbookオブジェクトを利用する

新規ブックの作成は「Workbooks.Add」メソッドで行います。

「Workbooks.Add」メソッドは、戻り値として作成した新規ブックのWorkbookオブジェクトが返ります。

新規ブックに対する操作を行う場合は、以下のように「Workbooks.Add」メソッドの戻り値を取得しておく必要があります。

Sub WorkbookAdd()
    Dim wbNew   As Workbook         '// 新規ブック
    
    '// 新規ブックの作成
    Set wbNew = Workbooks.Add
End Sub

アクティブブックのシートを新規ブックにコピーする

上記のように、作成した新規ブックのWorkbookオブジェクトを保持したあと、他のブックからシートをコピーするには「Workbook.Worksheets.Copy」メソッドを使います。

「Workbook.Worksheets.Copy」メソッドはWorksheetsオブジェクトを指定しており、なんらかのブック(Workbook)のシートであることを指定する必要があります。

以下はマクロを実行したときのアクティブブックの一番左のシートを、新規ブックにコピーする場合のコードです。

Sub CopySheetToNewBook()
    Dim wbActive    As Workbook     '// アクティブブック
    
    '// アクティブブックをWorkbookオブジェクトにセット
    Set wbActive = ActiveWorkbook
    
    Dim wbNew   As Workbook         '// 新規ブック
    
    '// 新規ブックの作成
    Set wbNew = Workbooks.Add
    
    '// アクティブブックの一番左のシートを、新規ブックの一番右のシートとしてコピー
    Call wbActive.Worksheets(1).Copy(After:=wbNew.Worksheets(wbNew.Worksheets.Count))
    
    '// シート名を指定したい場合
    'Call wbActive.Worksheets("Sheet1").Copy(After:=wbNew.Worksheets(wbNew.Worksheets.Count))
    '// 一番右のシートをコピーしたい場合
    'Call wbActive.Worksheets(wbActive.Worksheets.Count).Copy(After:=wbNew.Worksheets(wbNew.Worksheets.Count))
End Sub

アクティブブックのコピーするシートを名前で指定したい場合は「Call wbActive.Worksheets(1).Copy」の部分を「Call wbActive.Worksheets(“Sheet1”).Copy」のように””でシート名を指定します。1と書くと一番左のシートで、wbActive.Worksheets.Countと書くと一番右のシートを指定できます。

上のコードではWorkbookオブジェクトを2つ用意しています。1つはコピー元のアクティブブック用で、もう1つが新規ブック用です。新規ブック用は先のサンプルコードと同じです。

シートのコピーは、「どのブックからどのブックへコピーするのか?」という点が大事になってきます。

そのため、まずコピー元のアクティブブックのWorkbookオブジェクトを保持しています。

そして、新規ブックを作成し、保持しておいたアクティブブックのシートを新規ブックにコピーしています。

Copyメソッドの引数にAfterを指定していますが、これは、Afterで指定したシートの右側にコピーする、という意味になります。Before:=で指定すれば左側になります。

引数の設定方法などは「VBAでシートのコピーを行う(Worksheet.Copy)」に詳しく書いています。

アクティブブックのシートをコピーする場合の注意点

アクティブブックのシートをコピーする場合の注意点が1つあります。

上記コードでは、まずアクティブブックのWorkbookオブジェクトを取得し、そのあとに新規ブックの作成(Workbook.Add)を行っていますが、この順序であることが大事になってきます。

Workbooks.Addメソッドで新規ブックを作成すると、作成した新規ブックがアクティブになります。この時点で元々アクティブだったブックがアクティブブックではなくなります

そのため、コピー元のブックがアクティブブックであることを前提とするようなコードを書く場合には、新規ブックを作成する前にコピー元ブックのWorkbookオブジェクトを取得しておく必要があります。

後述しますが、アクティブブックではなくブックのファイル名でもコピー元ブックを指定することは可能ですので、この問題はアクティブブックをコピー元にする場合のみ考慮する内容です。

開いている既存ブックのシートを新規ブックにコピーする

上のコードはアクティブブックのシートをコピーする場合ですが、開いているブックの名前を指定することも可能です。

Workbooks(“開いているブック名”)」で指定します。

Sub CopySheetToNewBook2()
    Dim wb      As Workbook         '// コピー元ブック
    
    '// コピー元ブックをWorkbookオブジェクトにセット
    Set wb = Workbooks("abc.xlsx")
    
    Dim wbNew   As Workbook         '// 新規ブック
    
    '// 新規ブックの作成
    Set wbNew = Workbooks.Add
    
    '// コピー元ブックの一番左のシートを、新規ブックの一番右のシートとしてコピー
    Call wb.Worksheets(1).Copy(After:=wbNew.Worksheets(wbNew.Worksheets.Count))
End Sub

この書き方は開いているブックであることが前提です。開いていない場合はエラーになります。

開いていないブックのシートを新規ブックにコピーする

開いていないブックのシートをコピーする場合は、一度そのブックを開く必要があります。そして処理が終わったらブックを閉じます。

以下はブックパスを指定してWorkbooks.Openメソッドを使ってブックを開き、その戻り値として開いたブックのWorkbookオブジェクトを取得しています。あとは上のサンプルコードと同じです。

新規ブックに自動生成されるSheet1シートはいらないので削除する処理も追加しています。

Sub CopySheetToNewBook3()
    Dim wb          As Workbook     '// コピー元ブック
    Dim sFilePath   As String       '// ブックのファイルパス
    
    sFilePath = "D:\test\abc.xlsx"
    
    '// コピー元ブックを開き、Workbookオブジェクトにセット
    Set wb = Workbooks.Open(sFilePath)
    
    Dim wbNew   As Workbook         '// 新規ブック
    
    '// 新規ブックの作成
    Set wbNew = Workbooks.Add
    
    '// コピー元ブックの一番左のシートを、新規ブックの一番右のシートとしてコピー
    Call wb.Worksheets(1).Copy(After:=wbNew.Worksheets(wbNew.Worksheets.Count))
    
    '// Sheet1シートを削除
    Application.DisplayAlerts = False
    Call wbNew.Worksheets("Sheet1").Delete
    Application.DisplayAlerts = True
    
    '// 開いたブックを閉じる
    Call wb.Close
End Sub

新規ブックからSheet1を削除

新規ブックを作成すると、”Sheet1″シートが作成されます。

作成されるシートの数はExcelの設定によって異なりますが、Microsoft365の標準設定では”Sheet1″シートが作成されます。古いExcelの場合は3つシート作成されます。

他のブックから新規ブックにシートをコピーした場合、”Sheet1″シートは不要なことがほとんどだと思いますので、削除したい場合には上のサンプルのように、”Sheet1″シートの削除を行います。

なお、単純にWorksheets.Deleteメソッドを実行すると、Excel上でシートを削除するときと同じように「削除しますか?」というダイアログが出ますが、VBAで自動化する場合は邪魔なのでApplication.DisplayAlerts = Falseで表示しないようにしています。

'// Sheet1シートを削除
    Application.DisplayAlerts = False
    Call wbNew.Worksheets("Sheet1").Delete
    Application.DisplayAlerts = True

]]>
ブックを開いた時に実行するマクロの活用方法(Workbook_Open) https://vbabeginner.net/how-to-use-workbook-open/ Sun, 06 Feb 2022 06:58:55 +0000 https://vbabeginner.net/?p=6445 ブックを開いたときにマクロを実行するには

ブックを開いたときにマクロを実行するには、ThisWorkbookのWorkbook_Open関数を使います。

ThisWorkbookを開き、オブジェクトボックス(コードウィンドウの左上のコンボボックス)でWorkbookを選ぶと、自動でWorkbook_Open関数が表示されます。

Private Sub Workbook_Open()
    // ここに実行したい処理を書く
End Sub

あとは、ブックを開く度にWorkbook_Open関数に書かれている処理が実行されます。これで終わりです。ですが、本当の問題はここからです。

自動実行の実装方法は単純です。しかし大事なのは「その処理は本当に自動実行しなければならないのか?」、自動実行が必要なのであれば「どうやって自動実行するのか?」という点です。

Workbook_Open関数は自分でブックを開かないときに使う

問題なのは、Workbook_Open関数があるブックをどうやって開くかです。エクスプローラからダブルクリックで開くと実は問題があります

Workbook_Open関数はブックを開いたときに自動で実行してくれるという便利な点がありますが、その反面、実行してほしくないときでも必ず実行されてしまうという制約も当然含んでいます。

やってみると分かりますが、ブックを開くたびに毎度毎度、自動で実行されるというのは結構ストレスに感じます。そして結局「あー、うるさいなー・・・」となり、結局ボタンなどを用意して自分のタイミングで実行する方が使い勝手がいいことに気が付きます。

これが、あまり用途を考えずにWorkbook_Open関数を使った場合によくある失敗です。「ブックを開いたときに自動実行する」こと自体が最初は便利に感じても、しばらくすると、うるさく感じるのです。

結局、「エクスプローラでブックを開いたときに自動でちょっとやってもらう」というのは、おせっかいが過ぎたり、処理の待ち時間が発生したりと、多くの場合でイヤになって止めることになります。このようなエクスプローラからブックを開くWorkbook_Open関数の使い方は良い使い方ではない、ということです。

では、どのような使い方がよいのかというと、人の目に触れない実行方法がWorkbook_Open関数のいい使い方です。「自分が知らない間に勝手にブックが開いて、自動で何かの処理をやってくれる」状態にすることです。そして、一連の処理が終わったらブックは閉じておきます。完全な自動実行です。

例えば、PCを使っていない時間帯に勝手に処理をしてもらう、とかです。これであればストレスを感じることもありません。

自動実行させたいときだけ動く条件を用意する

先に書いた通り、「常に自動実行」するのは自動実行自体を邪魔に感じるという弊害があります。

そこで対応方法として、Workbook_Open関数が呼び出されても「ある特定の条件にある場合」にのみ自動実行するようにしておけば、エクスプローラーで開く場合は自動実行されずにストレスを感じなくて済むようになります。

ではどうしたらいいかというと、バッチファイルなど他のアプリケーションで「今から自動実行します」ということが分かる状態にしておき、それからブックを開いた場合にのみ、Workbook_Open関数の内部処理を実行するような方法が挙げられます。

ここではタスクスケジューラとバッチファイルを使った具体的な方法を紹介します。

処理順序と考え方

タスクスケジューラとバッチファイルを使う場合の処理の流れは以下のようになります。

  1. タスクスケジューラで指定した日時にバッチファイルを実行する。
  2. バッチファイルで自動実行用のテキストファイルを作成する。
  3. バッチファイルでマクロブックを開く。
  4. マクロブックのWorkbook_Open関数が実行される。自動実行用のテキストファイルがあるため、自動実行したい処理を実施する。
  5. 自動実行したい処理が終わったらブックを自ら閉じる。
  6. バッチファイルで自動実行用のテキストファイルを削除する。

バッチファイルからマクロブックを呼び出す前に「workbook-open.txt」というファイルをバッチファイルのコマンドで作成しておき、Workbook_Open関数の先頭で「workbook-open.txt」が無い場合は自動実行しない、という処理を入れておきます。そして、バッチファイルの最後に「workbook-open.txt」を削除します。このようにすると、エクスプローラーからマクロブックを開いた場合は「workbook-open.txt」が無いため自動実行が行われません。

テキストファイルの有無の条件を「テキストファイルが無い場合にのみ自動実行する」としてしまうと、テキストファイルのことを忘れたときにエクスプローラからブックを開いて自動実行が行われ、なにこれ?ということに陥る恐れがあります。自動実行はあくまでも「ある条件の場合にのみ実行する」としておいた方が安全です。

以下の例で使うファイルは3つあります。それぞれファイルの名前はなんでもいいのですが、ここではマクロブックのabc.xlsm、マクロブックを開くバッチファイルのauto.bat、自動実行判定用テキストファイルのworkbook-open.txtです。

マクロブックのabc.xlsm、マクロブックを開くバッチファイルのauto.batはどちらも同じフォルダにあるものとします。自動実行判定用テキストファイルのworkbook-open.txtはバッチファイル実行中の間だけ同じフォルダに存在します。

1. マクロブックを呼び出すバッチファイル

まずマクロブックを呼び出すバッチファイルを作成します。

バッチファイルに以下のように書きます。バッチファイルのファイル名はなんでもいいのですが、ここではauto.batとします。

set CUR_DIR=%~dp0
type null > %CUR_DIR%workbook-open.txt
%CUR_DIR%abc.xlsm
del %CUR_DIR%workbook-open.txt

1行目は、変数CUR_DIRにバッチファイルがあるディレクトリのパスを示す「%~dp0」を設定します。バッチファイルがC:\abc\auto.batにあるとすれば、「C:\abc\」が変数CUR_DIRにセットされます。

2行目は、自動実行判定用のテキストファイルを作成します。最後に削除します。このファイルがある間はマクロブックのWorkbook_Open関数内で自動実行を行うような処理を入れておくためです。

3行目は、マクロブックを開きます。バッチファイルでは「C:\abc.xlsm」のようにブックのフルパスを書けば開きます。

4行目は、自動実行判定用のテキストファイルを削除します。残しておくと次にマクロブックを開いたときに自動実行と判定されるため削除します。

2. Workbook_Open関数の内容

マクロブックのThisWorkbookには以下のようにWorkbook_Open関数を書きます。

バッチファイルで作成するテキストファイルが無い場合はExit Subで処理を抜けるようにし、ある場合は自動実行したい処理を行います。

処理が終わったあとはブックを自ら閉じます。閉じる際に「保存しますか?」ダイアログを回避するためにSaveChanges:=Falseを指定します。

Private Sub Workbook_Open()
    '// 自動実行用ファイルが無い場合
    If Dir(ThisWorkbook.Path & "\workbook-open.txt") = "" Then
        '// この場合はエクスプローラから開いているためブックは閉じない
        
        
        '// 自動実行せずに抜ける
        Exit Sub
    End If
    
    '// 自動実行したい処理をここに書く
    Debug.Print "abc"
    
    '// 自動実行時は処理終了後にブックを閉じる。保存しますか?ダイアログはOFF
    ThisWorkbook.Close SaveChanges:=False
End Sub

3. タイムスケジューラの設定

最後にタスクスケジューラの設定をします。ここでは指定日時になったらバッチファイルを実行するタスクを作成します。

コントロールパネル → 管理ツール → タスクスケジューラ を開きます。タスクスケジューラの操作メニューから「タスクの作成」を選択し、全般タブの名前を入力します。

トリガータブの新規ボタンで実行したい日時を指定します。

操作タブの新規ボタンでプログラム/スクリプトにバッチファイルのフルパスを指定します。

これで、指定した日時にバッチファイルが実行され、さらにバッチファイルからマクロブックが開かれ、Workbook_Open関数が実行されるようになります。

自動実行させたくない場合はタスクスケジューラに作成したタスクを無効にします。

Auto_Open関数は使わなくてよい

ブックを開いたときにマクロを実行する別の方法として、標準モジュールに書くAuto_Open関数もあります。

しかしAuto_Open関数は使う必要ありません

Auto_Open関数はVBAがExcelに実装された1990年代に使われていたもので、その当時はWorkbook_Open関数がありませんでした。互換性のために残されています。

使うと問題が起こるわけではありませんが、Workbook_Open関数でやりたいことは実現できるため使う必要はないでしょう。

]]>
VBAでブックを読み取り専用を推奨するように設定する https://vbabeginner.net/readonlyrecommended-true/ Sun, 09 Jan 2022 15:54:52 +0000 https://vbabeginner.net/?p=6430 読み取り専用を推奨するダイアログ

ブックを開く際に以下のようなダイアログを見たことがあるかもしれません。

これはブックを保存する際に「読み取り専用を推奨する」ように設定されている場合に表示され、無用にブックを更新されることを防ぎたい場合によく使われる設定です。

なお、Excel上で「読み取り専用を推奨する」手順は以下の通りです。

  1. ブックを開き、「ファイル」メニュー→名前を付けて保存、を選ぶ。
  2. ブック名を入力するテキストボックスの下にある「その他のオプション」を押す。(保存先フォルダでも可)
  3. 「名前を付けて保存」ダイアログ → 右下の「ツール」 → 「全般オプション」を選ぶ。
  4. 「全般オプション」ダイアログで「読み取り専用を推奨する」にチェックを付けてOKボタンを押す。

この設定は自動で設定されることはありません。必要と判断した場合に設定しなければなりません。

この手順をVBAで行う方法を以下で紹介します。

「読み取り専用を推奨する」の用途

「読み取り専用を推奨する」にチェックを付ける用途として考えられるのは2つあります。1つは誤って更新したくない場合、もう1つは複数の人が開くブックの場合です。

Excelはただ開いただけなのに、閉じようとすると「保存しますか?」という内容のダイアログで聞かれることがあります。ここで保存してしまうと更新日時が変わります。これが嫌な場合には効果があります。

また、複数の人が同じブックを扱う場合に、見たいだけの人、更新したい人、と、用途が異なる人が複数いる場合に、誰かが普通に開いてしまうと他の人は更新が出来なくなります。読み取り専用で開いておけば誤って更新することがなくなるのと、他の人の更新を妨害することもなくなります。

例えば5人が同じブックを見ようとしている場合に、4人が読み取り専用で開いていても、残る1人が「読み取り専用で開きますか?」のダイアログで「いいえ」を押せば、更新は可能です。

EXCEL.EXEには/rを付けて起動すれば読み取り専用で開くことが出来るスイッチがありますが、なかなかマニアックな機能なため、複数の人が普通にExcelを使う分にはそのような注意をもってもらうのは大変でしょう。

なお、/rでの読み取り専用の方法については「VBAでセルやハイパーリンクのブックを読み取り専用で開く」をご参照ください。

VBAで「読み取り専用を推奨する」にチェックを付ける

VBAでブックの読み取り専用を推奨をするように設定するには、Workbookオブジェクトの名前を付けて保存を行うSaveAsメソッドのReadOnlyRecommended引数にTrueを設定します。

SaveAsメソッドの詳細については「VBAでブックに名前を付けて保存する(SaveAs)」をご参照ください。

以下のコードは指定したブックを読み取り専用で推奨するように設定するサンプルです。

Sub SaveAsReadOnlyRecommendedTest()
    Dim wb          As Workbook     '// ブックを指すWorkbookオブジェクト
    Dim sBookPath   As String       '// ブックのファイルパス
    
    '// 上書き確認ダイアログを非表示にする
    Application.DisplayAlerts = False
    
    sBookPath = "V:\aaa\Book1.xlsx"
    
    '// 対象ブックを開く
    '// ReadOnly:=False(読み取り専用ではなく更新可能状態で開く)
    '// IgnoreReadOnlyRecommended:=True(既に読み取り専用を推奨が設定されていてもそのダイアログを表示しない)
    Set wb = Workbooks.Open(Filename:=sBookPath, ReadOnly:=False, IgnoreReadOnlyRecommended:=True)
    
    '// 読み取り専用を推奨する設定を行い、保存する
    Call wb.SaveAs(ReadOnlyRecommended:=True)
    
    '// ブックを閉じる
    Call wb.Close
    
    Application.DisplayAlerts = True
End Sub

コード説明

読み取り専用を推奨する場合の処理はSaveAsメソッドの部分ですが、実際に実行する場合には2つの注意点があります。

まず1つは、同じブック名で保存することになるため、「既にファイルが存在しています。上書きしますか?」というダイアログが表示されてしまう点です。これを防ぐために「Application.DisplayAlerts = False」で確認ダイアログを出さないようにしています。

確認ダイアログを非表示にする方法の詳細については「VBAでExcelブックを開く方法(Workbooks.Open)」をご参照ください。

もう1つは、既に「読み取り専用を推奨する」設定がされている場合に、ブックを開く際のOpenメソッドを実行すると、設定した通りに「読み取り専用を推奨する」ことを確認するダイアログが表示されてしまう点です。これも1つ目と同様に表示させないようにOpenメソッドの「IgnoreReadOnlyRecommended」引数にTrueを設定しています。

使い方

8行目のsBookPathの設定で、「読み取り専用を推奨する」にチェックを付けたいブックのフルパスを指定します。

あとは関数自体を実行すると、そのブックの「読み取り専用を推奨する」にチェックが付いた状態で保存されます。

次回からそのブックを開いた際には読み取り専用を推奨するかどうかの確認ダイアログが表示されるようになります。

]]>
不要な名前の定義をVBAで一括削除する https://vbabeginner.net/delete-unnecessary-name-define/ Tue, 19 Oct 2021 15:57:38 +0000 https://vbabeginner.net/?p=6314 名前の定義が邪魔

セルには「A1」などの座標がありますが、セル範囲に名前を付けて座標の別名として扱うことが出来るようになります。これが「名前の定義」です。

うまく使えば便利な機能ですが、複数の人が扱うブックに名前の定義を設定するのは避けた方がよいでしょう。

複数の人が扱うブックであれば通常はファイルサーバに置いてあると思いますが、ファイルサーバのどこかの参照先を指して名前の定義をしていると、その参照先が月日が経つことで存在しなくなることが多々あります。

名前の定義の値が「#REF!」になっていて参照先が存在しない場合や、ファイルパスが見たことも内容な場所を示していたりとか。年月を経てこの状況になっているため、これらの解決手段はほとんどの場合まず無いと言っていいでしょう。

そうなるともう悲惨です。

シートをコピーする度に「既にある名前が含まれています」エラーダイアログが多発し、エラーの数だけOKボタンを連打する羽目になります。イライラMAXです。

これが嫌いなので私は名前の定義は使いません。自分だけしか使わないブックであってもです。

以下ではこのような不要な名前の定義を一括削除するマクロを紹介します。

アクティブブックの名前の定義を一括削除するコード

以下の関数を実行するとアクティブブックに定義されている名前の定義を一括削除します

一括削除しますが、「Print_Area」と「Print_Titles」の2つは削除しないようにしています

Excelには自動で名前の定義を設定するものが2つあります。それが印刷範囲を示す「Print_Area」と、印刷タイトルを示す「Print_Titles」です。

この2つは定義自体は自動設定されるため、参照先が不正になることはまずありません。また、印刷範囲は個別に調整しているがよくあるため、削除してしまうと印刷範囲の設定が消えることになります。

そのため、この2つは削除はしないようにしています。

Sub DeleteNameDefine()
    On Error Resume Next
    
    Dim n       As Name         '// 名前の定義(Nameオブジェクト)
    Dim ar()    As String       '// 削除した名前の定義の配列
    Dim s       As String       '// MsgBox出力文字列
    Dim sName   As Variant      '// Nameプロパティ値
    Dim er()    As String       '// エラーで削除できなかった名前の定義の配列
    
    '// 配列初期化
    ReDim ar(0)
    ReDim er(0)
    
    '// 全ての名前の定義をループ
    For Each n In ActiveWorkbook.Names
        '// 印刷範囲と印刷タイトルの場合は処理対象外
        If InStr(1, n.Name, "Print_Area") > 0 Or InStr(1, n.Name, "Print_Titles") > 0 Then
            GoTo CONTINUE
        End If
        
        '// 名前の定義の名称を保持(Nameプロパティ取得)
        sName = n.Name
        
        '// 名前の定義を削除
        Call n.Delete
        
        '// エラー分
        If Err.Number <> 0 Then
            ReDim Preserve er(UBound(er) + 1)
            er(UBound(er) - 1) = sName
        '// 正常に削除した分
        Else
            ReDim Preserve ar(UBound(ar) + 1)
            ar(UBound(ar) - 1) = sName
        End If
        
        Err.Clear
CONTINUE:
    Next
    
    If ar(0) <> "" Then
        ReDim Preserve ar(UBound(ar) - 1)
    End If
    If er(0) <> "" Then
        ReDim Preserve er(UBound(er) - 1)
    End If
    
    '// エラー分を列挙
    For Each sName In er
        s = s & sName & vbCr
        Debug.Print sName
    Next
    
    Call MsgBox(s, vbOKOnly, "削除した名前の定義")
End Sub

コード説明

大体コメントに書いていますが、少し補足します。

コード内ではエラー処理をしています。その理由は、名前の定義の削除を行うDeleteメソッドでは消せない定義があった場合の措置です。

名前の定義の「名前」に制御文字が含まれているとDeleteメソッドがエラーになります。この場合はVBAでは消せないため、手で「名前の管理」ダイアログ(リボン→数式→定義された名前→名前の管理)から対象行を選択して削除する必要があります。

そのため、そのようなエラーが発生した場合はイミディエイトウィンドウとメッセージボックスでその名前を表示して、手で消すことを促すようにしています。

]]>
開いたり保存したブックの履歴を100%記録する https://vbabeginner.net/completely-record-history-open-saved-workbooks/ Thu, 03 Jun 2021 14:57:53 +0000 https://vbabeginner.net/?p=6157 あのブック、どこにあったっけ・・・

仕事でよくあるのが、「この前見た資料、どこに置いてあったっけ・・・」とか「どこに保存したっけ?」という状況です。

「最近使ったアイテム」に残っておらず、ファイルサーバーだったか、自分のPCだったか、ダウンロードした奴だったか、というのも覚えておらず、作った人も分からず、手帳にメモも書いておらず、当時聞いた人に「前に言いましたよね?」なんて言葉も聞きたくない。

でも探さないといけない。時間がない。探す時間が無駄すぎる。つらい。うーん、分かります。その状況はイヤです。

VBAで解決しましょう。

Excelのブックを開いた履歴は50個まで

Excelでブックを開く場合に、「最近使ったアイテム」の一覧から、過去に開いたブックを探して開くことが出来ます。便利な機能ですが、初期設定では50個までしか履歴管理されません。数を増やすにしても無限ではありません。

また、「最近使ったアイテム」の一覧に表示されるのは「開いたブック」が対象となりますが、あとから自分が保存したブックを特定したいときには使えません。

そこで、以下では、開いたブックの履歴と、保存したブックの履歴をテキストファイルに出力する方法を紹介します。

コードを書く場所と処理の説明

以下のコードはPERSONAL.XLSBのThisWorkbookに書いてください。ThisWorkbookに何も書いてないのであれば、まるごとコピペでOKです。このマクロはExcel起動時に存在していないと動作しないため、ThisWorkbookに書いて保存したら一度Excelのブックを全て閉じてください。これは最初の1度だけです。それ以降は次にブックを開いたときからPERSONAL.XLSBに書いたコードが動作します。

ブックを開いたり、保存したりすると、「Excelのオプション→保存→既定のローカルファイルの保存場所」で設定されているフォルダ(通常は「ドキュメント」フォルダ)に「Excel-History.txt」というファイルを作成し、日時、開いた(Open)もしくは保存(Save)、ブックパス、を書き込みます。

Excel-History.txtにはこんな感じで書き込まれます。

2021/06/03 02:18:45 [Open] V:\aaa\vba1.xlsm
2021/06/03 02:23:46 [Open] V:\test\bbb\test\手順書.xlsx
2021/06/03 02:28:03 [Save] V:\aaa\vba1.xlsm
2021/06/03 02:37:26 [Open] \\nwstrage\main\doc\資料\資料の書き方.xlsx

日時(yyyy/mm/dd hh:mm:ss)と、開いたor保存の[Open]または[Save]、そして、そのブックのフルパスが書き込まれます。ブックがファイルサーバなど\\で始まるパスにある場合でも問題ありません。

なお、Openステートメントを使っているためShift-JISで書き込まれており、テキストエディタでUTF-8で開いたりすると文字化けを起こします。

Excel-History.txtには単純に追加書き込みをしているだけのため、ブックを開いたり保存したりする度に書き込まれていきます。ただ、それだとファイルサイズが増え続けるため、100,000バイト(約100KB)を超えたらExcel-History.txtのファイル名に日時を付与してバックアップ(ファイル名変更)するようにしています。

100KBは、1日にブックを開いたり保存したりを100回行ったとすると、大体ですが半月ぐらいで達するぐらいの分量です。1年掛かってもバックアップファイル含めて2MB行かないぐらいですので、完全放置でも容量不足の問題はまず起きないでしょう。

コード

Option Explicit

'// Excelのイベント検知
Dim WithEvents x    As Application

'// PERSONAL.XLSBが開いたとき
Private Sub Workbook_Open()
    '// Excelアプリケーションのイベントを検知する
    Set x = Application
End Sub

'// ブックが開いた場合
Private Sub x_WorkbookOpen(ByVal Wb As Workbook)
    Call OutputHistory(Wb, "Open")
End Sub

'// ブックを保存後
Private Sub x_WorkbookAfterSave(ByVal Wb As Workbook, ByVal Success As Boolean)
    '// 保存失敗時
    If Success = False Then
        Exit Sub
    End If
    
    Call OutputHistory(Wb, "Save")
End Sub

'// 履歴書き込み
Private Sub OutputHistory(ByVal Wb As Workbook, a_sType As String)
    Dim sNow    As String       '// タイムスタンプ
    Dim sPath   As String       '// ファイルパス
    Dim n       As Integer      '// ファイル番号
    
    sPath = Application.DefaultFilePath & "\Excel-History.txt"
    
    '// 履歴ファイルが存在する場合
    If Dir(sPath) <> "" Then
        '// 履歴ファイル名が指定サイズを超過している場合
        If FileLen(sPath) > 100000 Then
            '// 履歴ファイル名をバックアップ名に変更
            Name sPath As sPath & Format(Now, "yyyymmdd-hhmmss")
        End If
    End If

    '// 現在日時を取得
    sNow = Format(Now, "yyyy/mm/dd hh:mm:ss")
    
    '// ファイル番号取得
    n = FreeFile
    
    '// 履歴ファイルを追加書き込みモードで開く
    Open sPath For Append As #n
    
    '// ブックのパスを書き込み
    Print #n, sNow & " [" & a_sType & "] " & Wb.FullName
    
    '// 履歴ファイルを閉じる
    Close #n
End Sub

コード説明

このコードでは少し特殊なことを行っています。それはWithEvents修飾子です。WithEvents修飾子を使って変数を定義すると、型として指定したオブジェクトのイベントを検知できるようにしています。ここでは「Application」を指定しているためExcel自体を指すことになります。

通常、VBAでは他のブックのイベントを検知することは出来ません。例えばa.xlsxでセルの値が変わったことを検知するChangeイベントはa.xlsxで取得するのが普通です。

Excelは起動時に「C:\Users\[ユーザ名]\AppData\Roaming\Microsoft\Excel\XLSTART」」フォルダにあるブックを開きます。PERSONAL.XLSBもこのフォルダに配置されるため、個人用マクロブックとしてExcel起動時に開かれます。

XLSTARTフォルダに他のブックを意図的に置かない限り、PERSONAL.XLSBは唯一のExcel起動時に開かれるブックのため、PERSONAL.XLSBにWithEvents修飾子を使ってExcelのイベントを検知できるようにすることで他のブックの挙動を検知できる仕組みを用意しています。

]]>
ブックにマクロが含まれているか確認する https://vbabeginner.net/check-if-the-workbook-contains-macros/ Mon, 31 May 2021 15:35:45 +0000 https://vbabeginner.net/?p=6155 ブックにマクロが含まれているか確認するには

ブックにマクロが含まれているかを確認するには、対象のブックのWorkbookオブジェクトのHasVBProjectプロパティを使用します。

マクロを含んでいればTrue、含んでいなければFalseが返されます。

Excel 2007以前はマクロの有無に関わらずブックの拡張子は「.xls」でしたが、Excel 2007からリボンが採用され、多数の機能が拡張されることになり、それに伴いマクロ無しの通常ブックが「.xlsx」、マクロ有りのブックが「.xlsm」と分かれました。HasVBProjectプロパティもそのときに追加された機能の1つです。そのため、Excel 2003以前のバージョンでは動作しません。

HasVBProjectプロパティの用途として、Excel2007以前の「.xls」で書かれたマクロが含まれているブックを、Excel 2007用の「.xlsm」に変換する際の判定に利用する方法があります。

その方法の詳細については「xls形式ファイルをxlsxとxlsm形式に一括変換する」をご参照ください。

構文

Property Workbook.HasVBProject As Boolean

親オブジェクト 親オブジェクトとして確認対象ブックのWorkbookオブジェクトを指定します。
戻り値 マクロを含んでいればTrue、含んでいなければFalseが返されます。

コード

以下はアクティブブックにマクロが含まれているかを確認するサンプルコードです。

マクロを含んでいればTrue、含んでいなければFalseがイミディエイトウィンドウに出力されます。

Sub HasVBProjectTest()
    Dim wb  As Workbook
    
    Set wb = ActiveWorkbook
    
    Debug.Print wb.HasVBProject
End Sub

]]>
VBAでブックに名前を付けて保存する(SaveAs) https://vbabeginner.net/save-the-workbook-as/ Sat, 29 May 2021 05:41:17 +0000 https://vbabeginner.net/?p=5564 ブックに名前を付けて保存する

新規作成したブックや、既存ブックに別の名前を付けて保存するには、WorkbookオブジェクトのSaveAsメソッドを利用します。

SaveAsメソッドで保存すると、ブックの内容が保存されるだけでなく、そのブックの更新日時がSaveAsメソッド実行時の日時が設定されるなど、Excelで名前を付けて保存したときと同様の動作になります。

なお、上書き保存を行いたい場合は「VBAでブックを上書き保存する(Save)」をご参照ください。

同名のブックが既にある場合

保存先のフォルダに同じ名前のブックがある場合は上書き確認ダイアログが表示されます。また、そのブックが開いている場合は上書きできないためエラーになります。

作成したブックをどのように扱うかは、状況によって変わります。最優先で保存しなければならない場合もあれば、既存ブックを残さないといけない場合など、何を優先していくかを決めておく必要があります。それらの方法については以下のリンクをご参照ください。

構文

Sub Workbook.SaveAs([Filename], [FileFormat], [Password], [WriteResPassword], [ReadOnlyRecommended], [CreateBackup], [AccessMode As XlSaveAsAccessMode = xlNoChange], [ConflictResolution], [AddToMru], [TextCodepage], [TextVisualLayout], [Local], [WorkIdentity])

引数がたくさんありますが、通常は1番目のFilename(ブックのフルパスを推奨)だけ指定すればOKです。

親オブジェクト 保存対象ブックのWorkbookオブジェクトを指定します。
Filename
(省略可だがフルパス推奨
ブックに付ける名前を指定します。フルパスの指定を推奨します。ブック名を変えずに保存先フォルダを変更したい場合は変更先のパスと元のブック名でのフルパスを指定します。

未設定時はカレントフォルダに元のファイル名で保存されますが、その場合はそもそもSaveAsメソッドを使う意味(名前を付けて保存する意味)が無いため、通常は指定します。新規ブックの場合に未設定の場合はカレントフォルダに「Book1.xlsx」のような名前で保存されます。

FileFormat
(省略可)
xlsxやxlsmなどのファイル形式をXlFileFormat列挙型の定数で指定します。XlFileFormat列挙型は50以上の定義がありますが、実際に使う定義はxlsxのxlOpenXMLWorkbookかxlsmのxlOpenXMLWorkbookMacroEnabledがほとんどです。

XlFileFormat列挙型(よく使うもののみ記載)

定数 内容
xlWorkbookDefault(省略時) 51 既定ブック(通常は.xlsx)
xlOpenXMLWorkbook 51 Excelブック(.xlsx)
xlOpenXMLWorkbookMacroEnabled 52 マクロブック(.xlsm)
Password
(省略可)
保護パスワードを15文字以内で指定します。大文字と小文字は区別されます。
WriteResPassword
(省略可)
書き込みパスワードを指定します。書き込みパスワードが指定されている場合は、そのブックを開く際にパスワードの入力が要求されます。正しい書き込みパスワードを入力しなかった場合は読み取り専用でブックは開きます。設定済みの書き込みパスワードを解除する場合は空文字列を設定して保存します。
ReadOnlyRecommended
(省略可)
読み取り専用の推奨を設定する場合はTrueを指定します。省略時はFalseの扱いになります。
CreateBackup
(省略可)
バックアップファイルを作成する場合はTrueを指定します。省略時はFalseの扱いになります。
AccessMode
(省略可)
ファイルのアクセス方法をXlSaveAsAccessMode列挙型の定数で指定します。

XlSaveAsAccessMode列挙型

定数 内容
xlExclusive 3 排他モード
xlNoChange(省略時) 1 変更なし
xlShared 2 共有モード
ConflictResolution
(省略可)
共有ブックを開いている場合で、他者による変更が自分の変更と競合した場合に自分が開いた共有ブックへどのように反映させるかをXlSaveConflictResolution列挙型の定数で指定します。

XlSaveConflictResolution列挙型

定数 内容
xlLocalSessionChanges 2 自分の変更を反映する
xlOtherSessionChanges 3 「競合の解決」ダイアログを表示して選択を行うようにする
xlUserResolution(省略時) 1 他のユーザーの変更を反映する
AddToMru
(省略可)
最近使用したブックの一覧に追加する場合はTrueを指定します。省略時はFalseの扱いになります。
TextCodepage
(省略可)
使いません。設定しても無視されます。
TextVisualLayout
(省略可)
使いません。設定しても無視されます。
Local
(省略可)
Excelの言語設定に合わせた形式で保存する場合はTrueを指定します。VBAの言語設定に合わせる場合はFalseを指定します。省略時はFalseの扱いになります。
WorkIdentity
(省略可)
不明。

サンプルコード

コード1:既にあるブックを開いて別名で保存する

以下のコードは、既に存在するブックを開いて、別名で保存します。

ブックを開くにはWorkbooks.Openメソッドを使います。詳細は「VBAでExcelブックを開く方法(Workbooks.Open)」をご参照ください。

Sub WorkbookSaveAsTest()
    Dim wb      As Workbook     '// ワークブック
    
    '// ワークブックを開く
    Set wb = Workbooks.Open("V:\SaveAsTest\a.xlsx")
    
    '// 一番左のシートのA1セルを書き換える
    wb.Worksheets(1).Range("A1").Value = "abc"
    
    '// 保存する
    Call wb.SaveAs(Filename:="V:\SaveAsTest\b.xlsx")
    
    '// 閉じる
    Call wb.Close
End Sub

コード1:ブックを新規作成して名前を付けて保存する

以下のコードは、ブックを新規作成して名前を付けて保存します。

ブックの新規作成はAddメソッドを利用します。Addメソッドについての詳細は「VBAでブックの新規作成を行う(Workbooks.Add)」をご参照ください。

Sub NewWorkbookSaveAsTest()
    Dim wb          As Workbook     '// ワークブック
    
    '// ワークブックを新規作成する
    Set wb = Workbooks.Add
    
    '// 一番左のシートのA1セルを書き換える
    wb.Worksheets(1).Range("A1").Value = "abc"
    
    '// 保存する
    Call wb.SaveAs(Filename:="V:\SaveAsTest\c.xlsx")
    
    '// 保存先パスを出力
    Debug.Print wb.FullName
    
    '// 閉じる
    Call wb.Close
End Sub

]]>
VBAでブックを上書き保存する(Save) https://vbabeginner.net/overwrite-and-save-the-workbook/ Tue, 18 May 2021 15:25:25 +0000 https://vbabeginner.net/?p=5550 ブックの保存(上書き保存)

ブックを上書き保存するには、保存対象ブックのWorkbookオブジェクトのSaveメソッドを利用します。

Saveメソッドで保存すると、ブックの内容が保存されるだけでなく、そのブックの更新日時が保存時点の日時に更新されるなど、Excelで保存したときと同様の動作になります。

なお、上書き保存ではなく名前を付けて保存を行いたい場合は「VBAでブックに名前を付けて保存する(SaveAs)」をご参照ください。

Saveメソッドの特殊な動作

Saveメソッドを使った保存の場合、既存のブックを開いて変更を行って保存した場合はExcelで保存したときと同様にそのまま上書き保存されます。しかし、新規作成ブック(まだ保存したことがないブック)に対して保存を行う場合は、注意が必要です。

新規作成したブックを初めて保存する場合、通常のExcel操作の場合は保存ダイアログが表示され、保存先やブック名を入力して保存しますが、VBAでのSaveメソッドの場合は保存先ダイアログは表示されず、無条件にカレントフォルダに「Book1.xlsx」のような名前で保存されます。

Saveメソッドは単に保存するだけのため、保存先やブック名を指定することができません。ただそれでは困るため、新規作成するブックの場合は「名前を付けて保存」を行うSaveAsメソッドを使うことで保存先やブック名などを指定することが出来ます。

構文

Saveメソッドの構文は以下になります。

Sub Workbook.Save()

戻り値や引数はありません。

「上書き保存」の場合は、そのブックを示すWorkbookオブジェクトのSaveメソッドを実行すると保存されます。保存されるだけでブックは開いたままです。

サンプルコード

以下では、既に存在しているブックを開いて保存する場合と、新規作成したブックを保存する場合について紹介します。

コード1:既にあるブックを開いて保存する

以下のコードは、既に作成済みのブックを開いて上書き保存します。

ブックを開くにはWorkbooks.Openメソッドを使います。詳細は「VBAでExcelブックを開く方法(Workbooks.Open)」をご参照ください。

Sub WorkbookSaveTest()
    Dim wb          As Workbook     '// ワークブック
    
    '// ワークブックを開く
    Set wb = Workbooks.Open("V:\aaa\abc.xlsx")
    
    '// 一番左のシートのA1セルを書き換える
    wb.Worksheets(1).Range("A1").Value = "abc"
    
    '// 保存する(単純な上書き保存)
    Call wb.Save
    
    '// 閉じる
    Call wb.Close
End Sub

コード2:ブックを新規作成して保存する

以下のコードは、ブックを新規作成して上書き保存します。

ブックの新規作成はAddメソッドを利用します。Addメソッドについての詳細は「VBAでブックの新規作成を行う(Workbooks.Add)」をご参照ください。

新規作成ブックをSaveメソッドで保存するとカレントフォルダに「Book1.xlsx」のような名前で保存されるため、カレントフォルダが不明な場合に困るため、保存後に保存先のパスを出力するようにしています。

Sub NewWorkbookSaveTest()
    Dim wb          As Workbook     '// ワークブック
    
    '// ワークブックを新規作成(この時点では未保存)
    Set wb = Workbooks.Add
    
    '// 一番左のシートのA1セルを書き換える
    wb.Worksheets(1).Range("A1").Value = "abc"
    
    '// 保存する(カレントフォルダにBook1.xlsxなどの名前で保存)
    Call wb.Save
    
    '// 保存先パスを出力
    Debug.Print wb.FullName
    
    '// 閉じる
    Call wb.Close
End Sub

]]>