Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

845 lines
22 KiB

  1. /*
  2. * ispersis.cpp - IPersist, IPersistFile, and IPersistStream implementations for
  3. * URL class.
  4. */
  5. #include "priv.h"
  6. #include "ishcut.h"
  7. #include "resource.h"
  8. // Need to flush the file to prevent win95 from barfing after stuff is written in
  9. VOID FlushFile(LPCTSTR pszFile)
  10. {
  11. if (!g_fRunningOnNT)
  12. {
  13. WritePrivateProfileString(NULL, NULL, NULL, pszFile);
  14. }
  15. }
  16. // save object to file
  17. STDMETHODIMP Intshcut::SaveToFile(LPCTSTR pszFile, BOOL bRemember)
  18. {
  19. HRESULT hres = InitProp();
  20. if (SUCCEEDED(hres))
  21. {
  22. m_pprop->SetFileName(pszFile);
  23. hres = m_pprop->Commit(STGC_DEFAULT);
  24. // Remember file if requested
  25. if (SUCCEEDED(hres))
  26. {
  27. if (bRemember)
  28. {
  29. Dirty(FALSE);
  30. if ( !Str_SetPtr(&m_pszFile, pszFile) )
  31. hres = E_OUTOFMEMORY;
  32. #ifdef DEBUG
  33. Dump();
  34. #endif
  35. }
  36. SHChangeNotify(SHCNE_UPDATEITEM, (SHCNF_PATH | SHCNF_FLUSH), pszFile, NULL);
  37. }
  38. if (!bRemember)
  39. m_pprop->SetFileName(m_pszFile);
  40. }
  41. if(pszFile && (S_OK == hres))
  42. FlushFile(pszFile);
  43. return hres;
  44. }
  45. STDMETHODIMP Intshcut::LoadFromFile(LPCTSTR pszFile)
  46. {
  47. HRESULT hres;
  48. if (Str_SetPtr(&m_pszFile, pszFile))
  49. {
  50. hres = InitProp();
  51. #ifdef DEBUG
  52. Dump();
  53. #endif
  54. }
  55. else
  56. {
  57. hres = E_OUTOFMEMORY;
  58. }
  59. return hres;
  60. }
  61. STDMETHODIMP Intshcut::LoadFromAsyncFileNow()
  62. {
  63. HRESULT hres = S_OK;
  64. if (m_pszFileToLoad)
  65. {
  66. hres = LoadFromFile(m_pszFileToLoad);
  67. Str_SetPtr(&m_pszFileToLoad, NULL);
  68. }
  69. return hres;
  70. }
  71. STDMETHODIMP Intshcut::GetCurFile(LPTSTR pszFile, UINT cchLen)
  72. {
  73. HRESULT hr;
  74. if (m_pszFile)
  75. {
  76. StrCpyN(pszFile, m_pszFile, cchLen);
  77. hr = S_OK;
  78. }
  79. else
  80. hr = S_FALSE;
  81. return hr;
  82. }
  83. STDMETHODIMP Intshcut::Dirty(BOOL bDirty)
  84. {
  85. HRESULT hres;
  86. ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
  87. if (bDirty)
  88. {
  89. if (IsFlagClear(m_dwFlags, ISF_DIRTY))
  90. TraceMsg(TF_INTSHCUT, "Intshcut now dirty.");
  91. SetFlag(m_dwFlags, ISF_DIRTY);
  92. }
  93. else
  94. {
  95. if (IsFlagSet(m_dwFlags, ISF_DIRTY))
  96. TraceMsg(TF_INTSHCUT, "Intshcut now clean.");
  97. ClearFlag(m_dwFlags, ISF_DIRTY);
  98. }
  99. hres = S_OK;
  100. ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
  101. return hres;
  102. }
  103. // IPersist::GetClassID method for Intshcut
  104. STDMETHODIMP Intshcut::GetClassID(CLSID *pclsid)
  105. {
  106. ASSERT(IS_VALID_WRITE_PTR(pclsid, CLSID));
  107. *pclsid = CLSID_InternetShortcut;
  108. return S_OK;
  109. }
  110. // IPersistFile::IsDirty handler for Intshcut
  111. STDMETHODIMP Intshcut::IsDirty(void)
  112. {
  113. HRESULT hres = LoadFromAsyncFileNow();
  114. if(SUCCEEDED(hres))
  115. {
  116. hres = InitProp();
  117. if (SUCCEEDED(hres))
  118. {
  119. if (IsFlagSet(m_dwFlags, ISF_DIRTY) || S_OK == m_pprop->IsDirty())
  120. hres = S_OK;
  121. else
  122. hres = S_FALSE;
  123. }
  124. }
  125. return hres;
  126. }
  127. // Helper function to save off Trident specific stuff
  128. STDMETHODIMP Intshcut::_SaveOffPersistentDataFromSite()
  129. {
  130. IOleCommandTarget *pcmdt = NULL;
  131. HRESULT hr = S_OK;
  132. if (_punkSite)
  133. {
  134. if(S_OK == _CreateTemporaryBackingFile())
  135. {
  136. ASSERT(m_pszTempFileName);
  137. hr = _punkSite->QueryInterface(IID_IOleCommandTarget, (LPVOID *)&pcmdt);
  138. if((S_OK == hr))
  139. {
  140. ASSERT(pcmdt);
  141. VARIANT varIn = {0};
  142. varIn.vt = VT_UNKNOWN;
  143. varIn.punkVal = (LPUNKNOWN)(SAFECAST(this, IUniformResourceLocator *));
  144. // Tell the site to save off it's persistent stuff
  145. hr = pcmdt->Exec(&CGID_ShortCut, CMDID_INTSHORTCUTCREATE, 0, &varIn, NULL);
  146. pcmdt->Release();
  147. }
  148. FlushFile(m_pszTempFileName);
  149. }
  150. }
  151. return hr;
  152. }
  153. // IPersistFile::Save handler for Intshcut
  154. STDMETHODIMP Intshcut::Save(LPCOLESTR pwszFile, BOOL bRemember)
  155. {
  156. HRESULT hres = LoadFromAsyncFileNow();
  157. if (SUCCEEDED(hres))
  158. {
  159. TCHAR szFile[MAX_PATH];
  160. if (pwszFile)
  161. SHUnicodeToTChar(pwszFile, szFile, SIZECHARS(szFile));
  162. else if (m_pszFile)
  163. StrCpyN(szFile, m_pszFile, ARRAYSIZE(szFile));
  164. else
  165. return E_FAIL;
  166. // Perhaps there is a site which wants to save off stuff ?
  167. // However, the site may end up calling via intefaces
  168. hres = _SaveOffPersistentDataFromSite();
  169. if ((S_OK == hres) && (m_pszTempFileName) && (StrCmp(m_pszTempFileName, szFile) != 0))
  170. {
  171. // Copy contents of the temp file to the destination
  172. // if they are different files
  173. EVAL(CopyFile(m_pszTempFileName, szFile, FALSE));
  174. }
  175. // Then save off in memory stuff to this file
  176. hres = SaveToFile(szFile, bRemember);
  177. }
  178. return hres;
  179. }
  180. STDMETHODIMP Intshcut::SaveCompleted(LPCOLESTR pwszFile)
  181. {
  182. return S_OK;
  183. }
  184. // IPersistFile::Load()
  185. STDMETHODIMP Intshcut::Load(LPCOLESTR pwszFile, DWORD dwMode)
  186. {
  187. HRESULT hres;
  188. if (m_pszFile || m_pszFileToLoad)
  189. {
  190. hres = E_FAIL; // can't ::Load twice
  191. }
  192. else
  193. {
  194. if (m_fMustLoadSync)
  195. hres = LoadFromFile(pwszFile);
  196. else
  197. {
  198. if (Str_SetPtr(&m_pszFileToLoad, pwszFile))
  199. hres = S_OK;
  200. else
  201. hres = E_OUTOFMEMORY;
  202. }
  203. }
  204. return hres;
  205. }
  206. // IPersistFile::GetCurFile method for Intshcut
  207. STDMETHODIMP Intshcut::GetCurFile(WCHAR **ppwszFile)
  208. {
  209. HRESULT hr;
  210. TCHAR szTempFile[MAX_PATH];
  211. ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
  212. ASSERT(IS_VALID_WRITE_PTR(ppwszFile, LPOLESTR));
  213. hr = LoadFromAsyncFileNow();
  214. if (FAILED(hr))
  215. return hr;
  216. if (m_pszFile)
  217. {
  218. StrCpyN(szTempFile, m_pszFile, SIZECHARS(szTempFile));
  219. hr = S_OK;
  220. }
  221. else
  222. {
  223. StrCpyN(szTempFile, TEXT("*.url"), ARRAYSIZE(szTempFile));
  224. hr = S_FALSE;
  225. }
  226. HRESULT hrTemp = SHStrDup(szTempFile, ppwszFile);
  227. if (FAILED(hrTemp))
  228. hr = hrTemp;
  229. ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
  230. return(hr);
  231. }
  232. // IPersistStream::Load method for Intshcut
  233. STDMETHODIMP Intshcut::Load(IStream *pstm)
  234. {
  235. // to implement this:
  236. // save stream to temp.ini
  237. // IPersistFile::Load() from that
  238. // delete temp file
  239. return E_NOTIMPL;
  240. }
  241. // IPersistStream::Save method for Intshcut
  242. STDMETHODIMP Intshcut::Save(IStream *pstm, BOOL bClearDirty)
  243. {
  244. HRESULT hr = InitProp();
  245. if (SUCCEEDED(hr))
  246. {
  247. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  248. hr = m_pprop->GetProp(PID_IS_URL, szURL, SIZECHARS(szURL));
  249. if (SUCCEEDED(hr))
  250. {
  251. LPSTR pszContents;
  252. hr = CreateURLFileContents(szURL, &pszContents);
  253. if (SUCCEEDED(hr)) {
  254. ASSERT(hr == lstrlenA(pszContents));
  255. hr = pstm->Write(pszContents, hr + 1, NULL);
  256. GlobalFree(pszContents);
  257. pszContents = NULL;
  258. } else {
  259. hr = E_OUTOFMEMORY;
  260. }
  261. }
  262. }
  263. return hr;
  264. }
  265. // IPersistStream::GetSizeMax method for Intshcut
  266. STDMETHODIMP Intshcut::GetSizeMax(PULARGE_INTEGER puliSize)
  267. {
  268. puliSize->LowPart = 0;
  269. puliSize->HighPart = 0;
  270. HRESULT hr = InitProp();
  271. if (SUCCEEDED(hr))
  272. {
  273. puliSize->LowPart = GetFileContentsAndSize(NULL);
  274. hr = S_OK;
  275. }
  276. return hr;
  277. }
  278. STDMETHODIMP Intshcut::_SetTempFileName(TCHAR *pszTempFileName)
  279. {
  280. ASSERT(NULL == m_pszTempFileName);
  281. if (m_pszTempFileName)
  282. DeleteFile(m_pszTempFileName);
  283. Str_SetPtr(&m_pszTempFileName, pszTempFileName);
  284. return (m_pszTempFileName ? S_OK : E_OUTOFMEMORY);
  285. }
  286. STDMETHODIMP Intshcut::_CreateTemporaryBackingFile()
  287. {
  288. HRESULT hres = E_FAIL;
  289. if (m_pszTempFileName)
  290. return S_OK;
  291. TCHAR szTempFileName[MAX_PATH];
  292. TCHAR szDirectory[MAX_PATH];
  293. DWORD dwRet = GetTempPath(ARRAYSIZE(szDirectory), szDirectory);
  294. if ((FALSE == dwRet) || (FALSE == PathFileExists(szDirectory)))
  295. {
  296. szDirectory[0] = TEXT('\\');
  297. szDirectory[1] = TEXT('\0');
  298. dwRet = TRUE;
  299. }
  300. dwRet = GetTempFileName(szDirectory, TEXT("www"), 0, szTempFileName);
  301. if (dwRet)
  302. {
  303. hres = _SetTempFileName(szTempFileName);
  304. // Now copy over the current file from which this was loaded and then save off
  305. // any changes
  306. if (S_OK == hres)
  307. {
  308. if (m_pszFile)
  309. {
  310. EVAL(CopyFile(m_pszFile, m_pszTempFileName, FALSE));
  311. SaveToFile(m_pszTempFileName, FALSE); // this flushes the file
  312. }
  313. }
  314. }
  315. return hres;
  316. }
  317. // Calculate the size of the contents to be transferred in a block.
  318. STDMETHODIMP_(DWORD) Intshcut::GetFileContentsAndSize(LPSTR *ppszBuf)
  319. {
  320. DWORD cbSize = 0; // this is in bytes, not characters
  321. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  322. BOOL fSuccess = FALSE;
  323. HRESULT hres;
  324. ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
  325. ASSERT(m_pprop);
  326. if (ppszBuf)
  327. *ppszBuf = NULL;
  328. // Create a temporary backing File here and save off everything that needs to be
  329. // saved off there and use that to satisfy this request
  330. if (S_OK == _CreateTemporaryBackingFile())
  331. {
  332. ASSERT(m_pszTempFileName);
  333. WCHAR wszTemp[MAX_PATH];
  334. SHTCharToUnicode(m_pszTempFileName, wszTemp, ARRAYSIZE(wszTemp));
  335. hres = Save(wszTemp, FALSE); // So our temp file is now up to date
  336. // Just copy the file
  337. HANDLE hFile = CreateFile(m_pszTempFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
  338. if (hFile != INVALID_HANDLE_VALUE)
  339. {
  340. DWORD dwTemp = 0;
  341. cbSize = GetFileSize(hFile, &dwTemp);
  342. if (ppszBuf)
  343. {
  344. if (0xFFFFFFFF != cbSize)
  345. {
  346. ASSERT(0 == dwTemp);
  347. *ppszBuf = (LPSTR)LocalAlloc(LPTR, cbSize);
  348. if (*ppszBuf)
  349. {
  350. dwTemp = 0;
  351. if(ReadFile(hFile, *ppszBuf, cbSize, &dwTemp, NULL))
  352. {
  353. ASSERT(cbSize >= dwTemp);
  354. fSuccess = TRUE;
  355. }
  356. }
  357. }
  358. }
  359. else
  360. {
  361. fSuccess = TRUE; // Just want the size - not contents
  362. }
  363. CloseHandle(hFile);
  364. }
  365. if (FALSE == fSuccess)
  366. {
  367. cbSize = 0;
  368. if(ppszBuf && (*ppszBuf))
  369. {
  370. LocalFree(*ppszBuf);
  371. *ppszBuf = NULL;
  372. }
  373. }
  374. }
  375. if (FALSE == fSuccess)
  376. {
  377. // if you couldn't read the file, then perhaps atleast this will work ?
  378. HRESULT hr = InitProp();
  379. if (SUCCEEDED(hr) && SUCCEEDED(m_pprop->GetProp(PID_IS_URL, szURL, SIZECHARS(szURL))))
  380. {
  381. hr = CreateURLFileContents(szURL, ppszBuf);
  382. // IEUNIX-This function should return the strlen not including the
  383. // null characters as this causes the shortcut file having a null
  384. // character causing a crash in the execution of the link.
  385. // Fortunately, that's what CreateURLFileContents returns
  386. cbSize = SUCCEEDED(hr) ? hr : 0;
  387. }
  388. }
  389. ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
  390. return cbSize;
  391. }
  392. #ifndef WC_NO_BEST_FIT_CHARS
  393. #define WC_NO_BEST_FIT_CHARS 0x00000400
  394. #endif
  395. // transfer the URL data in URL clipboard
  396. STDMETHODIMP Intshcut::TransferUniformResourceLocator(FORMATETC *pfmtetc, STGMEDIUM *pstgmed)
  397. {
  398. HRESULT hr;
  399. ASSERT(pfmtetc->dwAspect == DVASPECT_CONTENT);
  400. ASSERT(pfmtetc->lindex == -1);
  401. if (pfmtetc->tymed & TYMED_HGLOBAL)
  402. {
  403. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  404. ASSERT(m_pprop);
  405. hr = InitProp();
  406. if (SUCCEEDED(hr))
  407. {
  408. hr = m_pprop->GetProp(PID_IS_URL, szURL, SIZECHARS(szURL));
  409. if (SUCCEEDED(hr))
  410. {
  411. int cch = lstrlen(szURL) + 1;
  412. int cb = (cch-1) * 9 + 1; // the biggest result is an utf8 escaped version of the string
  413. // utf8 encoding can blow the size up to 3 times
  414. // escaping can blow each byte up to 3 times
  415. LPSTR pszURL = (LPSTR)GlobalAlloc(GPTR, cb);
  416. if (pszURL)
  417. {
  418. if (pfmtetc->cfFormat == CF_UNICODETEXT || pfmtetc->cfFormat == g_cfURLW)
  419. {
  420. StrCpyN((LPWSTR)pszURL, szURL, cch);
  421. }
  422. else
  423. {
  424. BOOL bUsedDefaultChar = FALSE;
  425. DWORD dwFlags = 0;
  426. if (IsOS(OS_WIN2000ORGREATER) || IsOS(OS_WIN98ORGREATER))
  427. {
  428. dwFlags |= WC_NO_BEST_FIT_CHARS;
  429. }
  430. int wcResult = WideCharToMultiByte(CP_ACP,
  431. dwFlags,
  432. szURL,
  433. cch,
  434. pszURL,
  435. cb,
  436. NULL,
  437. &bUsedDefaultChar);
  438. if ((0 == wcResult) || bUsedDefaultChar)
  439. {
  440. // the string is weird and can't be converted back to unicode
  441. // we're going to utf8-escaped encode it
  442. ConvertToUtf8Escaped(szURL, ARRAYSIZE(szURL));
  443. SHUnicodeToAnsi(szURL, pszURL, cb);
  444. }
  445. }
  446. pstgmed->tymed = TYMED_HGLOBAL;
  447. pstgmed->hGlobal = pszURL;
  448. }
  449. }
  450. }
  451. }
  452. else
  453. hr = DV_E_TYMED;
  454. return hr;
  455. }
  456. // transfer the URL data in text
  457. STDMETHODIMP Intshcut::TransferText(FORMATETC *pfmtetc, STGMEDIUM *pstgmed)
  458. {
  459. return TransferUniformResourceLocator(pfmtetc, pstgmed);
  460. }
  461. // assumes the current seek pos in the stream is at the start
  462. BOOL GetStreamMimeAndExt(LPCWSTR pszURL, IStream *pstm,
  463. LPTSTR pszMime, UINT cchMime, LPTSTR pszExt, UINT cchExt)
  464. {
  465. BYTE buf[256];
  466. ULONG cbRead;
  467. pstm->Read(buf, SIZEOF(buf), &cbRead);
  468. WCHAR *pwszMimeOut;
  469. if (SUCCEEDED(FindMimeFromData(NULL, pszURL, buf, cbRead, NULL, 0, &pwszMimeOut, 0)))
  470. {
  471. TCHAR szMimeTemp[MAX_PATH];
  472. if (pszMime == NULL)
  473. {
  474. pszMime = szMimeTemp;
  475. cchMime = ARRAYSIZE(szMimeTemp);
  476. }
  477. SHUnicodeToTChar(pwszMimeOut, pszMime, cchMime);
  478. CoTaskMemFree(pwszMimeOut);
  479. if (pszExt)
  480. MIME_GetExtension(pszMime, pszExt, cchExt);
  481. }
  482. // const LARGE_INTEGER c_li0 = {0, 0};
  483. pstm->Seek(c_li0, STREAM_SEEK_SET, NULL);
  484. return TRUE;
  485. }
  486. // pszName is assumed to be MAX_PATH
  487. STDMETHODIMP Intshcut::GetDocumentName(LPTSTR pszName)
  488. {
  489. GetDescription(pszName, MAX_PATH);
  490. WCHAR *pszURL;
  491. if (S_OK == GetURLW(&pszURL))
  492. {
  493. IStream *pstm;
  494. if (SUCCEEDED(URLOpenBlockingStreamW(NULL, pszURL, &pstm, 0, NULL)))
  495. {
  496. TCHAR szExt[MAX_PATH];
  497. GetStreamMimeAndExt(pszURL, pstm, NULL, 0, szExt, ARRAYSIZE(szExt));
  498. PathRenameExtension(pszName, szExt);
  499. pstm->Release();
  500. }
  501. SHFree(pszURL);
  502. }
  503. return S_OK;
  504. }
  505. // transfer URL data in file-group-descriptor clipboard format.
  506. STDMETHODIMP Intshcut::TransferFileGroupDescriptorA(FORMATETC *pfmtetc, STGMEDIUM *pstgmed)
  507. {
  508. HRESULT hr;
  509. if (pfmtetc->dwAspect != DVASPECT_COPY &&
  510. pfmtetc->dwAspect != DVASPECT_LINK &&
  511. pfmtetc->dwAspect != DVASPECT_CONTENT)
  512. {
  513. hr = DV_E_DVASPECT;
  514. }
  515. else if (pfmtetc->tymed & TYMED_HGLOBAL)
  516. {
  517. FILEGROUPDESCRIPTORA * pfgd = (FILEGROUPDESCRIPTORA *)GlobalAlloc(GPTR, SIZEOF(FILEGROUPDESCRIPTORA));
  518. if (pfgd)
  519. {
  520. FILEDESCRIPTORA * pfd = &(pfgd->fgd[0]);
  521. TCHAR szTemp[MAX_PATH];
  522. if (pfmtetc->dwAspect == DVASPECT_COPY)
  523. {
  524. pfd->dwFlags = FD_FILESIZE;
  525. GetDocumentName(szTemp);
  526. }
  527. else
  528. {
  529. pfd->dwFlags = FD_FILESIZE | FD_LINKUI;
  530. GetDescription(szTemp, ARRAYSIZE(szTemp));
  531. }
  532. SHTCharToAnsi(PathFindFileName(szTemp), pfd->cFileName, SIZECHARS(pfd->cFileName));
  533. pfd->nFileSizeHigh = 0;
  534. pfd->nFileSizeLow = GetFileContentsAndSize(NULL);
  535. pfgd->cItems = 1;
  536. pstgmed->tymed = TYMED_HGLOBAL;
  537. pstgmed->hGlobal = pfgd;
  538. hr = S_OK;
  539. }
  540. else
  541. hr = E_OUTOFMEMORY;
  542. }
  543. else
  544. hr = DV_E_TYMED;
  545. return hr;
  546. }
  547. // transfer URL data in file-group-descriptor clipboard format.
  548. STDMETHODIMP Intshcut::TransferFileGroupDescriptorW(FORMATETC *pfmtetc, STGMEDIUM *pstgmed)
  549. {
  550. HRESULT hr;
  551. if (pfmtetc->dwAspect != DVASPECT_COPY &&
  552. pfmtetc->dwAspect != DVASPECT_LINK &&
  553. pfmtetc->dwAspect != DVASPECT_CONTENT)
  554. {
  555. hr = DV_E_DVASPECT;
  556. }
  557. else if (pfmtetc->tymed & TYMED_HGLOBAL)
  558. {
  559. FILEGROUPDESCRIPTORW * pfgd = (FILEGROUPDESCRIPTORW *)GlobalAlloc(GPTR, SIZEOF(FILEGROUPDESCRIPTORW));
  560. if (pfgd)
  561. {
  562. FILEDESCRIPTORW * pfd = &(pfgd->fgd[0]);
  563. TCHAR szTemp[MAX_PATH];
  564. if (pfmtetc->dwAspect == DVASPECT_COPY)
  565. {
  566. pfd->dwFlags = FD_FILESIZE;
  567. GetDocumentName(szTemp);
  568. }
  569. else
  570. {
  571. pfd->dwFlags = FD_FILESIZE | FD_LINKUI;
  572. GetDescription(szTemp, ARRAYSIZE(szTemp));
  573. }
  574. SHTCharToUnicode(PathFindFileName(szTemp), pfd->cFileName, SIZECHARS(pfd->cFileName));
  575. pfd->nFileSizeHigh = 0;
  576. pfd->nFileSizeLow = GetFileContentsAndSize(NULL);
  577. pfgd->cItems = 1;
  578. pstgmed->tymed = TYMED_HGLOBAL;
  579. pstgmed->hGlobal = pfgd;
  580. hr = S_OK;
  581. }
  582. else
  583. hr = E_OUTOFMEMORY;
  584. }
  585. else
  586. hr = DV_E_TYMED;
  587. return hr;
  588. }
  589. #if defined(BIG_ENDIAN) && defined(BYTE_ORDER)
  590. #if BYTE_ORDER != BIG_ENDIAN
  591. #undef BIG_ENDIAN
  592. #endif
  593. #endif
  594. #ifdef BIG_ENDIAN
  595. #define BOM 0xfffe
  596. #else
  597. #define BOM 0xfeff
  598. #endif
  599. STDMETHODIMP Intshcut::GetDocumentStream(IStream **ppstm)
  600. {
  601. *ppstm = NULL;
  602. WCHAR *pszURL;
  603. HRESULT hres = GetURLW(&pszURL);
  604. if (S_OK == hres)
  605. {
  606. IStream *pstm;
  607. hres = URLOpenBlockingStreamW(NULL, pszURL, &pstm, 0, NULL);
  608. if (SUCCEEDED(hres))
  609. {
  610. TCHAR szMime[80];
  611. if (GetStreamMimeAndExt(pszURL, pstm, szMime, ARRAYSIZE(szMime), NULL, 0) &&
  612. StrCmpI(szMime, TEXT("text/html")) == 0)
  613. {
  614. IStream *aStreams[2];
  615. if(m_uiCodePage == 1200) // Unicode
  616. {
  617. WCHAR wzBaseTag[INTERNET_MAX_URL_LENGTH + 20];
  618. wnsprintfW(wzBaseTag, ARRAYSIZE(wzBaseTag), TEXT("%wc<BASE HREF=\"%ws\">\n"), (WCHAR)BOM, pszURL);
  619. aStreams[0] = SHCreateMemStream((BYTE *)wzBaseTag, lstrlenW(wzBaseTag) * SIZEOF(wzBaseTag[0]));
  620. }
  621. else
  622. {
  623. CHAR szURL[INTERNET_MAX_URL_LENGTH], szBaseTag[INTERNET_MAX_URL_LENGTH + 20];
  624. SHUnicodeToAnsi(pszURL, szURL, ARRAYSIZE(szURL));
  625. wnsprintfA(szBaseTag, ARRAYSIZE(szBaseTag), "<BASE HREF=\"%s\">\n", szURL);
  626. // NOTE: this is an ANSI stream
  627. aStreams[0] = SHCreateMemStream((BYTE *)szBaseTag, lstrlenA(szBaseTag) * SIZEOF(szBaseTag[0]));
  628. }
  629. if (aStreams[0])
  630. {
  631. aStreams[1] = pstm;
  632. hres = SHCreateStreamWrapperCP(aStreams, ARRAYSIZE(aStreams), STGM_READ, m_uiCodePage, ppstm);
  633. aStreams[0]->Release();
  634. }
  635. else
  636. hres = E_OUTOFMEMORY;
  637. pstm->Release();
  638. }
  639. else
  640. *ppstm = pstm;
  641. }
  642. SHFree(pszURL);
  643. }
  644. else
  645. hres = E_FAIL;
  646. return hres;
  647. }
  648. // transfer URL data in file-contents clipboard format.
  649. STDMETHODIMP Intshcut::TransferFileContents(FORMATETC *pfmtetc, STGMEDIUM *pstgmed)
  650. {
  651. HRESULT hr;
  652. if (pfmtetc->lindex != 0)
  653. return DV_E_LINDEX;
  654. if ((pfmtetc->dwAspect == DVASPECT_CONTENT ||
  655. pfmtetc->dwAspect == DVASPECT_LINK) &&
  656. (pfmtetc->tymed & TYMED_HGLOBAL))
  657. {
  658. LPSTR pszFileContents;
  659. DWORD cbSize = GetFileContentsAndSize(&pszFileContents);
  660. if (pszFileContents)
  661. {
  662. pstgmed->tymed = TYMED_HGLOBAL;
  663. pstgmed->hGlobal = pszFileContents;
  664. hr = S_OK;
  665. }
  666. else
  667. hr = E_OUTOFMEMORY;
  668. }
  669. else if ((pfmtetc->dwAspect == DVASPECT_COPY) && (pfmtetc->tymed & TYMED_ISTREAM))
  670. {
  671. hr = GetDocumentStream(&pstgmed->pstm);
  672. if (SUCCEEDED(hr))
  673. {
  674. pstgmed->tymed = TYMED_ISTREAM;
  675. hr = S_OK;
  676. }
  677. }
  678. else
  679. hr = DV_E_TYMED;
  680. return hr;
  681. }
  682. #ifdef DEBUG
  683. STDMETHODIMP_(void) Intshcut::Dump(void)
  684. {
  685. ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
  686. #define INDENT_STRING " "
  687. if (IsFlagSet(g_dwDumpFlags, DF_INTSHCUT))
  688. {
  689. TraceMsg(TF_ALWAYS, "%sm_dwFlags = %#08lx",
  690. INDENT_STRING,
  691. m_dwFlags);
  692. TraceMsg(TF_ALWAYS, "%sm_pszFile = \"%s\"",
  693. INDENT_STRING,
  694. Dbg_SafeStr(m_pszFile));
  695. if (m_pprop)
  696. m_pprop->Dump();
  697. }
  698. }
  699. #endif // DEBUG