От: | filkov | ||
Дата: | 12.04.10 18:00 | ||
Оценка: | 18 (1) |
Недавно на Code Project была опубликована моя статья VSS tool – mass unchecking.
Надеясь, что описанное в статье решение может оказаться интересным для участников RSDN, помещаю русский перевод.
// typelib filename: ssapi.dll
[
uuid(783CD4E0-9D54-11CF-B8EE-00608CC9A71F),
version(5.2),
helpstring("Microsoft SourceSafe 8.0 Type Library")
]
library SourceSafeTypeLib
...
interface IVSSItemOld : IDispatch {
...
[id(0x0000000d)]
HRESULT UndoCheckout(
[in, optional, defaultvalue("")] BSTR Local,
[in, optional, defaultvalue(0)] long iFlags);
interface IVSSUser : IDispatch {
...
[id(0x00000003), propput]
HRESULT Password([in] BSTR rhs);
...
// Hack the user: change the user's password and log in as the user
bool CMainDlg::HackUser(CString sUser, CString pw);
int CMainDlg::UndoCheckouts(CString strVssPath, LPCTSTR theUser);
int CMainDlg::UndoCheckouts(IVSSItemPtr vssi, CString strVssPath, LPCTSTR theUser);
_bstr_t bsVssPath = strVssPath;
IVSSItemPtr vssi = m_treeVss.m_pVssDB->GetVSSItem(bsVssPath, 0);
return UndoCheckouts(vssi, strVssPath, theUser);
if (vssi->GetType() == VSSITEM_PROJECT)
UndoCheckouts(vssi2, strVssPath, theUser);
UndoCheckout(vssi, strVssPath, theUser)
// undo checkout for the single file.
bool CMainDlg::UndoCheckout(IVSSItemPtr vssi, LPCTSTR strVssPath, LPCTSTR theUser);
IVSSItemPtr link;
IVSSItemsPtr links = vssi->Links;
int nLinks = vssi->Links->Count;
ATLTRACE(_T("Item %s has %d links\n"), (LPCTSTR)vssi->Spec, nLinks);
for(int i = 0; i < nLinks; i++)
{
IVSSItemPtr link = GetOneOfItems(links, i);
...
}
IVSSCheckoutsPtr lnkCheckouts = link->Checkouts;
long nCheckouts = lnkCheckouts->Count;
IVSSCheckoutPtr lnkCheckout;
for(long idx = 0; idx < nCheckouts; idx++) {...}
try
{
_bstr_t bsDefault;
bsDefault = "";
long nDefault = VSSFLAG_DELNO|VSSFLAG_KEEPYES;
hr = link->raw_UndoCheckout(bsDefault, nDefault);
}
catch (_com_error & e) {...}
////////////////////////////////////////////
// Headers:
//
#import "C:\Program Files\Microsoft Visual SourceSafe\SSAPI.DLL" no_namespace
// UndoCheckout menu-item selected
LRESULT CMainDlg::OnUnCheck(WORD /*wNotifyCode*/, WORD wID, HWND hwnd, BOOL& bHandled);
// Hack the user: change the user's password and log in as the user
bool CMainDlg::HackUser(CString sUser, CString pw);
// undo checkout recursively for the project
// verify strVssPath is part of the item->Spec!
// (there might be multiple links on the item)
int CMainDlg::UndoCheckouts(IVSSItemPtr vssi, CString strVssPath, LPCTSTR theUser);
// undo checkout for the single file; verify spec.
bool CMainDlg::UndoCheckout(IVSSItemPtr vssi, LPCTSTR strVssPath, LPCTSTR theUser);
////////////////////////////////////////////
// Implementation:
//
// UndoCheckout for specific user for:
// all subitems of the item selected on the tree / all items
// in the report / all selected items in the report
// returns the number of unchecked items
LRESULT CMainDlg::OnUnCheck(WORD /*wNotifyCode*/, WORD wID, HWND hwnd, BOOL& bHandled)
{
int unCount = 0;
// find out was it called from the tree or from the report
bool isTree = false;
if(m_hwndActive == m_wndListView.m_hWnd)
isTree = false;
else if(m_hwndActive == m_treeVss.m_hWnd)
isTree = true;
else
return 0;
// Retrieve the user from dialog control
CString theUser;
// ...
// Retrieve selected project
CString prj = m_treeVss.GetSelectedProject();
// ...
// if called from list view, check if there are selected files
// (one file, if just one selected; all files, if none selected)
if(!isTree)
{
int count = m_wndListView.GetItemCount();
int selCount = m_wndListView.GetSelectedCount();
// ...
// start unchecking
m_bReporting = true;
EnableControls(FALSE);
CWaitCursor cursor;
// ImpersonateUser(sUser); reset PW; open DB as the user
if(theUser.Compare(_T("Admin")))
bOk = HackUser(theUser, "exuser");
while((idx = m_wndListView.GetNextItem(idx, flag)) > -1)
{
dbg = m_wndListView.GetItemText(idx, 2, buf,
sizeof(buf)/sizeof(TCHAR));
if(!_tcslen(buf))
continue;
if(UndoCheckout(buf, theUser))
unCount++;
}
// reopen DB as admin
if(theUser.Compare(_T("Admin")))
OpenDatabase(m_sDbPath);
m_bReporting = false;
EnableControls();
}
else
{
CString message;
message.Format(_T("Undo '%s' checkouts recursively in %s?"), theUser, prj);
if(IDOK == MessageBox(message, _T("Uncheck"), MB_OKCANCEL|MB_ICONQUESTION))
{
// start unchecking
m_bReporting = true;
EnableControls(FALSE);
CWaitCursor cursor;
// ImpersonateUser(sUser); reset PW; open DB as the user
if(theUser.Compare(_T("Admin")))
bool bOk = HackUser(theUser, "exuser");
unCount = UndoCheckouts(prj, theUser);
// reopen DB as admin
if(theUser.Compare(_T("Admin")))
OpenDatabase(m_sDbPath);
}
}
m_bReporting = false;
EnableControls();
// restore selections; refresh controls
// ...
return unCount;
}
// Hack the user: change the user's password and log in as the user
bool CMainDlg::HackUser(CString sUser, CString pw)
{
bool bOk = false;
IVSSUsersPtr pUsers = NULL;
try
{
pUsers = m_treeVss.m_pVssDB->GetUsers();
CComVariant var(sUser);
IVSSUserPtr pUser = pUsers->GetItem(var);
_bstr_t bsPW = pw;
HRESULT hr = pUser->put_Password(bsPW);
if(FAILED(hr))
{
ATLTRACE(_T("HackUser::put_Password() error: %X\n"), hr);
return false;
}
_bstr_t bsDB = m_sDbPath;
_bstr_t bsUser = sUser;
hr = m_treeVss.m_pVssDB->Close();
hr = m_treeVss.m_pVssDB->raw_Open(bsDB, bsUser, bsPW);
if(FAILED(hr))
{
ATLTRACE(_T("HackUser:: raw_Open() error: %X\n"), hr);
return false;
}
bOk = true;
}
catch (_com_error & e)
{
ATLTRACE(_T("HackUser() error: %s\n"), e.ErrorMessage());
}
return bOk;
}
// undo checkout recursively for the project
// parameters are retrieved from the dialog controls:
// IVSSItemPtr vssi - VSS item;
// CString strVssPath - VSS item path;
// LPCTSTR theUser - the user to undo checkouts for;
int CMainDlg::UndoCheckouts(IVSSItemPtr vssi, CString strVssPath, LPCTSTR theUser)
{
int count = 0;
int idx = 0;
_variant_t var;
IVSSItemPtr vssi2;
IVSSItemsPtr vssis; // VSS collection
CWaitCursor cursor;
// if user clicked Cancel button – cancel checkouts
GetDlgItem(IDCANCEL).EnableWindow();
if (!Continue(m_bReporting))
{
GetDlgItem(IDCANCEL).EnableWindow(FALSE);
return idx;
}
if (vssi->GetType() == VSSITEM_PROJECT)
{
vssis = vssi->GetItems(FALSE);
for(idx = 0; idx < vssis->GetCount(); idx++)
{
var = (long)(idx + 1);
vssi2 = vssis->GetItem(var);
UndoCheckouts(vssi2, strVssPath, theUser);
}
}
else
{
// we hit the bottom: it's an item (not the project/folder)
ATLTRACE(_T("Uncheck item %s, version %d\n"),
(LPCTSTR)vssi->Spec, vssi->VersionNumber);
if(UndoCheckout(vssi, strVssPath, theUser))
count++;
}
return count;
}
// undo checkout for the specified VSS item
// IVSSItemPtr vssi - VSS item;
// CString strVssPath - VSS item path;
// LPCTSTR theUser - the user to undo checkouts for;
bool CMainDlg::UndoCheckout(IVSSItemPtr vssi, LPCTSTR strVssPath, LPCTSTR theUser)
{
bool bOk = false;
long nCheckouts = 0;
long nVersion = (long)(-1);
CString csUser;
csUser = theUser;
// find in the links the one with the right spec
// NB: there might be multiple links for the VSS items
//– the item may be shared between the projects
// and for each link there maight be several checkouts by different users
IVSSItemPtr link;
IVSSItemsPtr links = vssi->Links;
int nLinks = vssi->Links->Count;
ATLTRACE(_T("Item %s has %d links\n"), (LPCTSTR)vssi->Spec, nLinks);
for(int i = 0; i < nLinks; i++)
{
IVSSItemPtr link = GetOneOfItems(links, i);
// simple helper to get links[i]
_variant_t varDeleted = link->Deleted;
// skip deleted links
if((BOOL)varDeleted)
continue;
CString csLink;
_bstr_t lnkSpec = link->Spec;
csLink = (LPCTSTR)lnkSpec;
long ChkStatus = link->IsCheckedOut;
switch(ChkStatus)
{
case VSSFILE_NOTCHECKEDOUT:
ATLTRACE(_T"Link %s is NOT checked out\n"), csLink);
break;
case VSSFILE_CHECKEDOUT:
ATLTRACE(_T"Link %s is checked out by OTHER user\n"), csLink);
break;
case VSSFILE_CHECKEDOUT_ME:
ATLTRACE(_T"Link %s is checked out by ME\n"), csLink);
break;
}
// verify there is a checkout for the user
bool bFound = false;
IVSSCheckoutsPtr lnkCheckouts = link->Checkouts;
long nCheckouts = lnkCheckouts->Count;
IVSSCheckoutPtr lnkCheckout;
for(long idx = 0; idx < nCheckouts; idx++)
{
CComVariant var(idx + 1);
lnkCheckout = lnkCheckouts->GetItem(var);
_bstr_t user = lnkCheckout->Username;
// filter by the user (to simplify comparison, make it CString)
if(0 == csUser.CompareNoCase((LPCTSTR)user))
{
bFound = true; // checkout for the user was found
nVersion = lnkCheckout->VersionNumber;
CString sLocal;
sLocal = (LPCTSTR)lnkCheckout->LocalSpec;
ATLTRACE(_T "Found checkout ver: %d to: %s\n"), nVersion, sLocal);
break;
}
}
if(!bFound)
return false;
HRESULT hr = S_OK;
try
{
_bstr_t bsDefault;
bsDefault = "";
long nDefault = VSSFLAG_DELNO|VSSFLAG_KEEPYES;
hr = link->raw_UndoCheckout(bsDefault, nDefault);
}
catch (_com_error & e)
{
ATLTRACE(_T("%s\n"), e.ErrorMessage());
}
if(SUCCEEDED(hr))
{
bOk = true;
break;
}
else
LogCOMError(hr, _T("UndoCheckout()")); // simple helper function
}
return bOk;
}