Click here to Skip to main content
Click here to Skip to main content

Microsoft Visual Studio Solution File Version Changer

By , 18 Apr 2010
 

Introduction

This project is a Windows Explorer Shell Extension (right mouse menu) for quickly changing the version of a Visual Studio Solution File. The project source shows you how to create a Explorer Shell Extension and how to convert between the solution versions. The basis for this Shell Extension is Michael Dunn's The Complete Idiot's Guide to Writing Shell Extensions - Part II.

Shot_ContextMenu_v1.0.0.2.png

Visual Studio Solution File Versions

Here you have an overview of the Visual Studio Versions with the File and Product Versions as it might be a little confusing seeing through all the different versions involved.

Visual Studio Version File Version Product Version
Microsoft Visual Studio .NET (2002) 7.00 7
Visual Studio 2003 8.00 7.1
Visual Studio 2005 9.00 8
Visual Studio 2008 10.00 9
Visual Studio 2010 11.00 10

Solution File Version 8.00

Till version 8.00, all you need to change is the version number on the second line in the *.sln file:

2003_file.png

Solution File Version 9.00

In version 9.00 and above, you have to change the second line as well as the third:

2005_file.png

Using the Code

A VC++ project compiled with Visual Studio .NET 2008 but also can be compiled with VS2003. It's an ATL ComObject which has to be registered with regsvr32. The code shows you how to:

  • Create self registering COM Object with ATL
  • Convert Microsoft VS *.sln files between versions
  • Create submenus with icon in Explorer context menu

First we analyze the version and save the original file to an internal structure (vector of string):

SlnVersions CVersionChanger::AnalyzeFileVersion(const string_list* pFileList) {
    m_pFileList = pFileList;
    SlnVersions slnFoundVersion = SlnVersions::NA;

    int nSize = m_pFileList->size();
    vector< vector<string>> v_arr(nSize);
    vector<int> v_lines;
    vector<double> v_versions;

    int filePos = 0;    

    for ( string_list::const_iterator it = m_pFileList->begin(); 
	it != m_pFileList->end(); it++ ){
        ifstream ifs(it->c_str());
        string temp; 
        int linePos = 0;
        bool lineFound = false;

        while(getline(ifs, temp )){
            v_arr[filePos].push_back(temp);
            const char* sTmpLine = strstr(temp.c_str(), FORMAT_VERSION_TAG);
            if(sTmpLine != 0){
                v_lines.push_back(linePos);
                string sLine = temp.c_str();
                string str2 = sLine.substr(strlen(FORMAT_VERSION_TAG)+1, 
		sLine.length() - strlen(FORMAT_VERSION_TAG)-1);
                double dVar = 0;
                dVar = atof(str2.c_str()); 
                v_versions.push_back(dVar);
                switch((int)dVar){
                    case 11:
			slnFoundVersion = SlnVersions::eleven;
			break;
                    case 10:
                        slnFoundVersion = SlnVersions::ten;
                        break;
                    case 9:
                        slnFoundVersion = SlnVersions::nine;
                        break;
                    case 8:
                        slnFoundVersion = SlnVersions::eight;
                        break;
                    case 7:
                        slnFoundVersion = SlnVersions::seven;
                        break;
                    default:
                        slnFoundVersion = SlnVersions::NA;
                }
                v_slnVersions.push_back((int)slnFoundVersion);
                lineFound = true;
            }
            linePos++;
        }
        if(!lineFound)
            v_lines.push_back(-1);

        ifs.close();
        filePos++;
    } 
    v_lineContent  = v_arr;
    v_linePos = v_lines;
    v_fileVersions = v_versions;
    return slnFoundVersion;
    }

With the following function, we can convert the file(s) to any version we need.

void CVersionChanger::ChangeVersion(SlnVersions slnChangeTo){
    int nCounter = 0;
    for ( string_list::const_iterator it = m_pFileList->begin(); 
		it != m_pFileList->end(); it++ ) {
        
        
        if(cfgMgr.bBackup)
            ff.CreateBakFile(it->c_str(), cfgMgr.sBakExt);

        string sTmpExt = cfgMgr.sNewExt;
        string sTmpOut = it->c_str();

        if(!cfgMgr.bOverwrite)
            sTmpOut = sTmpOut + sTmpExt;

        ofstream outputFile(sTmpOut.c_str());

            //As long as output file is open...
        if(outputFile.is_open())
        {
            for(int i = 0; i < v_lineContent[nCounter].size(); i++){
                //And then write out all that was read
                string sOut = "";
                int nOutLen = 0;
                if(i == v_linePos.at(nCounter)){
                    char* sTmpOutput = new char[strlen(FORMAT_VERSION_TAG) + 
				(v_fileVersions.at(nCounter)>= 10 ? 4 : 3) + 2];
                    sprintf(sTmpOutput, "%s %i.00\n", FORMAT_VERSION_TAG,  
				(int)slnChangeTo);
                    sOut = sTmpOutput;
                    nOutLen = strlen(sTmpOutput);
                }else{
                    sOut = v_lineContent[nCounter].at(i) + "\n";
                    nOutLen = v_lineContent[nCounter].at(i).length()+1;
                }
                outputFile.write((char*)sOut.c_str(), nOutLen);
                if(i == v_linePos.at(nCounter)){
                   if(slnChangeTo == SlnVersions::eleven){
			outputFile.write(VS2010, strlen(VS2010));
			if(v_fileVersions.at(nCounter) != 
			(int)SlnVersions::eight | v_fileVersions.at(nCounter) != 
			(int)SlnVersions::seven)
		            i++;
                   }else if(slnChangeTo == SlnVersions::ten){
                        outputFile.write(VS2008, strlen(VS2008));
                        if(v_fileVersions.at(nCounter) != 
			(int)SlnVersions::eight | v_fileVersions.at(nCounter) != 
			(int)SlnVersions::seven)
                            i++;
                    }else if(slnChangeTo == SlnVersions::nine){
                        outputFile.write(VS2005, strlen(VS2005));
                        if(v_fileVersions.at(nCounter) != 
			(int)SlnVersions::eight | v_fileVersions.at(nCounter) != 
			(int)SlnVersions::seven)
                            i++;
                    }else if(slnChangeTo == SlnVersions::eight){
                        if(v_fileVersions.at(nCounter) != 
			(int)SlnVersions::eight | v_fileVersions.at(nCounter) != 
			(int)SlnVersions::seven)
                            i++;
                    }else if(slnChangeTo == SlnVersions::seven){
                        if(v_fileVersions.at(nCounter) != 
			(int)SlnVersions::eight | v_fileVersions.at(nCounter) != 
			(int)SlnVersions::seven)
                            i++;
                    }
                }
            }
        }
        //If there were problems with creating the file, let the user know
        else if(!outputFile.is_open())
        {
            printf("I couldn't open %s for creation!\n", "outputFilePath");
            v_bSucceeded.push_back(false);
            return 0;
        }
        outputFile.close();
        v_bSucceeded.push_back(true);
        v_slnNewVersions.push_back(slnChangeTo);

        nCounter++;
    }
    return;
}

Here a snippet of QueryContextMenu(). With this function, you build up the menu structure with the context menu lable text loaded from the registry.

HRESULT CVSSolutionVersionChangerDll::QueryContextMenu (
    HMENU hmenu, UINT uMenuIndex, UINT uidFirstCmd, UINT uidLastCmd, UINT uFlags )
{
UINT uCmdID = uidFirstCmd;

	SlnVersions slnVer = vc.AnalyzeFileVersion(&m_lsFiles);
	
    // If the flags include CMF_DEFAULTONLY then we shouldn't do anything.
    if ( uFlags & CMF_DEFAULTONLY )
        return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, 0 );

	HMENU mPopUp = CreatePopupMenu();

	UINT nFlags = MF_STRING | MF_BYPOSITION;
	if(m_lsFiles.size() == 1 &&  slnVer == SlnVersions::seven)
		nFlags = nFlags | MF_GRAYED;

	InsertMenu ( mPopUp,uMenuIndex, nFlags, uCmdID++, cMgr.s2002.c_str() ); 

	uMenuIndex++;

	nFlags = MF_STRING | MF_BYPOSITION;
	if(m_lsFiles.size() == 1 &&  slnVer == SlnVersions::eight)
		nFlags = nFlags | MF_GRAYED;

	InsertMenu ( mPopUp,uMenuIndex, nFlags, uCmdID++, cMgr.s2003.c_str() );

	uMenuIndex++;

	nFlags = MF_STRING | MF_BYPOSITION;
	if(m_lsFiles.size() == 1 &&  slnVer == SlnVersions::nine)
		nFlags = nFlags | MF_GRAYED;

	InsertMenu ( mPopUp,uMenuIndex, nFlags, uCmdID++, cMgr.s2005.c_str() );

	uMenuIndex++;

...		 

Config

On the config dialog, you can set your preferred conversion settings, whether to backup and/or overwrite the original file or you can set the context menu text.

Shot_Config_v1.0.0.2.png

Credits

  • Michael Dunn - The Complete Idiot's Guide to Writing Shell Extensions - Part II

History

  • April 18. 2010 - Version 1.0.0.2
    • New release with support for VS version 2002-2010 and more config options
  • April 03. 2010 - Version 1.0.0.0
    • Initial revision with converter for solution file version 7.00 (7), 8.00 (7.1), 9.00 (8) and 10.00 (9) // FileVersion (IconVersion)

License

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

About the Author

kim.david.hauser
Software Developer (Senior)
Switzerland Switzerland
Member
programmer and software junkie since 1991 zurich switzerland

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5membermail-2227 Apr '12 - 1:20 
спасибо
GeneralRe: My vote of 5memberkim.david.hauser13 May '13 - 9:24 
And thank you! Big Grin | :-D
Generalsmall fixmemberKarpov Andrey25 Dec '10 - 6:15 
else if(!outputFile.is_open())
{
	printf("I couldn't open %s for copying!\n", outputFilePath);
	return 0;
}
else if(!initialFile.is_open())
{
	printf("I couldn't open %s for copying!\n", initialFilePath);
	return 0;
}
 
Need fix printf() calls (details - here):
 
else if(!outputFile.is_open())
{
	printf("I couldn't open %s for copying!\n", outputFilePath.c_str());
	return 0;
}
else if(!initialFile.is_open())
{
	printf("I couldn't open %s for copying!\n", initialFilePath.c_str());
	return 0;
}

GeneralRe: small fixmemberkim.david.hauser13 May '13 - 9:26 
TNX for the hint - I'll fix this as soon as a have time Wink | ;) - sorry for the delay
GeneralVisual Studio 2003 Build - No Context menumemberStone Free22 Apr '10 - 0:02 
Since I couldn't run your original due to a dependency on the Debug CRT, and lack of any Visual Studio higher than 2003 on my system, I had to compile it myself.
 
However despite the registry entries mentioned in the .RGS file existing in the registry there is no right click menu showing up in explorer.
 

Peter
GeneralDLL Built with debug CRTmemberStone Free19 Apr '10 - 23:55 
As the title, I installed the VC2008 Redistributable to run your code after finding it would not register. However I had not looked at the Dependency Walker output closely enough, and the missing DLLs are the Debug versions of the CRT.
GeneralSuggestionmemberAdam Maras8 Apr '10 - 17:23 
Could you add a configuration option that allows one to change which text is displayed in the context menu (i.e. "Visual Studio 2008" as opposed to "version 10.0 (9)")?
Adam Maras | Software Developer
Microsoft Certified Professional Developer

GeneralRe: SuggestionmemberSaurabh.Garg9 Apr '10 - 16:40 
This is a minor change and you have the source, why not change it yourself?
 
-Saurabh
NewsRe: Suggestionmemberkim.david.hauser18 Apr '10 - 2:16 
Done and done > Check out the new version with support for VS 2002-2010 and more config options (also as you suggested) > Cheerz kim OMG | :OMG:
GeneralWindows 7 x64memberRoberto Guerzoni7 Apr '10 - 2:36 
Hello.
I tried the program with Windows7 x64 but the new feature is not active.
I saw that in compiling the release versions. Def file was broken and I replaced it with
VSSolutionVersionChanger.def
Again no functionality.
Any suggestions?
 
Thanks
 
Roberto Guerzoni
GeneralRe: Windows 7 x64memberkim.david.hauser8 Apr '10 - 11:51 
Hi Roberto -
 
Are all registry settings made? Is this the same for win7? > MSDN
 
Try to compile another shell extention like The Complete Idiot's Guide to Writing Shell Extensions - Part II[^]
 
Sorry - but I dont have a Win7 64bit system to test it on. But maybe you finde someone else or you search the msdn for shell extentions in Windows 7.
It would be nice if you could inform me - thnx
 
Kim
GeneralRe: Windows 7 x64memberDave Aronow9 Apr '10 - 10:56 
First, are you targeting 64 bit? If not you may need to run the 32 bit version of Windows Explorer found in c:\windows\syswow64\explorer.exe.
Generalthanksmemberryukiy6 Apr '10 - 14:54 
this tool is very helpful for me. thanks ...
ryuki

GeneralexcellentmemberAndreone6 Apr '10 - 9:25 
I thought recently about writing a little script for that, but the shell extension is a nice idea. Thanks.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 18 Apr 2010
Article Copyright 2010 by kim.david.hauser
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid