65.9K
CodeProject is changing. Read more.
Home

Microsoft Visual Studio Solution File Version Changer

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.95/5 (15 votes)

Apr 6, 2010

CPOL

2 min read

viewsIcon

101466

downloadIcon

4014

Microsoft Visual Studio Solution File Version Changer - for Visual Studio versions 2002, 2003, 2005, 2008 and 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)