VSS 是微软的 项目管理工具,全称是 MicroSoft Visual SourceSafe. 现在的版本是 VSS2005 ,老一点的公司有的还在用VSS6.0,是跟 VC++ 6.0 配套的管理工具。虽然是微软的产品,但这款软件是出了名的难用,连微软自己都不用。微软自己不用,但少不了别人用。鄙人的上一个项目就是用的VSS,后来改成了 AB(Alienbrain )。在网上下载代码阅读,发现好多也是用VSS管理的。用IDE打开的时候,会弹出对话框,多而且讨厌。这两天有空,就特意研究了一下VSS,写了个小工具用,系统上只装了 VSS2003 和 VS2008,所以主要是以这两个版本的VS 写的类
如果把一个项目传到VSS上去,那么VSS会对这个项目做如下操作。
第一,在每个文件夹下 添加 一些 .scc 文件 和 .vspscc 文件
第二, 更改 .sln 文件 在 其中的
GlobalSection(SourceCodeControl) = preSolution 和 EndGlobalSection 中间添加vss 控制的代码
第三,更改工程文件 ,既 .cproj (c++)或者 .csproj(c#) 文件等,在这些文件中添加Vss 控制的代码。
第四,把所有文件置为只读文件
只要把这些都消除了。那么工程也就会变成一个 纯的本地工程,打开的时候没有了烦人的提示框了。
下面是自己写的 C++ 清理类,
//-头文件
class CVssClearManager
{
public: //-Static Function
static unsigned _stdcall ThreadClearDirectory (void* params);
static void Delete ();
static CVssClearManager* g_VssClearManager;
public:
CVssClearManager ();
~CVssClearManager ();
public: //主要接口
void Execute (const string_t& DirectoyName); //
void Stop ();
//bool IsExecuting () const {return m_bExecute;}
public: //处理函数用的接口
void SetListBoxHwnd (HWND hwnd) ;
private:
void ProcessDirectory (const string_t& directoryName);
void ProcessFile_Sln (const string_t& fileName);
void ProcessFile_Proj (const string_t& fileName); //-
private:
void LoadFile (const string_t& fileName);
void SaveFile (const string_t& fileName);
private:
void ResetLog ();
void Log (const string_t& _msg);
private: //Flag
//bool m_bExecute;
bool m_bStop; //-
private:
ILog* m_pLog; //-Log File
string_t m_TmpString_1; //-tmp 1
string_t m_Directory; //-文件夹
StringVector m_ItemColl;
char* m_pFileBuffer; //-文件缓冲区
};
//-源文件
CVssClearManager* CVssClearManager::g_VssClearManager = NULL;
unsigned _stdcall CVssClearManager::ThreadClearDirectory(void *params)
{
if(g_VssClearManager == NULL)
g_VssClearManager = new CVssClearManager; //BuildClearManager
PTCDContent pParams = (PTCDContent)params;
g_VssClearManager ->SetListBoxHwnd(pParams ->hLogWnd);
g_VssClearManager ->Execute(pParams ->DirectoryName);
EnableWindow(GetDlgItem(pParams ->hWnd,IDC_PLAY),TRUE);
EnableWindow(GetDlgItem(pParams ->hWnd,IDC_STOP),FALSE);
g_VssClearManager ->Log(_T("完成 !!"));
_endthreadex(0);
return 0;
}
void CVssClearManager::Delete()
{
if(g_VssClearManager != NULL)
{
delete g_VssClearManager;
g_VssClearManager = NULL;
}
}
CVssClearManager::CVssClearManager()
{
m_bStop = true;
//m_bExecute = false;
m_Directory = _T("");
m_TmpString_1 = _T("");
m_ItemColl.clear();
m_pFileBuffer = NULL;
m_pLog = NULL;
}
CVssClearManager::~CVssClearManager()
{
delete [] m_pFileBuffer;
m_pFileBuffer = NULL;
delete m_pLog;
m_pLog = NULL;
m_Directory.clear();
m_ItemColl.clear();
}
void CVssClearManager::Execute(const string_t &DirectoryName)
{
m_bStop = false;
m_Directory = DirectoryName;
g_VssClearManager ->ResetLog();
g_VssClearManager ->Log(_T("开始 !!"));
ProcessDirectory(DirectoryName);
//m_bExecute = true; //-
}
void CVssClearManager::Stop()
{
//m_bExecute = false;
m_bStop = true;
}
void CVssClearManager::SetListBoxHwnd(HWND hWnd)
{
if(m_pLog != NULL)
delete m_pLog; //-
m_pLog = new CProcessLog(hWnd);
}
//private
void CVssClearManager::LoadFile(const string_t &fileName)
{
if(fileName.empty())
return;
if(!m_ItemColl.empty())
m_ItemColl.clear(); //-清理
FILE* fp = _tfopen(fileName.c_str(),_T("rb"));
if(fp)
{
#pragma region "读取文件"
long length = 0;
fseek(fp,0,SEEK_END);
length = ftell(fp);
fseek(fp,0,SEEK_SET);
if(m_pFileBuffer == NULL)
{
m_pFileBuffer = new char[length + 1];
}
else
{
int nFileBuffSize = _msize((void*)m_pFileBuffer);
if(nFileBuffSize < (length +1))
{
delete []m_pFileBuffer;
try
{
m_pFileBuffer = new char[length + 1];
}
catch(...)
{
delete []m_pFileBuffer;
m_pFileBuffer = NULL;
assert(!"内存不够了!!");
return;
}
}
}
memset((void*)m_pFileBuffer,0,length + 1);
fread((void*)m_pFileBuffer,1,length,fp);
if(ferror(fp))
{
assert(!"Error Reading File");
}
fclose(fp);
#pragma endregion
#pragma region "格式化字符串"
const char* pos = m_pFileBuffer;
const char* pos_0 = m_pFileBuffer;
while(*pos)
{
if(*pos++ == 10) //这里的换行都是 0x0D 0x0A,
{
int nLen = pos - pos_0;
string tmp1(pos_0,nLen);
m_ItemColl.push_back(tmp1);
pos_0 = pos;
}
}
#pragma endregion
}
}
void CVssClearManager::SaveFile(const string_t& fileName)
{
if(fileName.empty()) return;
FILE* fp = _tfopen(fileName.c_str(),_T("wb"));
if(fp)
{
StringVector::iterator it;
for(it = m_ItemColl.begin();it != m_ItemColl.end(); ++it)
{
::fwrite(it ->c_str(),1,it ->size(),fp);
}
if(ferror(fp))
{
assert(!"Error Writing File");
}
fclose(fp);
}
}
void CVssClearManager::ProcessDirectory(const string_t& directoryName)
{
if(m_bStop)
{
_endthreadex(0);
return;
}
string_t currentDir = directoryName;
string_t tmpString = _T("切换文件夹: ");
//m_TmpString = _T("切换文件夹");
//m_TmpString += directoryName.c_str(); //-
tmpString += currentDir.c_str();
//Log(m_TmpString); //-
Log(tmpString);
WIN32_FIND_DATA FindFileData;
HANDLE hFind = INVALID_HANDLE_VALUE;
tmpString = directoryName + _T("\\*");
hFind = FindFirstFile(tmpString.c_str(), &FindFileData);
if(hFind == INVALID_HANDLE_VALUE)
{
return;
}
else
{ //查找的第一个文件都是"."或者".."m,都是目录,所以不进行文件操作了
if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
tmpString = FindFileData.cFileName; //-
if(tmpString != _T(".") && tmpString != _T(".."))
{
tmpString = directoryName + _T("\\") + FindFileData.cFileName;
ProcessDirectory(tmpString);
}
}
}
while(FindNextFile(hFind,&FindFileData)!= 0)
{
if(m_bStop)
{
_endthreadex(0);
return; //-
}
if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
tmpString = FindFileData.cFileName;
if(tmpString != _T(".") && tmpString != _T(".."))
{
tmpString = directoryName + _T("\\") + FindFileData.cFileName;
ProcessDirectory(tmpString);
}
}
else
{
//-取消只读属性
tmpString = directoryName + _T("\\") + FindFileData.cFileName;
FindFileData.dwFileAttributes &= (~FILE_ATTRIBUTE_READONLY);
SetFileAttributes(tmpString.c_str(),FindFileData.dwFileAttributes);
string_t::size_type suffixpos = tmpString.rfind(_T("."));
if(suffixpos == string_t::npos)
continue; //
m_TmpString_1 = tmpString.substr(suffixpos);
if(
m_TmpString_1 == _T(".SCC") || m_TmpString_1 == _T(".scc")
||m_TmpString_1 == _T(".vssscc") ||m_TmpString_1 == _T(".VSSSCC")
||m_TmpString_1 == _T(".vspscc") ||m_TmpString_1 == _T(".VSPSCC")
)
{
::DeleteFile(tmpString.c_str());
tmpString = _T("删除文件: ") + tmpString;
Log(tmpString);
}
else if (m_TmpString_1 == _T(".SLN") || m_TmpString_1 == _T(".sln"))
{
ProcessFile_Sln(tmpString);
tmpString = _T("处理文件: ") + tmpString;
Log(tmpString);
}
else if(m_TmpString_1 == _T(".vcproj") || m_TmpString_1== _T(".VCPROJ")
|| m_TmpString_1 == _T(".csproj") || m_TmpString_1== _T(".CSPROJ"))
{
ProcessFile_Proj(tmpString);
tmpString = _T("处理文件: ") + tmpString;
Log(tmpString);
}
}
}
FindClose(hFind);
}
void CVssClearManager::ProcessFile_Proj(const string_t &fileName)
{
if(m_bStop)
{
_endthreadex(0);
return;
}
LoadFile(fileName);
if(m_ItemColl.empty()) return;
StringVector::iterator it = m_ItemColl.begin();
while(it != m_ItemColl.end())
{
string::size_type flag_pos = it ->find("\tScc");
string::size_type flag_pos_1 = it ->find(" Scc");
string::size_type flag_pos_end;
if(flag_pos != string::npos || flag_pos_1 != string::npos) //找到了
{
flag_pos_end = it ->find('>');
if(flag_pos_end != string::npos)
{
*it = "\t>";
++it;
}
else
{
it = m_ItemColl.erase(it);
}
}
else
{
++it;
}
}
SaveFile(fileName);
}
void CVssClearManager::ProcessFile_Sln(const string_t& fileName)
{
if(m_bStop)
{
_endthreadex(0);
return;
}
LoadFile(fileName);
if(m_ItemColl.empty()) return;
bool bEraseFlag = false;
StringVector::iterator it = m_ItemColl.begin();
while(it != m_ItemColl.end())
{
if( it ->find("GlobalSection(SourceCodeControl)") != string::npos)
{
bEraseFlag = true;
}
if(bEraseFlag)
{
if(it ->find("EndGlobalSection") != string::npos)
{
bEraseFlag = false;
}
it = m_ItemColl.erase(it);
}
else
{
++it;
}
}
SaveFile(fileName);
}
//-log
void CVssClearManager::ResetLog()
{
if(m_pLog != NULL)
{
m_pLog ->Clear();
}
}
void CVssClearManager::Log(const string_t& msg)
{
if(m_pLog != NULL)
{
m_pLog ->Log(msg);
}
}
//-完成 //
根据这个类,写了个小工具,传到CSDN资源里了。有问题欢迎大家评论交流
链接1 :VSS在 .sln 和 proj文件内部 做了什么改动
http://codeidol.com/windows/visual-studio-hack/Master-Projects-and-Solutions/Remove-SourceSafe-Bindings/#part-16