EXCELファイル内のVBAプロジェクトのソース一式をエクスポートする
EXCEL VBAでプログラムを書いた場合にSubversionなどでソースコードをテキストで管理したいのですが従来はEXCELのVBAプロジェクトではモジュールひとつずつ選択してエクスポートする方法しかなくて面倒な思いをしていました。
そこですべてのモジュールのソースコードを一括でエクスポートをする方法がないか調べたところVBAを使用すればできることがわかりました。
VBAを使用してVBAプロジェクトを操作する場合にはEXCELのセキュリティのオプションを変更する必要があります。
「EXCELのオプション」の「セキュリティセンター」タブで「セキュリティセンターの設定」を実行して「マクロの設定」タブで「開発者向けのマクロ設定」の「VBAプロジェクトオブジェクトモデルへのアクセスを信頼する」にチェックを入れます。
具体的にな方法としては下記の内容をSourceExporter.basとして保存して、VBAプロジェクトの「ファイル」メニューの「ファイルのインポート」でこのSourceExporter.basをインポートしてからマクロあるいはイミディエイトウィンドウからExportSource()関数を実行すればカレントフォルダの下にsrcフォルダが作成されてその下にすべてのモジュールのソースファイルが一括でエクスポートされます。
○SourceExporter.bas
Attribute VB_Name = "SourceExporter" Option Explicit '標準モジュール Const vbext_ct_StdModule As Integer = 1 'クラス モジュール Const vbext_ct_ClassModule As Integer = 2 'Microsoft Forms Const vbext_ct_MSForm As Integer = 3 'ActiveX デザイナー Const vbext_ct_ActiveXDesigner As Integer = 11 'ドキュメント モジュール Const vbext_ct_Document As Integer = 100 Sub ExportSource() Dim export_path As String export_path = "src" Dim vb_component As Object For Each vb_component In ThisWorkbook.VBProject.VBComponents Debug.Print vb_component.Name Dim extention As String Select Case vb_component.Type Case vbext_ct_StdModule '標準モジュール extention = ".bas" Case vbext_ct_ClassModule 'クラス モジュール extention = ".cls" Case vbext_ct_MSForm 'Microsoft Forms extention = ".frm" Case vbext_ct_ActiveXDesigner 'ActiveX デザイナー extention = ".cls" Case vbext_ct_Document 'ドキュメント モジュール extention = ".cls" End Select vb_component.Export ThisWorkbook.Path & "\\" & export_path & "\\" & vb_component.Name & extention Next End Sub
ただ、この方法だといちいちEXCELにSourceExporter.basをインポートしてから実行しなければならなくて面倒です。
そこで外部からVBAを実行するようにすればこの必要がありません。
わたしはActiveScriptRubyを使用しているのでそのスクリプトexcel_vba_source_export.rbを以下に引用しておきます。
このスクリプトexcel_vba_source_export.rbの第一引数でソースをエクスポートしたいVBAプロジェクトが含まれるEXCELファイルを指定して第二引数で出力先のパスを指定します。
たとえばExcelTool.xlsというEXCELファイルのVBAプロジェクトのソース一式をカレントの下のsrcフォルダの下にエクスポートする場合には以下のように実行します。
この場合にも上記のEXCELのセキュリティのオプションの変更が必要です。
○excel_vba_source_export.rb
# -*- coding: cp932 -*- require 'win32ole' require 'fileutils' if ARGV.length < 1 puts '引数が不足しています' p ARGV exit else excel_file = File.expand_path(ARGV[0]) unless test(?e, excel_file) puts 'EXCELファイルが存在しません' exit end if ARGV.length == 1 export_path = '.' else export_path = ARGV[1] end export_path = File.expand_path(export_path) FileUtils.mkdir_p(export_path) unless FileTest.exist?(export_path) end # EXCEL VBA オブジェクト excel = WIN32OLE.new('Excel.Application') book = excel.Workbooks.Open(excel_file) # 標準モジュール Const_vbext_ct_StdModule = 1 # クラス モジュール Const_vbext_ct_ClassModule = 2 # Microsoft Forms Const_vbext_ct_MSForm = 3 # ActiveX デザイナー Const_vbext_ct_ActiveXDesigner = 11 # ドキュメント モジュール Const_vbext_ct_Document = 100 book.VBProject.VBComponents.each do |vb_component| p vb_component.Name case vb_component.Type when Const_vbext_ct_StdModule # 標準モジュール extention = '.bas' when Const_vbext_ct_ClassModule # クラス モジュール extention = '.cls' when Const_vbext_ct_MSForm # Microsoft Forms extention = '.frm' when Const_vbext_ct_ActiveXDesigner # ActiveX デザイナー extention = '.cls' when Const_vbext_ct_Document # ドキュメント モジュール extention = '.cls' end vb_component.Export export_path + '\\' + vb_component.Name + extention end excel.Quit