Click here to Skip to main content
15,891,621 members
Articles / Desktop Programming / WTL

Cyclomatic Complexity Viewer

Rate me:
Please Sign up or sign in to vote.
4.29/5 (13 votes)
30 Jun 20055 min read 108.4K   2.8K   34  
A Cyclomatic complexity viewer application.
//Copyright (c) Microsoft Corporation.  All rights reserved.

// Connect.cpp : Implementation of CConnect
#include "stdafx.h"
#include "AddIn.h"
#include "Connect.h"
#include <string>
#include "metricdlg.h"
#include "funcmetricdlg.h"
#include <fstream>
#include "filegenerator.h"
#include "graphpreparator.h"

// CConnect
HRESULT CConnect::AddCommandsAndCommandBars()
{
	HRESULT hr = S_OK;
	CComPtr<EnvDTE::Commands> pCommands;
	CComPtr<IDispatch> pDispatch;

	hr = m_pDTE->get_Commands(&pCommands);

	// create the toolbar
	if (SUCCEEDED(hr))
	{
		CComPtr<EnvDTE::Command> pCreatedCommand;
		hr = pCommands->Item(CComVariant(L"CCMetricViewer.Connect.CalculateMetrics"), 2, &pCreatedCommand);
		if (SUCCEEDED(hr) && pCreatedCommand)
		{
			pCreatedCommand->Delete();
			pCreatedCommand = NULL;
		}
		hr = pCommands->Item(CComVariant(L"CCMetricViewer.Connect.CalculateMetric"), 1, &pCreatedCommand);
		if (SUCCEEDED(hr) && pCreatedCommand)
		{
			pCreatedCommand->Delete();
			pCreatedCommand = NULL;
		}
		hr = pCommands->AddCommandBar(CComBSTR("Metric Viewer"), EnvDTE::vsCommandBarTypeToolbar, NULL, 0, &pDispatch);
		// cast/QI the IDispatch for Office::CommandBar interface
		CComQIPtr<Office::CommandBar> pMenuBarCommandBar = pDispatch;
		CComPtr<Office::CommandBarControl> pCommandBarControl;

		if (SUCCEEDED(hr))
		{
			hr = pCommands->AddNamedCommand(
				m_pAddInInstance,
				CComBSTR("CalculateMetric"),
				CComBSTR("Calculate Metric"),
				CComBSTR("Calculates the cyclomatic complexity metric for the currently selected function"),
				VARIANT_FALSE,
				IDB_LOGO_1,
				NULL,
				EnvDTE::vsCommandStatusSupported+EnvDTE::vsCommandStatusEnabled,
				&pCreatedCommand);
			if (SUCCEEDED(hr))
			{
				hr = pCreatedCommand->AddControl(pMenuBarCommandBar, 1, &pCommandBarControl);
				if (SUCCEEDED(hr))
				{
					CComQIPtr<Office::_CommandBarButton> pButton(pCommandBarControl);
					if (pButton)
						pButton->put_Style(Office::msoButtonAutomatic);
				}
			}

			pCreatedCommand.Release();
			pCommandBarControl.Release();

			// add the named commands and controls to the toolbar
			hr = pCommands->AddNamedCommand(
				m_pAddInInstance,
                CComBSTR("CalculateMetrics"),
				CComBSTR("Calculate All Metrics"), 
				CComBSTR("Calculates the cyclomatic complexity metric for each function in the loaded solution"), 
				VARIANT_FALSE, 
				IDB_LOGO_2, 
				NULL, 
				EnvDTE::vsCommandStatusSupported+EnvDTE::vsCommandStatusEnabled,
				&pCreatedCommand);
			if (SUCCEEDED(hr))
			{
				hr = pCreatedCommand->AddControl(pMenuBarCommandBar, 2, &pCommandBarControl);
				if (SUCCEEDED(hr))
				{
					CComQIPtr<Office::_CommandBarButton> pButton(pCommandBarControl);
					if (pButton)
						pButton->put_Style(Office::msoButtonIcon);
				}
			}

			//original place for: pMenuBarCommandBar->put_Visible(VARIANT_TRUE);
		}
		pMenuBarCommandBar->put_Visible(VARIANT_TRUE);
	}

	return S_OK;
}

HRESULT CConnect::RemoveCommandsAndCommandBars()
{
	HRESULT hr = S_OK;
	CComPtr<EnvDTE::Commands> pCommands;
	CComPtr<Office::_CommandBars> pCommandBars;

	hr = m_pDTE->get_Commands(&pCommands);
	if(FAILED(hr))
		return hr;
	hr = m_pDTE->get_CommandBars(&pCommandBars);
	if(FAILED(hr))
		return hr;
	
	CComPtr<EnvDTE::Command> pCreatedCommand;
	CComPtr<Office::CommandBar> pMenuBarCommandBar;
	CComPtr<Office::CommandBarControl> pCommandBarControl;

	if (SUCCEEDED(pCommandBars->get_Item(CComVariant("Tools"),&pMenuBarCommandBar)))
	{
		// remove the named commands
		if (SUCCEEDED(pCommands->Item(CComVariant("CCMetricViewer.Connect.CalculateMetrics"), 2, &pCreatedCommand)))
		{
			pCreatedCommand->AddControl(pMenuBarCommandBar, 1, &pCommandBarControl);
			pCreatedCommand->Delete();
			pCreatedCommand.Release();
			pCommandBarControl.Release();
		}
		if (SUCCEEDED(pCommands->Item(CComVariant("CCMetricViewer.Connect.CalculateMetric"), 1, &pCreatedCommand)))
		{
			pCreatedCommand->AddControl(pMenuBarCommandBar, 1, &pCommandBarControl);
			pCreatedCommand->Delete();
			pCreatedCommand.Release();
			pCommandBarControl.Release();
		}
	
		pMenuBarCommandBar.Release();
	}

	// remove the toolbar
	if (SUCCEEDED(pCommandBars->get_Item(CComVariant("Metric Viewer"),&pMenuBarCommandBar)))
	{
		hr = pCommands->RemoveCommandBar(pMenuBarCommandBar);
		hr = pMenuBarCommandBar->Delete();
	}

	return S_OK;
}

STDMETHODIMP CConnect::OnConnection(IDispatch *pApplication, AddInDesignerObjects::ext_ConnectMode ConnectMode, IDispatch *pAddInInst, SAFEARRAY ** /*custom*/ )
{
	HRESULT hr = S_OK;
	pApplication->QueryInterface(__uuidof(EnvDTE::_DTE), (LPVOID*)&m_pDTE);
	pAddInInst->QueryInterface(__uuidof(EnvDTE::AddIn), (LPVOID*)&m_pAddInInstance);

	if(ConnectMode == 5) //5 == AddInDesignerObjects::ext_cm_UISetup
	{
		// add named commands and toolbars
		hr = AddCommandsAndCommandBars();
		if (FAILED(hr))
		{	
			// clean up if something went wrong
			hr = RemoveCommandsAndCommandBars();
			return hr;
		}
	}

	CComPtr<Office::_CommandBars> pCommandBars;
	CComPtr<Office::CommandBar> pMenuBarCommandBar;
	if (SUCCEEDED(m_pDTE->get_CommandBars(&pCommandBars)))
	{
		if (SUCCEEDED(pCommandBars->get_Item(CComVariant("Metric Viewer"),&pMenuBarCommandBar)))
		{
			pMenuBarCommandBar->put_Visible(VARIANT_TRUE);
		}
	}

	return S_OK;
}

STDMETHODIMP CConnect::OnDisconnection(AddInDesignerObjects::ext_DisconnectMode /*RemoveMode*/, SAFEARRAY ** /*custom*/ )
{
	CComPtr<Office::_CommandBars> pCommandBars;
	CComPtr<Office::CommandBar> pMenuBarCommandBar;
	if (SUCCEEDED(m_pDTE->get_CommandBars(&pCommandBars)))
	{
		if (SUCCEEDED(pCommandBars->get_Item(CComVariant("Metric Viewer"),&pMenuBarCommandBar)))
			pMenuBarCommandBar->put_Visible(VARIANT_FALSE);
	}

	m_pDTE = NULL;
	return S_OK;
}

STDMETHODIMP CConnect::OnAddInsUpdate (SAFEARRAY ** /*custom*/ )
{
	return S_OK;
}

STDMETHODIMP CConnect::OnStartupComplete (SAFEARRAY ** /*custom*/ )
{
	return S_OK;
}

STDMETHODIMP CConnect::OnBeginShutdown (SAFEARRAY ** /*custom*/ )
{
	CComPtr<Office::_CommandBars> pCommandBars;
	CComPtr<Office::CommandBar> pMenuBarCommandBar;
	if (SUCCEEDED(m_pDTE->get_CommandBars(&pCommandBars)))
	{
		if (SUCCEEDED(pCommandBars->get_Item(CComVariant("Metric Viewer"),&pMenuBarCommandBar)))
			pMenuBarCommandBar->put_Visible(VARIANT_FALSE);
	}
	return S_OK;
}

STDMETHODIMP CConnect::QueryStatus(BSTR bstrCmdName, EnvDTE::vsCommandStatusTextWanted NeededText, EnvDTE::vsCommandStatus* pStatusOption, VARIANT* pvarCommandText)
{
	if (NeededText == EnvDTE::vsCommandStatusTextWantedNone)
	{
		if (!_wcsicmp(bstrCmdName, L"CCMetricViewer.Connect.CalculateMetric"))
			*pStatusOption = (EnvDTE::vsCommandStatus)(EnvDTE::vsCommandStatusEnabled | EnvDTE::vsCommandStatusSupported);
		if (!_wcsicmp(bstrCmdName, L"CCMetricViewer.Connect.CalculateMetrics"))
			*pStatusOption = (EnvDTE::vsCommandStatus)(EnvDTE::vsCommandStatusEnabled | EnvDTE::vsCommandStatusSupported);
	}
	return S_OK;
}

STDMETHODIMP CConnect::Exec(BSTR bstrCmdName, EnvDTE::vsCommandExecOption ExecuteOption, VARIANT* /*pvarVariantIn*/, VARIANT* /*pvarVariantOut*/, VARIANT_BOOL* pvbHandled)
{
	*pvbHandled = VARIANT_FALSE;
	if (ExecuteOption == EnvDTE::vsCommandExecOptionDoDefault)
	{
		if (!_wcsicmp(bstrCmdName, L"CCMetricViewer.Connect.CalculateMetrics"))
		{
			ObtainSolutionData();
			CMetricDlg dlg;
			dlg.LoadData(metric_data, CW2A(LPCWSTR(explorer->GetSolutionName())));
			dlg.DoModal();

			*pvbHandled = VARIANT_TRUE;
			return S_OK;
		}
		if (!_wcsicmp(bstrCmdName, L"CCMetricViewer.Connect.CalculateMetric"))
		{
			int value;
			CComBSTR name;
			if (ObtainSelectedFuncMetric(value, name))
			{
/*				DrawGraph(std::wstring(LPCWSTR(name)));
				CComPtr<EnvDTE::Windows> pWindows;
				CComPtr<IDispatch> pCtrlObject;
				CComPtr<EnvDTE::Window> pWindow;
				m_pDTE->get_Windows(&pWindows);
				pWindows->CreateToolWindow(m_pAddInInstance, CComBSTR("GraphViewer.CGraphViewerCtrl.1"), CComBSTR("CCM Graph"), CComBSTR("{DA8D1868-9ADC-4B6F-8400-DC92BD73EC63}"), &pCtrlObject, &pWindow);
				pWindow->put_Visible(VARIANT_TRUE);
*/				CFuncMetricDlg dlg;
				dlg.LoadData(value, name, L"");
				dlg.DoModal();
			}
			*pvbHandled = VARIANT_TRUE;
			return S_OK;
		}
	}
	return S_OK;
}

void CConnect::ObtainSolutionData()
{
	explorer = new SolutionExplorer(m_pDTE);
	long num_projects = explorer->GetProjectCount();
	//Go through each project in the solution
	for (long i = 1; i <= num_projects; i++)
	{
		if (explorer->SetProject(i))
		{
			metric_data = explorer->GetMetrics();
#ifdef _DEBUG
	CGraphPreparator debugger;
	debugger.WriteVector("output.txt");
#endif
			explorer->ReleaseProject();
		}
	}
}

bool CConnect::ObtainSelectedFuncMetric(int& value, CComBSTR& name)
{
	explorer = new SolutionExplorer(m_pDTE);
	CComBSTR text;
	if (explorer->GetFunctionText(text))
	{
		const wchar_t* w_bodytext = LPCWSTR(text);
		name = explorer->GetFunctionName(const_cast<wchar_t*>(w_bodytext));
		value = explorer->GetMetric(w_bodytext);
		return true;
	}
	else
		return false;
}

bool CConnect::DrawGraph(std::wstring& filename)
{
	string name = "\\.\\output.dot";
	CFileGenerator filebuilder(name);
	filebuilder.WriteFile();
	wstring parameter = L"-Tpng ";
	parameter += reinterpret_cast<const wchar_t*>(name.c_str());
	parameter += L" -o ";
	parameter += filename;
	if (!ShellExecute(NULL, L"open", L"dot.exe", parameter.c_str(), L"C:\\", SW_HIDE))
		return false;
	return true;
}

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United Kingdom United Kingdom
I am a qualified Veterinary Surgeon who prefers treating computers with viruses than animals with viruses. I have recently completed a MEng German Informatics degree at the University of Reading with a 2:1. I also have the ISEB Foundation Certificate in Software Testing.

Currently I am umemployed and desparately looking for a job in the IT industry.

Comments and Discussions