496 lines
12 KiB
C++
496 lines
12 KiB
C++
// =============================================================================
|
|
// Class Implementation : COXUserTool
|
|
// =============================================================================
|
|
//
|
|
// Source file : UserTool.cpp
|
|
|
|
// Version: 9.3
|
|
|
|
// This software along with its related components, documentation and files ("The Libraries")
|
|
// is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
|
|
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
|
|
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
|
|
// to obtain this file, or directly from our office. For a copy of the license governing
|
|
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
|
|
|
|
// //////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "StdAfx.h"
|
|
#include "OXUsertl.h"
|
|
#include <direct.h> // For directory functions
|
|
|
|
#include "UTBStrOp.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
const UINT USER_TOOL_SCHEMA = 1;
|
|
IMPLEMENT_SERIAL( COXUserTool, CObject, USER_TOOL_SCHEMA );
|
|
|
|
#define new DEBUG_NEW
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Definition of static members
|
|
|
|
|
|
// Data members -------------------------------------------------------------
|
|
// protected:
|
|
|
|
// CString m_strMenuText;
|
|
// --- text to display in menu
|
|
|
|
// CString m_strCommand;
|
|
// --- command to execute
|
|
|
|
// CString m_strArgs;
|
|
// --- command arguments
|
|
|
|
// CString m_strDirectory;
|
|
// --- initial directory
|
|
|
|
// UINT m_uiShowFlag;
|
|
// --- flags to pass to an WINEXEC command
|
|
|
|
// private:
|
|
|
|
// Member functions ---------------------------------------------------------
|
|
// public:
|
|
|
|
// This function replaces occurances of the key within the given
|
|
// string object with the specified replacement, optionally
|
|
// ignoring case.
|
|
//
|
|
// returns: the number of substitutions made.
|
|
|
|
static int Replace( CString& str, LPCTSTR pcszKey,
|
|
LPCTSTR pcszReplacement,
|
|
BOOL bIgnoreCase = FALSE )
|
|
{
|
|
ASSERT( pcszKey != NULL );
|
|
ASSERT( *pcszKey != _T('\0') );
|
|
ASSERT( pcszReplacement != NULL );
|
|
|
|
if ( pcszKey == NULL || *pcszKey == _T('\0') || pcszReplacement == NULL )
|
|
return -1;
|
|
|
|
int iStrLength = str.GetLength();
|
|
int iKeyLength = lstrlen( pcszKey );
|
|
|
|
// A quick optimization; if the key is larger than our current string,
|
|
// it cannot exist within -- get out of here.
|
|
|
|
if ( iKeyLength > iStrLength )
|
|
return 0;
|
|
|
|
// First, figure out how large a buffer we need. If the replacement
|
|
// is smaller or equal to the key, we can simply allocate the same
|
|
// size as the number of characters currently in the string. If not,
|
|
// we can figure out the maximum number of keys that will be found,
|
|
// multiply by the size differential and allocate that much more.
|
|
// Once we have a number, we can allocate the buffer.
|
|
|
|
int iBufLength;
|
|
int iRepLength = lstrlen( pcszReplacement );
|
|
|
|
if ( iRepLength <= iKeyLength )
|
|
{
|
|
iBufLength = iStrLength + 1;
|
|
}
|
|
else
|
|
{
|
|
int iMaxKeys = iStrLength / iKeyLength + 1;
|
|
int iDelta = iRepLength - iKeyLength;
|
|
iBufLength = iStrLength + iMaxKeys * iDelta + 1;
|
|
}
|
|
|
|
LPTSTR p = new TCHAR[iBufLength];
|
|
memset(p,0,iBufLength*sizeof(TCHAR));
|
|
|
|
if ( p == NULL )
|
|
return -1;
|
|
|
|
// declare some strings to handle case insensitivity
|
|
CString strStr( str );
|
|
CString strKey( pcszKey );
|
|
|
|
if ( bIgnoreCase )
|
|
{
|
|
strStr.MakeUpper();
|
|
strKey.MakeUpper();
|
|
}
|
|
|
|
// set up some loop controls and get to work!
|
|
LPCTSTR pSource = str;
|
|
LPCTSTR pCurr = strStr;
|
|
LPTSTR pOut = p;
|
|
int iReplacements = 0;
|
|
|
|
while ( *pCurr != _T('\0') )
|
|
{
|
|
// if we find a match...
|
|
if ( _tcsnccmp( pCurr, strKey, iKeyLength ) == 0 )
|
|
{
|
|
// copy the replacement string into the output buffer
|
|
lstrcpy( pOut, pcszReplacement );
|
|
|
|
// Increment the output pointer by the string just copied.
|
|
// Increment the source and current pointers by the key length.
|
|
// Increment the replacement count.
|
|
|
|
pOut += iRepLength;
|
|
pSource += iKeyLength;
|
|
pCurr += iKeyLength;
|
|
iReplacements++;
|
|
}
|
|
else
|
|
{
|
|
// otherwise, copy the character across and increment pointers
|
|
*( pOut++ ) = *( pSource++ );
|
|
pCurr++;
|
|
}
|
|
}
|
|
|
|
str = p;
|
|
delete [] p;
|
|
return iReplacements;
|
|
}
|
|
|
|
// This function determines if a disk file of the specified name exists,
|
|
// optionally returning file status information.
|
|
//
|
|
// returns: true if the file exists, false otherwise.
|
|
|
|
static BOOL FileExists( LPCTSTR pcszFilename, CFileStatus* pfs = NULL )
|
|
{
|
|
CFileStatus fs;
|
|
if ( pfs == NULL )
|
|
pfs = &fs;
|
|
return CFile::GetStatus( pcszFilename, *pfs );
|
|
}
|
|
|
|
// This function locates an item of the given ID with the specified
|
|
// menu, optionally returning the item's zero-indexed position.
|
|
//
|
|
// returns: true if found, false otherwise.
|
|
|
|
static BOOL FindMenuItem( CMenu* pMenu, UINT uiID, UINT* puiPos )
|
|
{
|
|
if ( pMenu != NULL )
|
|
{
|
|
UINT uiNum = pMenu->GetMenuItemCount();
|
|
for ( UINT ui = 0; ui < uiNum; ui++ )
|
|
{
|
|
if ( pMenu->GetMenuItemID( ui ) == uiID )
|
|
{
|
|
if ( puiPos != NULL )
|
|
*puiPos = ui;
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// This function launches the specified command from within the given
|
|
// directory, showing (or hiding) the window based upon the supplied
|
|
// ShowWindow compatible parameter.
|
|
//
|
|
// returns: true if successful, false otherwise.
|
|
|
|
static BOOL Run( LPCTSTR pcszDir, LPCTSTR pcszCmd, UINT uiCmdShow )
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
|
|
// Change directory if needed.
|
|
|
|
if ( pcszDir != NULL && *pcszDir != _T('\0') )
|
|
{
|
|
_chdrive( _totupper( *pcszDir ) - _T('\0') + 1 );
|
|
_tchdir( pcszDir );
|
|
}
|
|
|
|
// Launch the command and set the return variable if successful.
|
|
|
|
const UINT FIRST_VALID_INSTANCE = 32;
|
|
|
|
#ifdef _UNICODE
|
|
const size_t len = ::lstrlen(pcszCmd);
|
|
LPSTR pszCommandLine = new char[(char)len];
|
|
size_t t;
|
|
UTBStr::wcstombs(&t, pszCommandLine, len, pcszCmd, lstrlen(pcszCmd));
|
|
if ( WinExec( pszCommandLine, uiCmdShow ) >= FIRST_VALID_INSTANCE )
|
|
#else
|
|
if ( WinExec( pcszCmd, uiCmdShow ) >= FIRST_VALID_INSTANCE )
|
|
#endif
|
|
bReturn = TRUE;
|
|
|
|
ASSERT( bReturn );
|
|
return bReturn;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// COXUserTool implementation.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
COXUserTool::COXUserTool()
|
|
: m_uiShowFlag( SW_SHOWNORMAL )
|
|
{
|
|
}
|
|
|
|
COXUserTool::COXUserTool( const COXUserTool& rhs )
|
|
{
|
|
*this = rhs;
|
|
}
|
|
|
|
COXUserTool::~COXUserTool()
|
|
{
|
|
}
|
|
|
|
void COXUserTool::Serialize( CArchive& archive )
|
|
{
|
|
CObject::Serialize( archive );
|
|
|
|
if ( archive.IsStoring() )
|
|
{
|
|
archive << m_strMenuText;
|
|
archive << m_strCommand;
|
|
archive << m_strArgs;
|
|
archive << m_strDirectory;
|
|
LONG l = m_uiShowFlag;
|
|
archive << l;
|
|
}
|
|
else
|
|
{
|
|
archive >> m_strMenuText;
|
|
archive >> m_strCommand;
|
|
archive >> m_strArgs;
|
|
archive >> m_strDirectory;
|
|
LONG l;
|
|
archive >> l;
|
|
m_uiShowFlag = (UINT)l;
|
|
}
|
|
}
|
|
|
|
BOOL COXUserTool::ParseReplacement( LPCTSTR p, CString& strKey,
|
|
CString& strData ) const
|
|
{
|
|
CString strTmp( p );
|
|
int iIndex = strTmp.Find( _T('=') );
|
|
|
|
if ( iIndex > -1 )
|
|
{
|
|
strKey = strTmp.Left( iIndex );
|
|
strData = strTmp.Right( strTmp.GetLength() - iIndex - 1 );
|
|
return !strKey.IsEmpty() && !strData.IsEmpty();
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL COXUserTool::Execute( CStringList* pReplacements ) const
|
|
{
|
|
CString strCmd( GetCommand() );
|
|
CString strArgs( GetArgs() );
|
|
CString strDir( GetDirectory() );
|
|
|
|
if ( ( pReplacements != NULL ) && !pReplacements->IsEmpty() )
|
|
{
|
|
CString strKey, strData;
|
|
|
|
for ( POSITION pos = pReplacements->GetHeadPosition();
|
|
pos != NULL;
|
|
pReplacements->GetNext( pos ) )
|
|
{
|
|
CString& str = pReplacements->GetAt( pos );
|
|
|
|
if ( ParseReplacement( str, strKey, strData ) )
|
|
{
|
|
Replace( strCmd, strKey, strData );
|
|
Replace( strArgs, strKey, strData );
|
|
Replace( strDir, strKey, strData );
|
|
}
|
|
}
|
|
}
|
|
|
|
CString strCmdLine( strCmd );
|
|
if ( !strArgs.IsEmpty() )
|
|
{
|
|
strCmdLine += _T(" ");
|
|
strCmdLine += strArgs;
|
|
}
|
|
|
|
BOOL bReturn = Run( strDir, strCmdLine, GetShowFlag() );
|
|
ASSERT( bReturn );
|
|
return bReturn;
|
|
}
|
|
|
|
COXUserTool& COXUserTool::operator=( const COXUserTool& rhs )
|
|
{
|
|
if ( &rhs != this )
|
|
{
|
|
m_strMenuText = rhs.m_strMenuText;
|
|
m_strCommand = rhs.m_strCommand;
|
|
m_strArgs = rhs.m_strArgs;
|
|
m_strDirectory = rhs.m_strDirectory;
|
|
m_uiShowFlag = rhs.m_uiShowFlag;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
COXUserTool* COXUserTool::Clone() const
|
|
{
|
|
return new COXUserTool( *this );
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
void COXUserTool::Dump(CDumpContext& dc) const
|
|
{
|
|
CObject::Dump(dc);
|
|
dc << _T("\nm_strMenuText : ") << m_strMenuText;
|
|
dc << _T("\nm_strCommand : ") << m_strCommand;
|
|
dc << _T("\nm_strArgs : ") << m_strArgs;
|
|
dc << _T("\nm_strDirectory : ") << m_strDirectory;
|
|
}
|
|
|
|
void COXUserTool::AssertValid() const
|
|
{
|
|
CObject::AssertValid();
|
|
}
|
|
#endif
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Public utility functions.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL ReadUserToolFile( LPCTSTR pcszFilename, CObArray& a )
|
|
{
|
|
ASSERT( pcszFilename != NULL && *pcszFilename != _T('\0') );
|
|
|
|
if ( FileExists( pcszFilename ) )
|
|
{
|
|
TRY
|
|
{
|
|
CFile i( pcszFilename, CFile::modeRead | CFile::shareDenyNone );
|
|
CArchive archive( &i, CArchive::load );
|
|
INT_PTR iInitialSize = a.GetSize();
|
|
a.Serialize( archive );
|
|
return a.GetSize() > iInitialSize;
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
TRACE(_T("ReadUserToolFile exception\n"));
|
|
}
|
|
END_CATCH
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL WriteUserToolFile( LPCTSTR pcszFilename, CObArray& a )
|
|
{
|
|
ASSERT( pcszFilename != NULL && *pcszFilename != _T('\0') );
|
|
ASSERT( a.GetSize() > 0 );
|
|
|
|
TRY
|
|
{
|
|
CFile o( pcszFilename, CFile::modeWrite | CFile::modeCreate |
|
|
CFile::shareExclusive );
|
|
CArchive archive( &o, CArchive::store );
|
|
a.Serialize( archive );
|
|
return TRUE;
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
TRACE(_T("WriteUserToolFile exception\n"));
|
|
}
|
|
END_CATCH
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL AppendUserTools( CMenu* pMenu, UINT uiFirstID, const CObArray& a )
|
|
{
|
|
ASSERT( pMenu != NULL );
|
|
ASSERT( uiFirstID > 0 );
|
|
|
|
if ( pMenu != NULL && uiFirstID > 0 )
|
|
{
|
|
int iAdded = 0;
|
|
UINT uiPos;
|
|
UINT uiLastItem = pMenu->GetMenuItemCount() - 1;
|
|
|
|
// If the menu item already exists, remove all subsequent
|
|
// menu items before continuing.
|
|
|
|
if ( FindMenuItem( pMenu, uiFirstID, &uiPos ) )
|
|
{
|
|
// Used to be UINT ui, but this caused an infinite loop when
|
|
// uiPos was 0, the UINT ui can never become negative, so the test
|
|
// ui >= uiPos was never FALSE
|
|
for ( int i = uiLastItem; i >= (int)uiPos; i-- )
|
|
pMenu->RemoveMenu( i, MF_BYPOSITION );
|
|
|
|
uiLastItem = uiPos > 0 ? uiPos - 1 : 0;
|
|
}
|
|
|
|
// Continue on only if we actually have items to be added
|
|
// to the menu.
|
|
|
|
if ( a.GetSize() > 0 )
|
|
{
|
|
// Add a separator if the last item is not at the zero
|
|
// position and is not already a separator.
|
|
|
|
if ( uiLastItem > 0 &&
|
|
!( pMenu->GetMenuState( uiLastItem, MF_BYPOSITION ) & MF_SEPARATOR ) )
|
|
{
|
|
pMenu->AppendMenu( MF_SEPARATOR );
|
|
}
|
|
|
|
// Append the list of tools to the menu.
|
|
|
|
INT_PTR iNum = a.GetSize();
|
|
for ( int i = 0; i < iNum; i++ )
|
|
{
|
|
COXUserTool* pTool = (COXUserTool*)a.GetAt( i );
|
|
LPCTSTR pText = pTool->GetMenuText();
|
|
|
|
if ( pMenu->AppendMenu( MF_STRING, uiFirstID + iAdded, pText ) )
|
|
iAdded++;
|
|
}
|
|
}
|
|
else if ( uiLastItem > 0 )
|
|
{
|
|
UINT uiState = pMenu->GetMenuState( uiLastItem, MF_BYPOSITION );
|
|
if ( uiState & MF_SEPARATOR )
|
|
pMenu->RemoveMenu( uiLastItem, MF_BYPOSITION );
|
|
}
|
|
|
|
return iAdded == a.GetSize();
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void EmptyUserToolArray( CObArray& a )
|
|
{
|
|
INT_PTR iNum = a.GetSize();
|
|
if ( iNum > 0 )
|
|
{
|
|
for ( int i = 0; i < iNum; i++ )
|
|
delete (COXUserTool*)a.GetAt( i );
|
|
a.RemoveAll();
|
|
}
|
|
}
|
|
|