Click here to Skip to main content
15,891,136 members
Articles / Desktop Programming / ATL

Increment File and Product Version Number - Multiple IDE

Rate me:
Please Sign up or sign in to vote.
4.58/5 (32 votes)
21 Oct 2008CPOL12 min read 292.6K   1.2K   134  
An add-in to automatically increment the FileVersion and ProductVersion fields in your application's resource file. Works in VC6 and VS2005, and probably all versions in between.
#ifndef DTEADDIN_H_E212DF6C_4B8E_4DDE_9653_D9262759406F
#define DTEADDIN_H_E212DF6C_4B8E_4DDE_9653_D9262759406F
/**
 * \file DTEAddIn.h
 *
 * \brief Header file for class CDTEAddIn
 *
 * $Id: DTEAddIn.h, v1.1.1.1 2006/09/24 23:12:30 mgh Exp $
 *
 *
 * Copyright (C) 2006 Michael G. Herstine <sp1ff@pobox.com>
 *
 * Permission to use, copy, or modify this source code is hereby granted
 * free of charge, provided that this copyright notice appear on all
 * copies and on all source code derived from this code.  No
 * representation is made regarding the suitability of this software for
 * any purpose.  It is provided "as is" without express or implied
 * warranty.
 *
 *
 */
 
////////////////////////////////////////////////////////////////////////////
// Modified by Jordan Walters, 01.03.2008 for multi-IDE version increment //
////////////////////////////////////////////////////////////////////////////

#ifndef STDAFX_H_10C3F2AB_C971_462D_AE43_8D659E613A34
#error "#include 'stdafx.h' before this file for PCH!"
#endif // not "stdafx.h"

#ifndef RESOURCE_H_INCLUDED
#include "resource.h"			// Resource definitions
#endif // not "resource.h"

#ifndef INCVERSION_H_INCLUDED
#include "IncVersion.h"			// MIDL-generated COM bindings
#endif // not "IncVersion.h"

#include <map>

class CAddIn;                   // Used in the interface, below
class CDTEAddIn;                // Forward declaration for class
// CWindowEventsSink
/**
 * \class CWindowEventSink
 *
 * \brief C++ class sinking Visual Studio's Window-related events
 *
 *
 */

class CWindowEventsSink:
	public IDispEventImpl<1, CWindowEventsSink, &__uuidof(EnvDTE::_dispWindowEvents), &EnvDTE::LIBID_EnvDTE, 8, 0>
{
public:
	/// Construct with a reference to our owner
	CWindowEventsSink(CDTEAddIn *pParent);

#ifndef DOXYGEN_INVOKED        // Shield the macros from doxygen...
	BEGIN_SINK_MAP(CWindowEventsSink)
		SINK_ENTRY_EX(1, __uuidof(EnvDTE::_dispWindowEvents), 1, WindowClosing)
		SINK_ENTRY_EX(1, __uuidof(EnvDTE::_dispWindowEvents), 2, WindowMoved)
		SINK_ENTRY_EX(1, __uuidof(EnvDTE::_dispWindowEvents), 3, WindowActivated)
		SINK_ENTRY_EX(1, __uuidof(EnvDTE::_dispWindowEvents), 4, WindowCreated)
	END_SINK_MAP()
#endif // not DOXYGEN_INVOKED

public:
	void __stdcall WindowClosing(EnvDTE::Window *Window);
	void __stdcall WindowMoved(EnvDTE::Window *Window, long Top, long Left, long Width, long Height);
	void __stdcall WindowActivated(EnvDTE::Window *GotFocus, EnvDTE::Window *LostFocus);
	void __stdcall WindowCreated(EnvDTE::Window *Window);

private:
	CDTEAddIn *m_pParent;

}; // End CWindowEventsSink.

// CBuildEventsSink
/**
 * \class CBuildEventsSink
 *
 * \brief C++ class sinking Visual Studio's build-related events
 *
 *
 */
class CBuildEventsSink:
	public IDispEventImpl<1, CBuildEventsSink, &__uuidof(EnvDTE::_dispBuildEvents), &EnvDTE::LIBID_EnvDTE, 7, 0>
{
public:
	/// Construct with a reference to our owner
	CBuildEventsSink(CDTEAddIn *pParent);

#ifndef DOXYGEN_INVOKED        // Shield the macros from doxygen...
	BEGIN_SINK_MAP(CBuildEventsSink)
		SINK_ENTRY_EX(1, __uuidof(EnvDTE::_dispBuildEvents), 3, BeforeBuildStart)
		SINK_ENTRY_EX(1, __uuidof(EnvDTE::_dispBuildEvents), 4, AfterBuildFinish)
		SINK_ENTRY_EX(1, __uuidof(EnvDTE::_dispBuildEvents), 5, BeforeProjConfBuildStart)
		SINK_ENTRY_EX(1, __uuidof(EnvDTE::_dispBuildEvents), 6, BuildProjConfFinish)
	END_SINK_MAP()
#endif // not DOXYGEN_INVOKED

public:
	void __stdcall BeforeBuildStart(EnvDTE::vsBuildScope Scope, EnvDTE::vsBuildAction Action);
	void __stdcall AfterBuildFinish(EnvDTE::vsBuildScope Scope, EnvDTE::vsBuildAction Action);
	void __stdcall BeforeProjConfBuildStart(BSTR sProject, BSTR sProjectConfig, BSTR sPlatform, BSTR sSolutionConfig);
	void __stdcall BuildProjConfFinish(BSTR sProject, BSTR sProjectConfig, BSTR sPlatform, BSTR sSolutionConfig, bool bSuccess);

private:
	CDTEAddIn *m_pParent;

	// If there are any problems during the increment version process,
	// collect the error messages from each project build and then
	// display them all at the end.
	std::list<std::string>	m_listIncWarningMessages;
}; // End CBuildEventsSink.

extern _ATL_FUNC_INFO OnClickButtonInfo;

/**
 * \class CDTEAddIn
 *
 * \sa CAddIn
 *
 * \brief Incarnates the INCVERSION.CoDTEAddIn Com component
 *
 *
 * \note This component is not externally creatble; it is only meant to
 * be aggregated into CoAddIn.
 *
 *
 */

class ATL_NO_VTABLE CDTEAddIn :
	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<CDTEAddIn, &CLSID_CoDTEAddIn>,
	public ISupportErrorInfo,
	public IDispatchImpl<EnvDTE::IDTCommandTarget, &EnvDTE::IID_IDTCommandTarget, &EnvDTE::LIBID_EnvDTE, 7, 0>,
	public IDispatchImpl<AddInDO::_IDTExtensibility2, &AddInDO::IID__IDTExtensibility2, &AddInDO::LIBID_AddInDesignerObjects, 1, 0>,
	// N.B. We only want to sink a few events fired through this
	// interface, so we use IDispEventSimplImpl rather than
	// IDispatchImpl, which requires that the entire interface
	// be implemented.
	public IDispEventSimpleImpl<1, CDTEAddIn, &__uuidof(Office::_CommandBarButtonEvents)>,
	public IDispEventSimpleImpl<2, CDTEAddIn, &__uuidof(Office::_CommandBarButtonEvents)>
{
public:
	/// ATL requires a default ctor
	CDTEAddIn();
	/// ATL-defined initialization routine
	HRESULT FinalConstruct();
	/// ATL-defined cleanup routine
	void FinalRelease();
	/// VisEmacs initialization routine
	void SetParam(CAddIn *pParent);

#ifndef DOXYGEN_INVOKED        // Shield the macros from doxygen...
	/// Tell the ATL Registrar *not* to register us
	DECLARE_NO_REGISTRY();
	/// This component may only be created as an aggregate
	DECLARE_ONLY_AGGREGATABLE(CDTEAddIn)
	/// Tell ATL which interfaces we support
	BEGIN_COM_MAP(CDTEAddIn)
		COM_INTERFACE_ENTRY(ISupportErrorInfo)
		COM_INTERFACE_ENTRY(EnvDTE::IDTCommandTarget)
		COM_INTERFACE_ENTRY(AddInDO::_IDTExtensibility2)
		COM_INTERFACE_ENTRY2(IDispatch, AddInDO::IDTExtensibility2)
	END_COM_MAP()

	BEGIN_SINK_MAP(CDTEAddIn)
		SINK_ENTRY_INFO(1, __uuidof(Office::_CommandBarButtonEvents),/*dispid*/ 0x01, OnClickInc, &OnClickButtonInfo)
		SINK_ENTRY_INFO(2, __uuidof(Office::_CommandBarButtonEvents),/*dispid*/ 0x01, OnClickCfg, &OnClickButtonInfo)
	END_SINK_MAP()
#endif // not DOXYGEN_INVOKED

	//////////////////////////////////////////////////////////////////////
	// Interface ISupportsErrorInfo
public:
	STDMETHOD(InterfaceSupportsErrorInfo)(/*[in]*/ REFIID riid);

	//////////////////////////////////////////////////////////////////////
	// IDTCommandTarget
public:
	/// Returns the current status of the specified named command
	STDMETHOD(QueryStatus)(BSTR bstrCmdName, EnvDTE::vsCommandStatusTextWanted nNeededText, EnvDTE::vsCommandStatus *pnStatusOption, VARIANT *varCommandText);
	/// Execute a given named command
	STDMETHOD(Exec)(BSTR bstrCmdName, EnvDTE::vsCommandExecOption nExecuteOption, VARIANT *pvarVariantIn, VARIANT *pvarVariantOut, VARIANT_BOOL *pvbHandled);

	//////////////////////////////////////////////////////////////////////
	// IDTExtensibility2
public:
	/// Called by our host to setup a connection to this AddIn
	STDMETHOD(OnConnection)(IDispatch *pApplication, AddInDO::ext_ConnectMode nMode, IDispatch *pAddInInst, SAFEARRAY **ppCustom);
	/// Called by our host when this AddIn is unloaded
	STDMETHOD(OnDisconnection)(AddInDO::ext_DisconnectMode nMode, SAFEARRAY **custom);
	STDMETHOD(OnAddInsUpdate)(SAFEARRAY **custom);
	STDMETHOD(OnStartupComplete)(SAFEARRAY **custom);
	STDMETHOD(OnBeginShutdown)(SAFEARRAY **custom);

	void __stdcall OnClickInc(IDispatch * /*Office::_CommandBarButton**/ pCtrl, VARIANT_BOOL *pCancelDefault);
	void __stdcall OnClickCfg(IDispatch * /*Office::_CommandBarButton**/ pCtrl, VARIANT_BOOL *pCancelDefault);

	typedef IDispEventSimpleImpl</*nID =*/ 1, CDTEAddIn, &__uuidof(Office::_CommandBarButtonEvents)> IncEvents;
	typedef IDispEventSimpleImpl</*nID =*/ 2, CDTEAddIn, &__uuidof(Office::_CommandBarButtonEvents)> CfgEvents;

public:
	_bstr_t GetActiveProjectName();
	CAddIn *GetParent() {return m_pParent;}
	std::string GetSolutionPath();
	CComPtr<EnvDTE::_DTE> GetApplication() {return m_pApp;}
private:
	CComPtr<EnvDTE::Project> GetActiveProject();
	CComPtr<EnvDTE::Project> GetFirstStartupProject();
	CComPtr<EnvDTE::Project> GetProjectByFileName(const _bstr_t &sPrjFileName);
	CComPtr<EnvDTE::Project> GetProject(const _bstr_t &sProject, BOOL bIsFileName=FALSE);
	long GetProjectCount();

	/// Make sure our commands are present & setup any needed toolbars
	void AddCommands(AddInDO::ext_ConnectMode nMode);
	/// Add our commands to Visual Studio .Net 2003
	void AddCommandsVS2003(AddInDO::ext_ConnectMode nMode);
	/// Add our commands to Visual Studio 2005
	void AddCommandsVS2005(AddInDO::ext_ConnectMode nMode);
	/// Either get our host to display it's configuration UI, or delegate
	/// to the parent to display our own configuration dialog
	void ConfigureInternal();
	/// Deduce our host based on what interfaces it supports
	Host GuessHostType(IDispatch *pApp);
	/// Remove our command bars, if needed
	void RemoveCommands(AddInDO::ext_DisconnectMode nMode);
	/// Remove our commands from Visual Studio .Net 2003
	void RemoveCommandsVS2003(AddInDO::ext_DisconnectMode nMode);
	/// Remove our commands from Visual Studio 2005
	void RemoveCommandsVS2005(AddInDO::ext_DisconnectMode nMode);
	/// Sink any host-generated events we care about
	void SinkEvents(AddInDO::ext_ConnectMode nMode);
	/// Un-advise an sinks we've setup
	void UnSinkEvents(AddInDO::ext_DisconnectMode nMode);

private:
	/// Command bar name
	static const wchar_t *CMD_BAR_NAME;
	/// Short name of our "IncVersion" command
	static const CComBSTR CMD_INCREMENT;
	/// "IncVersion" command description
	static const CComBSTR CMD_DSC_INCREMENT;
	/// Fully qualified name of our "IncVersion" command
	static const wchar_t * CMD_FULL_INCREMENT;
	/// Short name of our "Configure" command
	static const CComBSTR CMD_CONFIGURE;
	/// "Configure" command  description
	static const CComBSTR CMD_DSC_CONFIGURE;
	/// Fully qualified name of our "Configure" command
	static const wchar_t * CMD_FULL_CONFIGURE;

private:
	/// Reference on our AddIn instance
	CComPtr<EnvDTE::AddIn> m_pAddIn;
	/// Reference to our host's Application object
	CComPtr<EnvDTE::_DTE> m_pApp;
	/// Which host are we loaded into
	Host m_nHost;
	/// Non-owning reference to our parent CAddIn instance
	CAddIn *m_pParent;
	/// DTE Window Event Sink
	CWindowEventsSink m_objWindowEvents;
	/// Reference on our host for advising & un-advising of Events
	CComPtr<EnvDTE::_WindowEvents> m_pWinEvents;
	/// DTE Build Event Sink
	CBuildEventsSink m_objBuildEvents;
	/// Reference on our host for advising & un-advising of Events
	CComPtr<EnvDTE::_BuildEvents> m_pBuildEvents;
	/// Reference on our temporary command bar (not VS 8.0)
	CComPtr<Office::CommandBar> m_pCommandBar;
#if(INCVERSION_COMMAND_BAR_STYLE == INCVERSION_COMMAND_BAR_TEMPORARY)
	/// Reference on our temporary command bar (VS 8.0)
	CComPtr<MSVSCBs::CommandBar> m_pCommandBar80;
#endif
}; // End CDTEAddIn.

OBJECT_ENTRY_AUTO(__uuidof(CoDTEAddIn), CDTEAddIn)

// Local Variables:
// fill-column: 72
// indent-tabs-mode: nil
// show-trailing-whitespace: t
// End:

#endif // DTEADDIN_H_E212DF6C_4B8E_4DDE_9653_D9262759406F

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)
United Kingdom United Kingdom
Ok, it's about time I updated this profile. I still live near 'Beastly' Eastleigh in Hampshire, England. However I have recently been granted a permamant migration visa to Australia - so if you're a potential employer from down under and like the look of me, please get in touch.
Still married - just, still with just a son and daughter. But they are now 8 and 7 resp and when together they have the energy of a nuclear bomb.
I worked at Teleca UK for over 8.5 years (but have now moved to TikitTFB) and have done loads of different things. Heavily involved with MFC, SQL, C#, The latest is ASP.NET with C# and Javascript. Moving away from Trolltech Qt3 and 4.
Jordan.

Comments and Discussions