Leaked source code of windows server 2003
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.

1184 lines
30 KiB

  1. #include "precomp.h"
  2. #include <urlmon.h>
  3. #include <mshtml.h>
  4. #include <mshtmdid.h>
  5. #include <idispids.h>
  6. #include <ocidl.h>
  7. #include <optary.h>
  8. #include "thumbutil.h"
  9. #include "strsafe.h"
  10. #ifdef SetWaitCursor
  11. #undef SetWaitCursor
  12. #endif
  13. #define SetWaitCursor() hcursor_wait_cursor_save = SetCursor(LoadCursorA(NULL, (LPCSTR) IDC_WAIT))
  14. #define ResetWaitCursor() SetCursor(hcursor_wait_cursor_save)
  15. #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
  16. #define REGSTR_THUMBNAILVIEW TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Thumbnail View")
  17. // the default size to render to .... these constants must be the same
  18. #define DEFSIZE_RENDERWIDTH 800
  19. #define DEFSIZE_RENDERHEIGHT 800
  20. #define REGSTR_HTMLTIMEOUT TEXT("HTMLExtractTimeout")
  21. #define PROGID_HTML L"htmlfile"
  22. #define PROGID_MHTML L"mhtmlfile"
  23. #define PROGID_XML L"xmlfile"
  24. #define DLCTL_DOWNLOAD_FLAGS (DLCTL_DLIMAGES | \
  25. DLCTL_VIDEOS | \
  26. DLCTL_NO_DLACTIVEXCTLS | \
  27. DLCTL_NO_RUNACTIVEXCTLS | \
  28. DLCTL_NO_JAVA | \
  29. DLCTL_NO_SCRIPTS | \
  30. DLCTL_SILENT)
  31. // get color resolution of the current display.
  32. UINT GetCurColorRes(void)
  33. {
  34. HDC hdc = GetDC(NULL);
  35. UINT uColorRes = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL);
  36. ReleaseDC(NULL , hdc);
  37. return uColorRes;
  38. }
  39. // Register the classes.
  40. CHtmlThumb::CHtmlThumb()
  41. {
  42. m_lState = IRTIR_TASK_NOT_RUNNING;
  43. ASSERT(!m_fAsync);
  44. ASSERT(!m_hDone);
  45. ASSERT(!m_pHTML);
  46. ASSERT(!m_pOleObject);
  47. ASSERT(!m_pMoniker);
  48. m_dwXRenderSize = DEFSIZE_RENDERWIDTH;
  49. m_dwYRenderSize = DEFSIZE_RENDERHEIGHT;
  50. }
  51. CHtmlThumb::~CHtmlThumb()
  52. {
  53. // make sure we are not registered for callbacks...
  54. if (m_pConPt)
  55. {
  56. m_pConPt->Unadvise(m_dwPropNotifyCookie);
  57. ATOMICRELEASE(m_pConPt);
  58. }
  59. if (m_hDone)
  60. {
  61. CloseHandle(m_hDone);
  62. }
  63. ATOMICRELEASE(m_pHTML);
  64. ATOMICRELEASE(m_pOleObject);
  65. ATOMICRELEASE(m_pViewObject);
  66. ATOMICRELEASE(m_pMoniker);
  67. }
  68. STDMETHODIMP CHtmlThumb::Run()
  69. {
  70. return E_NOTIMPL;
  71. }
  72. STDMETHODIMP CHtmlThumb::Kill(BOOL fWait)
  73. {
  74. if (m_lState == IRTIR_TASK_RUNNING)
  75. {
  76. LONG lRes = InterlockedExchange(&m_lState, IRTIR_TASK_PENDING);
  77. if (lRes == IRTIR_TASK_FINISHED)
  78. {
  79. m_lState = lRes;
  80. }
  81. else if (m_hDone)
  82. {
  83. // signal the event it is likely to be waiting on
  84. SetEvent(m_hDone);
  85. }
  86. return S_OK;
  87. }
  88. else if (m_lState == IRTIR_TASK_PENDING || m_lState == IRTIR_TASK_FINISHED)
  89. {
  90. return S_FALSE;
  91. }
  92. return E_FAIL;
  93. }
  94. STDMETHODIMP CHtmlThumb::Suspend()
  95. {
  96. if (m_lState != IRTIR_TASK_RUNNING)
  97. {
  98. return E_FAIL;
  99. }
  100. // suspend ourselves
  101. LONG lRes = InterlockedExchange(&m_lState, IRTIR_TASK_SUSPENDED);
  102. if (lRes == IRTIR_TASK_FINISHED)
  103. {
  104. m_lState = lRes;
  105. return S_OK;
  106. }
  107. // if it is running, then there is an Event Handle, if we have passed where
  108. // we are using it, then we are close to finish, so it will ignore the suspend
  109. // request
  110. ASSERT(m_hDone);
  111. SetEvent(m_hDone);
  112. return S_OK;
  113. }
  114. STDMETHODIMP CHtmlThumb::Resume()
  115. {
  116. if (m_lState != IRTIR_TASK_SUSPENDED)
  117. {
  118. return E_FAIL;
  119. }
  120. ResetEvent(m_hDone);
  121. m_lState = IRTIR_TASK_RUNNING;
  122. // the only point we allowed for suspension was in the wait loop while
  123. // trident is doing its stuff, so we just restart where we left off...
  124. SetWaitCursor();
  125. HRESULT hr = InternalResume();
  126. ResetWaitCursor();
  127. return hr;
  128. }
  129. STDMETHODIMP_(ULONG) CHtmlThumb::IsRunning()
  130. {
  131. return m_lState;
  132. }
  133. STDMETHODIMP CHtmlThumb::OnChanged(DISPID dispID)
  134. {
  135. if (DISPID_READYSTATE == dispID && m_pHTML && m_hDone)
  136. {
  137. CheckReadyState();
  138. }
  139. return S_OK;
  140. }
  141. STDMETHODIMP CHtmlThumb::OnRequestEdit (DISPID dispID)
  142. {
  143. return E_NOTIMPL;
  144. }
  145. // IExtractImage
  146. STDMETHODIMP CHtmlThumb::GetLocation(LPWSTR pszPathBuffer, DWORD cch,
  147. DWORD * pdwPriority, const SIZE * prgSize,
  148. DWORD dwRecClrDepth, DWORD *pdwFlags)
  149. {
  150. HRESULT hr = S_OK;
  151. m_rgSize = *prgSize;
  152. m_dwClrDepth = dwRecClrDepth;
  153. // fix the max colour depth at 8 bit, otherwise we are going to allocate a boat load of
  154. // memory just to scale the thing down.
  155. DWORD dwColorRes = GetCurColorRes();
  156. if (m_dwClrDepth > dwColorRes && dwColorRes >= 8)
  157. {
  158. m_dwClrDepth = dwColorRes;
  159. }
  160. if (*pdwFlags & IEIFLAG_SCREEN)
  161. {
  162. HDC hdc = GetDC(NULL);
  163. m_dwXRenderSize = GetDeviceCaps(hdc, HORZRES);
  164. m_dwYRenderSize = GetDeviceCaps(hdc, VERTRES);
  165. ReleaseDC(NULL, hdc);
  166. }
  167. if (*pdwFlags & IEIFLAG_ASPECT)
  168. {
  169. // scale the rect to the same proportions as the new one passed in
  170. if (m_rgSize.cx > m_rgSize.cy)
  171. {
  172. // make the Y size bigger
  173. m_dwYRenderSize = MulDiv(m_dwYRenderSize, m_rgSize.cy, m_rgSize.cx);
  174. }
  175. else
  176. {
  177. // make the X size bigger
  178. m_dwXRenderSize = MulDiv(m_dwXRenderSize, m_rgSize.cx, m_rgSize.cy);
  179. }
  180. }
  181. m_Host.m_fOffline = BOOLIFY(*pdwFlags & IEIFLAG_OFFLINE);
  182. if (m_pMoniker)
  183. {
  184. LPOLESTR pszName = NULL;
  185. hr = m_pMoniker->GetDisplayName(NULL, NULL, &pszName);
  186. if (SUCCEEDED(hr))
  187. {
  188. hr = StringCchCopyW(pszPathBuffer, cch, pszName);
  189. CoTaskMemFree(pszName);
  190. }
  191. }
  192. else
  193. {
  194. hr = StringCchCopyW(pszPathBuffer, cch, m_szPath);
  195. }
  196. // scale our drawing size to match the in
  197. if (SUCCEEDED(hr) && (*pdwFlags & IEIFLAG_ASYNC))
  198. {
  199. hr = E_PENDING;
  200. // much lower priority, this task could take ages ...
  201. *pdwPriority = 0x00010000;
  202. m_fAsync = TRUE;
  203. }
  204. *pdwFlags = IEIFLAG_CACHE;
  205. return hr;
  206. }
  207. STDMETHODIMP CHtmlThumb::Extract(HBITMAP * phBmpThumbnail)
  208. {
  209. if (m_lState != IRTIR_TASK_NOT_RUNNING)
  210. {
  211. return E_FAIL;
  212. }
  213. // check we were initialized somehow..
  214. if (m_szPath[0] == 0 && !m_pMoniker)
  215. {
  216. return E_FAIL;
  217. }
  218. // we use manual reset so that once fired we will always get it until we reset it...
  219. m_hDone = CreateEventA(NULL, TRUE, TRUE, NULL);
  220. if (!m_hDone)
  221. {
  222. return E_OUTOFMEMORY;
  223. }
  224. ResetEvent(m_hDone);
  225. // the one thing we cache is the place where the result goes....
  226. m_phBmp = phBmpThumbnail;
  227. IMoniker *pURLMoniker = NULL;
  228. CLSID clsid;
  229. IUnknown *pUnk = NULL;
  230. IConnectionPointContainer * pConPtCtr = NULL;
  231. LPCWSTR pszDot = NULL;
  232. BOOL fUrl = FALSE;
  233. LPCWSTR pszProgID = NULL;
  234. if (!m_pMoniker)
  235. {
  236. // work out what the extension is....
  237. pszDot = PathFindExtension(m_szPath);
  238. if (pszDot == NULL)
  239. {
  240. return E_UNEXPECTED;
  241. }
  242. // check for what file type it is ....
  243. if (StrCmpIW(pszDot, L".htm") == 0 ||
  244. StrCmpIW(pszDot, L".html") == 0 ||
  245. StrCmpIW(pszDot, L".url") == 0)
  246. {
  247. pszProgID = PROGID_HTML;
  248. }
  249. else if (StrCmpIW(pszDot, L".mht") == 0 ||
  250. StrCmpIW(pszDot, L".mhtml") == 0 ||
  251. StrCmpIW(pszDot, L".eml") == 0 ||
  252. StrCmpIW(pszDot, L".nws") == 0)
  253. {
  254. pszProgID = PROGID_MHTML;
  255. }
  256. else if (StrCmpIW(pszDot, L".xml") == 0)
  257. {
  258. pszProgID = PROGID_XML;
  259. }
  260. else
  261. return E_INVALIDARG;
  262. }
  263. else
  264. {
  265. pszProgID = PROGID_HTML;
  266. }
  267. HRESULT hr = S_OK;
  268. LONG lRes = InterlockedExchange(&m_lState, IRTIR_TASK_RUNNING);
  269. if (lRes == IRTIR_TASK_PENDING)
  270. {
  271. ResetWaitCursor();
  272. m_lState = IRTIR_TASK_FINISHED;
  273. return E_FAIL;
  274. }
  275. LPWSTR pszFullURL = NULL;
  276. if (m_pMoniker)
  277. {
  278. pURLMoniker = m_pMoniker;
  279. pURLMoniker->AddRef();
  280. }
  281. else if (StrCmpIW(pszDot, L".url") == 0)
  282. {
  283. hr = Create_URL_Moniker(&pURLMoniker);
  284. if (FAILED(hr))
  285. {
  286. return hr;
  287. }
  288. fUrl = TRUE;
  289. }
  290. SetWaitCursor();
  291. // reached here with a valid URL Moniker hopefully.....
  292. // or we are to use the text string and load it from a file ...
  293. // now fish around in the registry for the data for the MSHTML control ...
  294. hr = CLSIDFromProgID(pszProgID, &clsid);
  295. if (hr == S_OK)
  296. {
  297. hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
  298. IID_PPV_ARG(IUnknown, &pUnk));
  299. }
  300. if (SUCCEEDED(hr))
  301. {
  302. // now set the extent of the object ....
  303. hr = pUnk->QueryInterface(IID_PPV_ARG(IOleObject, &m_pOleObject));
  304. }
  305. if (SUCCEEDED(hr))
  306. {
  307. // give trident to our hosting sub-object...
  308. hr = m_Host.SetTrident(m_pOleObject);
  309. }
  310. if (SUCCEEDED(hr))
  311. {
  312. hr = pUnk->QueryInterface(IID_PPV_ARG(IViewObject, &m_pViewObject));
  313. }
  314. // try and load the file, either through the URL moniker or
  315. // via IPersistFile::Load()
  316. if (SUCCEEDED(hr))
  317. {
  318. if (pURLMoniker != NULL)
  319. {
  320. IBindCtx *pbc = NULL;
  321. IPersistMoniker * pPersistMon = NULL;
  322. // have reached here with the interface I need ...
  323. hr = pUnk->QueryInterface(IID_PPV_ARG(IPersistMoniker, &pPersistMon));
  324. if (SUCCEEDED(hr))
  325. {
  326. hr = CreateBindCtx(0, &pbc);
  327. }
  328. if (SUCCEEDED(hr) && fUrl)
  329. {
  330. IHtmlLoadOptions *phlo;
  331. hr = CoCreateInstance(CLSID_HTMLLoadOptions, NULL, CLSCTX_INPROC_SERVER,
  332. IID_PPV_ARG(IHtmlLoadOptions, &phlo));
  333. if (SUCCEEDED(hr))
  334. {
  335. // deliberately ignore failures here
  336. phlo->SetOption(HTMLLOADOPTION_INETSHORTCUTPATH, m_szPath, (lstrlenW(m_szPath) + 1)*sizeof(WCHAR));
  337. pbc->RegisterObjectParam(L"__HTMLLOADOPTIONS", phlo);
  338. phlo->Release();
  339. }
  340. }
  341. if (SUCCEEDED(hr))
  342. {
  343. //tell MSHTML to start to load the page given
  344. hr = pPersistMon->Load(TRUE, pURLMoniker, pbc, NULL);
  345. }
  346. if (pPersistMon)
  347. {
  348. pPersistMon->Release();
  349. }
  350. if (pbc)
  351. {
  352. pbc->Release();
  353. }
  354. }
  355. else
  356. {
  357. IPersistFile *pPersistFile;
  358. hr = pUnk->QueryInterface(IID_PPV_ARG(IPersistFile, &pPersistFile));
  359. if (SUCCEEDED(hr))
  360. {
  361. hr = pPersistFile->Load(m_szPath, STGM_READ | STGM_SHARE_DENY_NONE);
  362. pPersistFile->Release();
  363. }
  364. }
  365. }
  366. if (pURLMoniker != NULL)
  367. {
  368. pURLMoniker->Release();
  369. }
  370. if (SUCCEEDED(hr))
  371. {
  372. SIZEL rgSize;
  373. rgSize.cx = m_dwXRenderSize;
  374. rgSize.cy = m_dwYRenderSize;
  375. HDC hDesktopDC = GetDC(NULL);
  376. // convert the size to himetric
  377. rgSize.cx = (rgSize.cx * 2540) / GetDeviceCaps(hDesktopDC, LOGPIXELSX);
  378. rgSize.cy = (rgSize.cy * 2540) / GetDeviceCaps(hDesktopDC, LOGPIXELSY);
  379. hr = m_pOleObject->SetExtent(DVASPECT_CONTENT, &rgSize);
  380. ReleaseDC(NULL, hDesktopDC);
  381. }
  382. if (SUCCEEDED(hr))
  383. {
  384. hr = pUnk->QueryInterface(IID_PPV_ARG(IHTMLDocument2, &m_pHTML));
  385. }
  386. if (pUnk)
  387. {
  388. pUnk->Release();
  389. }
  390. if (SUCCEEDED(hr))
  391. {
  392. // get the timeout from the registry....
  393. m_dwTimeout = 0;
  394. DWORD cbSize = sizeof(m_dwTimeout);
  395. // SHGetValueW
  396. SHRegGetUSValueW(REGSTR_THUMBNAILVIEW, REGSTR_HTMLTIMEOUT, NULL, &m_dwTimeout, &cbSize, FALSE, NULL, 0);
  397. if (m_dwTimeout == 0)
  398. {
  399. m_dwTimeout = TIME_DEFAULT;
  400. }
  401. // adjust to milliseconds
  402. m_dwTimeout *= 1000;
  403. // register the connection point for notification of the readystate
  404. hr = m_pOleObject->QueryInterface(IID_PPV_ARG(IConnectionPointContainer, &pConPtCtr));
  405. }
  406. if (SUCCEEDED(hr))
  407. {
  408. hr = pConPtCtr->FindConnectionPoint(IID_IPropertyNotifySink, &m_pConPt);
  409. }
  410. if (pConPtCtr)
  411. {
  412. pConPtCtr->Release();
  413. }
  414. if (SUCCEEDED(hr))
  415. {
  416. hr = m_pConPt->Advise((IPropertyNotifySink *) this, &m_dwPropNotifyCookie);
  417. }
  418. if (SUCCEEDED(hr))
  419. {
  420. m_dwCurrentTick = 0;
  421. // delegate to the shared function
  422. hr = InternalResume();
  423. }
  424. ResetWaitCursor();
  425. return hr;
  426. }
  427. // this function is called from either Create or from
  428. HRESULT CHtmlThumb::InternalResume()
  429. {
  430. HRESULT hr = WaitForRender();
  431. // if we getE_PENDING, we will drop out of Run()
  432. // all errors and succeeds excepting Suspend() need to Unadvise the
  433. // connection point
  434. if (hr != E_PENDING)
  435. {
  436. // unregister the connection point ...
  437. m_pConPt->Unadvise(m_dwPropNotifyCookie);
  438. ATOMICRELEASE(m_pConPt);
  439. }
  440. if (m_lState == IRTIR_TASK_PENDING)
  441. {
  442. // we were told to quit, so do it...
  443. hr = E_FAIL;
  444. }
  445. if (SUCCEEDED(hr))
  446. {
  447. hr = Finish(m_phBmp, &m_rgSize, m_dwClrDepth);
  448. }
  449. if (m_lState != IRTIR_TASK_SUSPENDED)
  450. {
  451. m_lState = IRTIR_TASK_FINISHED;
  452. }
  453. if (hr != E_PENDING)
  454. {
  455. // we are not being suspended, so we don't need any of this stuff anymore so ...
  456. // let it go here so that its on the same thread as where we created it...
  457. ATOMICRELEASE(m_pHTML);
  458. ATOMICRELEASE(m_pOleObject);
  459. ATOMICRELEASE(m_pViewObject);
  460. ATOMICRELEASE(m_pMoniker);
  461. }
  462. return hr;
  463. }
  464. HRESULT CHtmlThumb::WaitForRender()
  465. {
  466. DWORD dwLastTick = GetTickCount();
  467. CheckReadyState();
  468. do
  469. {
  470. MSG msg;
  471. while (PeekMessageWrapW(&msg, NULL, 0, 0, PM_REMOVE))
  472. {
  473. if ((msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST) ||
  474. (msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST && msg.message != WM_MOUSEMOVE))
  475. {
  476. continue;
  477. }
  478. TranslateMessage(&msg);
  479. DispatchMessageWrapW(&msg);
  480. }
  481. HANDLE rgWait[1] = {m_hDone};
  482. DWORD dwRet = MsgWaitForMultipleObjects(1, rgWait, FALSE,
  483. m_dwTimeout - m_dwCurrentTick, QS_ALLINPUT);
  484. if (dwRet != WAIT_OBJECT_0)
  485. {
  486. // check the handle, TRIDENT pumps LOADS of messages, so we may never
  487. // detect the handle fired, even though it has...
  488. DWORD dwTest = WaitForSingleObject(m_hDone, 0);
  489. if (dwTest == WAIT_OBJECT_0)
  490. {
  491. break;
  492. }
  493. }
  494. if (dwRet == WAIT_OBJECT_0)
  495. {
  496. // Done signalled (either killed, or complete)
  497. break;
  498. }
  499. // was it a message that needed processing ?
  500. if (dwRet != WAIT_TIMEOUT)
  501. {
  502. DWORD dwNewTick = GetTickCount();
  503. if (dwNewTick < dwLastTick)
  504. {
  505. // it wrapped to zero,
  506. m_dwCurrentTick += dwNewTick + (0xffffffff - dwLastTick);
  507. }
  508. else
  509. {
  510. m_dwCurrentTick += (dwNewTick - dwLastTick);
  511. }
  512. dwLastTick = dwNewTick;
  513. }
  514. if ((m_dwCurrentTick > m_dwTimeout) || (dwRet == WAIT_TIMEOUT))
  515. {
  516. ASSERT(m_pOleObject);
  517. m_pOleObject->Close(OLECLOSE_NOSAVE);
  518. return E_FAIL;
  519. }
  520. }
  521. while (TRUE);
  522. if (m_lState == IRTIR_TASK_SUSPENDED)
  523. {
  524. return E_PENDING;
  525. }
  526. if (m_lState == IRTIR_TASK_PENDING)
  527. {
  528. // it is being killed,
  529. // close the renderer down...
  530. m_pOleObject->Close(OLECLOSE_NOSAVE);
  531. }
  532. return S_OK;
  533. }
  534. HRESULT CHtmlThumb::Finish(HBITMAP * phBmp, const SIZE * prgSize, DWORD dwClrDepth)
  535. {
  536. HRESULT hr = S_OK;
  537. RECTL rcLRect;
  538. HBITMAP hOldBmp = NULL;
  539. HBITMAP hHTMLBmp = NULL;
  540. BITMAPINFO * pBMI = NULL;
  541. LPVOID pBits;
  542. HPALETTE hpal = NULL;;
  543. // size is in pixels...
  544. SIZEL rgSize;
  545. rgSize.cx = m_dwXRenderSize;
  546. rgSize.cy = m_dwYRenderSize;
  547. //draw into temp DC
  548. HDC hDesktopDC = GetDC(NULL);
  549. HDC hdcHTML = CreateCompatibleDC(hDesktopDC);
  550. if (hdcHTML == NULL)
  551. {
  552. hr = E_OUTOFMEMORY;
  553. }
  554. if (dwClrDepth == 8)
  555. {
  556. // use the shell's palette as the default
  557. hpal = SHCreateShellPalette(hDesktopDC);
  558. }
  559. else if (dwClrDepth == 4)
  560. {
  561. // use the stock 16 colour palette...
  562. hpal = (HPALETTE) GetStockObject(DEFAULT_PALETTE);
  563. }
  564. if (SUCCEEDED(hr))
  565. {
  566. CreateSizedDIBSECTION(&rgSize, dwClrDepth, hpal, NULL, &hHTMLBmp, &pBMI, &pBits);
  567. if (hHTMLBmp == NULL)
  568. {
  569. hr = E_OUTOFMEMORY;
  570. }
  571. }
  572. if (SUCCEEDED(hr))
  573. {
  574. hOldBmp = (HBITMAP) SelectObject(hdcHTML, hHTMLBmp);
  575. BitBlt(hdcHTML, 0, 0, rgSize.cx, rgSize.cy, NULL, 0, 0, WHITENESS);
  576. /****************** RENDER HTML PAGE to MEMORY DC *******************
  577. We will now call IViewObject::Draw in MSHTML to render the loaded
  578. URL into the passed in hdcMem. The extent of the rectangle to
  579. render in is in RectForViewObj. This is the call that gives
  580. us the image to scroll, animate, or whatever!
  581. ********************************************************************/
  582. rcLRect.left = 0;
  583. rcLRect.right = rgSize.cx;
  584. rcLRect.top = 0;
  585. rcLRect.bottom = rgSize.cy;
  586. hr = m_pViewObject->Draw(DVASPECT_CONTENT,
  587. NULL, NULL, NULL, NULL,
  588. hdcHTML, &rcLRect,
  589. NULL, NULL, NULL);
  590. SelectObject(hdcHTML, hOldBmp);
  591. }
  592. if (SUCCEEDED(hr))
  593. {
  594. SIZEL rgCur;
  595. rgCur.cx = rcLRect.bottom;
  596. rgCur.cy = rcLRect.right;
  597. ASSERT(pBMI);
  598. ASSERT(pBits);
  599. hr = ConvertDIBSECTIONToThumbnail(pBMI, pBits, phBmp, prgSize, dwClrDepth, hpal, 50, FALSE);
  600. }
  601. if (hHTMLBmp)
  602. {
  603. DeleteObject(hHTMLBmp);
  604. }
  605. if (hDesktopDC)
  606. {
  607. ReleaseDC(NULL, hDesktopDC);
  608. }
  609. if (hdcHTML)
  610. {
  611. DeleteDC(hdcHTML);
  612. }
  613. if (pBMI)
  614. {
  615. LocalFree(pBMI);
  616. }
  617. if (hpal)
  618. {
  619. DeleteObject(hpal);
  620. }
  621. return hr;
  622. }
  623. HRESULT CHtmlThumb::CheckReadyState()
  624. {
  625. VARIANT varState;
  626. DISPPARAMS dp;
  627. if (!m_pHTML)
  628. {
  629. ASSERT(FALSE);
  630. return E_UNEXPECTED;
  631. }
  632. VariantInit(&varState);
  633. if (SUCCEEDED(m_pHTML->Invoke(DISPID_READYSTATE,
  634. IID_NULL,
  635. GetUserDefaultLCID(),
  636. DISPATCH_PROPERTYGET,
  637. &dp,
  638. &varState, NULL, NULL)) &&
  639. V_VT(&varState)==VT_I4 &&
  640. V_I4(&varState)== READYSTATE_COMPLETE)
  641. {
  642. // signal the end ..
  643. SetEvent(m_hDone);
  644. }
  645. return S_OK;
  646. }
  647. HRESULT CHtmlThumb::Create_URL_Moniker(IMoniker ** ppMoniker)
  648. {
  649. // we are dealing with a URL file
  650. WCHAR szURLData[8196];
  651. // URL files are actually ini files that
  652. // have a section [InternetShortcut]
  653. // and a Value URL=.....
  654. int iRet = SHGetIniStringW(L"InternetShortcut", L"URL",
  655. szURLData, ARRAYSIZE(szURLData), m_szPath);
  656. if (iRet == 0)
  657. {
  658. return E_FAIL;
  659. }
  660. return CreateURLMoniker(0, szURLData, ppMoniker);
  661. }
  662. STDMETHODIMP CHtmlThumb::GetClassID(CLSID *pClassID)
  663. {
  664. return E_NOTIMPL;
  665. }
  666. STDMETHODIMP CHtmlThumb::IsDirty()
  667. {
  668. return E_NOTIMPL;
  669. }
  670. STDMETHODIMP CHtmlThumb::Load(LPCOLESTR pszFileName, DWORD dwMode)
  671. {
  672. HRESULT hr = E_INVALIDARG;
  673. if (pszFileName)
  674. {
  675. hr = StringCchCopyW(m_szPath, ARRAYSIZE(m_szPath), pszFileName);
  676. if (SUCCEEDED(hr))
  677. {
  678. DWORD dwAttrs = GetFileAttributesWrapW(m_szPath);
  679. if ((dwAttrs != (DWORD) -1) && (dwAttrs & FILE_ATTRIBUTE_OFFLINE))
  680. {
  681. hr = E_FAIL;
  682. }
  683. }
  684. }
  685. return hr;
  686. }
  687. STDMETHODIMP CHtmlThumb::Save(LPCOLESTR pszFileName, BOOL fRemember)
  688. {
  689. return E_NOTIMPL;
  690. }
  691. STDMETHODIMP CHtmlThumb::SaveCompleted(LPCOLESTR pszFileName)
  692. {
  693. return E_NOTIMPL;
  694. }
  695. STDMETHODIMP CHtmlThumb::GetCurFile(LPOLESTR *ppszFileName)
  696. {
  697. return E_NOTIMPL;
  698. }
  699. CTridentHost::CTridentHost()
  700. {
  701. m_cRef = 1;
  702. }
  703. CTridentHost::~CTridentHost()
  704. {
  705. // all refs should have been released...
  706. ASSERT(m_cRef == 1);
  707. }
  708. HRESULT CTridentHost::SetTrident(IOleObject * pTrident)
  709. {
  710. ASSERT(pTrident);
  711. return pTrident->SetClientSite((IOleClientSite *) this);
  712. }
  713. STDMETHODIMP CTridentHost::QueryInterface(REFIID riid, void ** ppvObj)
  714. {
  715. static const QITAB qit[] = {
  716. QITABENT(CTridentHost, IOleClientSite),
  717. QITABENT(CTridentHost, IDispatch),
  718. QITABENT(CTridentHost, IDocHostUIHandler),
  719. // IThumbnailView is needed by Trident for some reason. The cast to IOleClientSite is because that's what we used to do
  720. QITABENTMULTI(CTridentHost, IThumbnailView, IOleClientSite),
  721. { 0 }
  722. };
  723. return QISearch(this, qit, riid, ppvObj);
  724. }
  725. STDMETHODIMP_(ULONG) CTridentHost::AddRef(void)
  726. {
  727. m_cRef ++;
  728. return m_cRef;
  729. }
  730. STDMETHODIMP_(ULONG) CTridentHost::Release(void)
  731. {
  732. m_cRef --;
  733. // because we are created with our parent, we do not do a delete here..
  734. ASSERT(m_cRef > 0);
  735. return m_cRef;
  736. }
  737. STDMETHODIMP CTridentHost::GetTypeInfoCount(UINT *pctinfo)
  738. {
  739. return E_NOTIMPL;
  740. }
  741. STDMETHODIMP CTridentHost::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo)
  742. {
  743. return E_NOTIMPL;
  744. }
  745. STDMETHODIMP CTridentHost::GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgdispid)
  746. {
  747. return E_NOTIMPL;
  748. }
  749. STDMETHODIMP CTridentHost::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
  750. DISPPARAMS *pdispparams, VARIANT *pvarResult,
  751. EXCEPINFO *pexcepinfo, UINT *puArgErr)
  752. {
  753. if (!pvarResult)
  754. return E_INVALIDARG;
  755. ASSERT(pvarResult->vt == VT_EMPTY);
  756. if (wFlags == DISPATCH_PROPERTYGET)
  757. {
  758. switch (dispidMember)
  759. {
  760. case DISPID_AMBIENT_DLCONTROL :
  761. pvarResult->vt = VT_I4;
  762. pvarResult->lVal = DLCTL_DOWNLOAD_FLAGS;
  763. if (m_fOffline)
  764. {
  765. pvarResult->lVal |= DLCTL_OFFLINE;
  766. }
  767. return S_OK;
  768. case DISPID_AMBIENT_OFFLINEIFNOTCONNECTED:
  769. pvarResult->vt = VT_BOOL;
  770. pvarResult->boolVal = m_fOffline ? TRUE : FALSE;
  771. return S_OK;
  772. case DISPID_AMBIENT_SILENT:
  773. pvarResult->vt = VT_BOOL;
  774. pvarResult->boolVal = TRUE;
  775. return S_OK;
  776. }
  777. }
  778. return DISP_E_MEMBERNOTFOUND;
  779. }
  780. // IOleClientSite
  781. STDMETHODIMP CTridentHost::SaveObject()
  782. {
  783. return E_NOTIMPL;
  784. }
  785. STDMETHODIMP CTridentHost::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker **ppmk)
  786. {
  787. return E_NOTIMPL;
  788. }
  789. STDMETHODIMP CTridentHost::GetContainer(IOleContainer **ppContainer)
  790. {
  791. return E_NOTIMPL;
  792. }
  793. STDMETHODIMP CTridentHost::ShowObject()
  794. {
  795. return E_NOTIMPL;
  796. }
  797. STDMETHODIMP CTridentHost::OnShowWindow(BOOL fShow)
  798. {
  799. return E_NOTIMPL;
  800. }
  801. STDMETHODIMP CTridentHost::RequestNewObjectLayout()
  802. {
  803. return E_NOTIMPL;
  804. }
  805. // IPersistMoniker stuff
  806. STDMETHODIMP CHtmlThumb::Load(BOOL fFullyAvailable, IMoniker *pimkName, LPBC pibc, DWORD grfMode)
  807. {
  808. if (!pimkName)
  809. {
  810. return E_INVALIDARG;
  811. }
  812. if (pibc || grfMode != STGM_READ)
  813. {
  814. return E_NOTIMPL;
  815. }
  816. if (m_pMoniker)
  817. {
  818. m_pMoniker->Release();
  819. }
  820. m_pMoniker = pimkName;
  821. ASSERT(m_pMoniker);
  822. m_pMoniker->AddRef();
  823. return S_OK;
  824. }
  825. STDMETHODIMP CHtmlThumb::Save(IMoniker *pimkName, LPBC pbc, BOOL fRemember)
  826. {
  827. return E_NOTIMPL;
  828. }
  829. STDMETHODIMP CHtmlThumb::SaveCompleted(IMoniker *pimkName, LPBC pibc)
  830. {
  831. return E_NOTIMPL;
  832. }
  833. STDMETHODIMP CHtmlThumb::GetCurMoniker(IMoniker **ppimkName)
  834. {
  835. return E_NOTIMPL;
  836. }
  837. STDMETHODIMP CTridentHost::ShowContextMenu(DWORD dwID, POINT *ppt, IUnknown *pcmdtReserved, IDispatch *pdispReserved)
  838. {
  839. return E_NOTIMPL;
  840. }
  841. STDMETHODIMP CTridentHost::GetHostInfo(DOCHOSTUIINFO *pInfo)
  842. {
  843. if (!pInfo)
  844. {
  845. return E_INVALIDARG;
  846. }
  847. DWORD dwIE = URL_ENCODING_NONE;
  848. DWORD dwOutLen = sizeof(DWORD);
  849. UrlMkGetSessionOption(URLMON_OPTION_URL_ENCODING, &dwIE, sizeof(DWORD), &dwOutLen, NULL);
  850. pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT;
  851. pInfo->dwFlags |= DOCHOSTUIFLAG_SCROLL_NO;
  852. if (dwIE == URL_ENCODING_ENABLE_UTF8)
  853. {
  854. pInfo->dwFlags |= DOCHOSTUIFLAG_URL_ENCODING_ENABLE_UTF8;
  855. }
  856. else
  857. {
  858. pInfo->dwFlags |= DOCHOSTUIFLAG_URL_ENCODING_DISABLE_UTF8;
  859. }
  860. return S_OK;
  861. }
  862. STDMETHODIMP CTridentHost::ShowUI(DWORD dwID,
  863. IOleInPlaceActiveObject *pActiveObject,
  864. IOleCommandTarget *pCommandTarget,
  865. IOleInPlaceFrame *pFrame,
  866. IOleInPlaceUIWindow *pDoc)
  867. {
  868. return E_NOTIMPL;
  869. }
  870. STDMETHODIMP CTridentHost::HideUI (void)
  871. {
  872. return E_NOTIMPL;
  873. }
  874. STDMETHODIMP CTridentHost::UpdateUI (void)
  875. {
  876. return E_NOTIMPL;
  877. }
  878. STDMETHODIMP CTridentHost::EnableModeless (BOOL fEnable)
  879. {
  880. return E_NOTIMPL;
  881. }
  882. STDMETHODIMP CTridentHost::OnDocWindowActivate (BOOL fActivate)
  883. {
  884. return E_NOTIMPL;
  885. }
  886. STDMETHODIMP CTridentHost::OnFrameWindowActivate (BOOL fActivate)
  887. {
  888. return E_NOTIMPL;
  889. }
  890. STDMETHODIMP CTridentHost::ResizeBorder (LPCRECT prcBorder, IOleInPlaceUIWindow *pUIWindow, BOOL fRameWindow)
  891. {
  892. return E_NOTIMPL;
  893. }
  894. STDMETHODIMP CTridentHost::TranslateAccelerator (LPMSG lpMsg, const GUID *pguidCmdGroup, DWORD nCmdID)
  895. {
  896. return E_NOTIMPL;
  897. }
  898. STDMETHODIMP CTridentHost::GetOptionKeyPath (LPOLESTR *pchKey, DWORD dw)
  899. {
  900. return E_NOTIMPL;
  901. }
  902. STDMETHODIMP CTridentHost::GetDropTarget (IDropTarget *pDropTarget, IDropTarget **ppDropTarget)
  903. {
  904. return E_NOTIMPL;
  905. }
  906. STDMETHODIMP CTridentHost::GetExternal (IDispatch **ppDispatch)
  907. {
  908. return E_NOTIMPL;
  909. }
  910. STDMETHODIMP CTridentHost::TranslateUrl (DWORD dwTranslate, OLECHAR *pchURLIn, OLECHAR **ppchURLOut)
  911. {
  912. return E_NOTIMPL;
  913. }
  914. STDMETHODIMP CTridentHost::FilterDataObject (IDataObject *pDO, IDataObject **ppDORet)
  915. {
  916. return E_NOTIMPL;
  917. }
  918. STDMETHODIMP CHtmlThumb::CaptureThumbnail(const SIZE * pMaxSize, IUnknown * pHTMLDoc2, HBITMAP * phbmThumbnail)
  919. {
  920. HRESULT hr = E_INVALIDARG;
  921. if (pMaxSize != NULL &&
  922. pHTMLDoc2 != NULL &&
  923. phbmThumbnail != NULL)
  924. {
  925. IHTMLDocument2 *pDoc = NULL;
  926. hr = pHTMLDoc2->QueryInterface(IID_PPV_ARG(IHTMLDocument2, &pDoc));
  927. if (SUCCEEDED(hr))
  928. {
  929. ASSERT(m_pViewObject == NULL);
  930. hr = pDoc->QueryInterface(IID_PPV_ARG(IViewObject, &m_pViewObject));
  931. if (SUCCEEDED(hr))
  932. {
  933. SIZE sizeThumbnail;
  934. sizeThumbnail.cy = pMaxSize->cy;
  935. sizeThumbnail.cx = pMaxSize->cx;
  936. hr = m_pViewObject->QueryInterface(IID_PPV_ARG(IOleObject, &m_pOleObject));
  937. if (SUCCEEDED(hr))
  938. {
  939. SIZEL rgSize = {0,0};
  940. // get the size at which trident is currently rendering
  941. hr = m_pOleObject->GetExtent(DVASPECT_CONTENT, &rgSize);
  942. if (SUCCEEDED(hr))
  943. {
  944. HDC hdcDesktop = GetDC(NULL);
  945. // get the actual size at which trident renders
  946. if (hdcDesktop)
  947. {
  948. // (overwrite) convert from himetric
  949. rgSize.cx = rgSize.cx * GetDeviceCaps(hdcDesktop, LOGPIXELSX) / 2540;
  950. rgSize.cy = rgSize.cy * GetDeviceCaps(hdcDesktop, LOGPIXELSY) / 2540;
  951. ReleaseDC(NULL, hdcDesktop);
  952. m_dwXRenderSize = rgSize.cx;
  953. m_dwYRenderSize = rgSize.cy;
  954. DWORD dwColorDepth = SHGetCurColorRes();
  955. hr = Finish(phbmThumbnail, &sizeThumbnail, dwColorDepth);
  956. }
  957. else
  958. {
  959. hr = E_FAIL;
  960. }
  961. }
  962. ASSERT(m_pOleObject != NULL);
  963. m_pOleObject->Release();
  964. }
  965. ASSERT(m_pViewObject != NULL);
  966. m_pViewObject->Release();
  967. }
  968. ASSERT(pDoc != NULL);
  969. pDoc->Release();
  970. }
  971. }
  972. return hr;
  973. }