VBAでZIPの圧縮・解凍をやらせてみる

自分がこれまで手掛けた特定企業向けの業務アプリケーションで非常に大がかりであったものは「酪農経営シミュレータ」「医薬品卸価格分析ツール」などがあります。これらは使う人によっていくつものパターンや分析を行う必要があるため、データを簡単にエクスポートし、簡単に入れ替えられるようにしておく必要がありました。今から10年以上前の話です。

Accessでこれらを作成するにあたり、Accessファイルでの管理は煩雑なので(いくつものaccdbファイルで構成されている為)、ZIP形式でまとめて出力や入力が出来るようにしてあります。これらのZIPファイルを相手に渡せば、忠実に計算結果を再現できるので非常に地味ながら重宝する機能です。そこで今回はこの部分を書いてみようと思います。

※今回のルーチンはファイルの指定やフォルダの指定などのダイアログを実装していないので、実用する場合にはファイル・フォルダ指定のダイアログ等が必要になるかと思います。

今回使用するファイルやライブラリ

ソースコード

OS標準機能を使ったパターン

Windows7からはOS標準でZIPの圧縮・解凍の機能が使えるようになっているため、別途DLLがなくともZIPをVBAから扱えるようになっています。但し、標準機能なので、暗号化ZIPを作成・解凍する事は出来ません(sendkeyでパスワードを送る手段はありますが、賢明な方法とは言えません)。

圧縮をしてみる

圧縮は解凍よりも若干厄介です。こちらのサイトにVBSのパターンの圧縮用コードがありますが、VBAでも利用が可能です。同一ファイル名が先にあった場合には削除をし、圧縮時にエラーが発生した場合用にエラートラップをし、成功時にTrue、失敗時にはfalseを返すようにしています。

また、圧縮中にすべてのファイルの圧縮が完了するまでの100ms程度のsleepを入れているので、Generalプロシージャにkernel32のロードが必要です。

解凍をしてみる

今回は指定のフォルダがない場合には自動的にフォルダを作成し解凍を続行するようにしています。また、解凍時にエラーが発生した時用にエラートラップをし、成功時にはtrueを失敗時にはfalseを返すようにしています。

7zip.dllを使ったパターン

7zip.dllは非常に優れたライブラリで、7z形式だけでなく通常のZIP形式にも対応、また暗号化ZIPの作成・解凍にも対応している為、VBAで使う上ではとても良い選択肢です。32bit版と64bit版とでDLLが分かれているので、利用する場合にはExcel VBAがどちらで動いているのか?注意が必要です。また、7zipの様々なオプション指定により細かく圧縮・解凍する際に指示を与えられるので、オプションリストを見ておくと良いでしょう。

導入手順

外部DLLが必要になるので、7-zip32.dllもしくは7-zip64.dllをWindowsのSystem32ディレクトリ等に入れておく必要があります。ただし、32bit版は、64bit OSならば、c:¥Windows¥SysWow64へ入れ、32bit OSならば、c:¥windows¥system32に入れなければなりません。64bit版は、c:¥windows¥system32に入れることになります。

しかし、環境によってはSystem32ディレクトリに入れることが出来ない環境(管理者権限がない等)もあり得ます。

その場合、DLLを使う関数内で以下のコードを追記し、参照するディレクトリをカレントディレクトリに変更し、DLLはAccessファイルと同じディレクトリに入れておく事で利用する事が可能になります。Excelの場合には、ActiveWorkbook.Pathを使用します。

また、利用する為にはGeneralプロシージャにDLL参照用の宣言が必要になります。下記は32bitおよび64bit両方に対応した宣言です。

実際に使ってみる

圧縮をしてみる

今回は適当なディレクトリにファイルを突っ込んで、フォルダを圧縮してみたいと思います。今回は通常通りのzip形式で、暗号化ZIPとして生成します。

  • 暗号化のオプションは、cmdlinの中にある「-p」です。これに間を空けずにパスワードを繋げるのがポイントです。この部分がなければ、通常のZIPファイルの圧縮となります(よってその場合、引数にstrPassも不要になる)
  • SevenZipに渡すまでの間の処理で、2つの作業用関数を使用しています(SevenZipcmpGetSevenZipOption
  • SevenZip関数に渡す場合、ウィンドウハンドルを渡す必要がありますが、Excelの場合はApplication.hwnd、Accessの場合はApplication.hWndAccessAppで渡します。
  • 圧縮実行時のfolderpathは今回はフォルダを指定していますが、ファイル単体を指定しても圧縮してくれます。
  • 今回は圧縮オプションとして7zip互換のLZMAで圧縮レベル9で実行しています。
解凍をしてみる

今回はExcelで暗号化ZIPを解凍してみようと思います。今回は通常通りのzip形式です。

  • 暗号化のオプションは、cmdlinの中にある「-p」です。これに間を空けずにパスワードを繋げるのがポイントです。この部分がなければ、通常のZIPファイルの解凍となります(よってその場合、引数にstrPassも不要になる)
  • SevenZipに渡すまでの間の処理で、2つの作業用関数を使用しています(GetpbslGetDirectoryMemberSplit
  • SevenZip関数に渡す場合、ウィンドウハンドルを渡す必要がありますが、Excelの場合はApplication.hwnd、Accessの場合はApplication.hWndAccessAppで渡します。

関連リンク

VBAでZIPの圧縮・解凍をやらせてみる” に対して2件のコメントがあります。

  1. 小谷 より:

    初めまして。
    まさに自分がやりたいことを掲載されていたので、参考にさせていただいております。
    まだまだ勉強中で、知識が足らず困っております。
    もしよければご教授いただけませんでしょうか?

    やりたいこととしましては、outlookのメールを受信した際にパスワードのかかった添付ファイル(ZIPファイル)を自動保存し、別送のパスワードで解凍をVBAで行いたいと考えております。
    現状、添付ファイルを自動的に保存することはできている状態です。

    上記を参考にし、エクセルVBAで解凍はできました。
    outlookでやろうとするとデバックしてしまいます。

    1. akanemaru2017 より:

      コードを見ていないので推測なのですが
      コードのどのあたりでデバッグで止まるのか?というのがわかると良いのですが

      当方のコードは64bitコード/32bitコードを判定しての共用コードなのでありえる事象としては
      1.Outlook VBA実行環境が32bit版のOutlookである
      2.暗号化ZIPの解凍には7-zip64.dllが必要ですが、32bitの場合は7-zip32.dllが必要
      3.VBAから見て、2.のDLLが見つからない(カレントディレクトリもしくは、32bitだとsystem32ディレクトリ内にDLLが入っていない)
      4.64bitの場合、カレントディレクトリもしくはSysWOW64のディレクトリ内にDLLが入っていない

      のいくつかになるかなぁと思います。DLLの呼び出し宣言はPtrSafeつけるかつけないかが、64bit/32bitの違いなので、おそらくは3.4.あたりかなぁと思います。
      ただ、Outlookの場合、カレントディレクトリと呼べるものがないので、system32もしくはSysWOW64に7-zipのそれぞれのバージョンのDLLが入っていないとか。

      どうでしょう?

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)