|
|
/*
* ispersis.cpp - IPersist, IPersistFile, and IPersistStream implementations for * URL class. */
#include "priv.h"
#include "ishcut.h"
#include "resource.h"
// Need to flush the file to prevent win95 from barfing after stuff is written in
VOID FlushFile(LPCTSTR pszFile) { if (!g_fRunningOnNT) { WritePrivateProfileString(NULL, NULL, NULL, pszFile); } }
// save object to file
STDMETHODIMP Intshcut::SaveToFile(LPCTSTR pszFile, BOOL bRemember) { HRESULT hres = InitProp(); if (SUCCEEDED(hres)) { m_pprop->SetFileName(pszFile);
hres = m_pprop->Commit(STGC_DEFAULT);
// Remember file if requested
if (SUCCEEDED(hres)) { if (bRemember) { Dirty(FALSE);
if ( !Str_SetPtr(&m_pszFile, pszFile) ) hres = E_OUTOFMEMORY;
#ifdef DEBUG
Dump(); #endif
} SHChangeNotify(SHCNE_UPDATEITEM, (SHCNF_PATH | SHCNF_FLUSHNOWAIT), pszFile, NULL); }
if (!bRemember) m_pprop->SetFileName(m_pszFile); }
if(pszFile && (S_OK == hres)) FlushFile(pszFile); return hres; }
STDMETHODIMP Intshcut::LoadFromFile(LPCTSTR pszFile) { HRESULT hres;
if (Str_SetPtr(&m_pszFile, pszFile)) { hres = InitProp(); #ifdef DEBUG
Dump(); #endif
} else { hres = E_OUTOFMEMORY; }
return hres; }
STDMETHODIMP Intshcut::LoadFromAsyncFileNow() { HRESULT hres = S_OK; if (m_pszFileToLoad) { hres = LoadFromFile(m_pszFileToLoad); Str_SetPtr(&m_pszFileToLoad, NULL); } return hres; }
STDMETHODIMP Intshcut::GetCurFile(LPTSTR pszFile, UINT cchLen) { HRESULT hr;
if (m_pszFile) { hr = StringCchCopy(pszFile, cchLen, m_pszFile); } else hr = S_FALSE;
return hr; }
STDMETHODIMP Intshcut::Dirty(BOOL bDirty) { HRESULT hres; ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut)); if (bDirty) { if (IsFlagClear(m_dwFlags, ISF_DIRTY)) TraceMsg(TF_INTSHCUT, "Intshcut now dirty."); SetFlag(m_dwFlags, ISF_DIRTY); } else { if (IsFlagSet(m_dwFlags, ISF_DIRTY)) TraceMsg(TF_INTSHCUT, "Intshcut now clean."); ClearFlag(m_dwFlags, ISF_DIRTY); } hres = S_OK; ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut)); return hres; }
// IPersist::GetClassID method for Intshcut
STDMETHODIMP Intshcut::GetClassID(CLSID *pclsid) { ASSERT(IS_VALID_WRITE_PTR(pclsid, CLSID));
*pclsid = CLSID_InternetShortcut; return S_OK; }
// IPersistFile::IsDirty handler for Intshcut
STDMETHODIMP Intshcut::IsDirty(void) { HRESULT hres = LoadFromAsyncFileNow();
if(SUCCEEDED(hres)) { hres = InitProp(); if (SUCCEEDED(hres)) { if (IsFlagSet(m_dwFlags, ISF_DIRTY) || S_OK == m_pprop->IsDirty()) hres = S_OK; else hres = S_FALSE; } } return hres; }
// Helper function to save off Trident specific stuff
STDMETHODIMP Intshcut::_SaveOffPersistentDataFromSite() { IOleCommandTarget *pcmdt = NULL; HRESULT hr = S_OK; if (_punkSite) { if(S_OK == _CreateTemporaryBackingFile()) { ASSERT(m_pszTempFileName); hr = _punkSite->QueryInterface(IID_IOleCommandTarget, (LPVOID *)&pcmdt); if((S_OK == hr)) { ASSERT(pcmdt); VARIANT varIn = {0}; varIn.vt = VT_UNKNOWN; varIn.punkVal = (LPUNKNOWN)(SAFECAST(this, IUniformResourceLocator *)); // Tell the site to save off it's persistent stuff
hr = pcmdt->Exec(&CGID_ShortCut, CMDID_INTSHORTCUTCREATE, 0, &varIn, NULL); pcmdt->Release(); } FlushFile(m_pszTempFileName); } } return hr; }
// IPersistFile::Save handler for Intshcut
STDMETHODIMP Intshcut::Save(LPCOLESTR pwszFile, BOOL bRemember) { HRESULT hres = LoadFromAsyncFileNow(); if (SUCCEEDED(hres)) { TCHAR szFile[MAX_PATH];
if (pwszFile) SHUnicodeToTChar(pwszFile, szFile, SIZECHARS(szFile)); else if (m_pszFile) hres = StringCchCopy(szFile, ARRAYSIZE(szFile), m_pszFile); else hres = E_FAIL;
if (FAILED(hres)) { return hres; } // Perhaps there is a site which wants to save off stuff ?
// However, the site may end up calling via intefaces
hres = _SaveOffPersistentDataFromSite();
if ((S_OK == hres) && (m_pszTempFileName) && (StrCmp(m_pszTempFileName, szFile) != 0)) { // Copy contents of the temp file to the destination
// if they are different files
EVAL(CopyFile(m_pszTempFileName, szFile, FALSE)); }
// Then save off in memory stuff to this file
hres = SaveToFile(szFile, bRemember); } return hres; }
STDMETHODIMP Intshcut::SaveCompleted(LPCOLESTR pwszFile) { return S_OK; }
// IPersistFile::Load()
STDMETHODIMP Intshcut::Load(LPCOLESTR pwszFile, DWORD dwMode) { HRESULT hres;
if (m_pszFile || m_pszFileToLoad) { hres = E_FAIL; // can't ::Load twice
} else { if (m_fMustLoadSync) hres = LoadFromFile(pwszFile); else { if (Str_SetPtr(&m_pszFileToLoad, pwszFile)) hres = S_OK; else hres = E_OUTOFMEMORY; } } return hres; }
// IPersistFile::GetCurFile method for Intshcut
STDMETHODIMP Intshcut::GetCurFile(WCHAR **ppwszFile) { HRESULT hr; TCHAR szTempFile[MAX_PATH];
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut)); ASSERT(IS_VALID_WRITE_PTR(ppwszFile, LPOLESTR));
hr = LoadFromAsyncFileNow(); if (FAILED(hr)) return hr;
if (m_pszFile) { hr = StringCchCopy(szTempFile, ARRAYSIZE(szTempFile), m_pszFile); } else { hr = StringCchCopy(szTempFile, ARRAYSIZE(szTempFile), TEXT("*.url")); if (SUCCEEDED(hr)) { // This code path returns S_FALSE on success
hr = S_FALSE; } }
HRESULT hrTemp = SHStrDup(szTempFile, ppwszFile); if (FAILED(hrTemp)) hr = hrTemp;
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
return(hr); }
// IPersistStream::Load method for Intshcut
STDMETHODIMP Intshcut::Load(IStream *pstm) { // to implement this:
// save stream to temp.ini
// IPersistFile::Load() from that
// delete temp file
return E_NOTIMPL; }
// IPersistStream::Save method for Intshcut
STDMETHODIMP Intshcut::Save(IStream *pstm, BOOL bClearDirty) { HRESULT hr = InitProp(); if (SUCCEEDED(hr)) { TCHAR szURL[INTERNET_MAX_URL_LENGTH]; hr = m_pprop->GetProp(PID_IS_URL, szURL, SIZECHARS(szURL)); if (SUCCEEDED(hr)) { LPSTR pszContents; hr = CreateURLFileContents(szURL, &pszContents); if (SUCCEEDED(hr)) { ASSERT(hr == lstrlenA(pszContents)); hr = pstm->Write(pszContents, hr + 1, NULL); GlobalFree(pszContents); pszContents = NULL; } else { hr = E_OUTOFMEMORY; } } } return hr; }
// IPersistStream::GetSizeMax method for Intshcut
STDMETHODIMP Intshcut::GetSizeMax(PULARGE_INTEGER puliSize) { puliSize->LowPart = 0; puliSize->HighPart = 0;
HRESULT hr = InitProp(); if (SUCCEEDED(hr)) { puliSize->LowPart = GetFileContentsAndSize(NULL); hr = S_OK; } return hr; }
STDMETHODIMP Intshcut::_SetTempFileName(TCHAR *pszTempFileName) { ASSERT(NULL == m_pszTempFileName); if (m_pszTempFileName) DeleteFile(m_pszTempFileName); Str_SetPtr(&m_pszTempFileName, pszTempFileName); return (m_pszTempFileName ? S_OK : E_OUTOFMEMORY); }
STDMETHODIMP Intshcut::_CreateTemporaryBackingFile() { HRESULT hres = E_FAIL;
if (m_pszTempFileName) return S_OK;
TCHAR szTempFileName[MAX_PATH]; TCHAR szDirectory[MAX_PATH]; DWORD dwRet = GetTempPath(ARRAYSIZE(szDirectory), szDirectory);
if ((FALSE == dwRet) || (FALSE == PathFileExists(szDirectory))) { szDirectory[0] = TEXT('\\'); szDirectory[1] = TEXT('\0'); dwRet = TRUE; }
dwRet = GetTempFileName(szDirectory, TEXT("www"), 0, szTempFileName); if (dwRet) { hres = _SetTempFileName(szTempFileName); // Now copy over the current file from which this was loaded and then save off
// any changes
if (S_OK == hres) { if (m_pszFile) { EVAL(CopyFile(m_pszFile, m_pszTempFileName, FALSE)); SaveToFile(m_pszTempFileName, FALSE); // this flushes the file
} } }
return hres; }
// Calculate the size of the contents to be transferred in a block.
STDMETHODIMP_(DWORD) Intshcut::GetFileContentsAndSize(LPSTR *ppszBuf) { DWORD cbSize = 0; // this is in bytes, not characters
TCHAR szURL[INTERNET_MAX_URL_LENGTH]; BOOL fSuccess = FALSE; HRESULT hres; ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut)); ASSERT(m_pprop);
if (ppszBuf) *ppszBuf = NULL; // Create a temporary backing File here and save off everything that needs to be
// saved off there and use that to satisfy this request
if (S_OK == _CreateTemporaryBackingFile()) { ASSERT(m_pszTempFileName); WCHAR wszTemp[MAX_PATH]; SHTCharToUnicode(m_pszTempFileName, wszTemp, ARRAYSIZE(wszTemp)); hres = Save(wszTemp, FALSE); // So our temp file is now up to date
// Just copy the file
HANDLE hFile = CreateFile(m_pszTempFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (hFile != INVALID_HANDLE_VALUE) { DWORD dwTemp = 0; cbSize = GetFileSize(hFile, &dwTemp); if (ppszBuf) { if (0xFFFFFFFF != cbSize) { ASSERT(0 == dwTemp); *ppszBuf = (LPSTR)LocalAlloc(LPTR, cbSize); if (*ppszBuf) { dwTemp = 0; if(ReadFile(hFile, *ppszBuf, cbSize, &dwTemp, NULL)) { ASSERT(cbSize >= dwTemp); fSuccess = TRUE; } } } } else { fSuccess = TRUE; // Just want the size - not contents
} CloseHandle(hFile); } if (FALSE == fSuccess) { cbSize = 0; if(ppszBuf && (*ppszBuf)) { LocalFree(*ppszBuf); *ppszBuf = NULL; } } } if (FALSE == fSuccess) { // if you couldn't read the file, then perhaps atleast this will work ?
HRESULT hr = InitProp(); if (SUCCEEDED(hr) && SUCCEEDED(m_pprop->GetProp(PID_IS_URL, szURL, SIZECHARS(szURL)))) { hr = CreateURLFileContents(szURL, ppszBuf);
// IEUNIX-This function should return the strlen not including the
// null characters as this causes the shortcut file having a null
// character causing a crash in the execution of the link.
// Fortunately, that's what CreateURLFileContents returns
cbSize = SUCCEEDED(hr) ? hr : 0; } } ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut)); return cbSize; }
#ifndef WC_NO_BEST_FIT_CHARS
#define WC_NO_BEST_FIT_CHARS 0x00000400
#endif
// transfer the URL data in URL clipboard
STDMETHODIMP Intshcut::TransferUniformResourceLocator(FORMATETC *pfmtetc, STGMEDIUM *pstgmed) { HRESULT hr;
ASSERT(pfmtetc->dwAspect == DVASPECT_CONTENT); ASSERT(pfmtetc->lindex == -1);
if (pfmtetc->tymed & TYMED_HGLOBAL) { TCHAR szURL[INTERNET_MAX_URL_LENGTH]; ASSERT(m_pprop); hr = InitProp(); if (SUCCEEDED(hr)) { hr = m_pprop->GetProp(PID_IS_URL, szURL, SIZECHARS(szURL)); if (SUCCEEDED(hr)) { int cch = lstrlen(szURL) + 1; int cb = (cch-1) * 9 + 1; // the biggest result is an utf8 escaped version of the string
// utf8 encoding can blow the size up to 3 times
// escaping can blow each byte up to 3 times
LPSTR pszURL = (LPSTR)GlobalAlloc(GPTR, cb); if (pszURL) { if (pfmtetc->cfFormat == CF_UNICODETEXT || pfmtetc->cfFormat == g_cfURLW) { StrCpyN((LPWSTR)pszURL, szURL, cch); } else { BOOL bUsedDefaultChar = FALSE; DWORD dwFlags = 0; if (IsOS(OS_WIN2000ORGREATER) || IsOS(OS_WIN98ORGREATER)) { dwFlags |= WC_NO_BEST_FIT_CHARS; } int wcResult = WideCharToMultiByte(CP_ACP, dwFlags, szURL, cch, pszURL, cb, NULL, &bUsedDefaultChar); if ((0 == wcResult) || bUsedDefaultChar) { // the string is weird and can't be converted back to unicode
// we're going to utf8-escaped encode it
ConvertToUtf8Escaped(szURL, ARRAYSIZE(szURL)); SHUnicodeToAnsi(szURL, pszURL, cb); } } pstgmed->tymed = TYMED_HGLOBAL; pstgmed->hGlobal = pszURL; } } } } else hr = DV_E_TYMED;
return hr; }
// transfer the URL data in text
STDMETHODIMP Intshcut::TransferText(FORMATETC *pfmtetc, STGMEDIUM *pstgmed) { return TransferUniformResourceLocator(pfmtetc, pstgmed); }
// assumes the current seek pos in the stream is at the start
BOOL GetStreamMimeAndExt(LPCWSTR pszURL, IStream *pstm, LPTSTR pszMime, UINT cchMime, LPTSTR pszExt, UINT cchExt) { BYTE buf[256]; ULONG cbRead; pstm->Read(buf, SIZEOF(buf), &cbRead);
WCHAR *pwszMimeOut; if (SUCCEEDED(FindMimeFromData(NULL, pszURL, buf, cbRead, NULL, 0, &pwszMimeOut, 0))) { TCHAR szMimeTemp[MAX_PATH];
if (pszMime == NULL) { pszMime = szMimeTemp; cchMime = ARRAYSIZE(szMimeTemp); }
SHUnicodeToTChar(pwszMimeOut, pszMime, cchMime); CoTaskMemFree(pwszMimeOut);
if (pszExt) MIME_GetExtension(pszMime, pszExt, cchExt); }
// const LARGE_INTEGER c_li0 = {0, 0};
pstm->Seek(c_li0, STREAM_SEEK_SET, NULL);
return TRUE; }
// pszName is assumed to be MAX_PATH
STDMETHODIMP Intshcut::GetDocumentName(LPTSTR pszName) { GetDescription(pszName, MAX_PATH); WCHAR *pszURL; if (S_OK == GetURLW(&pszURL)) { IStream *pstm; if (SUCCEEDED(URLOpenBlockingStreamW(NULL, pszURL, &pstm, 0, NULL))) { TCHAR szExt[MAX_PATH]; GetStreamMimeAndExt(pszURL, pstm, NULL, 0, szExt, ARRAYSIZE(szExt));
PathRenameExtension(pszName, szExt); pstm->Release(); } SHFree(pszURL); } return S_OK; }
// transfer URL data in file-group-descriptor clipboard format.
STDMETHODIMP Intshcut::TransferFileGroupDescriptorA(FORMATETC *pfmtetc, STGMEDIUM *pstgmed) { HRESULT hr;
if (pfmtetc->dwAspect != DVASPECT_COPY && pfmtetc->dwAspect != DVASPECT_LINK && pfmtetc->dwAspect != DVASPECT_CONTENT) { hr = DV_E_DVASPECT; } else if (pfmtetc->tymed & TYMED_HGLOBAL) { FILEGROUPDESCRIPTORA * pfgd = (FILEGROUPDESCRIPTORA *)GlobalAlloc(GPTR, SIZEOF(FILEGROUPDESCRIPTORA)); if (pfgd) { FILEDESCRIPTORA * pfd = &(pfgd->fgd[0]); TCHAR szTemp[MAX_PATH];
if (pfmtetc->dwAspect == DVASPECT_COPY) { pfd->dwFlags = FD_FILESIZE; GetDocumentName(szTemp); } else { pfd->dwFlags = FD_FILESIZE | FD_LINKUI; GetDescription(szTemp, ARRAYSIZE(szTemp)); } SHTCharToAnsi(PathFindFileName(szTemp), pfd->cFileName, SIZECHARS(pfd->cFileName));
pfd->nFileSizeHigh = 0; pfd->nFileSizeLow = GetFileContentsAndSize(NULL);
pfgd->cItems = 1;
pstgmed->tymed = TYMED_HGLOBAL; pstgmed->hGlobal = pfgd;
hr = S_OK; } else hr = E_OUTOFMEMORY; } else hr = DV_E_TYMED;
return hr; }
// transfer URL data in file-group-descriptor clipboard format.
STDMETHODIMP Intshcut::TransferFileGroupDescriptorW(FORMATETC *pfmtetc, STGMEDIUM *pstgmed) { HRESULT hr;
if (pfmtetc->dwAspect != DVASPECT_COPY && pfmtetc->dwAspect != DVASPECT_LINK && pfmtetc->dwAspect != DVASPECT_CONTENT) { hr = DV_E_DVASPECT; } else if (pfmtetc->tymed & TYMED_HGLOBAL) { FILEGROUPDESCRIPTORW * pfgd = (FILEGROUPDESCRIPTORW *)GlobalAlloc(GPTR, SIZEOF(FILEGROUPDESCRIPTORW)); if (pfgd) { FILEDESCRIPTORW * pfd = &(pfgd->fgd[0]); TCHAR szTemp[MAX_PATH]; if (pfmtetc->dwAspect == DVASPECT_COPY) { pfd->dwFlags = FD_FILESIZE; GetDocumentName(szTemp); } else { pfd->dwFlags = FD_FILESIZE | FD_LINKUI; GetDescription(szTemp, ARRAYSIZE(szTemp)); }
SHTCharToUnicode(PathFindFileName(szTemp), pfd->cFileName, SIZECHARS(pfd->cFileName));
pfd->nFileSizeHigh = 0; pfd->nFileSizeLow = GetFileContentsAndSize(NULL);
pfgd->cItems = 1;
pstgmed->tymed = TYMED_HGLOBAL; pstgmed->hGlobal = pfgd;
hr = S_OK; } else hr = E_OUTOFMEMORY; } else hr = DV_E_TYMED;
return hr; }
#if defined(BIG_ENDIAN) && defined(BYTE_ORDER)
#if BYTE_ORDER != BIG_ENDIAN
#undef BIG_ENDIAN
#endif
#endif
#ifdef BIG_ENDIAN
#define BOM 0xfffe
#else
#define BOM 0xfeff
#endif
STDMETHODIMP Intshcut::GetDocumentStream(IStream **ppstm) { *ppstm = NULL;
WCHAR *pszURL; HRESULT hres = GetURLW(&pszURL); if (S_OK == hres) { IStream *pstm; hres = URLOpenBlockingStreamW(NULL, pszURL, &pstm, 0, NULL); if (SUCCEEDED(hres)) { TCHAR szMime[80];
if (GetStreamMimeAndExt(pszURL, pstm, szMime, ARRAYSIZE(szMime), NULL, 0) && StrCmpI(szMime, TEXT("text/html")) == 0) { IStream *aStreams[2];
if(m_uiCodePage == 1200) // Unicode
{ WCHAR wzBaseTag[INTERNET_MAX_URL_LENGTH + 20];
wnsprintfW(wzBaseTag, ARRAYSIZE(wzBaseTag), TEXT("%wc<BASE HREF=\"%ws\">\n"), (WCHAR)BOM, pszURL); aStreams[0] = SHCreateMemStream((BYTE *)wzBaseTag, lstrlenW(wzBaseTag) * SIZEOF(wzBaseTag[0])); } else { CHAR szURL[INTERNET_MAX_URL_LENGTH], szBaseTag[INTERNET_MAX_URL_LENGTH + 20];
SHUnicodeToAnsi(pszURL, szURL, ARRAYSIZE(szURL)); wnsprintfA(szBaseTag, ARRAYSIZE(szBaseTag), "<BASE HREF=\"%s\">\n", szURL);
// NOTE: this is an ANSI stream
aStreams[0] = SHCreateMemStream((BYTE *)szBaseTag, lstrlenA(szBaseTag) * SIZEOF(szBaseTag[0])); } if (aStreams[0]) { aStreams[1] = pstm; hres = SHCreateStreamWrapperCP(aStreams, ARRAYSIZE(aStreams), STGM_READ, m_uiCodePage, ppstm); aStreams[0]->Release(); } else hres = E_OUTOFMEMORY; pstm->Release(); } else *ppstm = pstm; } SHFree(pszURL); } else hres = E_FAIL; return hres; }
// transfer URL data in file-contents clipboard format.
STDMETHODIMP Intshcut::TransferFileContents(FORMATETC *pfmtetc, STGMEDIUM *pstgmed) { HRESULT hr;
if (pfmtetc->lindex != 0) return DV_E_LINDEX;
if ((pfmtetc->dwAspect == DVASPECT_CONTENT || pfmtetc->dwAspect == DVASPECT_LINK) && (pfmtetc->tymed & TYMED_HGLOBAL)) { LPSTR pszFileContents; DWORD cbSize = GetFileContentsAndSize(&pszFileContents); if (pszFileContents) { pstgmed->tymed = TYMED_HGLOBAL; pstgmed->hGlobal = pszFileContents; hr = S_OK; } else hr = E_OUTOFMEMORY; } else if ((pfmtetc->dwAspect == DVASPECT_COPY) && (pfmtetc->tymed & TYMED_ISTREAM)) { hr = GetDocumentStream(&pstgmed->pstm); if (SUCCEEDED(hr)) { pstgmed->tymed = TYMED_ISTREAM; hr = S_OK; } } else hr = DV_E_TYMED;
return hr; }
#ifdef DEBUG
STDMETHODIMP_(void) Intshcut::Dump(void) { ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
#define INDENT_STRING " "
if (IsFlagSet(g_dwDumpFlags, DF_INTSHCUT)) { TraceMsg(TF_ALWAYS, "%sm_dwFlags = %#08lx", INDENT_STRING, m_dwFlags); TraceMsg(TF_ALWAYS, "%sm_pszFile = \"%s\"", INDENT_STRING, Dbg_SafeStr(m_pszFile));
if (m_pprop) m_pprop->Dump(); } }
#endif // DEBUG
|