常常需要计算文件的MD5。到网上一搜,发现有的MD5计算程序还不是免费的。那还不如自己动手写一个。用Windows API,要不了多少代码。下面给出我写的小程序的完整源代码:
/*
* md5.c
* Calc file's MD5 hash value by WIN32 crypto API.
* Version: 1.00.00
* Copyright (c) 2010, Wang Xiaojian <[email protected]>,
* Bit R&D Studio. All rights reserved.
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <windows.h>
#include <tchar.h>
#pragma comment(lib,"crypt32")
// 把文件中的所有数据读取到缓冲区中
// 应用程序负责在适当的时候用free释放缓冲区
__inline BOOL LoadFile(LPCTSTR pszFile,LPBLOB pBlob)
{
HANDLE hFile =CreateFile(pszFile,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
if(INVALID_HANDLE_VALUE==hFile)
return FALSE;
pBlob->cbSize =GetFileSize(hFile,NULL);
if(pBlob->cbSize!=0)
{
pBlob->pBlobData =(LPBYTE)malloc(pBlob->cbSize);
if(pBlob->pBlobData!=NULL)
{
if(!ReadFile(hFile,pBlob->pBlobData,pBlob->cbSize,&pBlob->cbSize,NULL))
{
free(pBlob->pBlobData);
pBlob->pBlobData =NULL;
pBlob->cbSize =0;
}
}
}
CloseHandle(hFile);
return (pBlob->pBlobData!=NULL);
}
// 封装CryptAcquireContext函数
__inline BOOL AcquireContext(HCRYPTPROV* phProv)
{
return (CryptAcquireContext(phProv,NULL,MS_STRONG_PROV,PROV_RSA_FULL,0) ||
CryptAcquireContext(phProv,NULL,MS_STRONG_PROV,PROV_RSA_FULL,CRYPT_NEWKEYSET));
}
// 计算二进制数据的MD5
// 参数说明:
// pData [in] 指向包含待计算MD5的二进制数据的缓冲区地址
// cbData [in] 二进制数据长度,以字节为单位
// pHashData [out, size_is(cbMaxSize)] 指向接收MD5的缓冲区地址
// cbMaxSize [in] 接收MD5的缓冲区长度,以字节为单位
// 返回值:
// 填充pHashData的数据长度,以字节为单位
DWORD GetMD5(const void* pData,DWORD cbData,PBYTE pHashData,DWORD cbMaxSize)
{
HCRYPTPROV hProv;
HCRYPTHASH hHash;
DWORD cb=0,cbSize =cbMaxSize;
if(AcquireContext(&hProv))
{
if(CryptCreateHash(hProv,CALG_MD5,0,0,&hHash))
{
if(CryptHashData(hHash,pData,cbData,0))
{
if(CryptGetHashParam(hHash,HP_HASHVAL,pHashData,&cbSize,0))
{
cb =cbSize;
}
}
CryptDestroyHash(hHash);
}
CryptReleaseContext(hProv,0);
}
return cb;
}
// 计算文件MD5
// 参数说明:
// pszFile [in, string] 指向包含待计算MD5的文件路径字符串的缓冲区地址
void ShowMD5(LPCTSTR pszFile)
{
BLOB blob;
BYTE pHashData[32];
DWORD cbHash,cbSize =sizeof(pHashData);
TCHAR szText[MAX_PATH];
DWORD cb =MAX_PATH;
if(!LoadFile(pszFile,&blob))
return;
cbHash =GetMD5(blob.pBlobData,blob.cbSize,pHashData,cbSize);
if(cb!=0)
{
if(CryptBinaryToString(pHashData,cbHash,CRYPT_STRING_HEX,szText,&cb))
{
MessageBox(NULL,szText,pszFile,MB_OK);
}
}
free(blob.pBlobData);
}
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
hInstance;
hPrevInstance;
nCmdShow;
if(0==*lpCmdLine)
{
TCHAR szFile[MAX_PATH];
OPENFILENAME ofn ={sizeof(OPENFILENAME)};
*szFile =0;
ofn.hwndOwner =NULL;
ofn.lpstrFile =szFile;
ofn.nMaxFile =MAX_PATH;
ofn.Flags =OFN_NONETWORKBUTTON|OFN_FILEMUSTEXIST;
if(!GetOpenFileName(&ofn))
return -1;
ShowMD5(szFile);
}
else
{
if(0xFFFFFFFF==GetFileAttributes(lpCmdLine))
return -1;
ShowMD5(lpCmdLine);
}
return 0;
}