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

Auto-Incrementing Build Numbers

Rate me:
Please Sign up or sign in to vote.
4.89/5 (13 votes)
8 Mar 2000 144.9K   2.2K   64  
Describes a way to automatically generate an application build number.
// Commands.cpp : implementation file
//
#include "stdafx.h"
#include "AutoBuild.h"
#include "Commands.h"

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

/////////////////////////////////////////////////////////////////////////////
// CCommands

CCommands::CCommands()
{
	m_pApplication = NULL;
	m_pApplicationEventsObj = NULL;
	m_pDebuggerEventsObj = NULL;
}

CCommands::~CCommands()
{
	ASSERT (m_pApplication != NULL);
	m_pApplication->Release();
}

void CCommands::SetApplicationObject(IApplication* pApplication)
{
	// This function assumes pApplication has already been AddRef'd
	//  for us, which CDSAddIn did in its QueryInterface call
	//  just before it called us.
	m_pApplication = pApplication;

	// Create Application event handlers
	XApplicationEventsObj::CreateInstance(&m_pApplicationEventsObj);
	m_pApplicationEventsObj->AddRef();
	m_pApplicationEventsObj->Connect(m_pApplication);
	m_pApplicationEventsObj->m_pCommands = this;

	// Create Debugger event handler
	CComPtr<IDispatch> pDebugger;
	if (SUCCEEDED(m_pApplication->get_Debugger(&pDebugger)) 
		&& pDebugger != NULL)
	{
		XDebuggerEventsObj::CreateInstance(&m_pDebuggerEventsObj);
		m_pDebuggerEventsObj->AddRef();
		m_pDebuggerEventsObj->Connect(pDebugger);
		m_pDebuggerEventsObj->m_pCommands = this;
	}
}

void CCommands::UnadviseFromEvents()
{
	ASSERT (m_pApplicationEventsObj != NULL);
	m_pApplicationEventsObj->Disconnect(m_pApplication);
	m_pApplicationEventsObj->Release();
	m_pApplicationEventsObj = NULL;

	if (m_pDebuggerEventsObj != NULL)
	{
		// Since we were able to connect to the Debugger events, we
		//  should be able to access the Debugger object again to
		//  unadvise from its events (thus the VERIFY_OK below--see stdafx.h).
		CComPtr<IDispatch> pDebugger;
		VERIFY_OK(m_pApplication->get_Debugger(&pDebugger));
		ASSERT (pDebugger != NULL);
		m_pDebuggerEventsObj->Disconnect(pDebugger);
		m_pDebuggerEventsObj->Release();
		m_pDebuggerEventsObj = NULL;
	}
}


/////////////////////////////////////////////////////////////////////////////
// Event handlers

// TODO: Fill out the implementation for those events you wish handle
//  Use m_pCommands->GetApplicationObject() to access the Developer
//  Studio Application object

// Application events

HRESULT CCommands::XApplicationEvents::BeforeBuildStart()
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	
	//=====================================================================
	IDispatch* pDispatch;
	m_pCommands->GetApplicationObject()->get_ActiveProject(&pDispatch);
	if (!pDispatch)
	{
		m_pCommands->GetApplicationObject()->PrintToOutputWindow(CComBSTR(_T("Build Number Unchanged")));
		return S_OK; // or some error message
	}
    CComQIPtr<IGenericProject, &IID_IGenericProject> pProject(pDispatch);
	CComBSTR bsName;
	pProject->get_FullName(&bsName);
	CString sName = bsName;
	pDispatch->Release();
	//======================================================================
	m_pCommands->GetApplicationObject()->PrintToOutputWindow(bsName);
	
	// check whether the application file has a incrementbuild flag set.
	int iLastSlash = sName.ReverseFind('\\');
	if(iLastSlash == -1)
	{
		m_pCommands->GetApplicationObject()->PrintToOutputWindow(CComBSTR(_T("Build Number Unchanged")));
		return S_OK; // or some error message
	}

	CString sPath = sName.Left(iLastSlash+1);
	CString sApp = sName.Left(sName.GetLength()-4).Mid(iLastSlash+1);
	
	// now that we got the project name, compute the name of the rc file.
	CString sFileRC = sPath + sApp + ".rc";
	
	// also compute the path of our header file.
	CString sFileAutoBld = sPath + "AutoBuild.h";
	
	// check whether the rc file is read-only.
	CStdioFile cFile;
	CFileStatus cStatus;
	cFile.GetStatus(sFileRC, cStatus);
	if(cStatus.m_attribute & CFile::Attribute::readOnly)
	{
		m_pCommands->GetApplicationObject()->PrintToOutputWindow(CComBSTR(_T("Build Number Unchanged")));
		return S_OK; // or some error message
	}
	
	// check whether the autobuild file can be opened in read-write mode.
	cFile.GetStatus(sFileAutoBld, cStatus);
	if(cStatus.m_attribute & CFile::Attribute::readOnly)
	{
		m_pCommands->GetApplicationObject()->PrintToOutputWindow(CComBSTR(_T("Build Number Unchanged")));
		return S_OK; // or some error message
	}
	
	// open the autobld file and see whether the user wants to increment the build.
	
	CFileException cFileException;
	if(!cFile.Open(sFileAutoBld, CFile::modeReadWrite, &cFileException))
	{
		// file does not exist, so create it.
		cFile.Open(sFileAutoBld, CFile::modeCreate|CFile::modeWrite, &cFileException);
		cFile.WriteString("#ifndef __AUTOBUILD_H__\n");
		cFile.WriteString("#define __AUTOBUILD_H__\n");
		cFile.WriteString("//change the FALSE to TRUE for autoincrement of build number\n");
		cFile.WriteString("#define INCREMENT_BUILD_NUM FALSE\n");
		cFile.WriteString("#define BUILD_NUM 0\n");
		cFile.WriteString("#endif //__AUTOBUILD_H__\n");
		cFile.Close();
		
		m_pCommands->GetApplicationObject()->PrintToOutputWindow(CComBSTR(_T("Build Number Unchanged")));
		return S_OK; // or some error message
	}
	else
		cFile.Close();

	BOOL bIncrement = FALSE;
	
	CString sLine;
	cFile.Open(sFileAutoBld, CFile::modeRead, &cFileException);
	
	CString ksIncrementBuild = "#define INCREMENT_BUILD_NUM";
	while(cFile.ReadString(sLine))
	{
		if( sLine.Find(ksIncrementBuild) != -1 &&
			(sLine.Find("TRUE")+1 || sLine.Find("1")+1))
		{
			bIncrement = TRUE;
			break;
		}
	}
	cFile.Close();
	if(!bIncrement)
	{
		m_pCommands->GetApplicationObject()->PrintToOutputWindow(CComBSTR(_T("Build Number Unchanged")));
		return S_OK; // or some error message
	}



	cFile.Open(sFileAutoBld, CFile::modeReadWrite, &cFileException);
	// check whether the first line contains 
	// #define INCREMENTBUILD TRUE
	CString sLines;
	
	CString ksBuildNum = "#define BUILD_NUM";
	int iBuildNum = 0;
	CString sBuildNum;
	while(cFile.ReadString(sLine))
	{
		if(int i = sLine.Find(ksBuildNum)+1)
		{
			sBuildNum = sLine.Mid(i + strlen(ksBuildNum));
			sBuildNum.TrimLeft();
			iBuildNum=atol(sBuildNum);
			
			// increment the BuildNum;
			sBuildNum.Format("%d",++iBuildNum); 
			sLine = ksBuildNum+ " " + sBuildNum;
		}
		
		sLines += sLine + "\n";
	}
	cFile.SeekToBegin();
	cFile.WriteString(sLines);
	sLines="";
	cFile.Close();

	m_pCommands->GetApplicationObject()->PrintToOutputWindow(
		CComBSTR(_T("Incrementing Build Number To: " + sBuildNum)));
	
	// now that we have incremented the autobuild.h file,
	// update the rc file.
	cFile.Open(sFileRC, CFile::modeReadWrite, &cFileException);
	// p.s. already confirmed that we can open this file.
	
	/*  Go throuth the rc file and replace the build version info.
	VS_VERSION_INFO     VERSIONINFO
	  FILEVERSION       1,0,0,1
	  PRODUCTVERSION    1,0,0,1
	...
				VALUE "FileVersion",     "1, 0, 0, 1\0"
	...
				VALUE "ProductVersion",  "1, 0, 0, 1\0"
	...
	END
	*/	
	CString ksVERSION_INFO = "VS_VERSION_INFO";
	CString ksFILEVERSION = "FILEVERSION";
	CString ksPRODUCTVERSION = "PRODUCTVERSION";
	CString ksFileVersion = "VALUE \"FileVersion\",";
	CString ksProductVersion = "VALUE \"ProductVersion\",";
	BOOL bInBlock = FALSE;
	int iFound=0;
	while(cFile.ReadString(sLine))
	{
		if(!bInBlock && sLine.Find(ksVERSION_INFO) != -1)
			bInBlock = TRUE;
		if(bInBlock)
		{
			if( ((iFound = sLine.Find(ksFILEVERSION)) != -1) ||
				((iFound = sLine.Find(ksPRODUCTVERSION)) != -1))
			{
				int i = sLine.ReverseFind(',');	
				sLine = sLine.Left(++i) + sBuildNum;
			}
			if( ((iFound = sLine.Find(ksFileVersion)) != -1) ||
				((iFound = sLine.Find(ksProductVersion)) != -1))
			{
				CString sVersion = sLine.Mid(iFound);
				int i = sVersion.ReverseFind(',')+2;
				int j = sVersion.ReverseFind('\\');
				sLine = sLine.Left(iFound) + sVersion.Left(i) + sBuildNum + sVersion.Mid(j); 	
			}
		}
		sLines += sLine + "\n";
	}
	cFile.SeekToBegin();
	cFile.WriteString(sLines);
	cFile.Close();

	return S_OK;
}

HRESULT CCommands::XApplicationEvents::BuildFinish(long nNumErrors, long nNumWarnings)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

HRESULT CCommands::XApplicationEvents::BeforeApplicationShutDown()
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

HRESULT CCommands::XApplicationEvents::DocumentOpen(IDispatch* theDocument)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

HRESULT CCommands::XApplicationEvents::BeforeDocumentClose(IDispatch* theDocument)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

HRESULT CCommands::XApplicationEvents::DocumentSave(IDispatch* theDocument)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

HRESULT CCommands::XApplicationEvents::NewDocument(IDispatch* theDocument)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

HRESULT CCommands::XApplicationEvents::WindowActivate(IDispatch* theWindow)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

HRESULT CCommands::XApplicationEvents::WindowDeactivate(IDispatch* theWindow)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

HRESULT CCommands::XApplicationEvents::WorkspaceOpen()
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

HRESULT CCommands::XApplicationEvents::WorkspaceClose()
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

HRESULT CCommands::XApplicationEvents::NewWorkspace()
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

// Debugger event

HRESULT CCommands::XDebuggerEvents::BreakpointHit(IDispatch* pBreakpoint)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}


/////////////////////////////////////////////////////////////////////////////
// CCommands methods

STDMETHODIMP CCommands::AutoBuildCommandMethod() 
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	// TODO: Replace this with the actual code to execute this command
	//  Use m_pApplication to access the Developer Studio Application object,
	//  and VERIFY_OK to see error strings in DEBUG builds of your add-in
	//  (see stdafx.h)

	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));
//	::MessageBox(NULL, "AutoBuild Command invoked.", "AutoBuild", MB_OK | MB_ICONINFORMATION);
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
	return S_OK;
}

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 States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions