Click here to Skip to main content
15,895,799 members
Articles / Desktop Programming / MFC

CPath - juggling file names made easy

Rate me:
Please Sign up or sign in to vote.
4.88/5 (29 votes)
9 Sep 2005CPOL4 min read 160.4K   3.6K   78  
A wrapper class for path strings based on (and improving) the Shell Lightweight utility API.
// XShellPathDlg.cpp : implementation file
//

#include "stdafx.h"
#include "XShellPath.h"
#include "XShellPathDlg.h"
#include "path.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CXShellPathDlg dialog

CXShellPathDlg::CXShellPathDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CXShellPathDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CXShellPathDlg)
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CXShellPathDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CXShellPathDlg)
	DDX_Control(pDX, IDC_SPIN_COMPACT, m_spinCompact);
	DDX_Control(pDX, IDC_ST_COMPACT, m_stCompact);
	DDX_Control(pDX, IDC_ED_PATH_2, m_edPath2);
	DDX_Control(pDX, IDC_LC_LIST, m_lcList);
	DDX_Control(pDX, IDC_ED_PATH, m_edPath);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CXShellPathDlg, CDialog)
	//{{AFX_MSG_MAP(CXShellPathDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_EN_CHANGE(IDC_ED_PATH, OnChangeEdPath)
	ON_EN_CHANGE(IDC_ED_PATH_2, OnChangeEdPath2)
	ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN_COMPACT, OnDeltaposSpinCompact)
	ON_BN_CLICKED(IDC_CB_OFN, OnCbOfn)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CXShellPathDlg message handlers

BOOL CXShellPathDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here

    m_lcList.InsertColumn(0, NULL, 0, 120, 0);
    m_lcList.InsertColumn(1, NULL, 0, 120, 1);

    m_edPath.SetWindowText("C:\\temp\\foo.txt");

    CRect r;
    m_stCompact.GetWindowRect(&r);
    m_spinCompact.SetRange32(0, r.right-r.left);
    m_spinCompact.SetPos(r.Width() / 2); 

    ScreenToClient(r);
    r.right = r.left + r.Width()/2; 
    m_stCompact.MoveWindow(r);

    // some registry path to read a key from
    LPCTSTR regPath = _T("Software\\Microsoft\\windows\\CurrentVersion\\Explorer\\User Shell Folders");
    LPCTSTR regName = _T("Common AppData");

    SetDlgItemText(IDC_ST_SOME_MRU, 
            nsPath::FromRegistry(HKEY_LOCAL_MACHINE, regPath, regName));

    //* Local manual test: ToRegistry
    //    nsPath::CPath path = "C:\\WinNT\\System32\\Something.dat";
    //    path.ToRegistry(HKEY_LOCAL_MACHINE, "Software", "temptest");

  // */

    OnOK();
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CXShellPathDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}


void CXShellPathDlg::AddToList(LPCTSTR name, LPCTSTR value)
{
    CString valStr;
    valStr.Format("[%s]", value);
    AddToListUF(name, valStr);
}

void CXShellPathDlg::AddToListUF(LPCTSTR name, LPCTSTR value)
{
    int idx = m_lcList.InsertItem(m_lcList.GetItemCount(), name);
    m_lcList.SetItemText(idx, 1, value);
}


void CXShellPathDlg::AddToList(LPCTSTR name, LPCTSTR param, LPCTSTR value)
{
    CString strName;
    strName.Format("%s(\"%s\")", name, param); 
    AddToList(strName, value);
}


void CXShellPathDlg::AddToList(LPCTSTR name, LPCTSTR param, bool value)
{
    AddToList(name, param, value ? "yes" : "no");
}

void CXShellPathDlg::AddToList(LPCTSTR name, bool value)
{
    AddToList(name, value ? "yes" : "no");
}




void CXShellPathDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CXShellPathDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}





void CXShellPathDlg::OnOK() 
{
    using namespace nsPath;

    // some assignments - to see that there are no ambiguities...
    LPCTSTR lpctstr = "C:\\temp\\foo.txt";
    CString cstring = "C:\\temp\\foo.txt";

    CPath path1(lpctstr);
    CPath path2(cstring);
    CPath path3(path1);

    path1 = lpctstr;
    path2 = cstring;
    path3 = path1;

    lpctstr = path1;
    cstring = path2;
    path1   = path3;


    CString s1, s2;
    m_edPath.GetWindowText(s1);
    CPath path = s1;

    m_edPath2.GetWindowText(s2);
    path2 = s2;
    CString temp;


    int firstVisible = m_lcList.GetTopIndex(); 
    int lastVisible  = firstVisible + m_lcList.GetCountPerPage()-1;

    m_lcList.DeleteAllItems();

    AddToList("Path", path);
    AddToList("Create Path(epcRemoveArgs)", CPath(s1, epc_Default | epcRemoveArgs));
    AddToList("Append", path2, path & path2);
    AddToList("GetRoot", path.GetRoot());
    AddToList("GetRoot (greedy=false)", path.GetRoot(NULL, false));
    AddToList("GetPath (with root)", path.GetPath());
    AddToList("GetPath (w/out root)", path.GetPath(false));
    AddToList("GetFileName", path.GetName());
    AddToList("GetFileTitle", path.GetTitle());
    AddToList("GetExtension", path.GetExtension());
    AddToList("AddExtension", path2, CPath(path).AddExtension(path2));
    AddToList("RemoveExtension", CPath(path).RemoveExtension());
    AddToList("RenameExtension", s2, CPath(path).RenameExtension(s2));
    AddToList("RemoveFileSpec", CPath(path).RemoveFileSpec());
    AddToList("Canonicalize", CPath(s1,0).Canonicalize());

    AddToList("IsFileSpec", path.IsFileSpec());
    AddToList("IsPrefix",   path2, path.IsPrefix(path2));
    AddToList("IsRelative", path.IsRelative());
    AddToList("IsRoot",     path.IsRoot());
    AddToList("IsSameRoot", path2, path.IsSameRoot(path2));
    AddToList("IsUNC",      path.IsUNC());
    AddToList("IsUNCServer", path.IsUNCServer());
    AddToList("IsUNCServerShare", path.IsUNCServerShare());
    AddToList("IsURL",      path.IsURL());
    AddToList("MakePretty", CPath(path).MakePretty());

    AddToList("QuoteSpaces(string)", nsPath::QuoteSpaces(s1));
    AddToList("Get(eppBackslashToSlash)", path.GetStr(nsPath::eppBackslashToSlash));

    AddToList("GetCommonPrefix", s2, path.GetCommonPrefix(s2));
    AddToList("GetDriveNumber", (temp.Format("%i", path.GetDriveNumber()), temp));
    AddToList("GetDriveLetter", path.GetDriveLetter() ? (temp.Format("'%c'", path.GetDriveLetter()),temp) : "\\0");

    AddToList("RelativePathTo(s2, false)", path.RelativePathTo(s2, false));
    AddToList("RelativePathTo(s2, true)",  path.RelativePathTo(s2, true));

    AddToList("MatchSpec(s2)", path.MatchSpec(s2));

    AddToList("SearchAndQualify", CPath(path).SearchAndQualify());
    AddToList("FindOnPath", CPath(path).FindOnPath());

    CString sargs;
    AddToList("CreateSplitArgs", SplitArgs(s1, &sargs));
    AddToList("... and the args are", sargs);

    int icon;
    CString iconStr;
    AddToList("PathSplitIconLocation", SplitIconLocation(s1, &icon)); 
    iconStr.Format("%i", icon);
    AddToList("... and the icon index is", iconStr);

    AddToList("EXE path", GetModuleFileName().GetPath());
    AddToList("current path", GetCurrentDirectory().GetPath());

    // decompose path
    CPath copy = path;

    CString segment = copy.SplitRoot();
    CString fmt;
    fmt.Format("[%s]   [%s]", segment, copy);
    AddToListUF("SplitRoot", fmt);
    while (copy.GetLength())
    {
        segment = copy.SplitRoot();
        fmt.Format("[%s]    [%s]", segment, copy);
        AddToListUF(" ...", fmt);
    }

    AddToList("IsDot", path.IsDot());
    AddToList("IsDotDot", path.IsDotDot());
    AddToList("IsDotty", path.IsDotty());
    AddToList("IsValid", path.IsValid());
    AddToList("ReplaceInvalid", nsPath::ReplaceInvalid(path.GetStr(0)));

    // Autosize list columns
    m_lcList.SetColumnWidth(0, LVSCW_AUTOSIZE);
    m_lcList.SetColumnWidth(1, LVSCW_AUTOSIZE_USEHEADER);

    // PathCompact...
    path.SetDlgItem(m_hWnd, IDC_ST_COMPACT);
    
    // scroll to original location
    m_lcList.EnsureVisible(firstVisible, false);
    m_lcList.EnsureVisible(lastVisible, true);
}




void CXShellPathDlg::OnChangeEdPath() 
{
    OnOK();
	// TODO: If this is a RICHEDIT control, the control will not
	// send this notification unless you override the CDialog::OnInitDialog()
	// function and call CRichEditCtrl().SetEventMask()
	// with the ENM_CHANGE flag ORed into the mask.
	
	// TODO: Add your control notification handler code here
	
}

void CXShellPathDlg::OnChangeEdPath2() 
{
    OnOK();
	// TODO: If this is a RICHEDIT control, the control will not
	// send this notification unless you override the CDialog::OnInitDialog()
	// function and call CRichEditCtrl().SetEventMask()
	// with the ENM_CHANGE flag ORed into the mask.
	
	// TODO: Add your control notification handler code here
	
}

void CXShellPathDlg::OnDeltaposSpinCompact(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NMUPDOWN & nm = *(NM_UPDOWN*)pNMHDR;

    CRect r;
    m_stCompact.GetWindowRect(&r);
    r.right = r.left + nm.iPos + nm.iDelta;
    ScreenToClient(&r);
    m_stCompact.MoveWindow(r);

    CString s;
    m_edPath.GetWindowText(s);
    nsPath::CPath path(s);

    path.SetDlgItem(m_hWnd, IDC_ST_COMPACT);

	*pResult = 0;
}



void CXShellPathDlg::OnCbOfn() 
{
    /// Filter test:
    /*
    using namespace nsPath;
    CFilterList flist;
    flist.Add("foo files", "*.foo").Add("All files", "*.*"); // .Add("Something else|*.else");
    flist.Add("Other files|*.o|More Other files|*.mof|", '|', true);

    CFileDialog dlg(true, NULL, NULL, 0, NULL);
    OPENFILENAME ofn = dlg.m_ofn;
    ofn.lpstrFilter = flist;
    ofn.lpfnHook = NULL;
    GetOpenFileName(&ofn);
    */
}

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Klippel
Germany Germany
Peter is tired of being called "Mr. Chen", even so certain individuals insist on it. No, he's not chinese.

Peter has seen lots of boxes you youngsters wouldn't even accept as calculators. He is proud of having visited the insides of a 16 Bit Machine.

In his spare time he ponders new ways of turning groceries into biohazards, or tries to coax South American officials to add some stamps to his passport.

Beyond these trivialities Peter works for Klippel[^], a small german company that wants to make mankind happier by selling them novel loudspeaker measurement equipment.


Where are you from?[^]



Please, if you are using one of my articles for anything, just leave me a comment. Seeing that this stuff is actually useful to someone is what keeps me posting and updating them.
Should you happen to not like it, tell me, too

Comments and Discussions