windows-nt/Source/XPSP1/NT/shell/ext/mydocs2/util.cpp
2020-09-26 16:20:57 +08:00

320 lines
9.9 KiB
C++

#include "precomp.hxx"
#pragma hdrstop
#include <shguidp.h> // CLSID_MyDocuments, CLSID_ShellFSFolder
#include <shlobjp.h> // SHFlushSFCache()
#include "util.h"
#include "dll.h"
#include "resource.h"
#include "sddl.h"
HRESULT GetFolderDisplayName(UINT csidl, LPTSTR pszPath, UINT cch)
{
*pszPath = 0;
LPITEMIDLIST pidl;
if (SUCCEEDED(SHGetFolderLocation(NULL, csidl | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, &pidl)))
{
SHGetNameAndFlags(pidl, SHGDN_NORMAL, pszPath, cch, NULL);
ILFree(pidl);
}
return *pszPath ? S_OK : E_FAIL;
}
#define MYDOCS_CLSID TEXT("{450d8fba-ad25-11d0-98a8-0800361b1103}") // CLSID_MyDocuments
// Create/Updates file in SendTo directory to have current display name
void UpdateSendToFile()
{
TCHAR szSendToDir[MAX_PATH];
if (S_OK == SHGetFolderPath(NULL, CSIDL_SENDTO, NULL, SHGFP_TYPE_CURRENT, szSendToDir))
{
// Create c:\winnt\profile\chrisg\sendto\<display name>.mydocs
BOOL bDeleteOnly = FALSE;
TCHAR szNewFile[MAX_PATH];
TCHAR szName[MAX_PATH];
if (SUCCEEDED(GetFolderDisplayName(CSIDL_PERSONAL, szName, ARRAYSIZE(szName))))
{
PathCleanupSpec(NULL, szName); // map any illegal chars to file sys chars
PathRemoveBlanks(szName);
PathCombine(szNewFile, szSendToDir, szName);
lstrcat(szNewFile, TEXT(".mydocs"));
}
else
{
// we can't create a new file, because we don't have a name
bDeleteOnly = TRUE;
}
TCHAR szFile[MAX_PATH];
WIN32_FIND_DATA fd;
// delete c:\winnt\profile\chrisg\sendto\*.mydocs
PathCombine(szFile, szSendToDir, TEXT("*.mydocs"));
HANDLE hFind = FindFirstFile(szFile, &fd);
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
PathCombine(szFile, szSendToDir, fd.cFileName);
if (0 == lstrcmp(szFile, szNewFile))
{
// The file that we needed to create already exists,
// just leave it in place instead of deleting it and
// then creating it again below (this fixes
// app compat problems - see NT bug 246932)
bDeleteOnly = TRUE;
// file now has the exact display name, MUI adjusts the return from GetFolderDisplayName and
// since we run this every time we dont have to worry about localizing the sendto target.
}
else
{
DeleteFile(szFile);
}
} while (FindNextFile(hFind, &fd));
FindClose(hFind);
}
if (!bDeleteOnly)
{
hFind = CreateFile(szNewFile, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFind != INVALID_HANDLE_VALUE)
{
CloseHandle(hFind);
// file now has the exact display name, MUI adjusts the return from GetFolderDisplayName and
// since we run this every time we dont have to worry about localizing the sendto target.
}
else
{
// might be illegal chars in the file name, fall back to the default MyDocs name here
}
}
}
}
// test pszChild against pszParent to see if
// pszChild is equal (PATH_IS_EQUAL) or
// a DIRECT child (PATH_IS_CHILD)
DWORD ComparePaths(LPCTSTR pszChild, LPCTSTR pszParent)
{
DWORD dwRet = PATH_IS_DIFFERENT;
TCHAR szParent[MAX_PATH];
StrCpyN(szParent, pszParent, ARRAYSIZE(szParent));
if (PathIsRoot(szParent) && (-1 != PathGetDriveNumber(szParent)))
{
szParent[2] = 0; // trip D:\ -> D: to make code below work
}
INT cchParent = lstrlen(szParent);
INT cchChild = lstrlen(pszChild);
if (cchParent <= cchChild)
{
TCHAR szChild[MAX_PATH];
lstrcpyn(szChild, pszChild, ARRAYSIZE(szChild));
LPTSTR pszChildSlice = szChild + cchParent;
if (TEXT('\\') == *pszChildSlice)
{
*pszChildSlice = 0;
}
if (lstrcmpi(szChild, szParent) == 0)
{
if (cchParent < cchChild)
{
LPTSTR pTmp = pszChildSlice + 1;
while (*pTmp && *pTmp != TEXT('\\'))
{
pTmp++; // find second level path segments
}
if (!(*pTmp))
{
dwRet = PATH_IS_CHILD; // direct child
}
}
else
{
dwRet = PATH_IS_EQUAL;
}
}
}
return dwRet;
}
// Checks the path to see if it is marked as system or read only and
// then check desktop.ini for CLSID or CLSID2 entry...
BOOL IsPathAlreadyShellFolder(LPCTSTR pszPath, DWORD dwAttrib)
{
BOOL bIsShellFolder = FALSE;
if (PathIsSystemFolder(pszPath, dwAttrib))
{
TCHAR szDesktopIni[MAX_PATH];
PathCombine(szDesktopIni, pszPath, TEXT("desktop.ini"));
// Check for CLSID entry...
TCHAR szBuffer[MAX_PATH];
GetPrivateProfileString(TEXT(".ShellClassInfo"), TEXT("CLSID"), TEXT("foo"), szBuffer, ARRAYSIZE(szBuffer), szDesktopIni);
if ((lstrcmpi(szBuffer, TEXT("foo")) !=0) &&
(lstrcmpi(szBuffer, MYDOCS_CLSID) !=0))
{
bIsShellFolder = TRUE;
}
// Check for CLSID2 entry...
GetPrivateProfileString(TEXT(".ShellClassInfo"), TEXT("CLSID2"), TEXT("foo"), szBuffer, ARRAYSIZE(szBuffer), szDesktopIni);
if ((lstrcmpi(szBuffer, TEXT("foo")) != 0) &&
(lstrcmpi(szBuffer, MYDOCS_CLSID) != 0))
{
bIsShellFolder = TRUE;
}
}
return bIsShellFolder;
}
const struct
{
DWORD dwDir;
DWORD dwFlags;
DWORD dwRet;
}
_adirs[] =
{
{ CSIDL_DESKTOP, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_DESKTOP },
{ CSIDL_PERSONAL, PATH_IS_EQUAL , PATH_IS_MYDOCS },
{ CSIDL_SENDTO, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_SENDTO },
{ CSIDL_RECENT, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_RECENT },
{ CSIDL_HISTORY, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_HISTORY },
{ CSIDL_COOKIES, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_COOKIES },
{ CSIDL_PRINTHOOD, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_PRINTHOOD },
{ CSIDL_NETHOOD, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_NETHOOD },
{ CSIDL_STARTMENU, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_STARTMENU },
{ CSIDL_TEMPLATES, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_TEMPLATES },
{ CSIDL_FAVORITES, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_FAVORITES },
{ CSIDL_FONTS, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_FONTS },
{ CSIDL_APPDATA, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_APPDATA },
{ CSIDL_INTERNET_CACHE, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_TEMP_INET },
{ CSIDL_COMMON_STARTMENU, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_STARTMENU },
{ CSIDL_COMMON_DESKTOPDIRECTORY, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_DESKTOP },
{ CSIDL_WINDOWS, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_WINDOWS },
{ CSIDL_SYSTEM, PATH_IS_EQUAL | PATH_IS_CHILD, PATH_IS_SYSTEM },
{ CSIDL_PROFILE, PATH_IS_EQUAL , PATH_IS_PROFILE },
};
BOOL PathEndsInDot(LPCTSTR pszPath)
{
// CreateDirectory("c:\foo.") or CreateDirectory("c:\foo.....")
// will succeed but create a directory named "c:\foo", which isn't
// what the user asked for. So we use this function to guard
// against those cases.
//
// Note that this simple test also picks off "c:\foo\." -- ok for
// our purposes.
UINT cLen = lstrlen(pszPath);
return (cLen >= 1) && (pszPath[cLen - 1] == TEXT('.'));
}
//
// Checks the path to see if it is okay as a MyDocs path
//
DWORD IsPathGoodMyDocsPath(HWND hwnd, LPCTSTR pszPath)
{
if (NULL == pszPath)
{
return PATH_IS_ERROR;
}
TCHAR szRootPath[MAX_PATH];
lstrcpyn(szRootPath, pszPath, ARRAYSIZE(szRootPath));
if (!PathStripToRoot(szRootPath))
{
return PATH_IS_ERROR;
}
if (PathEndsInDot(pszPath))
{
return PATH_IS_ERROR;
}
DWORD dwRes, dwAttr = GetFileAttributes(pszPath);
if (dwAttr == 0xFFFFFFFF)
{
if (0xFFFFFFFF == GetFileAttributes(szRootPath))
{
// If the root path doesn't exist, then we're not going
// to be able to create a path:
return PATH_IS_ERROR;
}
else
{
return PATH_IS_NONEXISTENT;
}
}
if (!(dwAttr & FILE_ATTRIBUTE_DIRECTORY))
{
return PATH_IS_NONDIR;
}
for (int i = 0; i < ARRAYSIZE(_adirs); i++)
{
TCHAR szPathToCheck[MAX_PATH];
//
// Check for various special shell folders
//
if (S_OK == SHGetFolderPath(hwnd, _adirs[i].dwDir | CSIDL_FLAG_DONT_VERIFY, NULL, SHGFP_TYPE_CURRENT, szPathToCheck))
{
dwRes = ComparePaths(pszPath, szPathToCheck);
if (dwRes & _adirs[i].dwFlags)
{
//
// The inevitable exceptions
//
switch (_adirs[i].dwDir)
{
case CSIDL_DESKTOP:
if (PATH_IS_CHILD == dwRes)
{
continue; // allowing subfolder of CSIDL_DESKTOP
}
break;
default:
break;
} // switch
return _adirs[i].dwRet;
}
}
}
//
// Make sure path isn't set as a system or some other kind of
// folder that already has a CLSID or CLSID2 entry...
//
if (IsPathAlreadyShellFolder(pszPath, dwAttr))
{
return PATH_IS_SHELLFOLDER;
}
return PATH_IS_GOOD;
}