Microsoft Visual Studio 解决方案文件版本更改器






4.95/5 (15投票s)
Microsoft Visual Studio 解决方案文件版本转换器 - 适用于 Visual Studio 2002、2003、2005、2008 和 2010 版本
引言
该项目是 Windows Explorer Shell 扩展(右键菜单),用于快速更改 Visual Studio 解决方案文件的版本。项目源代码展示了如何创建 Explorer Shell 扩展以及如何在解决方案版本之间进行转换。此 Shell 扩展的基础是 Michael Dunn 的 编写 Shell 扩展的完全傻瓜指南 - 第二部分。

Visual Studio 解决方案文件版本
以下是 Visual Studio 版本的概述,以及文件和产品版本,这可能有点令人困惑,因为涉及了许多不同的版本。
Visual Studio 版本 | 文件版本 | 产品版本 |
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 |
解决方案文件版本 8.00
直到版本 8.00,您只需要更改 *.sln 文件中第二行的版本号
解决方案文件版本 9.00
在版本 9.00 及更高版本中,您需要更改第二行和第三行

Using the Code
一个使用 Visual Studio .NET 2008 编译的 VC++ 项目,但也可以使用 VS2003 编译。它是一个 ATL ComObject,需要使用 regsvr32 注册。代码展示了如何
- 使用 ATL 创建自注册 COM 对象
- 转换 Microsoft VS *.sln 文件之间的版本
- 在 Explorer 上下文菜单中创建带有图标的子菜单
首先,我们分析版本并将原始文件保存到内部结构(字符串向量)
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;
}
使用以下函数,我们可以将文件转换为所需的任何版本。
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;
}
这里是 QueryContextMenu()
的一个片段。使用此函数,您可以从注册表中加载的上下文菜单标签文本构建菜单结构。
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++;
...
配置
在配置对话框中,您可以设置首选转换设置,例如是否备份和/或覆盖原始文件,或者您可以设置上下文菜单文本。

致谢
- Michael Dunn - 编写 Shell 扩展的完全傻瓜指南 - 第二部分
历史
- 2010 年 4 月 18 日 - 版本 1.0.0.2
- 新版本,支持 VS 版本 2002-2010 和更多配置选项
- 2010 年 4 月 3 日 - 版本 1.0.0.0
- 初始修订版,包含解决方案文件版本 7.00 (7)、8.00 (7.1)、9.00 (8) 和 10.00 (9) 的转换器 // 文件版本 (图标版本)