既存のエクセルファイル(.xlsm)のシートを同じブック内にコピーする方法です。
以下の設定がされていてもコピーされていることを確認しています。
- ズーム設定
- 文字フォント
- 文字サイズ
- 文字の色
- セルの書式設定(#,##0;[赤]-#,##0)
- セルの計算式
- コマンドボタン
- シート裏に書いたVBAソース
- 標準モジュールに書いたVBAソース
動作確認環境
確認環境
- VisualStudio2022
- Windows10(x64)
- .NET Framework4.8
- Windowsフォームアプリケーション
サンプルの完成イメージ
操作画面
テキストボックスのオブジェクト名はtxtOutFolder、ボタンの名前はButton1としています。
ひな型ファイルのイメージ
出力ファイルのイメージ
サンプルのソースコード
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を用意して使い終わったら解放する構成でソースを組んだ方が良いと考えています。