人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

《コンペ》 VBAマクロでサムチェックツール

職場でちょっとしたプログラムを作っているのですが、機能追加などで改修することになり、バージョン管理の一環として、サムチェック値の計算ツールを作りたいと考えています。
要は、作成した実行ファイル(バイナリ)について、サム値を計算すればいいので、FCIVとか巷のフリーツールでもいいのですが、ExcelVBAの勉強を兼ねて色々アレンジしたいのでマクロ文でお願いします。

要求を満たすものが複数挙がった場合は、私の主観で点数分配します。
評価ポイントは以下の通りですが、質問あれば随時受け付けます。
よろしくお願い致します。

評価ポイント:
・動作が軽い事。
・可読性。自分で色々アレンジしたいので。コメント等も多ければ良いとは思いませんがわかりやすいコメントや構文は好評価。
・機能別にサブルーチン化されていること。たぶん個別にボタン割り付けて使うので。

●質問者: GM91
●カテゴリ:コンピュータ 学習・教育
○ 状態 :終了
└ 回答数 : 2/2件

▽最新の回答へ

質問者から

仕様は以下の通りです。
★:必須
※:できれば

★ファイルの読み書きはWindows7上で動作すればOK。その他のOS対応は不要。
★Excel2010のVBAマクロ記述だけで動作が完結すること。
他のツールを呼び出すとかはNG。
★対象は バイナリファイル×1 複数ファイルとかフォルダ毎とかは不要。
★対象ファイルは、シートの特定箇所にファイル名を記載して指定する。
※そのExcelファイルが置かれたパスを検出してくれるか、選択用のダイアログが出ると便利。
★サムチェック値は32bitのHEX表現で、特定のシートに出力される。
※マクロ実行する毎に次の行へ書き込んでくれると嬉しい。
★サム値の計算アルゴリズムは任意。
改ざん防止や保安度については考慮しなくてよい。
★処理速度優先。ファイルの中身が同じなら毎回同じサム値を出す。
これができれば複雑な演算は不要。
※最悪、単純加算でもOKだが、データを2箇所変更するとサム値が同じになってもうたとかそういうのが回避されるとちょっとだけ嬉しい。
★複数のアルゴリズムを切り替える機能は不要。
(どれでやったかわからなくなるので実装禁止)
★対象となるファイルのサイズは変動あり。固定長で処理を中断しないこと。


1 ● cx20
●50ポイント ベストアンサー

<Sheet1 の内容>

A B
1C:\Data\Tools\FCIV\fciv.exe

[コマンドボタン]
<Sheet1 / コマンドボタンクリック時処理>

' ボタンクリック時にシートに記載したファイルのハッシュ値を取得する
Private Sub CommandButton1_Click()
 Dim strFileName
 strFileName = Range("A1").Value
 Dim strMD5
 strMD5 = GetFileHashMD5(strFileName)
  ' MD5 ハッシュ値128bit中32bitを表示する
 Range("B1").Value = Mid(strMD5, 24, 8)
End Sub

<標準モジュール>

Option Explicit

' 指定したファイルの MD5 ハッシュ値を取得する
Function GetFileHashMD5(strFileName)
 Dim md5
 Set md5 = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider")
 md5.ComputeHash_2 (ReadBinaryFile(strFileName))
 Dim msxml
 Set msxml = CreateObject("MSXML2.DOMDocument")
 Dim el
 Set el = msxml.CreateElement("tmp")
 el.DataType = "bin.hex"
 el.NodeTypedValue = md5.Hash
 GetFileHashMD5 = el.Text
End Function

' 指定したファイルのバイト配列を取得する
Function ReadBinaryFile(strFileName)
 Const adTypeBinary = 1
 Dim stm
 Set stm = CreateObject("ADODB.Stream")
 stm.Type = adTypeBinary
 stm.Open
 stm.LoadFromFile strFileName
 ReadBinaryFile = stm.Read
End Function

<実行結果>

A B
1C:\Data\Tools\FCIV\fciv.exe 4e9c07c6

<参考サイト>

■ WindowsでSHA1とMD5を調べる
http://d.hatena.ne.jp/papaking_ken/20110224/1298564016


対応要否要求仕様 実装状況コメント
ファイルの読み書きはWindows7上で動作すればOK。その他のOS対応は不要。Windows10にて開発。バージョン依存する機能は未使用の為、Windows7でも動作すると思われる。
Excel2010のVBAマクロ記述だけで動作が完結すること。 Excel2013にて開発。バージョン依存する機能は未使用の為、Excel2010でも動作すると思われる。
対象は バイナリファイル×1 複数ファイルとかフォルダ毎とかは不要。バイナリファイルにて確認済み
対象ファイルは、シートの特定箇所にファイル名を記載して指定する。 セルA1にファイル名を指定。ボタン押下にてマクロ起動
サムチェック値は32bitのHEX表現で、特定のシートに出力される。 MD5ハッシュ値128bitのうち32bitを出力。妥当性については未確認
サム値の計算アルゴリズムは任意。 MD5
処理速度優先。ファイルの中身が同じなら毎回同じサム値を出す。 Crypto APIを使用している為、ネイティブ並みの処理速度を実現
複数のアルゴリズムを切り替える機能は不要。 MD5のみを使用
対象となるファイルのサイズは変動あり。固定長で処理を中断しないこと。任意のファイルサイズに対応。数百MBでも数秒でチェック可能

GM91さんのコメント
ありがとうございます 補足に挙げてある必須項目については網羅するようお願いします。

cx20さんのコメント
必須項目について可能な範囲で対応しました。 実機による動作テストについては、手元に、Windows7+Excel2010環境が無い為、出来ていません。 お手数ですが、お手持ちの環境にて確認お願いします。

GM91さんのコメント
ありがとうございます。確認してみます。

2 ● TransFreeBSD
●50ポイント

チェックサムと言えばCRC32なので探し出しましたがスピードは遅いです。
たぶんライブラリ使ったid:cx20さんのにかなうのはないと思います。

※そのExcelファイルが置かれたパスを検出してくれるか、選択用のダイアログが出ると便利。
※マクロ実行する毎に次の行へ書き込んでくれると嬉しい。

この辺実装しました。
id:cx20さんのと組み合わせていただければ良いかと思います。

Option Explicit
Const FileNameSheet = "ファイル名"
Const FileNameCell = "A1"
Const HashStoreSheet = "サム値"
Const HashStoreColumn = "B"

Dim Crc32Table&(255)

' Mainマクロを実行する
Sub Main()
 Dim strFileName As String
 strFileName = GetFileName()
 Dim hash
 hash = GetCrc32FromFile(strFileName)
 hash = Hex(hash)
  'hash = GetFileHashMD5(strFileName)
  'hash = Mid(strHash, 24, 8)
 StoreResult hash
End Sub

Function GetFileName()
  ' カレントディレクトリをブックのあるフォルダにすることで絶対パス・相対パスどちらでも対応可能にする
  ' 参考: http://www.asahi-net.or.jp/~ef2o-inue/vba_o/sub05_110_140.html
 ChDrive ThisWorkbook.Path
 ChDir ThisWorkbook.Path
  ' 以下三種の取得方法
  ' GetFileName = Sheets(FileNameSheet).Range(FileNameCell).Value ' 特定シートの特定セルから得る
 GetFileName = Range(FileNameCell).Value ' 現在のシートの特定位置のセルから得る
  ' GetFileName = Selection.Value ' 選択中のセルから得る
End Function

Sub StoreResult(strResult)
 Sheets(HashStoreSheet).Cells(Rows.Count, HashStoreColumn).End(xlUp).Item(2).Value = strResult
  ' Rows.Count 行の最大値
  ' Cells(Rows.Count, "B") B列最終行のセル
  ' End(xlUp) 上方向(xlUp)でデータのある最初のセル(Ctrl+↑)
  ' 最終行のセル + Ctrl+↑ = データのある最後のセル
  ' Item(2) その下のセル(現在位置を(1)として上下に2番の位置)
End Sub

' 以下コピペ
' http://d.hatena.ne.jp/n7shi/20100910/1284112553
' https://code.msdn.microsoft.com/office/VBACRC-32-dad7d087
' Dim I%, J%, R&, R1&等参考
' http://www.atmarkit.co.jp/fdotnet/vb6tonet/vb6tonet30/vb6tonet30_01.html

Private Sub InitCrc32Table()
 Dim I%, J%, R&, R1&
 For I = 0 To 255
 R = I
 For J = 0 To 7
 R1 = R And 1
 R = (R - R1) / 2
 If R < 0 Then R = R - &H80000000
 If R1 Then R = R Xor &HEDB88320
 Next J
 Crc32Table(I) = R
 Next I
End Sub

Public Function GetCrc32FromFile&(Path$)
 Dim R&, I&, B As Byte, FL&
 If Crc32Table(255) = 0 Then InitCrc32Table
 FL = FileLen(Path)
 Open Path For Binary Lock Read As #2
 R = Not 0
 For I = 1 To FL
 Get #2, , B
 R = (Int(R / 256) And &HFFFFFF) Xor Crc32Table((R Xor B) And &HFF)
 Next I
 Close #2
 GetCrc32FromFile = Not R
End Function

GM91さんのコメント
ありがとうございます。 処理の速さは、極端に重くなければそれでOKです。 それよりか、こういうふうに演算自体を記述してくれるほうがありがたいです。 私と依頼先の若い子の勉強用なので。

TransFreeBSDさんのコメント
書いておいて何ですが、そういえば勉強用でしたね…… 前半は数行で済む所を無駄に関数化してたり、後半は古い書き方だったりで、あまり向かない気もしてきました。 まあ、知識として知っておいた方が良い部分はあると思いますけども。

GM91さんのコメント
いえ、関数は小分けにしてもらえるほうがありがたいです。 つけたし、流用、はその方がやりやすいので。

質問者から

ありがとうございました。


関連質問

●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ