Click here to Skip to main content
15,885,546 members
Articles / Desktop Programming / WTL

SSBrowser: A Sample Visual SourceSafe Automation

Rate me:
Please Sign up or sign in to vote.
4.59/5 (13 votes)
3 Jun 20044 min read 92.7K   3K   55  
A sample VC++ program for performing Visual SourceSafe operations in your application.
// maindlg.h : interface of the CMainDlg class
//
/////////////////////////////////////////////////////////////////////////////

#if !defined(AFX_MAINDLG_H__9F3A1221_3E05_4B24_9BA5_51A5C7D96478__INCLUDED_)
#define AFX_MAINDLG_H__9F3A1221_3E05_4B24_9BA5_51A5C7D96478__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

#include "SSConnection.h"
#include "LoginDlg.h"
#include "ListCtrlEx.h"
#include "SSTreeCtrl.h"
#include "SSItemOperationDlg.h"

const UINT gaui_EDIT_CONTROLS[] = {
	IDC_SS_PATH,
	IDC_LOCAL_PATH,
	IDC_ITEMTYPE,
	IDC_CHECKOUT_STATUS,
	IDC_LATEST_VERSION,
	IDC_LATEST_ACTION,
	IDC_LATEST_USER,
	IDC_LATEST_DATE,
	IDC_LATEST_LABEL,
	IDC_LATEST_COMMENT,
	IDC_HISTORY_LIST,
};

const UINT gaui_BUTTON_CONTROLS[] = {
	IDC_CHECKOUT,
	IDC_UNDO_CHECKOUT,
	IDC_CHECKIN,
	IDC_LABEL,
	IDC_ADD,
	IDC_NEW,
	IDC_GET_FILE,
};

class CMainDlg : public CDialogImpl<CMainDlg>, public CDialogResize<CMainDlg>,
	public CWinDataExchange<CMainDlg>
{
protected:
	CSSConnection	m_vssConnection;
	CString			mstr_userName;
	CString			mstr_defaultPath;
	IVSSItemPtr		m_currentVssItem;

	CListCtrlEx		m_versionsListCtrl;
	CSSTreeCtrl		m_ssTreeCtrl;
	CImageList	m_imageSmall;

public:
	enum { IDD = IDD_MAINDLG };
	typedef CDialogResize<CMainDlg> TBase;

    BEGIN_DLGRESIZE_MAP(CMainDlg)

		DLGRESIZE_CONTROL(IDC_LAST_ACTIVITY_GROUP, DLSZ_SIZE_X)
		DLGRESIZE_CONTROL(IDC_HISTORY_GROUP, DLSZ_SIZE_X)

		DLGRESIZE_CONTROL(IDC_LOGIN_BUTTON, DLSZ_MOVE_X)
		DLGRESIZE_CONTROL(IDC_CHECKOUT, DLSZ_MOVE_X)
		DLGRESIZE_CONTROL(IDC_UNDO_CHECKOUT, DLSZ_MOVE_X)
		DLGRESIZE_CONTROL(IDC_CHECKIN, DLSZ_MOVE_X)
		DLGRESIZE_CONTROL(IDC_LABEL, DLSZ_MOVE_X)
		DLGRESIZE_CONTROL(IDC_ADD, DLSZ_MOVE_X)
		DLGRESIZE_CONTROL(IDC_NEW, DLSZ_MOVE_X)
		DLGRESIZE_CONTROL(IDC_LOAD_HISTORY, DLSZ_MOVE_X)
		DLGRESIZE_CONTROL(IDC_GET_FILE, DLSZ_MOVE_X)
		DLGRESIZE_CONTROL(IDC_GET_LATEST, DLSZ_MOVE_X)

		DLGRESIZE_CONTROL(IDC_SS_TREE, DLSZ_SIZE_Y)
		DLGRESIZE_CONTROL(IDC_HISTORY_GROUP, DLSZ_SIZE_Y)
		DLGRESIZE_CONTROL(IDC_HISTORY_LIST, DLSZ_SIZE_Y)

		BEGIN_DLGRESIZE_GROUP()
			DLGRESIZE_CONTROL(IDC_SS_TREE, DLSZ_SIZE_X)
			DLGRESIZE_CONTROL(IDC_LAST_ACTIVITY_GROUP, DLSZ_SIZE_X)
			DLGRESIZE_CONTROL(IDC_HISTORY_GROUP, DLSZ_SIZE_X)
			DLGRESIZE_CONTROL(IDC_HISTORY_LIST, DLSZ_SIZE_X)

			DLGRESIZE_CONTROL(IDC_LABEL_USERNAME, DLSZ_MOVE_X)
			DLGRESIZE_CONTROL(IDC_LABEL_SOURCEPATH, DLSZ_MOVE_X)
			DLGRESIZE_CONTROL(IDC_LABEL_LOCALPATH, DLSZ_MOVE_X)
			DLGRESIZE_CONTROL(IDC_LABEL_TYPE, DLSZ_MOVE_X)
			DLGRESIZE_CONTROL(IDC_LABEL_STATUS, DLSZ_MOVE_X)
			DLGRESIZE_CONTROL(IDC_LABEL_VERSION, DLSZ_MOVE_X)
			DLGRESIZE_CONTROL(IDC_LABEL_ACTION, DLSZ_MOVE_X)
			DLGRESIZE_CONTROL(IDC_LABEL_USER, DLSZ_MOVE_X)
			DLGRESIZE_CONTROL(IDC_LABEL_DATE, DLSZ_MOVE_X)
			DLGRESIZE_CONTROL(IDC_LABEL_LABEL, DLSZ_MOVE_X)
			DLGRESIZE_CONTROL(IDC_LABEL_COMMENT, DLSZ_MOVE_X)

			DLGRESIZE_CONTROL(IDC_USER_NAME, DLSZ_SIZE_X)
			DLGRESIZE_CONTROL(IDC_SS_PATH, DLSZ_SIZE_X)
			DLGRESIZE_CONTROL(IDC_LOCAL_PATH, DLSZ_SIZE_X)
			DLGRESIZE_CONTROL(IDC_ITEMTYPE, DLSZ_SIZE_X)
			DLGRESIZE_CONTROL(IDC_CHECKOUT_STATUS, DLSZ_SIZE_X)
			DLGRESIZE_CONTROL(IDC_LATEST_VERSION, DLSZ_SIZE_X)
			DLGRESIZE_CONTROL(IDC_LATEST_ACTION, DLSZ_SIZE_X)
			DLGRESIZE_CONTROL(IDC_LATEST_USER, DLSZ_SIZE_X)
			DLGRESIZE_CONTROL(IDC_LATEST_DATE, DLSZ_SIZE_X)
			DLGRESIZE_CONTROL(IDC_LATEST_LABEL, DLSZ_SIZE_X)
			DLGRESIZE_CONTROL(IDC_LATEST_COMMENT, DLSZ_SIZE_X)
		END_DLGRESIZE_GROUP()

	END_DLGRESIZE_MAP()

	BEGIN_DDX_MAP(CMainDlg)
		DDX_TEXT(IDC_USER_NAME, mstr_userName);
		DDX_CONTROL(IDC_HISTORY_LIST, m_versionsListCtrl);
		DDX_CONTROL(IDC_SS_TREE, m_ssTreeCtrl);
	END_DDX_MAP()

	BEGIN_MSG_MAP(CMainDlg)
		CHAIN_MSG_MAP(TBase)
		MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
		COMMAND_ID_HANDLER(IDC_LOGIN_BUTTON, OnLogin)
		COMMAND_ID_HANDLER(IDC_LOAD_HISTORY, OnLoadHistory)
		COMMAND_ID_HANDLER(IDCANCEL, OnCancel)
		COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)

		COMMAND_ID_HANDLER(IDC_CHECKOUT, OnCheckOut)
		COMMAND_ID_HANDLER(IDC_UNDO_CHECKOUT, OnUndoCheckOut)
		COMMAND_ID_HANDLER(IDC_CHECKIN, OnCheckIn)
		COMMAND_ID_HANDLER(IDC_LABEL, OnLabel)
		COMMAND_ID_HANDLER(IDC_ADD, OnAddSubItem)
		COMMAND_ID_HANDLER(IDC_NEW, OnNewProject)
		COMMAND_ID_HANDLER(IDC_GET_FILE, OnGetVersion)

		NOTIFY_HANDLER(IDC_SS_TREE, TVN_SELCHANGED, OnTreeSelchanged)
		NOTIFY_HANDLER(IDC_HISTORY_LIST, LVN_ITEMCHANGED , OnHistorySelchanged)
		REFLECT_NOTIFICATIONS()
	END_MSG_MAP()


	LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
	{
        // Init the CDialogResize code
        DlgResize_Init();
		
		// center the dialog on the screen
		CenterWindow();

		// set icons
		HICON hIcon = (HICON)::LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MAINFRAME), 
			IMAGE_ICON, ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR);
		SetIcon(hIcon, TRUE);
		HICON hIconSmall = (HICON)::LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MAINFRAME), 
			IMAGE_ICON, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR);
		SetIcon(hIconSmall, FALSE);

		// Initial Sourcesafe location
		_TCHAR str_buffer[_MAX_PATH];
		ZeroMemory(str_buffer, _MAX_PATH);
		BOOL bHasHistory = b_GetProfileString(_T("LastProject"), _T(""), str_buffer, _MAX_PATH);

		m_imageSmall.Create(IDB_SMALL_IMAGELIST, 16, 0, RGB(255, 0, 255));

		CString str_lastPath;
		str_lastPath.Format(_T("%s"),str_buffer);
		if (m_vssConnection.b_Connect(NULL, NULL))
		{
			mstr_userName = m_vssConnection.str_GetUser();
		}

		if (m_vssConnection.b_SetSourcesafeProject(bHasHistory?static_cast<LPCTSTR>(str_lastPath):NULL))
		{
			mstr_defaultPath = m_vssConnection.str_GetBaseSourcesafeProject();
		}

		DoDataExchange(FALSE);

		m_ssTreeCtrl.SetImageList(m_imageSmall, TVSIL_NORMAL);
		m_ssTreeCtrl.v_Initialize(mstr_defaultPath, m_vssConnection.p_GetSourcesafeDatabase());
		SetDlgItemText(IDC_SS_PATH, mstr_defaultPath);

		m_versionsListCtrl.InsertColumn(0, _T("Version"), LVCFMT_LEFT, 50 ,-1);
		m_versionsListCtrl.InsertColumn(1, _T("User"), LVCFMT_LEFT, 80 ,-1);
		m_versionsListCtrl.InsertColumn(2, _T("Date"), LVCFMT_LEFT, 100 ,-1);
		m_versionsListCtrl.InsertColumn(3, _T("Action"), LVCFMT_LEFT, 200 ,-1);
		m_versionsListCtrl.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT);

		return TRUE;
	}

	LRESULT OnLogin(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
	{
		// TODO: Add validation code 
		CLoginDlg loginDlg;
		loginDlg.mp_connection = &m_vssConnection;

		DoDataExchange(TRUE);

		if (loginDlg.DoModal()==IDOK)
		{
			CWaitCursor wait;
			if (m_vssConnection.b_Connect( 
				loginDlg.mstr_userName, //str_user, 
				loginDlg.mstr_password,	// 
				loginDlg.mstr_srcsafeIni // passing null, will search the nearest srcsafe.ini
				))
			{
				mstr_userName = loginDlg.mstr_userName;
				if (m_vssConnection.b_SetSourcesafeProject(NULL))
				{
					mstr_defaultPath = m_vssConnection.str_GetBaseSourcesafeProject();
					v_WriteProfileString(_T("LastProject"), _bstr_t(mstr_defaultPath));
				}

				DoDataExchange(FALSE);

			}
			m_ssTreeCtrl.v_Initialize(mstr_defaultPath, m_vssConnection.p_GetSourcesafeDatabase());
		}

		return 0;
	}

#ifdef _DEBUG
	void v_DumpItemHistory(IVSSItemPtr vss_item)
	{
		int i_type = 0;
		IVSSVersionsPtr versions;

		vss_item->get_Type(&i_type);
		// Get the IVSSVersions object of the item
		if (vss_item->get_Versions((i_type == VSSITEM_PROJECT)?VSSFLAG_HISTIGNOREFILES:0, &versions) == S_OK)
		{
			CComPtr<IEnumVARIANT> p_versionsEnum;
			CComPtr<IUnknown> spunk;

			versions->_NewEnum(&spunk);
			spunk->QueryInterface(IID_IEnumVARIANT, (LPVOID*)&p_versionsEnum);

			ULONG l_fetched;
			long l_value;
			CString str_display;
			CComBSTR bstr_text;
			DATE date;

			// We use this object to point to each version
			_variant_t object;

			// Now iterate through all the versions
			while (p_versionsEnum->Next(1, &object, &l_fetched) == S_OK)
			{
				try
				{
					IVSSVersionPtr p_version(object);

					// ...where we can get the version number
					p_version->get_VersionNumber(&l_value);
					// the user who did the changes
					p_version->get_Username(&bstr_text);
					ATLTRACE(_T("Version %d by %s"), l_value, bstr_text); 
					// the date it was checked in
					p_version->get_Date(&date);
					// the action done
					p_version->get_Action(&bstr_text);
					ATLTRACE(_T(" On %s '%s'\n"), str_FormatDateTime(date), bstr_text);
				}
				catch (_com_error & e)
				{
					ATLTRACE(_T("%s\n"), e.ErrorMessage());
				}
			}
		}
	}
#endif

	LRESULT OnLoadHistory(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
	{
		m_versionsListCtrl.DeleteAllItems();
		IVSSItemPtr vss_item = m_ssTreeCtrl.p_GetSelectedVssItem();

		if (vss_item == NULL)
		{
			return 0L;
		}

		HRESULT hr;
		int i_type;

		if ((hr = vss_item->get_Type(&i_type)) != S_OK)
		{
			return 0L;
		}

		IVSSVersionsPtr versions;
		if ((hr = vss_item->get_Versions((i_type == VSSITEM_PROJECT)?VSSFLAG_HISTIGNOREFILES:0, &versions)) == S_OK)
		{
			CComPtr<IEnumVARIANT> p_versionsEnum;
			CComPtr<IUnknown> spunk;

			versions->_NewEnum(&spunk);
			spunk->QueryInterface(IID_IEnumVARIANT, (LPVOID*)&p_versionsEnum);

			_variant_t object;
			ULONG l_fetched;
			long l_value;
			CString str_display;
			CComBSTR bstr_text;

			LVITEM item;
			item.iItem = 0;
			item.mask  = LVIF_TEXT;
			while (p_versionsEnum->Next(1, &object, &l_fetched) == S_OK)
			{
				try
				{
					IVSSVersionPtr p_version(object);

					// Version
					if ((hr = p_version->get_VersionNumber(&l_value)) == S_OK)
					{
						str_display.Format(_T("%d"), l_value);
					}
					else
					{
						str_display = _T("???");
					}
					item.iSubItem = 0;
					item.pszText = str_display.GetBuffer(0);
					item.cchTextMax = str_display.GetLength();
					m_versionsListCtrl.SetItemData(m_versionsListCtrl.InsertItem(&item), l_value);

					// User
					if ((hr = p_version->get_Username(&bstr_text)) == S_OK)
					{
						str_display = bstr_text;
					}
					else
					{
						str_display = _T("???");
					}
					item.iSubItem++;
					item.pszText = str_display.GetBuffer(0);
					item.cchTextMax = str_display.GetLength();
					m_versionsListCtrl.SetItem(&item);

					// Date
					DATE date;
					if ((hr = p_version->get_Date(&date)) == S_OK)
					{
						str_display = str_FormatDateTime(date);
					}
					else
					{
						str_display = _T("???");
					}
					item.iSubItem++;
					item.pszText = str_display.GetBuffer(0);
					item.cchTextMax = str_display.GetLength();
					m_versionsListCtrl.SetItem(&item);

					// Action
					if ((hr = p_version->get_Action(&bstr_text)) == S_OK)
					{
						str_display = bstr_text;
					}
					else
					{
						str_display = _T("???");
					}
					item.iSubItem++;
					item.pszText = str_display.GetBuffer(0);
					item.cchTextMax = str_display.GetLength();
					m_versionsListCtrl.SetItem(&item);

					item.iItem++;
				}
				catch (_com_error & e)
				{
					ATLTRACE(_T("%s\n"), e.ErrorMessage());
				}
			}
		}
		
		
		return 0L;
	}

	LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
	{
		return 0L;
	}

	LRESULT OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
	{
		CSimpleDialog<IDD_ABOUTBOX, FALSE> dlg;
		dlg.DoModal();
		return 0;
	}

	LRESULT OnCancel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
	{
		EndDialog(wID);
		return 0;
	}

	LRESULT OnHistorySelchanged(int , LPNMHDR pnmh, BOOL& bHandled)
	{
		LPNMLISTVIEW pnmv = (LPNMLISTVIEW) pnmh; 

		if (!(pnmv->uOldState&LVIS_SELECTED) && (pnmv->uNewState&LVIS_SELECTED))
		{
			::EnableWindow(GetDlgItem(IDC_GET_FILE), TRUE);
		}
		else if ((pnmv->uOldState&LVIS_SELECTED) && !(pnmv->uNewState&LVIS_SELECTED))
		{
			::EnableWindow(GetDlgItem(IDC_GET_FILE), FALSE);
		}

		// Allow reflection handler
		bHandled = FALSE;
		return 0L;
	}

	LRESULT OnCheckOut(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
	{
		IVSSItemPtr vss_item = m_ssTreeCtrl.p_GetSelectedVssItem();
		CSSItemOperationDlg dialog(vss_item, ge_OP_CHECKOUT);
		if (dialog.DoModal() == IDOK)
		{
			CComBSTR bstr_comment(dialog.mstr_comment);
			CComBSTR bstr_localSpec;
			vss_item->get_LocalSpec(&bstr_localSpec);
			vss_item->Checkout(bstr_comment, bstr_localSpec, dialog.ml_flags);
			if (!b_DisplayAnyError())
			{
				m_ssTreeCtrl.SetItemImage(m_ssTreeCtrl.GetSelectedItem(), ITEM_FILE_CHECKOUT_IMAGE, ITEM_FILE_CHECKOUT_IMAGE);
				v_UpdateDisplay();
			}
		}

		return 0;
	}
	LRESULT OnUndoCheckOut(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
	{
		IVSSItemPtr vss_item = m_ssTreeCtrl.p_GetSelectedVssItem();
		CSSItemOperationDlg dialog(vss_item, ge_OP_UNDOCHECKOUT);
		if (dialog.DoModal() == IDOK)
		{
			CComBSTR bstr_localSpec;
			vss_item->get_LocalSpec(&bstr_localSpec);
			vss_item->UndoCheckout(bstr_localSpec, dialog.ml_flags);
			if (!b_DisplayAnyError())
			{
				m_ssTreeCtrl.SetItemImage(m_ssTreeCtrl.GetSelectedItem(), ITEM_FILE_NORMAL_IMAGE, ITEM_FILE_NORMAL_IMAGE);
				v_UpdateDisplay();
			}
		}
		return 0;
	}
	LRESULT OnCheckIn(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
	{
		IVSSItemPtr vss_item = m_ssTreeCtrl.p_GetSelectedVssItem();
		CSSItemOperationDlg dialog(vss_item, ge_OP_CHECKIN);
		if (dialog.DoModal() == IDOK)
		{
			CComBSTR bstr_comment(dialog.mstr_comment);
			CComBSTR bstr_localSpec;
			vss_item->get_LocalSpec(&bstr_localSpec);
			vss_item->Checkin(bstr_comment, bstr_localSpec, dialog.ml_flags);
			if (!b_DisplayAnyError())
			{
				m_ssTreeCtrl.SetItemImage(m_ssTreeCtrl.GetSelectedItem(), ITEM_FILE_NORMAL_IMAGE, ITEM_FILE_NORMAL_IMAGE);
				v_UpdateDisplay();
			}
		}
		return 0;
	}
	LRESULT OnLabel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
	{
		IVSSItemPtr vss_item = m_ssTreeCtrl.p_GetSelectedVssItem();
		CSSItemOperationDlg dialog(vss_item, ge_OP_LABEL);
		if (dialog.DoModal() == IDOK)
		{
			CComBSTR bstr_comment(dialog.mstr_comment);
			CComBSTR bstr_label(dialog.mstr_label);
			vss_item->Label(bstr_label, bstr_comment);
			b_DisplayAnyError();
		}
		return 0;
	}
	LRESULT OnAddSubItem(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
	{
		IVSSItemPtr vss_item = m_ssTreeCtrl.p_GetSelectedVssItem();
		CSSItemOperationDlg dialog(vss_item, ge_OP_ADDSUBITEM);
		if (dialog.DoModal() == IDOK)
		{
			IVSSItemPtr vss_newItem;
			CComBSTR bstr_comment(dialog.mstr_comment);
			CComBSTR bstr_localSpec(dialog.mstr_labelValue);
			vss_item->Add(bstr_localSpec, bstr_comment, dialog.ml_flags, &vss_newItem);
			if (!b_DisplayAnyError())
			{
				HTREEITEM h_item = m_ssTreeCtrl.GetSelectedItem();
				HTREEITEM h_parentItem = m_ssTreeCtrl.GetParentItem(h_item);
				CString str_path = m_ssTreeCtrl.str_ItemToPath(h_item);
				m_ssTreeCtrl.DeleteItem(h_item);
				m_ssTreeCtrl.h_InsertPath(vss_item, h_parentItem, str_path, h_item);
				m_ssTreeCtrl.SelectItem(h_item);
			}
		}
		return 0;
	}
	LRESULT OnNewProject(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
	{
		IVSSItemPtr vss_item = m_ssTreeCtrl.p_GetSelectedVssItem();
		CSSItemOperationDlg dialog(vss_item, ge_OP_NEWPROJECT);
		if (dialog.DoModal() == IDOK)
		{
			IVSSItemPtr vss_newItem;
			CComBSTR bstr_comment(dialog.mstr_comment);
			CComBSTR bstr_name(dialog.mstr_labelValue);
			vss_item->NewSubproject(bstr_name, bstr_comment, &vss_newItem);
			if (!b_DisplayAnyError())
			{
				HTREEITEM h_item = m_ssTreeCtrl.GetSelectedItem();
				HTREEITEM h_parentItem = m_ssTreeCtrl.GetParentItem(h_item);
				CString str_path = m_ssTreeCtrl.str_ItemToPath(h_item);
				m_ssTreeCtrl.DeleteItem(h_item);
				m_ssTreeCtrl.h_InsertPath(vss_item, h_parentItem, str_path, h_item);
				m_ssTreeCtrl.SelectItem(h_item);
				m_ssTreeCtrl.Expand(h_item);
			}
		}
		return 0;
	}
	LRESULT OnGetVersion(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
	{
		LVITEM item;
		if (m_versionsListCtrl.GetSelectedItem(&item))
		{
			long l_version = m_versionsListCtrl.GetItemData(item.iItem);
			IVSSItemPtr vss_item = m_ssTreeCtrl.p_GetSelectedVssItem();
			IVSSItemPtr vss_oldItem;
			if (vss_item->get_Version(_variant_t(l_version), &vss_oldItem) == S_OK)
			{
				b_GetItem(vss_oldItem);
				b_DisplayAnyError();
			}
		}
		return 0;
	}

	LRESULT OnTreeSelchanged(int , LPNMHDR pnmh, BOOL& bHandled)
	{
		ATLTRACE(_T("Parent Selchange handler\n"));

		v_UpdateDisplay();

		// Allow reflection handler
		bHandled = FALSE;
		return 0L;
	}

	BOOL b_GetItem(IVSSItemPtr vss_item)
	{
		CSSItemOperationDlg dialog(vss_item, ge_OP_GET);
		if (dialog.DoModal() == IDOK)
		{
			IVSSItemPtr vss_newItem;
			CComBSTR bstr_localSpec(dialog.mstr_labelValue);
			return vss_item->Get(&bstr_localSpec, dialog.ml_flags) == S_OK;
		}
		return FALSE;
	}

	void v_UpdateDisplay()
	{
		IVSSItemPtr vss_item = m_ssTreeCtrl.p_GetSelectedVssItem();
		if (vss_item == NULL)
		{
			v_DisplayBlank();
			return;
		}

		CComBSTR bstr_text;
		_bstr_t str_text;
		CString str_temp;
		HRESULT hr;
		int i_type;
		long l_checkout;
		long l_value;

		// IDC_SS_PATH
		if ((hr = vss_item->get_Spec(&bstr_text)) == S_OK)
		{
			SetDlgItemText(IDC_SS_PATH, bstr_text);
		}
		else
		{
			SetDlgItemText(IDC_SS_PATH, _T("???"));
		}

		// IDC_ITEMTYPE
		if ((hr = vss_item->get_Type(&i_type)) == S_OK)
		{
			switch (i_type)
			{
			case VSSITEM_PROJECT:
				str_temp = _T("VSSITEM_PROJECT");
				break;
			case VSSITEM_FILE:
				str_temp = _T("VSSITEM_FILE");
				break;
			default:
				str_temp.Format(_T("Unknown (%d)"), i_type);
			}
			SetDlgItemText(IDC_ITEMTYPE, str_temp);
		}
		else
		{
			SetDlgItemText(IDC_ITEMTYPE, _T("???"));
		}

		// IDC_LOCAL_PATH
		IVSSItemPtr vss_path = vss_item;
		if (i_type == VSSITEM_FILE)
		{
			 vss_item->get_Parent(&vss_path);
		}
		if ((hr = vss_path->get_LocalSpec(&bstr_text)) == S_OK)
		{
			SetDlgItemText(IDC_LOCAL_PATH, bstr_text);
		}
		else
		{
			SetDlgItemText(IDC_LOCAL_PATH, _T("No Working Folder"));
		}

		// IDC_CHECKOUT_STATUS
		if (i_type == VSSITEM_PROJECT)
		{
			SetDlgItemText(IDC_CHECKOUT_STATUS, _T("n/a"));
		}
		else if ((hr = vss_item->get_IsCheckedOut(&l_checkout)) == S_OK)
		{
			switch (l_checkout)
			{
			case VSSFILE_NOTCHECKEDOUT:
				str_temp = _T("VSSFILE_NOTCHECKEDOUT");
				break;
			case VSSFILE_CHECKEDOUT:
				str_temp.Format(_T("VSSFILE_CHECKEDOUT (%s)"), str_WhoCheckedOut(vss_item));
				break;
			case VSSFILE_CHECKEDOUT_ME :
				str_temp = _T("VSSFILE_CHECKEDOUT_ME");
				break;
			default:
				str_temp.Format(_T("Unknown (%d)"), l_checkout);
			}
			SetDlgItemText(IDC_CHECKOUT_STATUS, str_temp);
		}
		else
		{
			SetDlgItemText(IDC_CHECKOUT_STATUS, _T("???"));
		}

		// IDC_LATEST_VERSION
		if ((hr = vss_item->get_VersionNumber(&l_value)) == S_OK)
		{
			SetDlgItemInt(IDC_LATEST_VERSION, l_value);
		}
		else
		{
			SetDlgItemText(IDC_LATEST_VERSION, _T("???"));
		}

		IVSSVersionsPtr versions;
		if ((hr = vss_item->get_Versions((i_type == VSSITEM_PROJECT)?VSSFLAG_HISTIGNOREFILES:0, &versions)) == S_OK)
		{
			CComPtr<IEnumVARIANT> p_versionsEnum;
			CComPtr<IUnknown> spunk;

			versions->_NewEnum(&spunk);
			spunk->QueryInterface(IID_IEnumVARIANT, (LPVOID*)&p_versionsEnum);

			_variant_t item;
			ULONG l_fetched;
			while (p_versionsEnum->Next(1, &item, &l_fetched) == S_OK)
			{
				try
				{
					IVSSVersionPtr p_version(item);

					// IDC_LATEST_ACTION
					if ((hr = p_version->get_Action(&bstr_text)) == S_OK)
					{
						SetDlgItemText(IDC_LATEST_ACTION, bstr_text);
					}
					else
					{
						SetDlgItemText(IDC_LATEST_ACTION, _T("???"));
					}

					// IDC_LATEST_USER
					if ((hr = p_version->get_Username(&bstr_text)) == S_OK)
					{
						SetDlgItemText(IDC_LATEST_USER, bstr_text);
					}
					else
					{
						SetDlgItemText(IDC_LATEST_USER, _T("???"));
					}

					// IDC_LATEST_DATE
					DATE date;
					if ((hr = p_version->get_Date(&date)) == S_OK)
					{
						SetDlgItemText(IDC_LATEST_DATE, str_FormatDateTime(date));
					}
					else
					{
						SetDlgItemText(IDC_LATEST_DATE, _T("???"));
					}

					// IDC_LATEST_LABEL
					if ((hr = p_version->get_Label(&bstr_text)) == S_OK)
					{
						SetDlgItemText(IDC_LATEST_LABEL, bstr_text);
					}
					else
					{
						SetDlgItemText(IDC_LATEST_LABEL, _T("???"));
					}

					// IDC_LATEST_COMMENT
					if ((hr = p_version->get_Comment(&bstr_text)) == S_OK)
					{
						SetDlgItemText(IDC_LATEST_COMMENT, bstr_text);
					}
					else
					{
						SetDlgItemText(IDC_LATEST_COMMENT, _T("???"));
					}

					// IDC_HISTORY_LIST
				}
				catch (_com_error & e)
				{
					ATLTRACE(_T("COM Error%s\n"), e.ErrorMessage());
				}

				// Get the latest only
				break;
			}
		}

		::EnableWindow(GetDlgItem(IDC_CHECKOUT), l_checkout == VSSFILE_NOTCHECKEDOUT);
		::EnableWindow(GetDlgItem(IDC_UNDO_CHECKOUT), l_checkout == VSSFILE_CHECKEDOUT_ME);
		::EnableWindow(GetDlgItem(IDC_CHECKIN), l_checkout == VSSFILE_CHECKEDOUT_ME);
		::EnableWindow(GetDlgItem(IDC_ADD), i_type == VSSITEM_PROJECT);
		::EnableWindow(GetDlgItem(IDC_NEW), i_type == VSSITEM_PROJECT);

		m_versionsListCtrl.DeleteAllItems();
		::EnableWindow(GetDlgItem(IDC_GET_FILE), FALSE);
	}

	CString str_WhoCheckedOut(IVSSItemPtr vss_item)
	{
		CString str_user(_T("None"));
		IVSSCheckoutsPtr checkOuts;
		vss_item->get_Checkouts(&checkOuts);

		IVSSCheckoutPtr vss_checkOutItem;
		checkOuts->get_Item(_variant_t(1L), &vss_checkOutItem);
		CComBSTR str_userName;
		vss_checkOutItem->get_Username(&str_userName);

		long l_count;
		checkOuts->get_Count(&l_count);
		if (l_count == 1)
		{
			str_user.Format(_T("%s"), (LPCTSTR)str_userName);
		}
		else if (l_count > 1)
		{
			str_user.Format(_T("%s et.al."), (LPCTSTR)str_userName);
		}
		return str_user;
	}

	CString str_FormatDateTime(DATE date)
	{
		SYSTEMTIME time;
		VariantTimeToSystemTime(date, &time);

		CString str_dateTime(_T("Format error"));

		_TCHAR sz_date[256];
		_TCHAR sz_time[256];
		int i_dateOK = GetDateFormat(
		  LOCALE_USER_DEFAULT,  // locale
		  0,					// options
		  &time,				// date
		  _T("MM'/'dd'/'yy"),	// date format
		  sz_date,				// formatted string buffer
		  256					// size of buffer
		);
		
		int i_timeOK = GetTimeFormat(
		  LOCALE_USER_DEFAULT,  // locale for which time is to be formatted
		  0,					// flags specifying function options
		  &time,				// time to be formatted
		  _T("hh':'mm':'ss tt"),// time format string
		  sz_time,				// buffer for storing formatted string
		  256					// size, in bytes or characters, of the buffer
		);
 
		if (i_dateOK && i_timeOK )
		{
			str_dateTime.Format(_T("%s %s"), sz_date, sz_time);
		}
		return str_dateTime;
	}

	void v_DisplayBlank()
	{
		for (int i = 0; i < sizeof(gaui_EDIT_CONTROLS)/sizeof(gaui_EDIT_CONTROLS[0]); i++)
		{
			SetDlgItemText(IDC_SS_PATH, _T(""));
		}
		for (i = 0; i < sizeof(gaui_BUTTON_CONTROLS)/sizeof(gaui_BUTTON_CONTROLS[0]); i++)
		{
			SetDlgItemText(IDC_SS_PATH, _T(""));
		}
	}
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_MAINDLG_H__9F3A1221_3E05_4B24_9BA5_51A5C7D96478__INCLUDED_)

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior)
United States United States
Roaming halfway around the globe programming in C++, MFC, COM/ATL, WTL, C#, .NET, OLEDB, ADO, ADO/X.

Living under the pleasant weather of Irvine, California, Ferdie is a Computer Engineering graduate of Mapua Institute of Technology (MIT Smile | :) ) in Philippines. Developed GIS applications in Japan for 5 years. Now a member of a team developing Windows GUI and real time software for semi-robotic equipments.

Comments and Discussions