|
|
#include "local.h"
#include "resource.h"
#include <mluisupp.h>
#ifdef _HSFOLDER
#define LODWORD(_qw) (DWORD)(_qw)
// Invoke Command verb strings
const CHAR c_szOpen[] = "open"; const CHAR c_szDelcache[] = "delete"; const CHAR c_szProperties[] = "properties"; const CHAR c_szCopy[] = "copy";
void FileTimeToDateTimeStringInternal(FILETIME UNALIGNED *ulpft, LPTSTR pszText, int cchText, BOOL fUsePerceivedTime) { FILETIME ft; FILETIME aft; LPFILETIME lpft;
aft = *ulpft; lpft = &aft;
if (!fUsePerceivedTime && (FILETIMEtoInt64(*lpft) != FT_NTFS_UNKNOWNGMT)) FileTimeToLocalFileTime(lpft, &ft); else ft = *lpft;
if (FILETIMEtoInt64(ft) == FT_NTFS_UNKNOWNGMT || FILETIMEtoInt64(ft) == FT_FAT_UNKNOWNLOCAL) { static TCHAR szNone[40] = {0}; if (szNone[0] == 0) MLLoadString(IDS_HSFNONE, szNone, ARRAYSIZE(szNone));
StrCpyN(pszText, szNone, cchText); } else { TCHAR szTempStr[MAX_PATH]; LPTSTR pszTempStr = szTempStr; SYSTEMTIME st; FileTimeToSystemTime(&ft, &st);
if (GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, szTempStr, ARRAYSIZE(szTempStr)) > 0) { int iLen = lstrlen(szTempStr); ASSERT(TEXT('\0') == szTempStr[iLen]); // Make sure multi-byte isn't biting us.
pszTempStr = (LPTSTR)(pszTempStr + iLen); *pszTempStr++ = ' '; GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, pszTempStr, ARRAYSIZE(szTempStr)-(iLen+1)); StrCpyN(pszText, szTempStr, cchText); } } }
HMENU LoadPopupMenu(UINT id, UINT uSubOffset) { HMENU hmParent, hmPopup;
HINSTANCE hinst = MLLoadShellLangResources(); hmParent = LoadMenu_PrivateNoMungeW(hinst, MAKEINTRESOURCEW(id)); if (!hmParent) { long error = GetLastError(); return NULL; }
hmPopup = GetSubMenu(hmParent, uSubOffset); RemoveMenu(hmParent, uSubOffset, MF_BYPOSITION); DestroyMenu(hmParent);
MLFreeLibrary(hinst);
return hmPopup; }
UINT MergePopupMenu(HMENU *phMenu, UINT idResource, UINT uSubOffset, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast) { HMENU hmMerge;
if (*phMenu == NULL) { *phMenu = CreatePopupMenu(); if (*phMenu == NULL) return 0;
indexMenu = 0; // at the bottom
}
hmMerge = LoadPopupMenu(idResource, uSubOffset); if (!hmMerge) return 0;
idCmdLast = Shell_MergeMenus(*phMenu, hmMerge, indexMenu, idCmdFirst, idCmdLast, MM_ADDSEPARATOR); DestroyMenu(hmMerge); return idCmdLast; }
///////////////////////////////////////////////////////////////////////////////
//
// Helper Fuctions for item.cpp and folder.cpp
//
///////////////////////////////////////////////////////////////////////////////
// copy and flatten the CACHE_ENTRY_INFO data
void _CopyCEI(UNALIGNED INTERNET_CACHE_ENTRY_INFO *pdst, LPINTERNET_CACHE_ENTRY_INFO psrc, DWORD dwBuffSize) { // This assumes how urlcache does allocation
memcpy(pdst, psrc, dwBuffSize);
// convert pointers to offsets
pdst->lpszSourceUrlName = (LPTSTR) PtrDifference(psrc->lpszSourceUrlName, psrc); pdst->lpszLocalFileName = (LPTSTR) PtrDifference(psrc->lpszLocalFileName, psrc); pdst->lpszFileExtension = (LPTSTR) PtrDifference(psrc->lpszFileExtension, psrc); pdst->lpHeaderInfo = psrc->lpHeaderInfo ? (TCHAR*) PtrDifference(psrc->lpHeaderInfo, psrc) : NULL; }
INT g_fProfilesEnabled = -1;
BOOL IsProfilesEnabled();
BOOL _FilterUserName(LPINTERNET_CACHE_ENTRY_INFO pcei, LPCTSTR pszCachePrefix, LPTSTR pszUserName) { TCHAR szTemp[MAX_URL_STRING]; LPCTSTR pszTemp = szTemp; // chrisfra 3/27/97, more constant crapola. this all needs to be fixed.
TCHAR szPrefix[80]; BOOL fRet = 0; if (g_fProfilesEnabled==-1) { g_fProfilesEnabled = IsProfilesEnabled(); }
if (g_fProfilesEnabled) { return TRUE; }
StrCpyN(szTemp, pcei->lpszSourceUrlName, ARRAYSIZE(szTemp)); StrCpyN(szPrefix, pszCachePrefix, ARRAYSIZE(szPrefix)); StrCatBuff(szPrefix, pszUserName, ARRAYSIZE(szPrefix));
// find the '@' character if it exists
pszTemp = StrChr(pszTemp, TEXT('@')); if ( (pszTemp) && (*pszTemp == TEXT('@')) ) { fRet = (StrCmpNI(szTemp, szPrefix, lstrlen(szPrefix)) == 0); } else { fRet = (*pszUserName == TEXT('\0')); }
return fRet; }
BOOL _FilterPrefix(LPINTERNET_CACHE_ENTRY_INFO pcei, LPCTSTR pszCachePrefix) { #define MAX_PREFIX (80)
TCHAR szTemp[MAX_URL_STRING]; LPCTSTR pszStripped; BOOL fRet = 0; StrCpyN(szTemp, pcei->lpszSourceUrlName, ARRAYSIZE(szTemp)); pszStripped = _StripContainerUrlUrl(szTemp);
if (pszStripped && pszStripped-szTemp < MAX_PREFIX) { fRet = (StrCmpNI(szTemp, pszCachePrefix, ((int) (pszStripped-szTemp))/sizeof(TCHAR)) == 0); } return fRet; }
LPCTSTR _StripContainerUrlUrl(LPCTSTR pszHistoryUrl) { // NOTE: for our purposes, we don't want a history URL if we can't detect our
// prefix, so we return NULL.
LPCTSTR pszTemp = pszHistoryUrl; LPCTSTR pszCPrefix; LPCTSTR pszReturn = NULL; // Check for "Visited: "
pszCPrefix = c_szHistPrefix; while (*pszTemp == *pszCPrefix && *pszTemp != TEXT('\0')) { pszTemp = CharNext(pszTemp); pszCPrefix = CharNext(pszCPrefix); } if (*pszCPrefix == TEXT('\0')) { // Found "Visited: "
pszReturn = pszTemp; } else if (pszTemp == (LPTSTR) pszHistoryUrl) { // Check for ":YYYYMMDDYYYYMMDD: "
pszCPrefix = TEXT(":nnnnnnnnnnnnnnnn: "); while (*pszTemp != TEXT('\0')) { if (*pszCPrefix == TEXT('n')) { if (*pszTemp < TEXT('0') || *pszTemp > TEXT('9')) break; } else if (*pszCPrefix != *pszTemp) break; pszTemp = CharNext(pszTemp); pszCPrefix = CharNext(pszCPrefix); } } return (*pszCPrefix == TEXT('\0')) ? pszTemp : pszReturn; }
LPCTSTR _StripHistoryUrlToUrl(LPCTSTR pszHistoryUrl) { LPCTSTR pszTemp = pszHistoryUrl;
if (!pszHistoryUrl) return NULL;
pszTemp = StrChr(pszHistoryUrl, TEXT('@')); if (pszTemp && *pszTemp) return CharNext(pszTemp); pszTemp = StrChr(pszHistoryUrl, TEXT(' ')); if (pszTemp && *pszTemp) return CharNext(pszTemp); else return NULL; // error, the URL passed in wasn't a history url
}
// assumes this is a real URL and not a "history" url
void _GetURLHostFromUrl_NoStrip(LPCTSTR lpszUrl, LPTSTR szHost, DWORD dwHostSize, LPCTSTR pszLocalHost) { DWORD cch = dwHostSize; if (S_OK != UrlGetPart(lpszUrl, szHost, &cch, URL_PART_HOSTNAME, 0) || !*szHost) { // default to the local host name.
StrCpyN(szHost, pszLocalHost, dwHostSize); } }
void _GetURLHost(LPINTERNET_CACHE_ENTRY_INFO pcei, LPTSTR szHost, DWORD dwHostSize, LPCTSTR pszLocalHost) { TCHAR szSourceUrl[MAX_URL_STRING];
ASSERT(ARRAYSIZE(szSourceUrl) > lstrlen(pcei->lpszSourceUrlName)) StrCpyN(szSourceUrl, pcei->lpszSourceUrlName, ARRAYSIZE(szSourceUrl));
_GetURLHostFromUrl(szSourceUrl, szHost, dwHostSize, pszLocalHost); }
LPHEIPIDL _IsValid_HEIPIDL(LPCITEMIDLIST pidl) { LPHEIPIDL phei = (LPHEIPIDL)pidl;
if (phei && ((phei->cb > sizeof(HEIPIDL)) && (phei->usSign == (USHORT)HEIPIDL_SIGN)) && (phei->usUrl == 0 || phei->usUrl < phei->cb) && (phei->usTitle == 0 || (phei->usTitle + sizeof(WCHAR)) <= phei->cb)) { return phei; } return NULL; }
LPBASEPIDL _IsValid_IDPIDL(LPCITEMIDLIST pidl) { LPBASEPIDL pcei = (LPBASEPIDL)pidl;
if (pcei && VALID_IDSIGN(pcei->usSign) && pcei->cb > 0) { return pcei; } return NULL; }
LPCTSTR _FindURLFileName(LPCTSTR pszURL) { LPCTSTR psz, pszRet = pszURL; // need to set to pszURL in case no '/'
LPCTSTR pszNextToLast = NULL; for (psz = pszURL; *psz; psz = CharNext(psz)) { if ((*psz == TEXT('\\') || *psz == TEXT('/'))) { pszNextToLast = pszRet; pszRet = CharNext(psz); } } return *pszRet ? pszRet : pszNextToLast; }
int _LaunchApp(HWND hwnd, LPCTSTR pszPath) { SHELLEXECUTEINFO ei = { 0 };
ei.cbSize = sizeof(SHELLEXECUTEINFO); ei.hwnd = hwnd; ei.lpFile = pszPath; ei.nShow = SW_SHOWNORMAL;
return ShellExecuteEx(&ei); }
int _LaunchAppForPidl(HWND hwnd, LPITEMIDLIST pidl) { SHELLEXECUTEINFO ei = { 0 };
ei.cbSize = sizeof(SHELLEXECUTEINFO); ei.fMask = SEE_MASK_IDLIST; ei.hwnd = hwnd; ei.lpIDList = pidl; ei.nShow = SW_SHOWNORMAL;
return ShellExecuteEx(&ei); }
void _GenerateEvent(LONG lEventId, LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlIn, LPCITEMIDLIST pidlNewIn) { LPITEMIDLIST pidl; if (pidlIn) { pidl = ILCombine(pidlFolder, pidlIn); } else { pidl = ILClone(pidlFolder); } if (pidl) { if (pidlNewIn) { LPITEMIDLIST pidlNew = ILCombine(pidlFolder, pidlNewIn); if (pidlNew) { SHChangeNotify(lEventId, SHCNF_IDLIST, pidl, pidlNew); ILFree(pidlNew); } } else { SHChangeNotify(lEventId, SHCNF_IDLIST, pidl, NULL); } ILFree(pidl); } }
const struct { LPCSTR pszVerb; UINT idCmd; } rgcmds[] = { { c_szOpen, RSVIDM_OPEN }, { c_szCopy, RSVIDM_COPY }, { c_szDelcache, RSVIDM_DELCACHE }, { c_szProperties, RSVIDM_PROPERTIES } };
int _GetCmdID(LPCSTR pszCmd) { if (HIWORD(pszCmd)) { int i;
for (i = 0; i < ARRAYSIZE(rgcmds); i++) { if (StrCmpIA(rgcmds[i].pszVerb, pszCmd) == 0) { return rgcmds[i].idCmd; } }
return -1; // unknown
} return (int)LOWORD(pszCmd); }
HRESULT _CreatePropSheet(HWND hwnd, LPCITEMIDLIST pidl, int iDlg, DLGPROC pfnDlgProc, LPCTSTR pszTitle) { PROPSHEETPAGE psp = { 0 }; PROPSHEETHEADER psh = { 0 } ;
// initialize propsheet page.
psp.dwSize = sizeof(PROPSHEETPAGE); psp.dwFlags = 0; psp.hInstance = MLGetHinst(); psp.DUMMYUNION_MEMBER(pszTemplate) = MAKEINTRESOURCE(iDlg); psp.DUMMYUNION2_MEMBER(pszIcon) = NULL; psp.pfnDlgProc = pfnDlgProc; psp.pszTitle = NULL; psp.lParam = (LPARAM)pidl; // send it the cache entry struct
// initialize propsheet header.
psh.dwSize = sizeof(PROPSHEETHEADER); psh.dwFlags = PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW | PSH_PROPTITLE; psh.hwndParent = hwnd; psh.pszCaption = pszTitle; psh.nPages = 1; psh.DUMMYUNION2_MEMBER(nStartPage) = 0; psh.DUMMYUNION3_MEMBER(ppsp) = (LPCPROPSHEETPAGE)&psp;
// invoke the property sheet
PropertySheet(&psh); return NOERROR; }
INT_PTR CALLBACK HistoryConfirmDeleteDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_INITDIALOG: SetDlgItemText(hDlg, IDD_TEXT4, (LPCTSTR)lParam); break; case WM_DESTROY: break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDYES: case IDNO: case IDCANCEL: EndDialog(hDlg, wParam); break; } break; default: return FALSE; } return TRUE; }
// This function restores the Unicode characters from file system URLs
//
// If the URL isn't a file URL, it is copied directly to pszBuf. Otherwise, any
// UTF8-escaped parts of the URL are converted into Unicode, and the result is
// stored in pszBuf. This should be the same as the string we received in
// History in the first place
//
// The return value is always pszBuf.
// The input and output buffers may be the same.
LPCTSTR ConditionallyDecodeUTF8(LPCTSTR pszUrl, LPTSTR pszBuf, DWORD cchBuf) { BOOL fDecoded = FALSE;
if (PathIsFilePath(pszUrl)) { TCHAR szDisplayUrl[MAX_URL_STRING]; DWORD cchDisplayUrl = ARRAYSIZE(szDisplayUrl); DWORD cchBuf2 = cchBuf; // we may need the old cchBuf later
// After PrepareUrlForDisplayUTF8, we have a fully unescaped URL. If we
// ShellExec this, then Shell will unescape it again, so we need to re-escape
// it to preserve any real %dd sequences that might be in the string.
if (SUCCEEDED(PrepareURLForDisplayUTF8(pszUrl, szDisplayUrl, &cchDisplayUrl, TRUE)) && SUCCEEDED(UrlCanonicalize(szDisplayUrl, pszBuf, &cchBuf2, URL_ESCAPE_UNSAFE | URL_ESCAPE_PERCENT))) { fDecoded = TRUE; } }
if (!fDecoded && (pszUrl != pszBuf)) { StrCpyN(pszBuf, pszUrl, cchBuf); }
return pszBuf; }
//
// These routines make a string into a legal filename by replacing
// all invalid characters with spaces.
//
// The list of invalid characters was obtained from the NT error
// message you get when you try to rename a file to an invalid name.
//
#ifndef UNICODE
#error The MakeLegalFilename code only works when it's part of a UNICODE build
#endif
//
// This function takes a string and makes it into a
// valid filename (by calling PathCleanupSpec).
//
// The PathCleanupSpec function wants to know what
// directory the file will live in. But it's going
// on the clipboard, so we don't know. We just
// guess the desktop.
//
// It only uses this path to decide if the filesystem
// supports long filenames or not, and to check for
// MAX_PATH overflow.
//
void MakeLegalFilenameW(LPWSTR pszFilename) { WCHAR szDesktopPath[MAX_PATH];
GetWindowsDirectoryW(szDesktopPath, ARRAYSIZE(szDesktopPath)); PathCleanupSpec(szDesktopPath, pszFilename);
}
//
// ANSI wrapper for above function
//
void MakeLegalFilenameA(LPSTR pszFilename, int cchFilename) { WCHAR szFilenameW[MAX_PATH];
SHAnsiToUnicode(pszFilename, szFilenameW, ARRAYSIZE(szFilenameW));
MakeLegalFilenameW(szFilenameW);
SHUnicodeToAnsi(szFilenameW, pszFilename, cchFilename);
}
#endif // _HSFOLDER
|