675 lines
17 KiB
C++
675 lines
17 KiB
C++
// this is the internal content - specific stuff related to the
|
|
// CShellExt object
|
|
|
|
#include "priv.h"
|
|
#include <tchar.h>
|
|
#include <iiscnfgp.h>
|
|
//
|
|
#include <inetinfo.h>
|
|
#include <winsvc.h>
|
|
#include <iwamreg.h>
|
|
#include <shlwapi.h>
|
|
|
|
#include "wrapmb.h"
|
|
#include "Sink.h"
|
|
#include "eddir.h"
|
|
#include "shellext.h"
|
|
|
|
#include "wrapmb.h"
|
|
|
|
|
|
//the key type string for the virtual directories
|
|
#define MDSZ_W3_VDIR_TYPE _T("IIsWebVirtualDir")
|
|
|
|
|
|
extern HINSTANCE g_hmodThisDll;
|
|
//Handle to this DLL itself.
|
|
|
|
BOOL MakeWAMApplication (IN LPCTSTR pszPath, IN BOOL fCreate);
|
|
BOOL MyFormatString1 (IN LPTSTR pszSource, IN DWORD cchMax, LPTSTR pszReplace);
|
|
|
|
//---------------------------------------------------------------
|
|
INT_PTR CALLBACK
|
|
EditDirDlgProc (HWND hDlg,
|
|
UINT uMessage,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
//the pointer to the object is passed in as the private lParam, store it away
|
|
if (uMessage == WM_INITDIALOG)
|
|
{
|
|
SetWindowLongPtr (hDlg, DWLP_USER, lParam);
|
|
}
|
|
|
|
//dialog object pointer from the window
|
|
CEditDirectory * pdlg = (CEditDirectory *) GetWindowLongPtr (hDlg, DWLP_USER);
|
|
if (!pdlg)
|
|
return FALSE;
|
|
|
|
//let the object do the work
|
|
return pdlg->OnMessage (hDlg, uMessage, wParam, lParam);
|
|
}
|
|
|
|
//=====================================================================================
|
|
|
|
|
|
//---------------------------------------------------------------
|
|
CEditDirectory::CEditDirectory (HWND hParent):
|
|
m_hParent (hParent),
|
|
m_bool_read (FALSE),
|
|
m_bool_write (FALSE),
|
|
m_bool_dirbrowse (FALSE),
|
|
m_bool_source (FALSE),
|
|
m_bool_oldSource (FALSE),
|
|
m_int_AppPerms (APPPERM_NONE),
|
|
// m_pMBCom (NULL),
|
|
m_fNewItem (FALSE),
|
|
m_hDlg (NULL)
|
|
{
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
CEditDirectory::~CEditDirectory ()
|
|
{
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
INT_PTR CEditDirectory::DoModal ()
|
|
{
|
|
return DialogBoxParam (
|
|
g_hmodThisDll, //handle to application instance
|
|
MAKEINTRESOURCE (IDD_ALIAS), //identifies dialog box template
|
|
m_hParent, //handle to owner window
|
|
EditDirDlgProc, //pointer to dialog box procedure
|
|
(LPARAM) this // initialization value
|
|
);
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
//return FALSE if we do NOT handle the message
|
|
BOOL CEditDirectory::OnMessage (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
//return success
|
|
return OnInitDialog (hDlg);
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD (wParam))
|
|
{
|
|
case IDC_FULLCONTROL:
|
|
OnSource (hDlg);
|
|
return TRUE;
|
|
case IDC_READ:
|
|
OnRead (hDlg);
|
|
return TRUE;
|
|
case IDC_WRITE:
|
|
OnWrite (hDlg);
|
|
return TRUE;
|
|
case IDOK:
|
|
OnOK (hDlg);
|
|
return TRUE;
|
|
case IDCANCEL:
|
|
EndDialog (IDCANCEL);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
};
|
|
|
|
//return whether or not we handled the message
|
|
return FALSE;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
//CDialog simulation routines
|
|
void CEditDirectory::UpdateData (BOOL fDialogToData)
|
|
{
|
|
//get the data from the dialog
|
|
if (fDialogToData)
|
|
{
|
|
//get the text items first
|
|
GetWindowText (m_hEditAlias, m_sz_alias, MAX_PATH);
|
|
GetWindowText (m_hEditPath, m_sz_path, MAX_PATH);
|
|
|
|
//read the checkboxes
|
|
m_bool_read = (SendMessage (m_hChkRead, BM_GETCHECK, 0, 0) == BST_CHECKED);
|
|
m_bool_write = (SendMessage (m_hChkWrite, BM_GETCHECK, 0, 0) == BST_CHECKED);
|
|
m_bool_dirbrowse = (SendMessage (m_hChkDirBrowse, BM_GETCHECK, 0, 0) == BST_CHECKED);
|
|
m_bool_source = (SendMessage (m_hChkSource, BM_GETCHECK, 0, 0) == BST_CHECKED);
|
|
|
|
//read the AppPerm radio buttons
|
|
if (SendMessage (m_hRdoScripts, BM_GETCHECK, 0, 0) == BST_CHECKED)
|
|
{
|
|
m_int_AppPerms = APPPERM_SCRIPTS;
|
|
}
|
|
else if (SendMessage (m_hRdoExecute, BM_GETCHECK, 0, 0) == BST_CHECKED)
|
|
{
|
|
m_int_AppPerms = APPPERM_EXECUTE;
|
|
}
|
|
else
|
|
{
|
|
m_int_AppPerms = APPPERM_NONE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//put it back into the dialog
|
|
// set the text items first
|
|
SetWindowText (m_hEditAlias, m_sz_alias);
|
|
SetWindowText (m_hEditPath, m_sz_path);
|
|
|
|
//set the checkboxes
|
|
SendMessage (m_hChkRead, BM_SETCHECK, m_bool_read ? BST_CHECKED :
|
|
BST_UNCHECKED, 0);
|
|
SendMessage (m_hChkWrite, BM_SETCHECK, m_bool_write ? BST_CHECKED :
|
|
BST_UNCHECKED, 0);
|
|
SendMessage (m_hChkDirBrowse, BM_SETCHECK, m_bool_dirbrowse ?
|
|
BST_CHECKED : BST_UNCHECKED, 0);
|
|
SendMessage (m_hChkSource, BM_SETCHECK, m_bool_source ? BST_CHECKED
|
|
: BST_UNCHECKED, 0);
|
|
|
|
//set the AppPerm radio buttons
|
|
SendMessage (m_hRdoNone, BM_SETCHECK,
|
|
(m_int_AppPerms == APPPERM_NONE) ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
SendMessage (m_hRdoScripts, BM_SETCHECK,
|
|
(m_int_AppPerms == APPPERM_SCRIPTS) ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
SendMessage (m_hRdoExecute, BM_SETCHECK,
|
|
(m_int_AppPerms == APPPERM_EXECUTE) ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
BOOL CEditDirectory::InitHandles (HWND hDlg)
|
|
{
|
|
m_hDlg = hDlg;
|
|
m_hEditAlias = GetDlgItem (hDlg, IDC_ALIAS);
|
|
m_hEditPath = GetDlgItem (hDlg, IDC_PATH);
|
|
|
|
m_hChkRead = GetDlgItem (hDlg, IDC_READ);
|
|
m_hChkWrite = GetDlgItem (hDlg, IDC_WRITE);
|
|
m_hChkDirBrowse = GetDlgItem (hDlg, IDC_DIRBROWSE);
|
|
m_hChkSource = GetDlgItem (hDlg, IDC_FULLCONTROL);
|
|
|
|
m_hRdoNone = GetDlgItem (hDlg, IDC_RDO_NONE);
|
|
m_hRdoExecute = GetDlgItem (hDlg, IDC_RDO_EXECUTE);
|
|
m_hRdoScripts = GetDlgItem (hDlg, IDC_RDO_SCRIPTS);
|
|
return TRUE;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
BOOL CEditDirectory::OnInitDialog (HWND hDlg)
|
|
{
|
|
BOOL f = FALSE;
|
|
CWrapMetaBase mb;
|
|
DWORD dword;
|
|
TCHAR sz[MAX_PATH];
|
|
|
|
InitHandles (hDlg);
|
|
ZeroMemory (sz, MAX_PATH);
|
|
//keep a copy of the original alias for later verification
|
|
StrCpy (m_szOrigAlias,
|
|
*m_sz_alias == _T ('/') ? m_sz_alias + 1 : m_sz_alias);
|
|
StrCpy (m_sz_alias, m_szOrigAlias);
|
|
|
|
//open up the metabase and read in the initial values
|
|
// first things first.init the mb object
|
|
if (!mb.FInit (m_pMBCom))
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
//build the metapath
|
|
StrCpy (sz, m_szRoot);
|
|
StrCat (sz, _T ("/"));
|
|
StrCat (sz, m_sz_alias);
|
|
|
|
//open the object - use root defaults if this is a new item
|
|
if (m_fNewItem || !mb.Open (sz))
|
|
{
|
|
//if the node doesn 't exist - get the default values of the root
|
|
if (!mb.Open (m_szRoot))
|
|
{
|
|
//if that doesn 't work - fail
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
//read the flags
|
|
if (mb.GetDword (_T (""), MD_ACCESS_PERM, IIS_MD_UT_FILE, &dword, METADATA_INHERIT))
|
|
{
|
|
//interpret that thing
|
|
m_bool_read = (dword & MD_ACCESS_READ) > 0;
|
|
m_bool_write = (dword & MD_ACCESS_WRITE) > 0;
|
|
m_bool_source = (dword & MD_ACCESS_SOURCE) > 0;
|
|
|
|
//choose the correct app permissions radio button
|
|
m_int_AppPerms = APPPERM_NONE;
|
|
if (dword & MD_ACCESS_EXECUTE)
|
|
{
|
|
m_int_AppPerms = APPPERM_EXECUTE;
|
|
}
|
|
else if (dword & MD_ACCESS_SCRIPT)
|
|
{
|
|
m_int_AppPerms = APPPERM_SCRIPTS;
|
|
}
|
|
}
|
|
|
|
//the dir browsing flag is stored in a different field
|
|
if (mb.GetDword (_T (""), MD_DIRECTORY_BROWSING, IIS_MD_UT_FILE, &dword, METADATA_INHERIT))
|
|
{
|
|
m_bool_dirbrowse = (dword & MD_DIRBROW_ENABLED) > 0;
|
|
}
|
|
|
|
//close the metabase
|
|
mb.Close ();
|
|
|
|
//if this is a new item, force the app perms to scripts
|
|
if (m_fNewItem)
|
|
{
|
|
m_int_AppPerms = APPPERM_SCRIPTS;
|
|
}
|
|
|
|
//set the data into place
|
|
UpdateData (FALSE);
|
|
|
|
//prep the source control button
|
|
m_bool_oldSource = m_bool_source;
|
|
EnableSourceControl ();
|
|
|
|
cleanup:
|
|
return f;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
//we need to make sure that there is something in the alias field
|
|
// an empty alias is not OK
|
|
void CEditDirectory::OnOK (HWND hDlg)
|
|
{
|
|
BOOL f;
|
|
DWORD err;
|
|
DWORD dword;
|
|
int iPar;
|
|
CWrapMetaBase mb;
|
|
|
|
TCHAR szPath[MAX_PATH];
|
|
TCHAR szParent[MAX_PATH];
|
|
TCHAR sz[MAX_PATH];
|
|
TCHAR szCaption[MAX_PATH];
|
|
ZeroMemory (sz, MAX_PATH);
|
|
ZeroMemory (szPath, MAX_PATH);
|
|
ZeroMemory (szParent, MAX_PATH);
|
|
ZeroMemory (szCaption, MAX_PATH);
|
|
|
|
UpdateData (TRUE);
|
|
|
|
//trim leading and trailing spaces
|
|
TrimLeft (m_sz_alias);
|
|
TrimRight (m_sz_alias);
|
|
|
|
//first test is to see if there is anything in it
|
|
if (*m_sz_alias == 0)
|
|
{
|
|
LoadString (g_hmodThisDll, IDS_PAGE_TITLE, szCaption, MAX_PATH);
|
|
LoadString (g_hmodThisDll, IDS_EMPTY_ALIAS, sz, MAX_PATH);
|
|
MessageBox (hDlg, sz, szCaption, MB_OK);
|
|
goto cleanup;
|
|
}
|
|
|
|
//at this point we need to check if write and execute / script are set as this
|
|
// could open a potential security hole.If they are set, then alert the user
|
|
// and ask if they reall really want to do that
|
|
if ( m_bool_write
|
|
&& ((m_int_AppPerms == APPPERM_SCRIPTS) || (m_int_AppPerms == APPPERM_EXECUTE))
|
|
)
|
|
{
|
|
LoadString (g_hmodThisDll, IDS_WRITEEXECUTE_WARNING, sz, MAX_PATH);
|
|
LoadString (g_hmodThisDll, IDS_WARNING, szCaption, MAX_PATH);
|
|
if (MessageBox (hDlg, sz, szCaption, MB_YESNO |
|
|
MB_ICONEXCLAMATION) != IDYES)
|
|
goto cleanup;
|
|
}
|
|
|
|
//get ready
|
|
if (!mb.FInit (m_pMBCom))
|
|
goto cleanup;
|
|
|
|
//next, if a parent has been specified, it must exist
|
|
// the alias may not contain a '/' character
|
|
if (NULL != StrPBrk (m_sz_alias, _T ("\\/")))
|
|
{
|
|
LPTSTR pPar = StrRChr (m_sz_alias, NULL, _T ('/'));
|
|
if (NULL == pPar)
|
|
pPar = StrRChr (m_sz_alias, NULL, _T ('\\'));
|
|
|
|
//make the parental path
|
|
StrCpy (szParent, m_szRoot);
|
|
StrCat (szParent, _T ("/"));
|
|
StrCatN (szParent, m_sz_alias, m_sz_alias - pPar);
|
|
|
|
//make sure the parent is there
|
|
if (!mb.Open (szParent))
|
|
{
|
|
LoadString (g_hmodThisDll, IDS_PAGE_TITLE, szCaption, MAX_PATH);
|
|
LoadString (g_hmodThisDll, IDS_NO_PARENT, sz, MAX_PATH);
|
|
MessageBox (hDlg, sz, szCaption, MB_OK);
|
|
goto cleanup;
|
|
}
|
|
//close right away - we are ok
|
|
mb.Close ();
|
|
}
|
|
|
|
//Now we need to make sure that alias isn 't already taken
|
|
_tcscpy (szPath, m_szRoot);
|
|
_tcscat (szPath, _T ("/"));
|
|
_tcscat (szPath, m_sz_alias);
|
|
|
|
//try to open the object
|
|
// however, if it is not a new object, and the alias has not changed,
|
|
// do not see if the object is there becuase we know that it is and it is ok in this case
|
|
if (_tcsicmp (m_sz_alias, m_szOrigAlias) || m_fNewItem)
|
|
{
|
|
if (mb.Open (szPath))
|
|
{
|
|
//we did open it ! Close it right away
|
|
mb.Close ();
|
|
//tell the user to pick another name
|
|
LoadString (g_hmodThisDll, IDS_ALIAS_IS_TAKEN, sz, MAX_PATH);
|
|
LoadString (g_hmodThisDll, IDS_PAGE_TITLE, szCaption, MAX_PATH);
|
|
MyFormatString1 (sz, MAX_PATH, m_sz_alias);
|
|
MessageBox (hDlg, sz, szCaption, MB_OK);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
SetCursor (LoadCursor (NULL, IDC_WAIT));
|
|
|
|
//if the name has changed, delete the old one
|
|
if (_tcscmp (m_szOrigAlias, m_sz_alias) && !m_fNewItem)
|
|
{
|
|
//first we have to open the root
|
|
if (mb.Open (m_szRoot, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE))
|
|
{
|
|
MakeWAMApplication (m_szOrigAlias, FALSE);
|
|
f = mb.DeleteObject (m_szOrigAlias);
|
|
mb.Close ();
|
|
}
|
|
}
|
|
|
|
//if we are creating a new object - then do so
|
|
if (_tcscmp (m_szOrigAlias, m_sz_alias) || m_fNewItem)
|
|
{
|
|
//first we have to open the root
|
|
if (mb.Open (m_szRoot, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE))
|
|
{
|
|
f = mb.AddObject (m_sz_alias);
|
|
//set the key type
|
|
f = mb.SetString (m_sz_alias, MD_KEY_TYPE, IIS_MD_UT_SERVER,
|
|
MDSZ_W3_VDIR_TYPE, 0);
|
|
mb.Close ();
|
|
|
|
//create the WAM application at the new virtual directory location
|
|
MakeWAMApplication (szPath, TRUE);
|
|
}
|
|
else
|
|
err = GetLastError ();
|
|
}
|
|
|
|
//make sure we have the right path again
|
|
_tcscpy (szPath, m_szRoot);
|
|
_tcscat (szPath, _T ("/"));
|
|
_tcscat (szPath, m_sz_alias);
|
|
|
|
//open the target new item and write out its parameters
|
|
if (mb.Open (szPath, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE))
|
|
{
|
|
//set the path into place
|
|
f = mb.SetString (_T (""), MD_VR_PATH, IIS_MD_UT_FILE, m_sz_path);
|
|
|
|
//put the access flags into place.There are other flags than the ones that are manupulated
|
|
// here, so be careful to read the value first, then flip the flags, then write it back
|
|
dword = 0;
|
|
mb.GetDword (_T (""), MD_ACCESS_PERM, IIS_MD_UT_FILE, &dword, METADATA_INHERIT);
|
|
//read permissions
|
|
if (m_bool_read)
|
|
dword |= MD_ACCESS_READ;
|
|
else
|
|
dword &= ~MD_ACCESS_READ;
|
|
|
|
// write permissions
|
|
if (m_bool_write)
|
|
dword |= MD_ACCESS_WRITE;
|
|
else
|
|
dword &= ~MD_ACCESS_WRITE;
|
|
|
|
// source read permissions
|
|
if (m_bool_source)
|
|
dword |= MD_ACCESS_SOURCE;
|
|
else
|
|
dword &= ~MD_ACCESS_SOURCE;
|
|
|
|
// since the app permissions are now a set of radio buttons, use a case to discern
|
|
switch (m_int_AppPerms)
|
|
{
|
|
case APPPERM_NONE:
|
|
dword &= ~MD_ACCESS_SCRIPT;
|
|
dword &= ~MD_ACCESS_EXECUTE;
|
|
break;
|
|
case APPPERM_SCRIPTS:
|
|
dword |= MD_ACCESS_SCRIPT;
|
|
dword &= ~MD_ACCESS_EXECUTE;
|
|
break;
|
|
case APPPERM_EXECUTE:
|
|
dword |= MD_ACCESS_SCRIPT;
|
|
dword |= MD_ACCESS_EXECUTE;
|
|
break;
|
|
};
|
|
|
|
//write the dword back into the metabase
|
|
f = mb.SetDword (_T (""), MD_ACCESS_PERM, IIS_MD_UT_FILE, dword);
|
|
|
|
//------------------
|
|
//the dir browsing flag is stored in a different field - so do it again
|
|
dword = 0;
|
|
mb.GetDword (_T (""), MD_DIRECTORY_BROWSING, IIS_MD_UT_FILE, &dword, METADATA_INHERIT);
|
|
|
|
//script permissions
|
|
if (m_bool_dirbrowse)
|
|
dword |= MD_DIRBROW_ENABLED;
|
|
else
|
|
dword &= ~MD_DIRBROW_ENABLED;
|
|
|
|
// write the dword back into the metabase
|
|
f = mb.SetDword (_T (""), MD_DIRECTORY_BROWSING, IIS_MD_UT_FILE, dword);
|
|
|
|
|
|
//finish up
|
|
mb.Close ();
|
|
}
|
|
|
|
//make sure the string goes back
|
|
UpdateData (FALSE);
|
|
|
|
// do the default...
|
|
EndDialog (IDOK);
|
|
|
|
//cleanup the strings
|
|
cleanup:
|
|
SetCursor (LoadCursor (NULL, IDC_ARROW));
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
void CEditDirectory::EnableSourceControl ()
|
|
{
|
|
//get the currect button values
|
|
UpdateData (TRUE);
|
|
|
|
//if both read and write are unchecked, then we clear and disable source control
|
|
if (!m_bool_read && !m_bool_write)
|
|
{
|
|
//save the value of source control
|
|
m_bool_oldSource = m_bool_source;
|
|
|
|
//clear the source control
|
|
m_bool_source = FALSE;
|
|
UpdateData (FALSE);
|
|
|
|
//disable the source control window
|
|
EnableWindow (m_hChkSource, FALSE);
|
|
}
|
|
else
|
|
{
|
|
//we enable source control
|
|
// disable the source control window
|
|
EnableWindow (m_hChkSource, TRUE);
|
|
|
|
//and set the value back
|
|
m_bool_source = m_bool_oldSource;
|
|
UpdateData (FALSE);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
void CEditDirectory::OnRead (HWND hDlg)
|
|
{
|
|
EnableSourceControl ();
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
void CEditDirectory::OnWrite (HWND hDlg)
|
|
{
|
|
EnableSourceControl ();
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
void CEditDirectory::OnSource (HWND hDlg)
|
|
{
|
|
UpdateData (TRUE);
|
|
m_bool_oldSource = m_bool_source;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
//return an index to the position of first ch in pszSearch in the string
|
|
// or return -1 if none are there
|
|
int CEditDirectory::FindOneOf (LPTSTR psz, LPCTSTR pszSearch)
|
|
{
|
|
PTCHAR p = _tcspbrk (psz, pszSearch);
|
|
if (!p)
|
|
return -1;
|
|
return (int) (p - psz);
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
//return an index to the position of ch in the string
|
|
// or return -1 if it is not there
|
|
int CEditDirectory::FindLastChr (LPTSTR psz, TCHAR ch)
|
|
{
|
|
PTCHAR p = _tcsrchr (psz, ch);
|
|
if (!p)
|
|
return -1;
|
|
return (int) (p - psz);
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
//trim leading whitespace
|
|
void CEditDirectory::TrimLeft (LPTSTR psz)
|
|
{
|
|
TCHAR buf[8];
|
|
ZeroMemory (&buf, sizeof (buf));
|
|
|
|
//copy over the first character
|
|
_tcsncpy (buf, psz, 1);
|
|
//and compare
|
|
while (_tcscmp (buf, _T (" ")) == 0)
|
|
{
|
|
_tcscpy (psz, _tcsinc (psz));
|
|
_tcsncpy (buf, psz, 1);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
//trim trailing whitespace
|
|
void CEditDirectory::TrimRight (LPTSTR psz)
|
|
{
|
|
TCHAR buf[8];
|
|
DWORD len;
|
|
|
|
ZeroMemory (&buf, sizeof (buf));
|
|
|
|
//copy over the last character
|
|
len = _tcslen (psz);
|
|
_tcsncpy (buf, _tcsninc (psz, len - 1), 1);
|
|
//and compare
|
|
while (_tcscmp (buf, _T (" ")) == 0)
|
|
{
|
|
//truncate the string
|
|
*(_tcsninc (psz, len - 1)) = 0;
|
|
//start over
|
|
len = _tcslen (psz);
|
|
_tcsncpy (buf, _tcsninc (psz, len - 1), 1);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
|
|
|
|
//----------------------------------------------------------------
|
|
|
|
//trim trailing whitespace
|
|
|
|
void CEditDirectory::TrimRight (LPTSTR psz)
|
|
|
|
{
|
|
|
|
|
|
TCHAR buf[8];
|
|
|
|
|
|
DWORD len;
|
|
|
|
|
|
|
|
|
|
ZeroMemory (&buf, sizeof (buf));
|
|
|
|
|
|
|
|
|
|
//copy over the last character
|
|
|
|
len = _tcslen (psz);
|
|
|
|
|
|
_tcsncpy (buf, _tcsninc (psz, len - 1), 1);
|
|
|
|
|
|
//and compare
|
|
|
|
while (_tcscmp (buf, _T (" ")) == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
//truncate the string
|
|
|
|
*(_tcsninc (psz, len - 1)) = 0;
|
|
|
|
|
|
//start over
|
|
|
|
len = _tcslen (psz);
|
|
|
|
|
|
_tcsncpy (buf, _tcsninc (psz, len - 1), 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|