★ Access2000VBA・Excel2000VBA独学~指定したフォルダの、すべてのサブフォルダも含めて、すべてのExcelファイル(xlsm拡張子)のすべてのモジュールの内容を一括書き出しするプログラム(32bit版のExcelファイルのみ有効。Accessなどはダメ。64bit版もダメ。Wordは不明。)
※関連記事
すべてのファイルを再帰的に順に編集
すべてのファイルのモジュールの内容を一括書き出し
すべてのファイルとフォルダの基本情報の吸い込み
処理速度がOpenメソッド利用時の2倍?すべてのExcelファイルのすべてのシート名をファイルを開かずにゲット
※2022/12/06 追記
★かなり重要な注意事項
ここでは「Dir」を使っていますが、
「Dir関数は認識できない文字(文字コード?)があるらしく、また、最悪なことに、プログラムの書き方によっては、”エラーが出てほしいところで出ない”」
という機能不足や不都合があるようです。
システムとしては致命的になってしまうので、基本的には「使わないほうが無難」なようです。
どうしても使いたいなら
『「確実にパソコン内」だけで付けたファイル名しか「絶対に・100%」ありえない 』、
という前提の場合しか役に立たないようです。
また、Dir関数を使うほうが速度は4、5倍は速いようですが、一部のファイル名を認識できずにエラーになるようでは、全てのファイルやフォルダを拾えません。「4、5倍は速い」なんてものは何の意味もない、ということになります。
そのあたりについて詳しく書いてあるWebサイトをご紹介します。
mhtmlなどで保存しておくことをおすすめします。
VBAでファイルリストを高速に取得する関数を自作する part1
VBAでファイルリストを高速に取得する関数を自作する part2
VBAでファイルリストを高速に取得する関数を自作する part3
VBAでファイルリストを高速に取得する関数を自作する part4
↑「ファイル・フォルダリストをゲットするだけ」というシーンでしか使えないかもしれませんが、Dir関数を使うよりも何倍も速いプログラムコードも紹介されています。
もちろん、文字コードの問題もありません。
ほんと、mhtmlなどで保存しておくことをおすすめします。
https://xxxx7.com/2016/06/06/100040
と
https://itlogs.net/vba-source-export/ を参考にして
少し作り変えしたものです。
APIがあるので、「32bit版」のExcelじゃないと動きません。
また、「FileDialog」オブジェクトの関係で、バージョンが(多分)2007以降じゃないと動きません。(2000などだと変数宣言の箇所でエラーになります。)
事前に、以下の2つの設定が必要です。
(01)VBEの「ツール→参照設定」にて、「Microsoft Scriptiong Runtime」の参照設定。
チェックを入れてOKします。
(02)Excelの「オプション」で、「VBA プロジェクト オブジェクト モデルへのアクセスを信頼する」の設定をONにする。
(2019の場合) →ファイル →オプション →トラストセンター →「トラストセンターの設定」ボタン →マクロの設定 →「VBA プロジェクト オブジェクト モデルへのアクセスを信頼する」にチェックを入れて、OK→OKする。
実際に実行するプログラムは、「ModuleExportAllSubFolder0001()」というプログラム「だけ」です。
フォルダの指定をダイアログにて求められるので、フォルダを選択してOKするとプログラムが動き出します。
xlsmファイルと同じ階層に、txt形式でプログラムが書き出されます。
すべてのサブフォルダが処理されます。
最後に、「おわり」と出て、処理したフォルダが開きます。
※バージョン2003以前で動かしたい場合は、以下の4行をコメントアウトして、
Dim o_AnswFDialg As FileDialog
Set o_AnswFDialg = Application.FileDialog(msoFileDialogFolderPicker)
If Not o_AnswFDialg.Show Then Exit Sub
s_FoldPath = o_AnswFDialg.SelectedItems(1)
以下の1行を復活させて使うとひとまずのテストはできます。
s_FoldPath = "D:\1\1"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
' ' Option Explicit '列挙型変数定義 Private Enum ComponentType STANDARD_MODULE = 1 '標準モジュール CLASS_MODULE = 2 'クラスモジュール USER_FORM = 3 'ユーザーフォーム EXCEL_OBJECTS = 100 'Excelオブジェクト(ワークブック・シート) End Enum '******************************************************************************** 'WindowsAPI宣言(バッチやコマンドラインを非同期じゃなくて「同期実行させる=待機させる」ための。 'OpenProcess関数 'プログラム実行状態の監視を開始させる関数 'GetExitCodeProcess関数 'プログラムが終了したか調査する関数 'CloseHandle関数 'プログラム実行状態の監視を終了させる為の関数 '******************************************************************************** Declare Function OpenProcess Lib "kernel32" _ (ByVal dwAccess As Long, ByVal lpCommandLine As Long, ByVal IDProcess As Long) As Long Declare Function GetExitCodeProcess Lib "kernel32" _ (ByVal lpdExitCode As Long, hHandle As Long) As Long Declare Function CloseHandle Lib "kernel32" _ (ByVal hObject As Long) As Long Public Const PROCESS_QUERY_INFORMATION = &H400 Public Const STILL_ACTIVE = &H103 Public Function WaitShell(CommandLine As String) Dim ShellReturn As Long Dim ShellStatus As Long Dim ProcessReturn As Long Dim ProcessStatus As Long 'Shell関数を実行する ShellReturn = Shell(CommandLine, 2) '第2引数が1だとウィンドウを表示、2はステータスバー。ファイルですか?フォルダですか?と聞かれることもあるので、vbHideにはしないほうがいい。 'プログラム実行状態の監視を開始 ProcessReturn = OpenProcess(PROCESS_QUERY_INFORMATION, False, ShellReturn) Do 'プログラムが終了しているか調査 GetExitCodeProcess ProcessReturn, ShellStatus DoEvents 'プログラムが実行されている間はループしつづける Loop While ShellStatus = STILL_ACTIVE 'プログラム実行状態の監視を終了 ProcessStatus = CloseHandle(ProcessReturn) End Function Sub ModuleExportAllSubFolder0001() 'https://xxxx7.com/2016/06/06/100040 を加工 Dim o_AnswFDialg As FileDialog Dim s_FoldPath As String Dim s_Cmd01 As String Dim s_Cmd02 As String '★ 設定部 Set o_AnswFDialg = Application.FileDialog(msoFileDialogFolderPicker) 'ユーザーに処理対象のフォルダを選ばせるための前準備。 '★ 実動部 If Not o_AnswFDialg.Show Then Exit Sub 'ファイル選択ダイアログを開き、ユーザーに処理対象のフォルダを実際に選ばせる。 'そしてフォルダを選んでOKされたら次へ行き、キャンセルされたらプログラムを終わる。 s_FoldPath = o_AnswFDialg.SelectedItems(1) ' s_FoldPath = "D:\1\1" '選ばれたフォルダのパスをゲット。 '●いったん、前回生成・出力されたプログラムコードのファイルを全部消す処理。 '(この処理が無いと、同じ内容のファイルが別名で作られてどんどん増えてしまうため。 ' コマンドプロンプトを使うけど、基本・コマンドプロンプトやバッチの実行は ' 非同期なので、そのコマンドラインが終わらなくても次に進んでしまう。 ' なので、同期処理にするか待機しないといけない。 ' 「同期処理」にするにはWshShellクラスを使う。 ' その場合、参照設定か実行時バインディングが要る。https://vbabeginner.net/vba%E3%81%A7%E3%83%90%E3%83%83%E3%83%81%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%EF%BC%88bat%EF%BC%89%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B/ を参照。 ' 「待つ」方法には、APIでやる方法と、「Application.Wait メソッド」を使う方法の2つがある。 ' ここでは、「待つ」方法のいずれかでできるようにしている。 ' ただし、WshShellクラスは「★超危険!!」なので使わない。 ' それを使うと、バッチはまともに動くかもしれないけど ' 細かいコマンドラインでDELを使うと他のディレクトリのファイルも全て消されてしまい、 ' マジで「★超危険!!」) ' なお、すでに同じファイルがあるときに、エラーが出るようなら、On Error などで ' 条件分岐+Resumeするなどすれば、 スルー出来ると思います。 s_Cmd01 = "cmd /C DEL """ & s_FoldPath & "\*.txt"" /s " '冒頭で指定されたフォルダ内のすべての「txt」ファイルを、 'すべてのサブフォルダの中も一括削除するコマンドライン命令の指定。 'なお、「cmd /C」の「/C」は、 '「処理が終わったら自動終了する=黒いウィンドウを閉じる」の意味。 s_Cmd02 = "cmd /C DEL """ & s_FoldPath & "\*.frx"" /s " '同上で、「frx」ファイルを削除するモノ。 ' Shell s_Cmd01, vbHide 'コマンドプロンプトのコマンドを「非表示」モードで実行 ' Call WaitSec01(6) '同期実行じゃないので処理が終わるまで待つ。 'この2行は「Application.Wait メソッド」を使う場合のもの。 'APIを使う倍は不要なのでコメントアウト。 Call WaitShell(s_Cmd01) 'WaitShell関数(API利用)で、 '実行が終わるのを待ちながら、 '「txtの一括削除」を実行する。 ' Shell s_Cmd02, vbHide ' Call WaitSec01(3) 'ここも待つ。 'この2行も「Application.Wait メソッド」を使う場合はコメントアウトをはずす。 'APIを使う倍は不要なのでコメントアウト。 Call WaitShell(s_Cmd02) 'WaitShell関数(API利用)で、 '実行が終わるのを待ちながら、 '「frxの一括削除」を実行する。 Call getFolderAndFileListSub(folderPath:=s_FoldPath) 'すべてのサブフォルダも対象に(再帰処理的に)、 'すべてのxlsmファイル、xlsファイルの全モジュールのコードを書き出し(エクスポート)。 Shell "cmd /C Explorer " & s_FoldPath & """" '最初に指定されたフォルダを、結果チェックのために開く。 MsgBox "おわり" End Sub 'コマンドプロンプトのコマンド実行で、 '「WshShellなどでの同期」や「APIでの待機」での実行じゃないときに '単純に「Application.Waitメソッド」で「待つ」ための関数 Sub WaitSec01(i_sec As Integer) Dim newHour As Date Dim newMinute As Date Dim newSecond As Date Dim waitTime As Date newHour = Hour(Now()) newMinute = Minute(Now()) newSecond = Second(Now()) + i_sec waitTime = TimeSerial(newHour, newMinute, newSecond) Application.Wait waitTime End Sub 'https://xxxx7.com/2016/06/06/100040 を加工 Sub getFolderAndFileListSub(folderPath As String, _ Optional myCount As Long = 0) 'Microsoft Spripting Runtime」 への参照設定が必要。 Dim fso As New FileSystemObject Dim myFolder As Folder Dim myFile As File 'そのフォルダの中「だけ」の、処理。 For Each myFile In fso.GetFolder(folderPath).Files Call ExportVBAFiles02(myFile.Path) '当該xlsmやxlsの、すべてのモジュールのコードを '外部にテキスト形式で書き出す。 '次の、「ExportVBAFiles02()」関数によって書き出す。 '必要に応じて、「ExportVBAFiles02()」関数の側で '「.bas」拡張子などで書き出せる設定にしたり '任意のフォルダを生成してから、その中に 'テキストでのプログラムソースを書き出すことも可能。 Next 'サブフォルダを再帰的に覗いていくだけの処理。 For Each myFolder In fso.GetFolder(folderPath).SubFolders Call getFolderAndFileListSub(myFolder.Path, myCount) Next End Sub 'https://itlogs.net/vba-source-export/ を参考にして少し作り変え 'VBAソースコードエクスポート関数 Function ExportVBAFiles02(s_TrgWbFullPath As String) '変数定義 Dim TempComponent As Object Dim ExportPath As String Dim o_Wb01 As Workbook Application.ScreenUpdating = False Set o_Wb01 = Workbooks.Open(s_TrgWbFullPath) 'エクスポート先ディレクトリの取得 ' ExportPath = ThisWorkbook.Path & "\export_" & Format(Now, "YYYYMMDDhhmm") ' ExportPath = o_Wb01.Path & "\export_" & o_Wb01.Name & "_" & Format(Now, "YYYYMMDDhhmm") ExportPath = o_Wb01.Path & "\" ' ' 'エクスポート先ディレクトリがない場合、ディレクトリ作成 ' If Dir(ExportPath) = "" Then ' Call MkDir(ExportPath) ' End If ' ' 'エクスポート先ディレクトリに「BAS」ディレクトリがない場合、ディレクトリ作成 ' If Dir(ExportPath & "\BAS") = "" Then ' Call MkDir(ExportPath & "\BAS") ' End If ' ' 'エクスポート先ディレクトリに「CLS」ディレクトリがない場合、ディレクトリ作成 ' If Dir(ExportPath & "\CLS") = "" Then ' Call MkDir(ExportPath & "\CLS") ' End If ' ' 'エクスポート先ディレクトリに「FRM」ディレクトリがない場合、ディレクトリ作成 ' If Dir(ExportPath & "\FRM") = "" Then ' Call MkDir(ExportPath & "\FRM") ' End If 'プロジェクトのソースコードをループ ' For Each TempComponent In ThisWorkbook.VBProject.VBComponents For Each TempComponent In o_Wb01.VBProject.VBComponents 'タイプ別判定 Select Case TempComponent.Type '標準モジュールの場合、「BAS」ディレクトリへ出力 Case STANDARD_MODULE ' TempComponent.Export ExportPath & "\BAS\" & TempComponent.Name & ".bas" TempComponent.Export ExportPath & "export_" & o_Wb01.Name & "_BAS_" & TempComponent.Name & ".txt" 'クラスモジュールの場合、「CLS」ディレクトリへ出力 Case CLASS_MODULE ' TempComponent.Export ExportPath & "\CLS\" & TempComponent.Name & ".cls" TempComponent.Export ExportPath & "export_" & o_Wb01.Name & "_CLS_" & TempComponent.Name & ".txt" 'ユーザーフォームの場合、「FRM」ディレクトリへ出力 Case USER_FORM ' TempComponent.Export ExportPath & "\FRM\" & TempComponent.Name & ".frm" TempComponent.Export ExportPath & "export_" & o_Wb01.Name & "_FRM_" & TempComponent.Name & ".txt" 'Excelオブジェクト(ワークブック・シート)の場合、「CLS」ディレクトリへ出力 Case EXCEL_OBJECTS ' TempComponent.Export ExportPath & "\CLS\" & TempComponent.Name & ".cls" TempComponent.Export ExportPath & "export_" & o_Wb01.Name & "_CLSobj_" & TempComponent.Name & ".txt" End Select Next o_Wb01.Close SaveChanges:=False Application.ScreenUpdating = True ' MsgBox "ソースエクスポート完了。" ' Debug.Print "ソースエクスポート完了。" End Function ' ' |
- 投稿タグ
- 「ニセモノ」への道, 「本物」に近づくために, AccessVBA, Accessの独学, Access操作の基礎, Accesの独学, ADO/DAO, ExcelSQL, ExcelVBA, Excelの独学, Excel操作の基礎, Excel連携VBA, MicrosoftQuery, ODBC, SQL, Win32API, パソコンでの自動化, ビジネスパソコンの基礎, ビジネス一般常識, マクロ, ワークシート関数, 独学, 自動化