Click here to Skip to main content
15,891,828 members
Articles / Desktop Programming / MFC

An MFC extension library to enable DLL plug-in technology for your application using MESSAGE_MAPs

Rate me:
Please Sign up or sign in to vote.
4.85/5 (47 votes)
8 Jun 2004CPOL17 min read 578.4K   8.6K   238  
A plug-in architecture which allows you to write plug-in DLLs for your application and extend/modify its functionality.
//////////////////////////////////////////////////////////////////////
//	Implemented by Samuel Gonzalo 
//
//	You may freely use or modify this code 
//////////////////////////////////////////////////////////////////////
//
// Path.cpp: implementation of the CPath class.
// http://www.codeproject.com/file/CFileFinderEx.asp
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Path.h"
#include "Shlwapi.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CPath::CPath()
{
	_bIsRelative = FALSE;
}

CPath::CPath(LPCTSTR szPath, BOOL bIsFolderPath, BOOL bHasArguments)
{
	SetPath(szPath, bIsFolderPath, bHasArguments);
}

CPath::CPath(DWORD dwSpecial)
{
	SetPath(dwSpecial);
}

CPath::~CPath()
{

}

void CPath::SetPath(DWORD dwSpecial)
{
	switch (dwSpecial)
	{
	case PATH_CMDLINE:
		SetPath(GetCommandLine(), FALSE, TRUE);
		break;

	case PATH_MODULE:
		{
			char szPath[_MAX_PATH];
			GetModuleFileName(0, szPath, _MAX_PATH);
			SetPath(szPath);
		}
		break;
	}
}

void CPath::SetPath(LPCTSTR szPath, BOOL bIsFolderPath, BOOL bHasArguments)
{
	char szParamPath[_MAX_PATH];
	char szDrive[_MAX_DRIVE], szDir[_MAX_DIR];
	char szName[_MAX_FNAME], szExt[_MAX_EXT];

	// Reset
	_sOriginalPath.Empty();
	_sDriveLabel.Empty();
	_bIsRelative = FALSE;
	_aDir.RemoveAll();
	_sExtName.Empty();
	_aArgs.RemoveAll();

	// Original path
	_sOriginalPath = szPath;

	// Get args and remove them from path
	szParamPath[0] = 0x0;
	strcpy(szParamPath, szPath);

	if (bHasArguments)
	{
		_sArgs = PathGetArgs(szParamPath);
		PathRemoveArgs(szParamPath);
	}

	PathUnquoteSpaces(szParamPath);
	if (szParamPath[0] == 0x0) return;

	_splitpath(szParamPath, szDrive, szDir, szName, szExt);

	// Drive
	_sDrive = szDrive;

	// Directory
	_sDir = szDir;
	_sDir.Replace('/', '\\');
	if (!_sDir.IsEmpty()) _bIsRelative = (_sDir[0] != '\\');
	
	// FileTitle
	if (bIsFolderPath)
	{
		_sDir = CPath::AddBackSlash(_sDir);
		_sDir += szName;
		_sDir = CPath::AddBackSlash(_sDir);
	}
	else
	{
		_sFileTitle = szName;
	}

	// Get extension name (e.g.: "txt")
	if (IsFilePath())
	{
		_sExtName = szExt;
		_sExtName.Remove('.');
	}
}

BOOL CPath::IsLocalPath()
{
	return !_sDrive.IsEmpty() && !_bIsRelative;
}

BOOL CPath::IsRelativePath()
{
	return _bIsRelative;
}

BOOL CPath::IsFilePath()
{
	return !_sFileTitle.IsEmpty();
}

BOOL CPath::ExistFile()
{
	if (!IsFilePath()) return FALSE;

	return PathFileExists(GetPath());
}

BOOL CPath::ExistLocation()
{
	return PathFileExists(GetLocation());
}

CString CPath::GetAbsolutePath(LPCTSTR szBaseFolder)
{
	if (!IsRelativePath()) return sCEmptyString;

	char	szAbsolutePath[_MAX_PATH];
	CString sFullPath(szBaseFolder);

	if (sFullPath.IsEmpty()) return sCEmptyString;

	sFullPath = CPath::AddBackSlash(sFullPath);
	sFullPath += GetPath();

	if (!PathCanonicalize(szAbsolutePath, sFullPath)) return sCEmptyString;

	return szAbsolutePath;
}

CString CPath::GetRelativePath(LPCTSTR szBaseFolder)
{
	if (IsRelativePath()) return sCEmptyString;

	char	szRelativePath[_MAX_PATH];
	CString	sRelPath;

	PathRelativePathTo(szRelativePath, szBaseFolder, FILE_ATTRIBUTE_DIRECTORY, 
					GetPath(), IsFilePath() ? 0 : FILE_ATTRIBUTE_DIRECTORY);

	sRelPath = szRelativePath;
	if (sRelPath.GetLength() > 1)
	{
		// Remove ".\" from the beginning
		if ((sRelPath[0] == '.') && (sRelPath[1] == '\\'))
			sRelPath.Right(sRelPath.GetLength() - 2);
	}

	return sRelPath;
}

CString CPath::GetPath(BOOL bAppendArgs, BOOL bOriginal)
{
	CString sPath;

	if (bOriginal)
		sPath = _sOriginalPath;
	else
		sPath = GetLocation() + GetFileName();

	if (bAppendArgs) sPath += GetArgument();

	return sPath;
}

CString	CPath::GetShortPath()
{
	char szShortPath[_MAX_PATH];
	szShortPath[0] = 0x0;

	//GetShortPathName(GetPath(), szShortPath, _MAX_PATH);

	return szShortPath;
}

CString	CPath::GetLongPath()
{
	char szLongPath[_MAX_PATH];
	szLongPath[0] = 0x0;

	//GetLongPathName(GetPath(), szLongPath, _MAX_PATH);

	return szLongPath;
}

CString CPath::GetDrive()
{
	return _sDrive;
}

CString	CPath::GetDriveLabel(BOOL bPCNameIfNetwork)
{
	if (_sDriveLabel.IsEmpty() && !IsRelativePath())
	{
		if ((bPCNameIfNetwork) && (!IsLocalPath()))
			_sDriveLabel = GetDir(0);
		else
		{
			CString sRoot;
			char	szVolumeName[256];

			szVolumeName[0] = '\0';
			if (IsLocalPath())
			{
				sRoot = _sDrive + CString("\\");
			}
			else if (GetDirCount() > 1)
			{
				sRoot.Format("\\\\%s\\%s\\", GetDir(0), GetDir(1));
			}

			GetVolumeInformation(sRoot, szVolumeName, 255, NULL, NULL, NULL, NULL, 0);

			_sDriveLabel = szVolumeName;
		}
	}

	return _sDriveLabel;
}

int	CPath::GetDirCount()
{
	FillDirArray();
	return _aDir.GetSize();
}

CString CPath::GetDir(int nIndex)
{
	if (nIndex < 0)
		return _sDir;
	else if (nIndex < GetDirCount())
	{
		FillDirArray();
		return _aDir[nIndex];
	}

	return sCEmptyString;
}

CString	CPath::GetLocation()
{
	return _sDrive + GetDir();
}

CString CPath::GetFileTitle()
{
	return _sFileTitle;
}

CString CPath::GetFileName()
{
	return _sFileTitle + GetExtension();
}

CString CPath::GetExtension()
{
	if (_sExtName.IsEmpty()) return sCEmptyString;

	return CString(".") + _sExtName;
}

CString CPath::GetExtName()
{
	return _sExtName;
}

int CPath::GetArgCount()
{
	FillArgArray();
	return _aArgs.GetSize();
}

CString CPath::GetArgument(int nIndex, BOOL bGetFlag)
{
	if (nIndex < 0)
	{
		if (_sArgs.IsEmpty())
		{
			for (int nItem = 0; nItem < _aArgs.GetSize(); nItem++)
				_sArgs += _aArgs[nItem].GetString();

			_sArgs.TrimLeft();
		}

		return _sArgs;
	}
	else if (nIndex < GetArgCount())
	{
		FillArgArray();

		if (bGetFlag)
			return _aArgs[nIndex].sFlag;
		else
			return _aArgs[nIndex].sValue;
	}

	return sCEmptyString;
}

void CPath::SetArguments(LPCTSTR szArgs)
{
	_aArgs.RemoveAll();
	_sArgs = szArgs;
}

void CPath::AddSetArgument(LPCTSTR szFlag, LPCTSTR szArgument)
{
	int	nIndex;

	nIndex = FindArgument(szFlag);

	if (nIndex != -1)
	{
		// An argument with the same flag already exists. Update it!
		_aArgs[nIndex].sValue = szArgument;
	}
	else
	{
		CArgument arg;

		arg.sValue = szArgument;
		arg.SetFlag(szFlag);

		_aArgs.Add(arg);
		_sArgs.Empty();
	}
}

void CPath::RemoveArgument(int nIndex)
{
	if ((nIndex >= 0) && (nIndex < _aArgs.GetSize()))
	{
		_aArgs.RemoveAt(nIndex);
		_sArgs.Empty();
	}
}

int CPath::FindArgument(LPCTSTR szFlag)
{
	bool		bFound = false;
	int			nIndex = -1 ;
	CArgument	arg;

	FillArgArray();

	arg.SetFlag(szFlag);

	if (!arg.sFlag.IsEmpty())
	{
		for (nIndex = 0; nIndex < _aArgs.GetSize(); nIndex++)
		{
			bFound = (_aArgs[nIndex].sFlag.CompareNoCase(arg.sFlag) == 0);
			if (bFound) break;
		}
	}

	return (bFound ? nIndex : -1);
}

BOOL CPath::GetFileSize(__int64 &nSize)
{
	BOOL bResult;

	bResult = FillFileInfoStruct();
	nSize = ((__int64)_fis.nFileSizeHigh * (__int64)MAXDWORD) + (__int64)_fis.nFileSizeLow;
	return bResult;
}

BOOL CPath::GetFileTime(CTime &time, DWORD dwType)
{
	BOOL bResult;
	FILETIME *pTime = NULL;

	bResult = FillFileInfoStruct();
	switch (dwType)
	{
	case FILE_CREATION:	pTime = &_fis.ftCreationTime;	break;
	case FILE_WRITE:	pTime = &_fis.ftLastWriteTime;	break;
	case FILE_ACCESS:	
	default:			pTime = &_fis.ftLastAccessTime;	break;
	}

	if (pTime != NULL) time = CTime(*pTime);
	return bResult;
}

/////////////////////////////////////////////////////////////////////////////////////////////
// Private methods

// This function must be called whenever _aDir array is needed, since this
// method is the one which parses _sDir and fill _aDir
void CPath::FillDirArray()
{
	if (_sDir.IsEmpty() || (_aDir.GetSize() > 0)) return;

	int nFrom, nTo;

	// nFrom: 0 - relative / 1 - local / 2 - network
	nFrom = IsLocalPath() ? 1 : (IsRelativePath() ? 0 : 2);

	while ((nTo = _sDir.Find('\\', nFrom)) != -1)
	{
		_aDir.Add(_sDir.Mid(nFrom, nTo - nFrom));
		nFrom = nTo + 1;
	}
}

// This function must be called whenever _aArgs array is needed, since this
// method is the one which parses _sArgs and fill _aArgs
void CPath::FillArgArray()
{
	if (_sArgs.IsEmpty() || (_aArgs.GetSize() > 0)) return;

	CString		sArgs(_sArgs);
	int			nFrom, nTo;
	bool		bQuotedArg = false;
	CArgument	arg;

	sArgs.TrimLeft();
	sArgs.TrimRight();

	// add a blank space at the end of the string to include the last argument
	sArgs += " ";
	while ((nTo = sArgs.FindOneOf(" \"")) != -1)
	{
		bQuotedArg = (sArgs[nTo] == '\"');

		if (bQuotedArg)
		{
			nFrom = nTo + 1;
			if ((nTo = sArgs.Find('\"', nFrom)) == -1) break;

			arg.sValue = sArgs.Mid(nFrom, nTo - nFrom);
		}
		else
		{
			CString *pStr;

			if ((sArgs[0] == '/') || (sArgs[0] == '-'))
			{
				if (!arg.sFlag.IsEmpty())
				{
					arg.SetFlag(arg.sFlag);
					_aArgs.Add(arg);
					arg.sFlag.Empty();
					arg.sValue.Empty();
				}

				pStr = &arg.sFlag;
			}
			else
				pStr = &arg.sValue;

			*pStr = sArgs.Left(nTo);
		}

		if (!arg.sValue.IsEmpty())
		{
			arg.SetFlag(arg.sFlag);
			_aArgs.Add(arg);
			arg.sFlag.Empty();
			arg.sValue.Empty();
		}

		sArgs = sArgs.Right(sArgs.GetLength() - nTo - 1);
		sArgs.TrimLeft();
	}

	// if the last argument is only a flag it hasn't been added yet
	if (!arg.sFlag.IsEmpty())
	{
		arg.SetFlag(arg.sFlag);
		_aArgs.Add(arg);
	}
}

BOOL CPath::FillFileInfoStruct()
{
	HANDLE	hFile;
	BOOL	bResult;

	::memset(&_fis, 0, sizeof(_fis));

	hFile = CreateFile(GetPath(), GENERIC_READ, FILE_SHARE_READ, NULL, 
						OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN |
						FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM, NULL);

	if (hFile == INVALID_HANDLE_VALUE) return FALSE;

	bResult = GetFileInformationByHandle(hFile, &_fis);

	CloseHandle(hFile);

	return bResult;
}

CString CPath::AddBackSlash(LPCTSTR szFolderPath, BOOL bInverted)
{
	CString	sResult(szFolderPath);
	int		nLastChar = sResult.GetLength() - 1;

	if (nLastChar >= 0)
	{
		if ((sResult[nLastChar] != '\\') && (sResult[nLastChar] != '/'))
			sResult += bInverted ? '/' : '\\';
	}

	return sResult;
}

CString CPath::RemoveBackSlash(LPCTSTR szFolderPath)
{
	CString	sResult(szFolderPath);
	int		nLastChar = sResult.GetLength() - 1;

	if (nLastChar >= 0)
	{
		if ((sResult[nLastChar] == '\\') || (sResult[nLastChar] == '/'))
			sResult = sResult.Left(nLastChar);
	}

	return sResult;
}

CPath::operator LPCTSTR ()
{
	_sLPCTSTRPath = GetPath();
	return _sLPCTSTRPath;
}

const CPath& CPath::operator = (LPCTSTR szPath)
{
	SetPath(szPath);
	return *this;
}

const CPath& CPath::operator = (CPath &ref)
{
	_aArgs.RemoveAll();
	_aArgs.Copy(ref._aArgs);
	_aDir.RemoveAll();
	_aDir.Copy(ref._aDir);
	
	_bIsRelative = ref._bIsRelative;

	_fis = ref._fis;

	_sArgs = ref._sArgs;
	_sDir = ref._sDir;
	_sDrive = ref._sDrive;
	_sDriveLabel = ref._sDriveLabel;
	_sExtName = ref._sExtName;
	_sFileTitle = ref._sFileTitle;
	_sOriginalPath = ref._sOriginalPath;
	return *this;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Sirius Analytical Instruments
United Kingdom United Kingdom
A research and development programmer working for a pharmaceutical instrument company for the past 17 years.

I am one of those lucky people who enjoys his work and spends more time than he should either doing work or reseaching new stuff. I can also be found on playing DDO on the Cannith server (Send a tell to "Maetrim" who is my current main)

I am also a keep fit fanatic, doing cross country running and am seriously into [url]http://www.ryushinkan.co.uk/[/url] Karate at this time of my life, training from 4-6 times a week and recently achieved my 1st Dan after 6 years.

Comments and Discussions