// CreateHash.cpp : Implementation of CCreateHash
#include "stdafx.h"
#include "CreateHash.h"
// CCreateHash
/////////////////////////////////////////////////////////////////////////////
// CCreateHash
#pragma warning ( push, 4 )
HRESULT CCreateHash::InvokeCommand ( LPCMINVOKECOMMANDINFO pCmdInfo )
{
unsigned int i = 0, j = 0;
// Friendly Name: 'MD5'
std::vector< std::wstring > hashnames;
// Hash: 47FD4214F5775826FB20FEC1091987A1
std::vector< std::wstring > hashvalues;
std::wstring ClipboardText;
std::wstring MsgBoxMessage;
MsgBoxMessage = L"The following was placed on the Windows Clipboard:\r\n\r\n";
// If lpVerb really points to a std::string,
// ignore this function call and bail out.
if ( 0 != HIWORD( pCmdInfo->lpVerb ) ) { return E_INVALIDARG; }
// Get the command index - the only valid one is 0.
switch( LOWORD( pCmdInfo->lpVerb ) )
{
case 0:
{
for( i = 0; i < files.size(); i++ )
{
CalculateFileHashes( files[ i ], hashnames, hashvalues );
ClipboardText += FileName( files[ i ] ) + L"\r\n";
MsgBoxMessage += FileName( files[ i ] ) + L"\r\n";
for( j = 0; j < hashvalues.size(); j++ )
{
// Clipboard Text is easy...
// Just dump the information
ClipboardText += hashnames[ j ] + L": " + hashvalues[ j ] + L"\r\n";
// Keep the Message Box reasonable
if( files.size() <= 2 )
{
// Less than 2 files - Dump everything
// inot the MessageBox
MsgBoxMessage += L" ";
MsgBoxMessage += hashnames[ j ] + L": ";
MsgBoxMessage += Snip( hashvalues[ j ] ) + L"\r\n";
}
else
{
if( 0 == i || 1 == i )
{
// The first two get a full print...
MsgBoxMessage += L" ";
MsgBoxMessage += hashnames[ j ] + L": ";
MsgBoxMessage += Snip( hashvalues[ j ] ) + L"\r\n";
}
else
if( 0 == j )
{
MsgBoxMessage += L" ...\r\n";
}
}
// End - Keep the Message Box reasonable
} // for( j = 0; j < hashnames.size(); j++ )
// Pretty Print
if( i + 1 < files.size() )
{
ClipboardText += L"\r\n";
if( files.size() <= 2 )
{
MsgBoxMessage += L"\r\n";
}
}
} // for( i = 0; i < files.size(); i++ )
SetClipboardText( pCmdInfo->hwnd, ClipboardText );
#ifdef _UNICODE
MessageBox( pCmdInfo->hwnd, MsgBoxMessage.c_str(),
_T("File Checksum Results"), MB_ICONINFORMATION );
#else
MessageBox( pCmdInfo->hwnd, StringNarrow( MsgBoxMessage ).c_str(),
_T("File Checksum Results"), MB_ICONINFORMATION );
#endif
return S_OK;
break;
}
case 1:
{
assert( false );
break;
}
default:
break;
}
return E_INVALIDARG;
}
HRESULT CCreateHash::GetCommandString( UINT idCmd, UINT uFlags,
UINT* pwReserved, LPSTR pszName, UINT cchMax )
{
pwReserved; // Warning C4100 suppression
// Check idCmd, it must be 0 since we have only one menu item.
if ( 0 != idCmd ) { return E_INVALIDARG; }
// If Explorer is asking for a help std::string, copy our std::string
// into the supplied buffer.
if( uFlags & GCS_HELPTEXT )
{
if ( uFlags & GCS_UNICODE )
{
LPCWSTR szText = L"File Checksum Extension by Jeffrey Walton";
// We need to cast pszName to a Unicode std::string, and then use the
// Unicode std::string copy API.
lstrcpynW ( reinterpret_cast<LPWSTR>( pszName ), szText, cchMax );
}
else
{
LPCSTR szText = "File Checksum Extension by Jeffrey Walton";
// Use the ANSI std::string copy API to return the help std::string.
lstrcpynA ( pszName, szText, cchMax );
}
return S_OK;
}
return E_INVALIDARG;
}
HRESULT CCreateHash::QueryContextMenu( HMENU hmenu, UINT uMenuIndex,
UINT uidFirstCmd, UINT uidLastCmd, UINT uFlags )
{
uidFirstCmd; // Warning C4100 suppression
uidLastCmd; // Warning C4100 suppression
// If the flags include CMF_DEFAULTONLY then we shouldn't do anything.
if( uFlags & CMF_DEFAULTONLY )
{ return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, 0 ); }
if( files.size() > 1 )
{
InsertMenu( hmenu, uMenuIndex, MF_BYPOSITION,
uidFirstCmd, _T("Create Checksums") );
}
else
{
InsertMenu( hmenu, uMenuIndex, MF_BYPOSITION,
uidFirstCmd, _T("Create Checksum") );
}
return MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_NULL, 1 );
}
STDMETHODIMP CCreateHash::Initialize( LPCITEMIDLIST pidlFolder,
LPDATAOBJECT pDataObj, HKEY hProgID )
{
pidlFolder; // Warning C4100 suppression
hProgID; // Warning C4100 suppression
FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stg = { TYMED_HGLOBAL };
HDROP hDrop;
// Look for CF_HDROP data in the data object. If there
// is no such data, return an error back to Explorer.
if( FAILED( pDataObj->GetData ( &fmt, &stg ) ))
{ return E_INVALIDARG; }
// Get a pointer to the actual data.
hDrop = static_cast<HDROP>( GlobalLock ( stg.hGlobal ) );
// Make sure it worked.
if( NULL == hDrop )
{ return E_INVALIDARG; }
// Sanity check - make sure there is at least one filename.
UINT uNumFiles = DragQueryFile( hDrop, static_cast<UINT>(-1), NULL, 0 );
if( 0 == uNumFiles )
{
GlobalUnlock ( stg.hGlobal );
ReleaseStgMedium ( &stg );
return E_INVALIDARG;
}
HRESULT hr = S_OK;
// The author has encountered situations where
// MAX_PATH*2 was a bit too small...
TCHAR file[ MAX_PATH * 4 + 1 ];
// Loop through all the files that were selected.
for(UINT i = 0; i < uNumFiles; i++)
{
DragQueryFile( static_cast<HDROP>( stg.hGlobal ), i, file, MAX_PATH * 4 );
// If the file name is a directory, silently skip
// We should not encounter this...
if (::GetFileAttributes( file ) & FILE_ATTRIBUTE_DIRECTORY)
{ continue; }
// Add the file name to the end of the list.
#ifdef UNICODE
files.push_back( file );
#else
files.push_back( StringWiden( file ) );
#endif
}
std::sort( files.begin(), files.end() );
GlobalUnlock ( stg.hGlobal );
ReleaseStgMedium ( &stg );
return hr;
}
bool CCreateHash::CalculateFileHashes( const std::wstring& filename,
std::vector< std::wstring >& hashnames,
std::vector< std::wstring >& hashvalues )
{
CryptoPP::MD5 hashMD5;
CryptoPP::HashFilter filterMD5(hashMD5);
CryptoPP::SHA1 hashSHA1;
CryptoPP::HashFilter filterSHA1(hashSHA1);
CryptoPP::SHA256 hashSHA256;
CryptoPP::HashFilter filterSHA256(hashSHA256);
CryptoPP::SHA512 hashSHA512;
CryptoPP::HashFilter filterSHA512(hashSHA512);
CryptoPP::Whirlpool hashWhirlpool;
CryptoPP::HashFilter filterWhirlpool(hashWhirlpool);
std::auto_ptr<CryptoPP::ChannelSwitch>
channelSwitch(new CryptoPP::ChannelSwitch);
channelSwitch->AddDefaultRoute(filterMD5);
channelSwitch->AddDefaultRoute(filterSHA1);
channelSwitch->AddDefaultRoute(filterSHA256);
channelSwitch->AddDefaultRoute(filterSHA512);
channelSwitch->AddDefaultRoute(filterWhirlpool);
try {
CryptoPP::FileSource( StringNarrow( filename ).c_str(),
true, channelSwitch.release() );
}
catch( CryptoPP::Exception& e ) { e; return false; } // e.what()
catch( std::exception& e ) { e; return false; } // e.what()
catch( ... ) { return false; }
std::string digest;
CryptoPP::HexEncoder encoder( new CryptoPP::StringSink( digest ),
true /* uppercase */ );
hashnames.clear(); hashvalues.clear();
filterMD5.TransferTo( encoder );
hashnames.push_back( StringWiden( filterMD5.AlgorithmName() ) );
hashvalues.push_back( StringWiden( digest ) );
digest.erase();
filterSHA1.TransferTo( encoder );
hashnames.push_back( StringWiden( filterSHA1.AlgorithmName() ) );
hashvalues.push_back( StringWiden( digest ) );
digest.erase();
filterSHA256.TransferTo( encoder );
hashnames.push_back( StringWiden( filterSHA256.AlgorithmName() ) );
hashvalues.push_back( StringWiden( digest ) );
digest.erase();
filterSHA512.TransferTo( encoder );
hashnames.push_back( StringWiden( filterSHA512.AlgorithmName() ) );
hashvalues.push_back( StringWiden( digest ) );
digest.erase();
filterWhirlpool.TransferTo( encoder );
hashnames.push_back( StringWiden( filterWhirlpool.AlgorithmName() ) );
hashvalues.push_back( StringWiden( digest ) );
digest.erase();
return true;
}
std::string CCreateHash::FileName( const std::string& file )
{
std::string filename = file;
std::string::size_type pos = file.find_last_of( "\\" );
if( std::string::npos != pos )
{
if( pos <= file.length() )
{ filename = file.substr( pos + 1 ); }
}
return filename;
}
std::wstring CCreateHash::FileName( const std::wstring& file )
{
std::wstring filename = file;
std::wstring::size_type pos = file.find_last_of( L"\\" );
if( std::string::npos != pos )
{
if( pos <= file.length() )
{ filename = file.substr( pos + 1 ); }
}
return filename;
}
bool CCreateHash::SetClipboardText( HWND hwnd, const std::wstring& text )
{
// Prepare Clipboard
if( FALSE != OpenClipboard( hwnd ) )
{
EmptyClipboard();
CloseClipboard();
}
#ifdef UNICODE
return SetClipboardTextWide( hwnd, text );
#else
return SetClipboardTextNarrow( hwnd, StringNarrow( text ) );
#endif
}
bool CCreateHash::SetClipboardText( HWND hwnd, const std::string& text )
{
// Prepare Clipboard
if( FALSE != OpenClipboard( hwnd ) )
{
EmptyClipboard();
CloseClipboard();
}
#ifdef UNICODE
return SetClipboardTextWide( hwnd, StringWiden( text ) );
#else
return SetClipboardTextNarrow( hwnd, text );
#endif
}
bool CCreateHash::SetClipboardTextWide( HWND hwnd, const std::wstring& text )
{
HGLOBAL hClipboardText = NULL;
// Open the clipboard
if( FALSE == OpenClipboard( hwnd ) )
{ return false; }
// Allocate memory for the text
hClipboardText = GlobalAlloc(GMEM_DDESHARE,
(text.length() + 1) * sizeof( wchar_t ) );
if( NULL == hClipboardText )
{
CloseClipboard();
return false;
}
wchar_t* pText = static_cast<wchar_t*>( GlobalLock( hClipboardText ) );
try
{
memcpy( pText, text.c_str(), text.length() * sizeof( wchar_t ) );
// Assure NULL termination
pText[ text.length() ] = L'\0';
}
catch( ... )
{
CloseClipboard();
return false;
}
GlobalUnlock( hClipboardText );
// Place the text on the clipboard.
bool result = ( FALSE != SetClipboardData( CF_UNICODETEXT, hClipboardText ) );
CloseClipboard();
return result;
}
bool CCreateHash::SetClipboardTextNarrow( HWND hwnd, const std::string& text )
{
HGLOBAL hClipboardText = NULL;
// Open the clipboard
if( FALSE == OpenClipboard( hwnd ) )
{ return false; }
// Allocate memory for the text
hClipboardText = GlobalAlloc(GMEM_DDESHARE,
(text.length() + 1) * sizeof( char ) );
// Sanity check
if( NULL == hClipboardText )
{
CloseClipboard();
return false;
}
char* pText = static_cast<char*>( GlobalLock( hClipboardText ) );
try
{
memcpy( pText, text.c_str(), text.length() * sizeof( char* ) );
// Assure NULL termination
pText[ text.length() ] = '\0';
}
catch( ... )
{
CloseClipboard();
return false;
}
GlobalUnlock( hClipboardText );
// Place the text on the clipboard.
bool result = ( FALSE != SetClipboardData( CF_TEXT, hClipboardText ) );
CloseClipboard();
return result;
}
std::wstring CCreateHash::Snip( const std::wstring& hash )
{
const unsigned int SIZE = 32;
std::wstring result;
if( hash.length() < SIZE + 4 ) { return hash; }
result = hash.substr( 0, SIZE/2 );
result += L"...";
result += hash.substr( hash.length() - SIZE/2 );
return result;
}
#pragma warning( pop )