【vb.net】エクセルマクロファイル(.xlsm)のシートをコピーする

VB.NET

既存のエクセルファイル(.xlsm)のシートを同じブック内にコピーする方法です。

以下の設定がされていてもコピーされていることを確認しています。

  • ズーム設定
  • 文字フォント
  • 文字サイズ
  • 文字の色
  • セルの書式設定(#,##0;[赤]-#,##0)
  • セルの計算式
  • コマンドボタン
  • シート裏に書いたVBAソース
  • 標準モジュールに書いたVBAソース

動作確認環境

確認環境

  • VisualStudio2022
  • Windows10(x64)
  • .NET Framework4.8
  • Windowsフォームアプリケーション

サンプルの完成イメージ

操作画面

テキストボックスのオブジェクト名はtxtOutFolder、ボタンの名前はButton1としています。

ひな型ファイルのイメージ

ファイル名はTemplate.xlsmとする

出力ファイルのイメージ

ファイル名はyyyyMMdd-HHmmss.xlsmとする。【テンプレートシート】を元に【出力】シートを作り、そこへ値を出力する。ソースコードも引き継げている

サンプルのソースコード

まず、Microsoft.Office.Interop.Excelをインストールする必要があります。NuGetなどを使ってまずインストールを行ってください。

{ディレクトリ}の箇所はテンプレートファイルがあるフォルダー、出力先フォルダーそれぞれに置き換えてください。

Imports Microsoft.Office.Interop
Imports System.Runtime.InteropServices

Public Class Form1

    Public Const TEMPLATE = "{ディレクトリ}\Template.xlsm"
    Public Const OUTFOLDER = "{ディレクトリ}\OutPut"

    ''' <summary>
    ''' 画面読み込み時の処理を行います。
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        txtOutFolder.Text = OUTFOLDER
    End Sub

    ''' <summary>
    ''' [出力]ボタンクリック時の処理を行います。
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

        Dim strOutFileName As String = ""

        Dim xlsApplication As Excel.Application = Nothing
        Dim xlsWorkbooks As Excel.Workbooks = Nothing
        Dim xlsWorkbook As Excel.Workbook = Nothing
        Dim xlsSheets As Excel.Sheets = Nothing

        Dim xlsWorkSheet1 As Excel.Worksheet = Nothing
        Dim xlsWorkSheet2 As Excel.Worksheet = Nothing
        Dim xlsWorkSheet3 As Excel.Worksheet = Nothing

        Dim xlsRange As Excel.Range = Nothing


        Try
            strOutFileName = txtOutFolder.Text & "\" & DateTime.Now.ToString("yyyyMMdd-HHmmss") & ".xlsm"

            'Excelアプリケーションを起動
            xlsApplication = New Excel.Application
            xlsApplication.Visible = False
            xlsApplication.DisplayAlerts = False

            'Workbooksコレクションを生成
            xlsWorkbooks = xlsApplication.Workbooks

            'Workbookオブジェクトを生成
            xlsWorkbook = xlsWorkbooks.Open(TEMPLATE)

            'Sheetsコレクションを生成
            xlsSheets = xlsWorkbook.Sheets

            xlsWorkSheet1 = xlsSheets.Item("テンプレート")
            xlsWorkSheet2 = xlsSheets.Item(xlsSheets.Count)
            xlsWorkSheet1.Copy(After:=xlsWorkSheet2)

            'Worksheetオブジェクトを生成。コピーしたシートを取得
            xlsWorkSheet3 = xlsSheets.Item(xlsSheets.Count)
            xlsWorkSheet3.Name = "出力"
            'Rangeオブジェクトを生成
            xlsRange = xlsWorkSheet3.Cells()

            'コピーしたシートへの書き込み
            xlsRange(1, 2) = "TEST PJ 1"
            xlsRange(4, 1) = 1
            xlsRange(4, 2) = "テスト"
            xlsRange(5, 1) = 1234
            xlsRange(6, 1) = -1234
            xlsRange(7, 2) = -12
            xlsRange(7, 3) = -24
            xlsRange(7, 4) = 48

            'xksm形式で名前をつけて保存
            xlsWorkbook.SaveAs(Filename:=strOutFileName, FileFormat:=Excel.XlFileFormat.xlOpenXMLWorkbookMacroEnabled)

            MessageBox.Show("完了しました")

        Catch ex As Exception

            MessageBox.Show(ex.Message)

        Finally

            'Rangeオブジェクトの解放
            Marshal.ReleaseComObject(xlsRange)

            'xlsWorkSheetオブジェクトの解放
            Marshal.ReleaseComObject(xlsWorkSheet1)
            Marshal.ReleaseComObject(xlsWorkSheet2)
            Marshal.ReleaseComObject(xlsWorkSheet3)

            'Sheetsオブジェクトの解放
            Marshal.ReleaseComObject(xlsSheets)

            'Workbookオブジェクトを解放
            Marshal.ReleaseComObject(xlsWorkbook)

            'Workbooksオブジェクトを解放
            Marshal.ReleaseComObject(xlsWorkbooks)

            '保存時の問合せダイアログ表示を有りに戻す
            xlsApplication.DisplayAlerts = True

            'Excelアプリケーションを閉じる 
            xlsApplication.Quit()

            'Excel.Applicationオブジェクトを解放 
            Marshal.ReleaseComObject(xlsApplication)

        End Try

    End Sub

End Class

補足

上記のソースではシートをコピーするにあたり、コピー対象のシートを格納するためのExcel.Worksheetオブジェクト(変数名:xlsWorkSheet1)、コピー先の場所を制御するためのExcel.Worksheetオブジェクト(変数名:xlsWorkSheet2)をそれぞれ用意してシートのコピーを行いました。

上記以外でも、例えば

xlsSheets.Item("テンプレート").Copy(After:=xlsSheets.Item(xlsSheets.Count))

のようにExcel.Worksheetオブジェクトを宣言しなくてもシートのコピーはできるのですが、この場合、処理が終わった時点でもExcelのプロセスが残ってしまいます。

フォームを閉じてアプリケーションを終了したら残っているExcelプロセスは消えますし、プロセスが残っているときに出力したエクセルファイルを開いてみても読み取り専用になったりすることはないので実害はあまりないないように思いますが、出来る限りプロセスは残らない方がいいと思いますので、Excel.Worksheetを用意して使い終わったら解放する構成でソースを組んだ方が良いと考えています。

タイトルとURLをコピーしました