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

LintProject - Improving the Usability of PC-Lint with Visual C++ Solutions and Projects

,
Rate me:
Please Sign up or sign in to vote.
4.83/5 (36 votes)
29 Jan 2009CPOL13 min read 279.2K   1.7K   52  
Utility to run PC-Lint on Visual C++ solutions and projects, generating XML and HTML reports of the results.
/************************************************************************
 *
 *  Description : CSolutionLintAnalyser - class for analysing Visual C++
 *                solutions (.sln) and workspaces (.dsw) using the
 *                PC-Lint code analysis tool.
 *
 *     (c) Copyright 2004-2008 by Anna-Jayne Metcalfe (anna@riverblade.co.uk)
 *     and Beth Mackenzie (beth@riverblade.co.uk) / Riverblade Limited
 *
 *  Licence Terms:
 *
 *     This code may be freely reused, subject to the licence terms below.
 *     Please do let us know of any bugs you find or improvements you make,
 *     so that we can pass them on to the rest of the development community.
 *
 *     This code is free software; you can redistribute it and/or
 *     modify it under the terms of the Code Project Open License (CPOL)
 *     version 1.0 (http://www.codeproject.com/info/cpol10.aspx).
 *
 *     This code is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     Code Project Open Licence for further details.
 *
 ************************************************************************
 *    $Archive: /Projects/Applications/LintProject/1.4/SolutionLintAnalyser.cpp $
 *   $Revision: 25 $
 *       $Date: 23/10/08 13:12 $
 *     $Author: Anna $
 * 
 * $Nokeywords: $
 ************************************************************************/

/// \file	
/// \brief CSolutionLintAnalyser class implementation.

#include "StdAfx.h"
#include "Shared/ModuleVersion.h"
#include "Shared/StringUtils.h"
#include "Shared/FileUtils.h"
#include "Shared/ResourceUtils.h"
#include "Shared/BrowserUtils.h"
#include "Shared/SplitPath.h"
#include "Shared/SolutionFileReader.h"
#include "Resource.h"

#include "SolutionLintAnalyser.h"


using namespace std;


CSolutionLintAnalyser::CSolutionLintAnalyser(	const CString& sSolutionFilePathName,
												const CString& sResultsFileFolder,
												const CString& sLintConfigFile,
												const CString& sAdditionalProjectParams,
												const CString& sAdditionalParams,
												const CString& sConfiguration,
                        						const std::set<CString>& setExcludedProjects)
	:	m_sLintFolder(_T("") ),
		m_sSolutionFilePathName(sSolutionFilePathName),
		m_sSolutionFileFolder(_T("") ),
		m_sSolutionName(_T("") ),
		m_sResultsFileFolder(sResultsFileFolder),
		m_sResultsIndexFilePathName(sResultsFileFolder + _T("\\index.html") ),
		m_sLintConfigFile(sLintConfigFile),
		m_sAdditionalProjectParams(sAdditionalProjectParams),
		m_sAdditionalParams(sAdditionalParams),
		m_sConfiguration(sConfiguration),
		m_setExcludedProjects(setExcludedProjects),
		m_bShowHtml(false),
		m_timeStarted(),
		m_nWarningCount(0),
		m_sElapsedTime(_T("") ),
		m_arrayProjectResults()
{
	m_timeStarted.SetStatus(COleDateTime::null);

	// Strip leading/trailing quotes - just in  case
	m_sSolutionFilePathName.TrimLeft( _T("\"") );
	m_sSolutionFilePathName.TrimRight( _T("\"") );

	m_sResultsFileFolder.TrimLeft( _T("\"") );
	m_sResultsFileFolder.TrimRight( _T("\"") );

	Utils::CSplitPath splitSolution(m_sSolutionFilePathName);

	m_sSolutionFileFolder	= splitSolution.GetDrive() + splitSolution.GetDirectory();
	m_sSolutionName			= splitSolution.GetFileName();
}


CSolutionLintAnalyser::CSolutionLintAnalyser(	const CString& sSolutionFilePathName,
												const CString& sResultsFileFolder,
												const CString& sLintConfigFile,
												const CString& sAdditionalProjectParams,
												const CString& sAdditionalParams,
												const CString& sConfiguration)
	:	m_sLintFolder(_T("") ),
		m_sSolutionFilePathName(sSolutionFilePathName),
		m_sSolutionFileFolder(_T("") ),
		m_sSolutionName(_T("") ),
		m_sResultsFileFolder(sResultsFileFolder),
		m_sResultsIndexFilePathName(sResultsFileFolder + _T("\\index.html") ),
		m_sLintConfigFile(sLintConfigFile),
		m_sAdditionalProjectParams(sAdditionalProjectParams),
		m_sAdditionalParams(sAdditionalParams),
		m_sConfiguration(sConfiguration),
		m_setExcludedProjects(),
		m_bShowHtml(false),
		m_timeStarted(),
		m_nWarningCount(0),
		m_sElapsedTime(_T("") ),
		m_arrayProjectResults()
{
	m_timeStarted.SetStatus(COleDateTime::null);

	// Strip leading/trailing quotes - just in  case
	m_sSolutionFilePathName.TrimLeft( _T("\"") );
	m_sSolutionFilePathName.TrimRight( _T("\"") );

	m_sResultsFileFolder.TrimLeft( _T("\"") );
	m_sResultsFileFolder.TrimRight( _T("\"") );

	Utils::CSplitPath splitSolution(m_sSolutionFilePathName);

	m_sSolutionFileFolder	= splitSolution.GetDrive() + splitSolution.GetDirectory();
	m_sSolutionName			= splitSolution.GetFileName();
}


CSolutionLintAnalyser::~CSolutionLintAnalyser(void)
{
}


INT_PTR CSolutionLintAnalyser::GetConfigurations(CAtlArray<CString>& rarrayConfigurations) const
{
	ATLASSERT(!m_sSolutionFilePathName.IsEmpty() );

	rarrayConfigurations.RemoveAll();

	if (!m_sSolutionFilePathName.IsEmpty() )
	{
		if (Utils::FileExists(m_sSolutionFilePathName) )
		{
			AddInSolutionModel::CSolutionFileReader parser;
			ATLVERIFY(parser.Read(m_sSolutionFilePathName) );

			(void)parser.GetConfigurations(rarrayConfigurations);

			return true;
		}
		else
		{
			CString sDesc;
			sDesc.Format(_T("Unable to open solution file %s"), m_sSolutionFilePathName);

			cout << CStringA(sDesc).GetString() << endl;
			return false;
		}
	}
	return false;
}


bool CSolutionLintAnalyser::SetLintFolder(const CString& sFolder)
{
	m_sLintFolder = sFolder;
	ATLASSERT(!m_sLintFolder.IsEmpty() );

	return !m_sLintFolder.IsEmpty();
}


bool CSolutionLintAnalyser::ShowHtml(const bool bShowHtml)
{
	m_bShowHtml = bShowHtml;

	return true;
}


int CSolutionLintAnalyser::GetWarningCount(void) const
{
	return m_nWarningCount;
}


CString CSolutionLintAnalyser::GetResultsIndexFilePathName(void) const
{
	return m_sResultsIndexFilePathName;
}


bool CSolutionLintAnalyser::Analyse(void)
{
	ATLASSERT(!m_sSolutionFilePathName.IsEmpty() );

	if (!m_sSolutionFilePathName.IsEmpty() )
	{
		CString sErrorMsg;

		if (!Utils::FileExists(m_sSolutionFilePathName) )
		{
			return false;
		}

		if (!Utils::FolderExists(m_sResultsFileFolder) )
		{
			// Create target and intermediate folders as required
			(void)::SHCreateDirectoryEx(NULL, m_sResultsFileFolder, NULL);
		}

		AddInSolutionModel::CSolutionFileReader parser;
		const bool bReadOk = parser.Read(m_sSolutionFilePathName);
		ATLASSERT(bReadOk);

		if (bReadOk)
		{
			// Set solution specific environment variables
			ATLVERIFY(SetEnvironmentVariables() );

			m_timeStarted = COleDateTime::GetCurrentTime();

			CAtlArray<CString> arrayProjectPathNames;
			(void)parser.GetProjectFilePathNames(arrayProjectPathNames);

			// Prescan to add all projects, so they show as "pending"
			for (size_t n = 0; n < arrayProjectPathNames.GetCount(); n++)
			{
				const CString sProjectFilePathName = arrayProjectPathNames[n];
				ATLASSERT(!sProjectFilePathName.IsEmpty() );

				const CString sExt = Utils::CSplitPath(sProjectFilePathName).GetExtension();

				const bool bIsCppProject = ( (_T(".vcproj") == sExt) ||
											 (_T(".dsp") == sExt) ||
											 (_T(".vcp") == sExt) );

				if (bIsCppProject)
				{
					Utils::CSplitPath splitprj(sProjectFilePathName);

					const CString sProjectName = splitprj.GetFileName();

					// !!! Check if sProjectName is in sSkipProjectParams
					CString sProjectNameLC = sProjectName;
					sProjectNameLC.MakeLower();		// Couldn't find the case independent traits class for std::set...

					if (m_setExcludedProjects.end() != m_setExcludedProjects.find(sProjectNameLC) )
					{
						CString sExcludedProjectMsg;
						sExcludedProjectMsg.Format( _T("Excluding project %s"), sProjectName);

						cout << endl << CStringA(sExcludedProjectMsg).GetString() << endl <<endl;

						continue;
					}

					CString sProjectResultsFileFolder = m_sResultsFileFolder;
					sProjectResultsFileFolder.TrimRight( _T("\\") );

					sProjectResultsFileFolder += _T("\\") + sProjectName;

					const CString sProjectConfig = parser.GetProjectConfigurationFromPathName(sProjectFilePathName, m_sConfiguration);

					CProjectLintAnalyser prj(	this,
												sProjectFilePathName,
												m_sResultsFileFolder,
												sProjectResultsFileFolder,
												m_sSolutionFileFolder, // [Alex McCarthy 21.10.2008]
												m_sLintConfigFile,
												m_sAdditionalProjectParams,
												m_sAdditionalParams,
												sProjectConfig);

					ATLVERIFY(prj.SetLintFolder(m_sLintFolder) );

					m_arrayProjectResults.Add(prj);
				}
			}

			ATLVERIFY(WriteResultsIndexFile() );

			if (m_bShowHtml)
			{
				// Open the output file in a browser window
				(void)::ShellExecute(	NULL,
										_T("open"),
										m_sResultsIndexFilePathName,
										NULL,
										NULL,
										SW_SHOWNORMAL);
			}

			// Now do the analysis
			for (size_t n = 0; n < m_arrayProjectResults.GetCount(); n++)
			{
				CProjectLintAnalyser& rprj = m_arrayProjectResults.GetAt(n);

				if (rprj.Analyse() )
				{
					ATLVERIFY(WriteResultsIndexFile() );
				}
			}

			// Reset solution specific environment variables
			ATLVERIFY(ResetEnvironmentVariables() );

			CString sSummary;
			sSummary.Format( _T("%d issues for solution %s"),
							m_nWarningCount,
							m_sSolutionName);

			cout << endl << CStringA(sSummary).GetString() << endl <<endl;

			return true;
		}
	}
	return false;
}


bool CSolutionLintAnalyser::WriteResultsIndexFile(void)
{
	if (m_timeStarted.m_dt > 0.0)
	{
		COleDateTimeSpan timeElapsed(COleDateTime::GetCurrentTime() - m_timeStarted);

		m_sElapsedTime = timeElapsed.Format( _T("%H hours, %M minutes, %S seconds") );
	}
	m_nWarningCount = 0;

	for (size_t n = 0; n < m_arrayProjectResults.GetCount(); n++)
	{
		CProjectLintAnalyser& rprj = m_arrayProjectResults.GetAt(n);

		m_nWarningCount+= rprj.GetWarningCount();
	}

	const CString sXslTemplate = Utils::LoadXsl(_Module.GetResourceInstance(), IDR_LINT_SOLUTION_TEMPLATE_HTML);
	ATLASSERT(!sXslTemplate.IsEmpty() );
	
	Utils::CSplitPath split(m_sResultsIndexFilePathName);

	const CString sXmlResultsFilePathName =	split.GetDrive() +
											split.GetDirectory() +
											split.GetFileName() + _T(".xml");

	ATLVERIFY(WriteXml(sXmlResultsFilePathName) );

	CString sErrorMsg;
	const bool bResult = WriteReport(m_sResultsIndexFilePathName, sXslTemplate, &sErrorMsg);

	if ( !sErrorMsg.IsEmpty() )
	{
		cout << CStringA(sErrorMsg).GetString() << endl;
	}

	(void)PostWriteResultsFile(m_sResultsIndexFilePathName);

	return bResult;
}


/// \brief Called when the results HTML file has been updated
///
/// Ideally, when this happens any browser windows with the file open should be refreshed
///
bool CSolutionLintAnalyser::PostWriteResultsFile(const CString& sResultsIndexFilePathName)
{
	ATLASSERT(Utils::FileExists(sResultsIndexFilePathName) );

	if (m_bShowHtml && Utils::FileExists(sResultsIndexFilePathName) )
	{
		return Utils::RefreshAllOpenBrowserWindows(sResultsIndexFilePathName);
	}
	return false;
}	//lint !e1961 (Elective Note -- virtual member function could be made const --- Eff. C++ 3rd Ed. item 3)


/// Write an XML Report stream to the given file
///
/// \param	sPathName		The pathname of the output file
/// \param	psMsg			A pointer to a CString object to return error information. May be NULL
/// \return					true if the file was written successfully, false otherwise
///
bool CSolutionLintAnalyser::WriteXml(const CString& sPathName, CString* psMsg /*= NULL*/)
{
	ATLASSERT(!sPathName.IsEmpty() );

	bool bResult = false;

	CString sErrorMsg;

	if (!sPathName.IsEmpty() )
	{
		try
		{
			MSXML2::IXMLDOMDocumentPtr ptrDOMDoc;

			// Create empty DOM
			HRESULT hr = ptrDOMDoc.CreateInstance("Msxml2.DOMDocument.3.0");

			if (FAILED(hr) )
			{
				sErrorMsg = _T("Failed to create XML DOM");

				throw _com_error(hr);
			}

			// tell our shape to save its state as XML (into ptrDOMDoc)
			hr = GenerateXml(ptrDOMDoc, &sErrorMsg);

			if (FAILED(hr) )
			{
				sErrorMsg = _T("Failed to save XML stream - ") + sErrorMsg;

				throw _com_error(hr);
			}

			try
			{
				const _variant_t varPathName = static_cast<LPCTSTR>(sPathName);

				ATLVERIFY(SUCCEEDED(ptrDOMDoc->save(varPathName) ) );

				bResult = true;
			}
			catch (const _com_error& e)
			{
				sErrorMsg = static_cast<LPCTSTR>(e.Description() );
			}
		}
		catch (const _com_error& e)
		{
			sErrorMsg = static_cast<LPCTSTR>(e.Description() );
		}
	}
	if (!bResult)
	{
		if ( (NULL != psMsg) && !sErrorMsg.IsEmpty() )
		{
			*psMsg = sErrorMsg;
		}
		ATLTRACE("ERROR in CXmlReportGenerator::WriteXml(): %s\n", sErrorMsg);
	}
	return bResult;
}	//lint !e1762


/// \brief Generate a Report and write it to the given file
///
/// \param	sPathName			The pathname of the output file
/// \param	sXslStyleSheetText	The text of the XSLT stylesheet
/// \param	psMsg				A pointer to a CString object to return error information. May be NULL
/// \return						true if the file was written sucessfully, false otherwise
///
bool CSolutionLintAnalyser::WriteReport(const CString& sPathName,
										const CString& sXslStyleSheetText,
										CString* psMsg /*= NULL*/)
{
	ATLASSERT(!sPathName.IsEmpty() );

	bool bResult = false;

	CString sErrorMsg;

	if (!sPathName.IsEmpty() )
	{
		const CString sReportText = GenerateReportText(	sXslStyleSheetText, &sErrorMsg);

		if (!sReportText.IsEmpty() )
		{
			bResult = SUCCEEDED(Utils::WriteTextFile(sPathName, sReportText) );
		}
	}
	if (!bResult)
	{
		if ( (NULL != psMsg) && !sErrorMsg.IsEmpty() )
		{
			*psMsg = sErrorMsg;
		}
		ATLTRACE( _T("ERROR in CSolutionLintAnalyser::WriteReport(): %s\n"), sErrorMsg);
	}
	return bResult;
}	//lint !e1762


CString CSolutionLintAnalyser::GenerateReportText(	const CString& sXslStyleSheetText,
													CString* psMsg /*= NULL*/) const
{
	USES_CONVERSION;

	CString sReportText;

	ATLASSERT(!sXslStyleSheetText.IsEmpty() );
	if (!sXslStyleSheetText.IsEmpty() )
	{
		CString sErrorMsg;
		
		try
		{
			MSXML2::IXMLDOMDocumentPtr ptrDOMDoc;
			MSXML2::IXMLDOMDocumentPtr ptrXSLTDOMDoc;

			// Create empty DOM
			HRESULT hr = ptrDOMDoc.CreateInstance("Msxml2.DOMDocument.3.0");
			if (FAILED(hr) )
			{
				sErrorMsg = _T("Failed to create XML DOM");

				throw _com_error(hr);
			}

			hr = ptrXSLTDOMDoc.CreateInstance("Msxml2.DOMDocument.3.0");
			if (FAILED(hr) )
			{
				sErrorMsg = _T("Failed to create XSLT DOM");

				throw _com_error(hr);
			}

			ptrXSLTDOMDoc->async = false;
			ATLVERIFY(ptrXSLTDOMDoc->loadXML(T2COLE(sXslStyleSheetText) ) );

			sReportText = GenerateReportText(	ptrDOMDoc,
												ptrXSLTDOMDoc,
												psMsg);

			// Workaround for XSLT bug: replace <cr><cr><lf> sequences with <cr><lf>
			sReportText.Replace( _T("\r\n"), _T("\n") );
		}
		catch (const _com_error& e)
		{
			const HRESULT hr = e.Error();
			ATLTRACE( _T("Unable to display report. Error code 0x%08x"), hr);
			if (NULL != psMsg)
			{
				psMsg->Format( _T("CSolutionLintAnalyser::GenerateReportText()\nException 0x%08x"), hr);
			}
		}
	}
	return sReportText;
}


/// \brief Generate a report using the given XML DOM document and XSLT stylesheet
///
/// \param	ptrDOMDoc			An interface pointer to the XML DOM document containing the stream
/// \param	pXslStyleSheetDoc	An interface pointer to an XML DOM document containing the XSLT template
/// \param	psMsg				A pointer to a CString object to return error information. May be NULL
/// \return						A Cstring object containing the text of the report
///
CString CSolutionLintAnalyser::GenerateReportText(	const MSXML2::IXMLDOMDocumentPtr& ptrXmlDoc,
													const MSXML2::IXMLDOMDocumentPtr& ptrXslStyleSheetDoc,
													CString* psMsg /*= NULL*/) const
{
	USES_CONVERSION;

	CString sErrorMsg;
	CString sReportText;

	try
	{
		// Generate the XML in ptrDOMDoc
		const HRESULT hr = GenerateXml(ptrXmlDoc, &sErrorMsg);

		if (FAILED(hr) )
		{
			sErrorMsg = _T("Failed to generate XML stream - ") + sErrorMsg;

			throw _com_error(hr);
		}

		ptrXslStyleSheetDoc->async = false;
 
		// Perform the transformation
		sReportText = OLE2CT(ptrXmlDoc->transformNode(ptrXslStyleSheetDoc) );
	}
	catch (const _com_error& e)
	{
		// Nothing to do here - we already know what's wrong
		UNREFERENCED_PARAMETER(e);
	}
	if (sReportText.IsEmpty())
	{
		if ( (NULL != psMsg) && !sErrorMsg.IsEmpty() )
		{
			*psMsg = sErrorMsg;
		}
		ATLTRACE( _T("ERROR in CSolutionLintAnalyser::GenerateReportText(): %s\n"), sErrorMsg);
	}
	return sReportText;
}


/// \brief Generate the XML stream
///
/// \param	pDOMDoc			An interface pointer to the XML DOM document containing the stream
/// \param	psMsg			A pointer to a CString object to return error information. May be NULL
/// \return					A Cstring object containing the text of the report
///
HRESULT CSolutionLintAnalyser::GenerateXml(	const MSXML2::IXMLDOMDocumentPtr& ptrDOMDoc,
											CString* psMsg /*= NULL*/) const
{
	USES_CONVERSION;

	HRESULT hr = S_OK;

	try
	{
		// Add xml version node
		const CString sAttribs = _T("version=\"1.0\" encoding=\"iso-8859-1\"");

		MSXML2::IXMLDOMProcessingInstructionPtr ptrIns;
		ptrIns = ptrDOMDoc->createProcessingInstruction(L"xml", T2COLE(sAttribs) );
		(void)ptrDOMDoc->appendChild(ptrIns);

		// Create root element
		MSXML2::IXMLDOMElementPtr const ptrRoot = ptrDOMDoc->createElement(L"SolutionLintResults");
		(void)ptrDOMDoc->appendChild(ptrRoot);

		Utils::CModuleVersion ver;
		ATLVERIFY(ver.GetFileVersionInfo() );

		const CString sVersion = ver.GetValue( _T("FileVersion") );

		MSXML2::IXMLDOMElementPtr const ptrApplication = ptrDOMDoc->createElement(L"Application");

		ATLVERIFY(SUCCEEDED(ptrApplication->setAttribute(L"Name",		PRODUCT_NAME) ) );
		ATLVERIFY(SUCCEEDED(ptrApplication->setAttribute(L"Version",	T2COLE(sVersion) ) ) );
		ATLVERIFY(SUCCEEDED(ptrApplication->setAttribute(L"Url",		PRODUCT_URL) ) );
		
		(void)ptrRoot->appendChild(ptrApplication);

		ATLVERIFY(SUCCEEDED(GenerateXml(ptrDOMDoc,
										ptrRoot,
										psMsg) ) );
	}
	catch (const _com_error& e)
	{
		hr = e.Error();

		if (NULL != psMsg)
		{
			psMsg->Format( _T("CSolutionLintAnalyser::GenerateXml()\nException 0x%08x"), hr);
		}
	}
	return hr;
}


HRESULT CSolutionLintAnalyser::GenerateXml(	const MSXML2::IXMLDOMDocumentPtr& ptrDOMDoc,
											const MSXML2::IXMLDOMElementPtr& ptrParentElement,
											CString* psMsg /*= NULL*/) const
{
	USES_CONVERSION;

	HRESULT hr = S_OK;

	try
	{
		MSXML2::IXMLDOMElementPtr const ptrSolution = ptrDOMDoc->createElement(L"Solution");

		MSXML2::IXMLDOMAttributePtr const ptrSolutionNameAttr = ptrDOMDoc->createAttribute(L"name");
		ptrSolutionNameAttr->value = T2COLE(m_sSolutionName);
		(void)ptrSolution->setAttributeNode(ptrSolutionNameAttr);

		MSXML2::IXMLDOMAttributePtr const ptrConfigurationAttr = ptrDOMDoc->createAttribute(L"configuration");
		ptrConfigurationAttr->value = T2COLE(m_sConfiguration);
		(void)ptrSolution->setAttributeNode(ptrConfigurationAttr);

		(void)ptrParentElement->appendChild(ptrSolution);

		MSXML2::IXMLDOMElementPtr const ptrProjects = ptrDOMDoc->createElement(L"Projects");
		(void)ptrSolution->appendChild(ptrProjects);

		for (size_t n = 0; n < m_arrayProjectResults.GetCount(); n++)
		{
			const CProjectLintAnalyser& project = m_arrayProjectResults[n];

			if (project.GetImplementationFileCount() > 0)
			{
				ATLVERIFY(SUCCEEDED(project.GenerateXml(ptrDOMDoc,
														ptrProjects,
														psMsg) ) );
			}
		}
		
		MSXML2::IXMLDOMElementPtr const ptrSummary = ptrDOMDoc->createElement(L"Summary");

		(void)ptrSolution->appendChild(ptrSummary);

		MSXML2::IXMLDOMElementPtr const ptrWarnings = ptrDOMDoc->createElement(L"Warnings");

		ptrWarnings->text = T2COLE(Utils::IntToStr(m_nWarningCount) );
		(void)ptrSummary->appendChild(ptrWarnings);

		MSXML2::IXMLDOMElementPtr const ptrStartTime = ptrDOMDoc->createElement(L"StartTime");

		const CString sStartTime = m_timeStarted.Format( _T("%a %d %b %Y, %H:%M:%S") );

		ptrStartTime->text = T2COLE(sStartTime);
		(void)ptrSummary->appendChild(ptrStartTime);

		MSXML2::IXMLDOMElementPtr const ptrElapsedTime = ptrDOMDoc->createElement(L"ElapsedTime");

		ptrElapsedTime->text = T2COLE(m_sElapsedTime);
		(void)ptrSummary->appendChild(ptrElapsedTime);
	}
	catch (const _com_error& e)
	{
		hr = e.Error();

		if (NULL != psMsg)
		{
			psMsg->Format(	_T("Exception 0x%08x in CSolutionLintAnalyser::GenerateXml()\n"), hr);
		}
	}
	return hr;
}


/// \brief Set solution specific environment variables.
///
/// \return					\em true if everything worked; \em false otherwise.
///
bool CSolutionLintAnalyser::SetEnvironmentVariables(void)
{
	return (FALSE != ::SetEnvironmentVariable( _T("SolutionDir"), m_sSolutionFileFolder) );
}	//lint !e1762	(Information -- Member function could be made const --- Eff. C++ 3rd Ed. item 3)


/// \brief Reset solution specific environment variables.
///
/// \return					\em true if everything worked; \em false otherwise.
///
bool CSolutionLintAnalyser::ResetEnvironmentVariables(void)
{
	return (FALSE != ::SetEnvironmentVariable( _T("SolutionDir"), NULL) );
}	//lint !e1762	(Information -- Member function could be made const --- Eff. C++ 3rd Ed. item 3)

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
Founder Riverblade Limited
United Kingdom United Kingdom
I haven't always written software for a living. When I graduated from Surrey University in 1989, it was with an Electronic Engineering degree, but unfortunately that never really gave me the opportunity to do anything particularly interesting (with the possible exception of designing Darth Vader's Codpiece * for the UK Army in 1990).
    * Also known as the Standard Army Bootswitch. But that's another story...
Since the opportunity arose to lead a software team developing C++ software for Avionic Test Systems in 1996, I've not looked back. More recently I've been involved in the development of subsea acoustic navigation systems, digital TV broadcast systems, port security/tracking systems, and most recently software development tools with my own company, Riverblade Ltd.

One of my personal specialities is IDE plug-in development. ResOrg was my first attempt at a plug-in, but my day to day work is with Visual Lint, an interactive code analysis tool environment with works within the Visual Studio and Eclipse IDEs or on build servers.

I love lots of things, but particularly music, photography and anything connected with history or engineering. I despise ignorant, intolerant and obstructive people - and it shows...I can be a bolshy cow if you wind me up the wrong way...Laugh | :laugh:

I'm currently based 15 minutes walk from the beach in Bournemouth on the south coast of England. Since I moved here I've grown to love the place - even if it is full of grockles in Summer!

Written By
Software Developer Riverblade Ltd
United Kingdom United Kingdom
I'm a software developer and/or tester with Riverblade Ltd (www.riverblade.co.uk) developing our core product range including our Visual Lint integration product and Lint Project Professional.

I incorporate a number of technologies into a daily basis including Windows API, C++ (VS2008), Managed C++, CLI, Databases, Java, JNI, Eclipse Framework, CDT and of course Visual Studio Extensibility (VSIP VSX).

In my spare time I enjoy cooking (prepping ingredients from scratch!), running, cycling, swimming, reading, interested in experimental electronic music (such as ClockDVA), movies, volunteering my IT skills where I can.

Comments and Discussions