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.

3009 lines
96 KiB

  1. // Copyright (C) 1996-1997 Microsoft Corporation. All rights reserved.
  2. #include "header.h"
  3. #include "sitemap.h"
  4. #include "hhctrl.h"
  5. #include "LocalObj.h"
  6. #include "Resource.h"
  7. #include "strtable.h"
  8. #include "hha_strtable.h"
  9. #include "infowiz.h"
  10. #include "web.h"
  11. #include "cprint.h"
  12. #include <exdisp.h>
  13. #undef WINUSERAPI
  14. #define WINUSERAPI
  15. #include "htmlhelp.h"
  16. #include <stdio.h>
  17. #ifndef _DEBUG
  18. #undef THIS_FILE
  19. static const char THIS_FILE[] = __FILE__;
  20. #endif
  21. const DWORD STREAMHDR_MAGIC = 12678L;
  22. // DO NOT LOCALIZE THESE!
  23. static const char txtAboutBox[] = "AboutBox";
  24. static const char txtHhCtrlVersion[] = "HH Version";
  25. static const char txtSplash[] = "Splash";
  26. static const char txtTCard[] = "TCard";
  27. static const char txtWinHelp[] = "WinHelp";
  28. static const char txtRelatedTopics[] = "Related Topics";
  29. static const char txtKeywordSearch[] = "Keyword Search";
  30. static const char txtContents[] = "Contents";
  31. static const char txtHelpContents[] = "HelpContents";
  32. static const char txtShortcut[] = "Shortcut";
  33. static const char txtClose[] = "Close";
  34. static const char txtHHWinPrint[] = "HHWinPrint";
  35. static const char txtMinimize[] = "Minimize";
  36. static const char txtMaximize[] = "Maximize";
  37. static const char txtIndex[] = "Index";
  38. static const char txtItem[] = "Item%u";
  39. static const char txtBitmap[] = "Bitmap:";
  40. static const char txtIcon[] = "Icon:";
  41. static const char txtText[] = "Text:";
  42. static const char txtHPad[] = "HPAD=";
  43. static const char txtVPad[] = "VPAD=";
  44. static const char txtHHWin[] = "hhwin:";
  45. static const char txtFileUrl[] = "file:";
  46. static const char txtActKLink[] = "KLink";
  47. static const char txtActSample[] = "Sample";
  48. static const char txtActALink[] = "ALink";
  49. static const char txtMenu[] = "MENU";
  50. static const char txtPopup[] = "Popup";
  51. static const WCHAR txtwImage[] = L"Image";
  52. static const WCHAR txtwFrame[] = L"Frame";
  53. static const WCHAR txtwWindow[] = L"Window";
  54. static const WCHAR txtwFont[] = L"Font";
  55. static const WCHAR txtwFlags[] = L"Flags";
  56. static const WCHAR txtwWebMap[] = L"WebMap";
  57. static const WCHAR txtwCommand[] = L"Command";
  58. static const WCHAR txtwButton[] = L"Button";
  59. static const WCHAR txtwText[] = L"Text";
  60. static const WCHAR txtwDefaultTopic[] = L"DefaultTopic";
  61. // shanemc 7883 - Support bgcolor for index
  62. static const WCHAR txtwBgColor[] = L"BgColor";
  63. // utility functions -- move to util.cpp someday
  64. /***************************************************************************
  65. FUNCTION: FindMessageParent
  66. PURPOSE: Find the parent to send messages to
  67. PARAMETERS:
  68. hwndChild
  69. RETURNS:
  70. COMMENTS:
  71. A control may be a child of a Tab Control, in which case, we
  72. need to send any messages to the Tab Control's parent
  73. MODIFICATION DATES:
  74. 20-Mar-1997 [ralphw]
  75. ***************************************************************************/
  76. HWND FindMessageParent(HWND hwndChild)
  77. {
  78. HWND hwndParent = GetParent(hwndChild);
  79. char szClass[50];
  80. GetClassName(hwndParent, szClass, sizeof(szClass));
  81. if (IsSamePrefix(szClass, WC_TABCONTROL, -2))
  82. hwndParent = GetParent(hwndParent);
  83. return hwndParent;
  84. }
  85. /***************************************************************************
  86. FUNCTION: JumpToUrl
  87. PURPOSE: Jump to a URL specified in a sitemapentry or SITE_ENTRY_RUL
  88. PARAMETERS:
  89. pUnkOuter -- used for HlinkSimpleNavigateToString
  90. hwndParent -- parent for secondary window (if jumped to)
  91. pSiteMapEntry
  92. pSiteMap
  93. pUrl
  94. RETURNS: Window handle if a secondary window is created, else NULL
  95. COMMENTS:
  96. Special processing for %SYSTEMROOT% anywhere in URL
  97. Special processing for "hhwin:" and "file:"
  98. MODIFICATION DATES:
  99. 04-Mar-1997 [ralphw]
  100. ***************************************************************************/
  101. HWND JumpToUrl(IUnknown* pUnkOuter, HWND hwndParent, SITEMAP_ENTRY* pSiteMapEntry, CInfoType *pInfoType,
  102. CSiteMap* pSiteMap, SITE_ENTRY_URL* pUrl, IWebBrowserAppImpl* pWebApp /* = NULL */)
  103. {
  104. ASSERT(pSiteMapEntry);
  105. ASSERT(pSiteMap);
  106. PCSTR pszFrame = pSiteMapEntry->GetFrameIndex() ?
  107. pSiteMap->GetEntryFrame(pSiteMapEntry) : pSiteMap->GetFrameName();
  108. PSTR pszInterTopic = NULL;
  109. PCSTR pszUrl = NULL;
  110. PCSTR pszSecondaryUrl = NULL;
  111. if (!pUrl) {
  112. if (pSiteMapEntry->fShowToEveryOne) {
  113. pUrl = pSiteMapEntry->pUrls;
  114. }
  115. else { // choose based on Information Type
  116. // If we get here, then we must match information types
  117. ASSERT_COMMENT(pSiteMap->m_pInfoTypes,
  118. "Info-type only URL specified without any user-specified Information Types");
  119. // for (UINT j = 0; j < pSiteMap->m_cUrlEntry - (sizeof(URL) * 2); j++) {
  120. INFOTYPE *pIT = pSiteMap->m_pInfoTypes;
  121. for (int j=0; j<pSiteMap->InfoTypeSize()/4;j++)
  122. {
  123. pUrl = pSiteMap->AreTheseInfoTypesDefined(pSiteMapEntry, *pIT+(INFOTYPE)j, j);
  124. if (pUrl)
  125. break;
  126. }
  127. //ASSERT_COMMENT(pUrl, "This entry should not have been displayed, since there is no matching info type.");
  128. if (!pUrl) {
  129. AuthorMsg(IDS_HHA_NO_URL, "", hwndParent, NULL);
  130. return NULL; // BUGBUG: we should notify the user
  131. }
  132. }
  133. }
  134. ASSERT(pUrl);
  135. if (pUrl->urlPrimary) {
  136. pszUrl = pSiteMap->GetUrlString(pUrl->urlPrimary);
  137. if (pUrl->urlSecondary)
  138. pszSecondaryUrl = pSiteMap->GetUrlString(pUrl->urlSecondary);
  139. }
  140. else if (pSiteMapEntry->pUrls->urlSecondary) {
  141. pszUrl = pSiteMap->GetUrlString(pUrl->urlSecondary);
  142. }
  143. else { // no primary or secondary URL
  144. AuthorMsg(IDS_HHA_NO_URL, "", hwndParent, NULL);
  145. return NULL;
  146. }
  147. /*
  148. * If the primary URL is a compiled HTML file, then first see if the
  149. * compiled HTML file exists. If not, switch to the alternate URL.
  150. */
  151. if (pszSecondaryUrl && IsCompiledHtmlFile(pszUrl, NULL)) {
  152. CStr cszPath;
  153. GetCompiledName(pszUrl, &cszPath);
  154. if (!FindThisFile(NULL, cszPath, &cszPath, FALSE)) {
  155. pszUrl = pszSecondaryUrl;
  156. pszSecondaryUrl = NULL;
  157. }
  158. }
  159. TrySecondary:
  160. CStr cszUrl;
  161. // Parse %SystemRoot%
  162. PSTR psz = stristr(pszUrl, txtSysRoot);
  163. if (psz) {
  164. char szPath[MAX_PATH];
  165. GetRegWindowsDirectory(szPath);
  166. strcat(szPath, psz + strlen(txtSysRoot));
  167. cszUrl = szPath;
  168. pszUrl = cszUrl.psz;
  169. }
  170. PCSTR pszWindowName =
  171. (pSiteMapEntry->GetWindowIndex() ?
  172. pSiteMap->GetEntryWindow(pSiteMapEntry) :
  173. pSiteMap->GetWindowName());
  174. if (IsNonEmptyString(pszWindowName) && (IsEmptyString(pszFrame) ||
  175. lstrcmpi(pszWindowName, pszFrame) != 0)) {
  176. cszUrl = "hhwin:";
  177. cszUrl += pszWindowName;
  178. cszUrl += ":";
  179. cszUrl += pszUrl;
  180. pszUrl = cszUrl.psz;
  181. }
  182. /*
  183. * If the URL is prefixed with hhwin: then we need to display this
  184. * topic in a secondary window.
  185. */
  186. CStr cszPrefix;
  187. int cb = CompareSz(pszUrl, txtHHWin);
  188. if (cb) {
  189. pszUrl += cb;
  190. CStr csz(pSiteMap->GetSiteMapFile() ? pSiteMap->GetSiteMapFile() : "");
  191. CStr cszWindow(pszUrl);
  192. PSTR pszTmp = StrChr(cszWindow, ':');
  193. if (!pszTmp) {
  194. // AuthorMsg(IDSHHA_INVALID_HHWIN, cszWindow);
  195. return NULL; // REVIEW: should we notify the user?
  196. }
  197. *pszTmp = '\0';
  198. pszUrl = FirstNonSpace(pszTmp + 1);
  199. /*
  200. * If we have a relative path specified, then we need to make it
  201. * relative to the location of our sitemap file. Look for the last
  202. * backslash or forward slash, and add our URL to the end.
  203. */
  204. if (*pszUrl == '.') {
  205. PSTR pszFilePortion = StrRChr(csz, '\\');
  206. PSTR pszTmp = StrRChr(pszFilePortion ? pszFilePortion : csz, '/');
  207. if (pszTmp)
  208. pszFilePortion = pszTmp;
  209. if (pszFilePortion) {
  210. pszFilePortion[1] = '\0';
  211. csz += pszUrl;
  212. pszUrl = csz.psz;
  213. }
  214. }
  215. if (!StrChr(pszUrl, ':') && pSiteMap->GetSiteMapFile() &&
  216. IsCompiledHtmlFile(pSiteMap->GetSiteMapFile(), &cszPrefix)) {
  217. PSTR pszSep = strstr(cszPrefix, txtDoubleColonSep);
  218. ASSERT(pszSep);
  219. if (!pszSep)
  220. return NULL; // should never happen, but beats GPF if it does
  221. strcpy(pszSep + 2, "/");
  222. while (*pszUrl == '.')
  223. pszUrl++;
  224. if (*pszUrl == '/' || *pszUrl == '\\')
  225. pszUrl++;
  226. cszPrefix += pszUrl;
  227. }
  228. else
  229. cszPrefix = pszUrl;
  230. /*
  231. Workaround for bug #5851
  232. Once upon a time there was a bug in that window types were not CHM specific.
  233. HTML Help shipped with this bug. Many people depended on the bug. In 1.1b we
  234. fixed the bug and broke exisiting content. Bug 5851 is such a case. Before, the fix
  235. below, the code was working EXACTLY as it should. However, we can't break those who
  236. have shipped no matter how broken the previous version. So, here we actually add in
  237. a bug to upbreak the already broken.
  238. The fix is as follows. If you are jumping to an url and you provide a window type,
  239. we check to see if there is a collection open which contains that url. If there is,
  240. we check to see if that window type is defined by the master chm in the collection
  241. and if it is open. If both of these are true, then we just navigate and don't create
  242. a new window.
  243. The result is that included CHMs cannot define windows with the same name as the MASTER CHM.
  244. */
  245. // Is this file part of a collection?
  246. CExCollection* pCollection = GetCurrentCollection(NULL, pszUrl);
  247. if (pCollection)
  248. {
  249. // Is the window we are attempting to open defined by the master CHM?
  250. CHHWinType* phh = FindWindowType(cszWindow.psz, NULL, pCollection->GetPathName());
  251. // Does this window actually exist?
  252. if (phh && IsWindow(phh->hwndHelp))
  253. {
  254. // We are going to reuse the exisiting window and just navigate.
  255. if (pWebApp)
  256. {
  257. pWebApp->Navigate(cszPrefix, NULL, NULL, NULL, NULL);
  258. return NULL ;
  259. }
  260. else if (IsWindow(hwndParent)) //--- Bug Fix for 7697: If hwndParent is NULL call OnDisplayTopic.
  261. {
  262. doHHWindowJump(cszPrefix, phh->hwndHelp);
  263. return NULL ;
  264. }
  265. /* fall through */
  266. }
  267. }
  268. // We will use a possiblity new window type, so call OnDisplayTopic.
  269. cszPrefix += ">";
  270. cszPrefix += cszWindow.psz;
  271. return OnDisplayTopic(hwndParent, cszPrefix, 0);
  272. }
  273. /*
  274. * If this is a file: URL, then first find out if the file
  275. * actually exits. If not, then switch to the remote URL.
  276. */
  277. cb = CompareSz(pszUrl, txtFileUrl);
  278. if (cb) {
  279. if ((pszInterTopic = StrChr(pszUrl, '#')))
  280. *pszInterTopic = '\0';
  281. if (GetFileAttributes(pszUrl + cb) == HFILE_ERROR) {
  282. if (pszSecondaryUrl) {
  283. pszUrl = pszSecondaryUrl;
  284. pszSecondaryUrl = NULL;
  285. goto TrySecondary;
  286. }
  287. AuthorMsg(IDS_HHA_NO_URL, "", hwndParent, NULL);
  288. return NULL;
  289. }
  290. }
  291. if (!pszInterTopic) {
  292. if ((pszInterTopic = StrChr(pszUrl, '#')))
  293. *pszInterTopic = '\0';
  294. }
  295. // Bug 7153, when this pointer gets moved pszInterTopic is pointing into the wrong string
  296. // and therefore the fragment gets lost for this jump. Doing a sugical fix to reduce
  297. // the massive regressions that could be caused by changing IsCompiledHtmlFile to correctly
  298. // handle URL's with fragments.
  299. BOOL bMovedPointer = FALSE;
  300. if (IsCompiledHtmlFile(pszUrl, &cszPrefix))
  301. {
  302. bMovedPointer = TRUE;
  303. pszUrl = cszPrefix.psz;
  304. }
  305. CWStr cwJump(pszUrl);
  306. if (pszInterTopic)
  307. {
  308. *pszInterTopic = '#'; // restore the original line
  309. if (bMovedPointer)
  310. {
  311. cszPrefix += pszInterTopic;
  312. pszUrl = cszPrefix.psz;
  313. }
  314. }
  315. CWStr cwLocation((pszInterTopic ? pszInterTopic : ""));
  316. if (!pUnkOuter) {
  317. /*
  318. * I couldn't find anything to to give
  319. * HlinkSimpleNavigateToString for pUnkOuter that wouldn't cause it
  320. * to fire of a new instance of IE. Trouble is, doHHWindowJump ends
  321. * up calling IWebBrowserAppImpl->Navigate who thinks all relative
  322. * paths start with http: instead of the current root (which could
  323. * be mk:). If we jump from a sitemap file, we fix that here.
  324. */
  325. CStr cszPrefix;
  326. if (!StrChr(pszUrl, ':') && pSiteMap &&
  327. IsCompiledHtmlFile(pSiteMap->GetSiteMapFile(), &cszPrefix)) {
  328. PSTR pszSep = strstr(cszPrefix, txtDoubleColonSep);
  329. ASSERT(pszSep);
  330. if (!pszSep)
  331. return NULL; // should never happen, but beats GPF if it does
  332. strcpy(pszSep + 2, "/");
  333. while (*pszUrl == '.')
  334. pszUrl++;
  335. if (*pszUrl == '/' || *pszUrl == '\\')
  336. pszUrl++;
  337. cszPrefix += pszUrl;
  338. if (pWebApp == NULL)
  339. doHHWindowJump(cszPrefix, hwndParent);
  340. else
  341. pWebApp->Navigate(cszPrefix, NULL, NULL, NULL, NULL);
  342. return NULL;
  343. }
  344. if (pWebApp == NULL)
  345. doHHWindowJump(pszUrl, hwndParent);
  346. else
  347. pWebApp->Navigate(pszUrl, NULL, NULL, NULL, NULL);
  348. return NULL;
  349. }
  350. CWStr cwFrame(pszFrame);
  351. // REVIEW: if authoring is on, might want to call IsValidURL and
  352. // let the author know if they messed up.
  353. /*
  354. * REVIEW: if we are inside of a compiled HTML file and this is a
  355. * relative jump, then do our own checking first to avoid the browser
  356. * error message.
  357. */
  358. HRESULT hr = HlinkSimpleNavigateToString(cwJump, cwLocation,
  359. cwFrame, pUnkOuter, NULL, NULL, 0, NULL);
  360. /*
  361. * If the jump failed, try the Remote jump (unless that's what we
  362. * have already tried).
  363. */
  364. if (!SUCCEEDED(hr)) {
  365. if (pszSecondaryUrl) {
  366. pszUrl = pszSecondaryUrl;
  367. pszSecondaryUrl = NULL;
  368. goto TrySecondary;
  369. }
  370. }
  371. return NULL;
  372. }
  373. #if 0 // enable for subset filtering
  374. BOOL ChooseInformationTypes(CInfoType *pInfoType, CSiteMap* pSiteMap, HWND hwndParent, CHtmlHelpControl* phhctrl, CHHWinType* phh)
  375. #else
  376. BOOL ChooseInformationTypes(CInfoType *pInfoType, CSiteMap* pSiteMap, HWND hwndParent, CHtmlHelpControl* phhctrl)
  377. #endif
  378. {
  379. if (!pInfoType->HowManyInfoTypes()) {
  380. #ifdef _DEBUG
  381. MsgBox("No Information Types have been defined");
  382. #endif
  383. return FALSE;
  384. }
  385. CInfoTypePageContents* apwiz[MAX_CATEGORIES + 1];
  386. int iMaxWizard = 0;
  387. CMem mem((int)lcSize(pInfoType->m_pInfoTypes));
  388. memcpy(mem.pb, pInfoType->m_pInfoTypes, lcSize(pInfoType->m_pInfoTypes));
  389. CMem memE((int)lcSize(pInfoType->m_pInfoTypes));
  390. memset(memE.pb, '\0', lcSize(pInfoType->m_pInfoTypes));
  391. INFO_PARAM infoParam;
  392. ZERO_STRUCTURE( infoParam );
  393. infoParam.pTypicalInfoTypes = pInfoType->m_pTypicalInfoTypes ?
  394. pInfoType->m_pTypicalInfoTypes : pInfoType->m_pInfoTypes;
  395. infoParam.pInfoTypes = (INFOTYPE*) mem.pb;
  396. #if 0 // enable for subset filtering
  397. infoParam.pExclusive = (INFOTYPE*) memE.pb;
  398. #endif
  399. infoParam.pSiteMap = pSiteMap;
  400. infoParam.idDlgTemplate = IDWIZ_INFOTYPE_CUSTOM_INCLUSIVE;
  401. infoParam.fExclusive = FALSE;
  402. infoParam.idNextPage = 0;
  403. infoParam.idPreviousPage = 0;
  404. infoParam.iCategory = -1;
  405. infoParam.fAll = FALSE;
  406. infoParam.fTypical = TRUE;
  407. infoParam.fCustom = FALSE;
  408. infoParam.pInfoType = pInfoType;
  409. CPropSheet cprop(NULL, PSH_WIZARD, hwndParent);
  410. #if 0 // enable for subset filtering
  411. CWizardIntro wizIntro(phh? phh->m_phmData->m_pTitleCollection : NULL, &infoParam);
  412. CInfoWizFinish wizFinish(phh, &infoParam);
  413. #else
  414. CWizardIntro wizIntro(phhctrl, &infoParam);
  415. CInfoWizFinish wizFinish(phhctrl, &infoParam);
  416. #endif
  417. int type;
  418. if ( pInfoType->HowManyCategories() > 0 )
  419. {
  420. for (int CatCount = 0; CatCount<pInfoType->HowManyCategories(); CatCount++)
  421. {
  422. BOOL fAllHidden = TRUE;
  423. infoParam.iCategory = CatCount;
  424. infoParam.pagebits = pInfoType->m_itTables.m_aCategories[CatCount].pInfoType;
  425. type = pInfoType->GetFirstCategoryType(CatCount); // check all the IT's to see if there is an exclusive type in the category.
  426. if ( type == -1 )
  427. continue; // we dont want categories without information types in them
  428. while ( type != -1 )
  429. {
  430. if ( !pInfoType->IsHidden ( type ) )
  431. fAllHidden = FALSE;
  432. if ( pInfoType->IsExclusive(type) )
  433. {
  434. infoParam.idDlgTemplate = IDWIZ_INFOTYPE_CUSTOM_EXCLUSIVE;
  435. infoParam.fExclusive = TRUE;
  436. break;
  437. }
  438. type = pInfoType->GetNextITinCategory();
  439. }
  440. if ( !fAllHidden )
  441. #if 0 // enable for subset filtering
  442. apwiz[iMaxWizard++] = new CInfoTypePageContents(phh->m_phmData->m_pTitleCollection, &infoParam);
  443. #else
  444. apwiz[iMaxWizard++] = new CInfoTypePageContents(phhctrl, &infoParam);
  445. #endif
  446. infoParam.idDlgTemplate = IDWIZ_INFOTYPE_CUSTOM_INCLUSIVE;
  447. infoParam.fExclusive = FALSE;
  448. }
  449. iMaxWizard--;
  450. }
  451. else
  452. { // there are no categories
  453. if ( pInfoType->HowManyInfoTypes() > 0 )
  454. {
  455. infoParam.iCategory = -1;
  456. infoParam.idNextPage = CInfoWizFinish::IDD;
  457. if ( pInfoType->GetFirstExclusive() != -1 ) // we have a set of exclusive ITs
  458. {
  459. infoParam.idDlgTemplate = IDWIZ_INFOTYPE_CUSTOM_EXCLUSIVE;
  460. infoParam.fExclusive = TRUE;
  461. infoParam.pagebits = pInfoType->m_itTables.m_pExclusive;
  462. #if 0 // enable for subset filtering
  463. apwiz[iMaxWizard] = new CInfoTypePageContents(phh->m_phmData->m_pTitleCollection, &infoParam);
  464. #else
  465. apwiz[iMaxWizard] = new CInfoTypePageContents(phhctrl, &infoParam);
  466. #endif
  467. }
  468. else // we have a set of inclusive ITs
  469. {
  470. infoParam.pagebits = NULL; // look in CInfoType for Inclusive IT.
  471. #if 0 // enable for subset filtering
  472. apwiz[iMaxWizard] = new CInfoTypePageContents(phh ? phh->m_phmData->m_pTitleCollection : NULL, &infoParam);
  473. #else
  474. apwiz[iMaxWizard] = new CInfoTypePageContents(phhctrl, &infoParam);
  475. #endif
  476. }
  477. }
  478. }
  479. cprop.AddPage(&wizIntro);
  480. ASSERT_COMMENT(iMaxWizard >= 0, "No information types specified")
  481. for (int i = 0; i <= iMaxWizard; i++)
  482. cprop.AddPage(apwiz[i]);
  483. cprop.AddPage(&wizFinish);
  484. if (phhctrl)
  485. phhctrl->ModalDialog(TRUE);
  486. BOOL fResult = cprop.DoModal();
  487. if (phhctrl)
  488. phhctrl->ModalDialog(FALSE);
  489. // Free the Wizzard Pages
  490. for (int j=0; j<iMaxWizard; j++)
  491. {
  492. if ( apwiz[j] >= 0 )
  493. delete apwiz[j];
  494. }
  495. if (!fResult)
  496. return FALSE;
  497. #if 1 // disable for subset filtering
  498. memcpy(pInfoType->m_pInfoTypes, infoParam.pInfoTypes, lcSize(pInfoType->m_pInfoTypes));
  499. #endif
  500. return TRUE;
  501. }
  502. //=--------------------------------------------------------------------------=
  503. // ActiveX Event Firing
  504. //=--------------------------------------------------------------------------=
  505. static VARTYPE rgBstr[] = { VT_BSTR };
  506. typedef enum {
  507. HHCtrlEvent_Click = 0,
  508. } HHCTRLEVENTS;
  509. static EVENTINFO rgHHCtrlEvents [] = {
  510. { DISPID_ONCLICK, 1, rgBstr } // Click method
  511. };
  512. //=--------------------------------------------------------------------------=
  513. // CHtmlHelpControl Class
  514. //=--------------------------------------------------------------------------=
  515. AUTO_CLASS_COUNT_CHECK( CHtmlHelpControl );
  516. CHtmlHelpControl::CHtmlHelpControl(IUnknown *pUnkOuter)
  517. : CInternetControl(pUnkOuter, OBJECT_TYPE_CTLHHCTRL, (IDispatch *)this)
  518. {
  519. memset(&m_state, 0, sizeof(HHCTRLCTLSTATE));
  520. m_state.bmpPath = 0;
  521. m_clrFont = CLR_INVALID;
  522. m_hpadding = -1;
  523. m_vpadding = -1;
  524. m_readystate = bdsNoBitsYet;
  525. m_ptoc = NULL;
  526. m_pindex = NULL;
  527. m_hfont = NULL;
  528. bSharedFont = FALSE;
  529. m_pszBitmap = NULL;
  530. m_pszWebMap = NULL;
  531. m_pszActionData = NULL;
  532. m_pwszButtonText = NULL;
  533. m_fButton = FALSE;
  534. m_fBuiltInImage = FALSE;
  535. m_ptblItems = NULL;
  536. m_hbrBackGround = NULL;
  537. m_hImage = NULL;
  538. m_pSiteMap = NULL;
  539. m_hwndHelp = NULL;
  540. m_pszEventString = NULL;
  541. m_pWebBrowserApp = NULL;
  542. m_ptblTitles = NULL;
  543. m_ptblURLs = NULL;
  544. m_ptblLocations = NULL;
  545. m_pszFrame = NULL;
  546. m_pszWindow = NULL;
  547. m_pszDefaultTopic = NULL;
  548. m_pInfoType = NULL;
  549. if (!g_hmodHHA && !g_fTriedHHA)
  550. LoadHHA(NULL, _Module.GetModuleInstance());
  551. m_pSelectedIndexInfoTypes = NULL;
  552. m_lpfnlStaticTextControlWndProc = NULL;
  553. m_hwndDisplayButton = NULL;
  554. m_dc = NULL;
  555. m_idBitmap = -1;
  556. m_fWinHelpPopup = 0;
  557. m_fPopupMenu = 0;
  558. memset( &m_rcButton, 0, sizeof(m_rcButton) );
  559. m_fIcon = 0;
  560. m_oldSize = 0;
  561. m_clrFontDisabled = GetSysColor(COLOR_GRAYTEXT);
  562. m_clrFontLink = RGB(0,0,255);
  563. m_clrFontLinkVisited = RGB(128,0,128);
  564. m_clrFontHover = RGB(255,0,0);
  565. m_szFontSpec[0] = '\0';
  566. m_Charset = -1;
  567. m_pIFont = 0;
  568. }
  569. CHtmlHelpControl::~CHtmlHelpControl ()
  570. {
  571. if (IsValidWindow(m_hwndHelp))
  572. DestroyWindow(m_hwndHelp);
  573. if ( m_pIFont && m_hfont )
  574. {
  575. m_pIFont->AddRefHfont(m_hfont);
  576. m_pIFont->ReleaseHfont(m_hfont);
  577. m_pIFont->Release();
  578. m_hfont = 0;
  579. }
  580. if (m_state.bmpPath)
  581. delete m_state.bmpPath;
  582. if (m_hfont && !bSharedFont )
  583. DeleteObject(m_hfont);
  584. if (m_pszActionData)
  585. lcFree(m_pszActionData);
  586. if ( m_pindex )
  587. delete m_pindex;
  588. if ( m_ptoc )
  589. delete m_ptoc;
  590. if (m_pwszButtonText)
  591. lcFree(m_pwszButtonText);
  592. if (m_pszBitmap)
  593. lcFree(m_pszBitmap);
  594. if (m_pszWebMap)
  595. lcFree(m_pszWebMap);
  596. if (m_ptblItems)
  597. delete m_ptblItems;
  598. if (m_pSiteMap)
  599. delete m_pSiteMap;
  600. if (m_hbrBackGround)
  601. DeleteObject((HGDIOBJ) m_hbrBackGround);
  602. if (!m_fBuiltInImage && m_hImage)
  603. DeleteObject(m_hImage);
  604. if (m_pszEventString)
  605. lcFree(m_pszEventString);
  606. if (m_pszFrame)
  607. lcFree(m_pszFrame);
  608. if (m_pszWindow)
  609. lcFree(m_pszWindow);
  610. if (m_pszDefaultTopic)
  611. lcFree(m_pszDefaultTopic);
  612. if (m_pWebBrowserApp)
  613. delete m_pWebBrowserApp;
  614. if (m_ptblTitles)
  615. delete m_ptblTitles;
  616. if (m_ptblURLs)
  617. delete m_ptblURLs;
  618. if ( m_ptblLocations )
  619. delete m_ptblLocations;
  620. #if 0
  621. if (m_dibFile)
  622. delete m_dibFile;
  623. if (m_dib)
  624. delete m_dib;
  625. #endif
  626. #if 0 // it appears that someone else (IE maybe) is destroying this for us
  627. if( m_hwndDisplayButton && IsValidWindow(m_hwndDisplayButton) )
  628. if( DestroyWindow( m_hwndDisplayButton ) == 0 )
  629. DWORD dwError = GetLastError();
  630. #endif
  631. #ifdef _DEBUG
  632. m_ptoc = NULL;
  633. m_pindex = NULL;
  634. m_state.bmpPath = 0;
  635. m_hfont = 0;
  636. m_pszActionData = 0;
  637. m_pwszButtonText = 0;
  638. m_pszBitmap = 0;
  639. m_pszWebMap = 0;
  640. m_ptblItems = 0;
  641. m_pSiteMap = 0;
  642. m_hImage = NULL;
  643. m_hbrBackGround = 0;
  644. m_pszEventString = 0;
  645. m_pszFrame = 0;
  646. m_pszWindow = 0;
  647. m_pWebBrowserApp = 0;
  648. m_ptblTitles = 0;
  649. m_ptblURLs = 0;
  650. m_ptblLocations = 0;
  651. #endif
  652. }
  653. //=--------------------------------------------------------------------------=
  654. // CHtmlHelpControl::Create
  655. //=--------------------------------------------------------------------------=
  656. //
  657. IUnknown* CHtmlHelpControl::Create(IUnknown *pUnkOuter)
  658. {
  659. // make sure we return the private unknown so that we support aggregation
  660. // correctly!
  661. CHtmlHelpControl *pNew = new CHtmlHelpControl(pUnkOuter);
  662. return pNew->PrivateUnknown();
  663. }
  664. //=--------------------------------------------------------------------------=
  665. // CHtmlHelpControl::RegisterClassData
  666. //=--------------------------------------------------------------------------=
  667. //
  668. BOOL CHtmlHelpControl::RegisterClassData(void)
  669. {
  670. WNDCLASS wndclass;
  671. ZeroMemory(&wndclass, sizeof(WNDCLASS));
  672. wndclass.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
  673. wndclass.lpfnWndProc = CInternetControl::ControlWindowProc;
  674. wndclass.hInstance = _Module.GetModuleInstance();
  675. switch (m_action) {
  676. // Non-UI or specialized UI
  677. case ACT_CONTENTS:
  678. case ACT_INDEX:
  679. case ACT_SPLASH:
  680. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  681. break;
  682. default:
  683. if (!m_fButton)
  684. wndclass.hCursor = LoadCursor(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDCUR_HAND));
  685. else
  686. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  687. break;
  688. }
  689. wndclass.hbrBackground =
  690. m_hbrBackGround ? m_hbrBackGround : (HBRUSH)(COLOR_WINDOW + 1);
  691. wndclass.lpszClassName = WNDCLASSNAMEOFCONTROL(OBJECT_TYPE_CTLHHCTRL);
  692. DBWIN("Class registered");
  693. return RegisterClass(&wndclass);
  694. }
  695. //=--------------------------------------------------------------------------=
  696. // CHtmlHelpControl::ShouldCreateWindow
  697. //=--------------------------------------------------------------------------=
  698. //
  699. // Essintialy called from Controls DoVerb() on OLEIVERB_SHOW, OLEIVERB_UIACTIVATE,
  700. // and OLEIVERB_INPLACEACTIVATE calls. We can safely implement code in this function
  701. // to cancel the creation of an ole control window.
  702. //
  703. // Output:
  704. // BOOL - false don't create the control.
  705. //
  706. BOOL CHtmlHelpControl::ShouldCreateWindow()
  707. {
  708. if ( (m_action == ACT_CONTENTS) || (m_action == ACT_INDEX) || (m_action == ACT_SPLASH))
  709. return TRUE;
  710. else return m_fButton;
  711. }
  712. //=--------------------------------------------------------------------------=
  713. // CHtmlHelpControl::BeforeCreateWindow
  714. //=--------------------------------------------------------------------------=
  715. // called just before the window is created. Great place to set up the
  716. // window title, etc, so that they're passed in to the call to CreateWindowEx.
  717. // speeds things up slightly.
  718. //
  719. // Parameters:
  720. // DWORD * - [out] dwWindowFlags
  721. // DWORD * - [out] dwExWindowFlags
  722. // LPSTR - [out] name of window to create
  723. //
  724. // Output:
  725. // BOOL - false means fatal error
  726. BOOL CHtmlHelpControl::BeforeCreateWindow(DWORD *pdwWindowStyle,
  727. DWORD *pdwExWindowStyle, LPSTR pszWindowTitle)
  728. {
  729. /*
  730. * TODO: users should set the values of *pdwWindowStyle,
  731. * *pdwExWindowStyle, and pszWindowTitle so that the call to
  732. * CreateWindowEx can use them. setting them here instead of calling
  733. * SetWindowStyle in WM_CREATE is a huge perf win if you don't use this
  734. * function, then you can probably just remove it.
  735. */
  736. switch (m_action)
  737. {
  738. case ACT_CONTENTS:
  739. break;
  740. case ACT_INDEX:
  741. *pdwExWindowStyle = WS_EX_CONTROLPARENT; // allow tab key in children
  742. break;
  743. case ACT_SPLASH:
  744. break;
  745. default:
  746. break;
  747. }
  748. return TRUE;
  749. }
  750. //=--------------------------------------------------------------------------=
  751. // CHtmlHelpControl::AfterCreateWindow
  752. //=--------------------------------------------------------------------------=
  753. //
  754. BOOL CHtmlHelpControl::AfterCreateWindow()
  755. {
  756. switch (m_action) {
  757. case ACT_CONTENTS:
  758. if (!m_ptblItems) {
  759. AuthorMsg(IDS_MUST_SPECIFY_HHC);
  760. break;
  761. }
  762. LoadContentsFile(
  763. IsEmptyString(m_pszWebMap) ? m_ptblItems->GetPointer(1) : m_pszWebMap);
  764. m_ptoc->SetStyles(m_flags[0], m_flags[1]);
  765. if (IsValidWindow(m_ptoc->m_hwndTree))
  766. return TRUE;
  767. if (!m_ptoc->Create(m_hwnd)) {
  768. // BUGBUG: default to a generic display
  769. return FALSE; // window can't be created
  770. }
  771. m_ptoc->m_fHack = FALSE;
  772. m_ptoc->InitTreeView();
  773. return TRUE;
  774. case ACT_INDEX:
  775. if (!m_ptblItems) {
  776. AuthorMsg(IDS_MUST_SPECIFY_HHC);
  777. break;
  778. }
  779. LoadIndexFile(IsEmptyString(m_pszWebMap) ? m_ptblItems->GetPointer(1) : m_pszWebMap);
  780. if ( m_pindex )
  781. m_pindex->m_phhctrl = this;
  782. if (!m_pindex || !m_pindex->Create(m_hwnd)) {
  783. // BUGBUG: default to a generic display
  784. return FALSE; // window can't be created
  785. }
  786. return TRUE;
  787. case ACT_SPLASH:
  788. CreateSplash();
  789. return TRUE;
  790. case ACT_TEXT_POPUP:
  791. case ACT_ALINK:
  792. case ACT_KLINK: {
  793. IHTMLDocument2* pHTMLDocument2 = NULL;
  794. if( m_pWebBrowserApp ) {
  795. LPDISPATCH lpDispatch = m_pWebBrowserApp->GetDocument();
  796. if( lpDispatch && SUCCEEDED(lpDispatch->QueryInterface(IID_IHTMLDocument2, (void **)&pHTMLDocument2))) {
  797. m_clrFontDisabled = GetSysColor(COLOR_GRAYTEXT);
  798. VARIANT varColor;
  799. ::VariantInit(&varColor);
  800. if( SUCCEEDED( pHTMLDocument2->get_linkColor(&varColor) ) )
  801. {
  802. m_clrFontLink = IEColorToWin32Color(varColor.puiVal);
  803. VariantClear(&varColor); // Delete memory allocated.
  804. }
  805. ::VariantInit(&varColor);
  806. if( SUCCEEDED( pHTMLDocument2->get_vlinkColor(&varColor) ) )
  807. {
  808. m_clrFontLinkVisited = IEColorToWin32Color(varColor.puiVal);
  809. VariantClear(&varColor); // Delete memory allocated.
  810. }
  811. #if 0 // [PaulTi] I don't know how to query this from IE4 -- so red it is for now
  812. ::VariantInit(&varColor);
  813. if( SUCCEEDED( pHTMLDocument2->get_alinkColor(&varColor) ) )
  814. {
  815. m_clrFontHover = IEColorToWin32Color(varColor.puiVal);
  816. VariantClear(&varColor); // Delete memory allocated.
  817. }
  818. #endif
  819. }
  820. if( lpDispatch )
  821. lpDispatch->Release();
  822. }
  823. if( pHTMLDocument2 )
  824. pHTMLDocument2->Release();
  825. }
  826. // intentionally fall thru
  827. default:
  828. if (m_fButton) {
  829. if (!CreateOnClickButton()) {
  830. // BUGBUG: default to a generic display
  831. return FALSE; // window can't be created
  832. }
  833. {
  834. SIZE size;
  835. size.cx = RECT_WIDTH(m_rcButton);
  836. size.cy = RECT_HEIGHT(m_rcButton);
  837. SetControlSize(&size);
  838. }
  839. ShowWindow(m_hwndDisplayButton, SW_SHOW);
  840. break;
  841. }
  842. break;
  843. }
  844. // REVIEW: not necessary if we aren't using 256-color bitmaps. Also,
  845. // shouldn't we be destroying this palette when we are done with it?
  846. #if 0
  847. m_dc = ::GetDC(m_hwnd);
  848. HPALETTE hpal = ::CreateHalftonePalette(m_dc);
  849. ::SelectPalette(m_dc, hpal, TRUE);
  850. #endif
  851. UpdateImage();
  852. return TRUE;
  853. }
  854. //=--------------------------------------------------------------------------=
  855. // CHtmlHelpControl::LoadTextState
  856. //=--------------------------------------------------------------------------=
  857. // load in our text state for this control.
  858. //
  859. // Parameters:
  860. // IPropertyBag * - [in] property bag to read from
  861. // IErrorLog * - [in] errorlog object to use with proeprty bag
  862. //
  863. // Output:
  864. // HRESULT
  865. //
  866. // Notes:
  867. // - NOTE: if you have a binary object, then you should pass an unknown
  868. // pointer to the property bag, and it will QI it for IPersistStream, and
  869. // get said object to do a Load()
  870. //
  871. //
  872. // We expect to see a single Name=Command, Value=command type followed by
  873. // any number of Name=Item<n> where n is any sequential digit. Note that in
  874. // some cases, the command value will include optional information
  875. // affecting the command.
  876. //
  877. // WinHelp Popup, help file
  878. // item1 = number or string for WinHelp popup
  879. // Text Popup
  880. // item1 = popup text
  881. //
  882. // AboutBox, title
  883. // item 1-3 = lines 1-3
  884. //
  885. // Related Topics[, Dialog | Menu] (default is Dialog)
  886. // item1=title=url
  887. // ...
  888. // item<n>=title=url
  889. // Contents, file.cnt
  890. // Index, file.kwd
  891. //
  892. STDMETHODIMP CHtmlHelpControl::LoadTextState(IPropertyBag *pPropertyBag,
  893. IErrorLog *pErrorLog)
  894. {
  895. VARIANT v;
  896. HRESULT hr;
  897. ZeroMemory(&v, sizeof(VARIANT));
  898. VariantInit(&v);
  899. v.vt = VT_BSTR;
  900. v.bstrVal = NULL;
  901. CHHWinType* phh = NULL;
  902. HWND hWnd;
  903. ZeroMemory(m_flags, sizeof(m_flags));
  904. m_flags[2] = (DWORD) -1;
  905. if ( (hWnd = GetHtmlHelpFrameWindow()) ) // Tunnels from the ActiveX control through IE to get to the HWND of HHCTRL.
  906. {
  907. if ( (phh = FindHHWindowIndex(hWnd)) )
  908. m_Charset = phh->GetContentCharset();
  909. }
  910. m_imgType = IMG_BITMAP; // default image type
  911. // Get the command for this control to perform
  912. hr = pPropertyBag->Read(txtwCommand, &v, pErrorLog);
  913. if (SUCCEEDED(hr)) {
  914. MAKE_ANSIPTR_FROMWIDE(psz, v.bstrVal);
  915. if (!g_fIE3) // fix for bug 5664, 5665
  916. VariantClear(&v); // Delete memory allocated for BSTR
  917. /*
  918. #ifdef _DEBUG
  919. {
  920. char szMsg[512];
  921. wsprintf(szMsg, "Command: %s\r\n", psz);
  922. SendStringToParent(szMsg);
  923. }
  924. #endif
  925. */
  926. // truncate command at 255 characters
  927. //
  928. if(strlen(psz) > 255)
  929. psz[255] = 0;
  930. // Always save a copy in this string...
  931. //
  932. lstrcpy(m_szRawAction, psz);
  933. if (isSameString(psz, txtWinHelp)) {
  934. // Let author know we're initialized
  935. m_action = ACT_WINHELP;
  936. m_fWinHelpPopup = ( stristr(psz, txtPopup) != NULL );
  937. }
  938. else if (isSameString(psz, txtRelatedTopics)) {
  939. m_action = ACT_RELATED_TOPICS;
  940. SetActionData(psz);
  941. m_fPopupMenu = isSameString(m_pszActionData, txtMenu);
  942. if (!m_pSiteMap)
  943. m_pSiteMap = new CSiteMap(MAX_RELATED_ENTRIES);
  944. }
  945. else if (isSameString(psz, txtActKLink)) {
  946. m_action = ACT_KLINK;
  947. SetActionData(psz);
  948. m_fPopupMenu = isSameString(m_pszActionData, txtMenu);
  949. }
  950. else if (isSameString(psz, txtActALink)) {
  951. m_action = ACT_ALINK;
  952. SetActionData(psz);
  953. m_fPopupMenu = isSameString(m_pszActionData, txtMenu);
  954. }
  955. else if (isSameString(psz, txtActSample)) {
  956. m_action = ACT_SAMPLE;
  957. SetActionData(psz);
  958. m_fPopupMenu = isSameString(m_pszActionData, txtMenu);
  959. }
  960. else if (isSameString(psz, txtKeywordSearch)) {
  961. m_action = ACT_KEYWORD_SEARCH;
  962. SetActionData(psz);
  963. m_fPopupMenu = isSameString(m_pszActionData, txtMenu);
  964. if (!m_pSiteMap)
  965. m_pSiteMap = new CSiteMap(MAX_KEYSEARCH_ENTRIES);
  966. }
  967. else if (isSameString(psz, txtShortcut)) {
  968. m_action = ACT_SHORTCUT;
  969. }
  970. else if (isSameString(psz, txtContents)) {
  971. m_flags[0] = WS_EX_CLIENTEDGE;
  972. m_flags[1] = DEFAULT_TOC_STYLES;
  973. m_action = ACT_CONTENTS;
  974. m_imgType = IMG_CHILD_WINDOW;
  975. SetActionData(psz);
  976. ProcessPadding(m_pszActionData);
  977. }
  978. else if (isSameString(psz, txtIndex))
  979. {
  980. // Let author know we're initialized
  981. m_flags[0] = WS_EX_WINDOWEDGE;
  982. m_action = ACT_INDEX;
  983. m_imgType = IMG_CHILD_WINDOW;
  984. SetActionData(psz);
  985. ProcessPadding(m_pszActionData);
  986. // see if the client has requested RTL layout
  987. //
  988. if(SUCCEEDED(pPropertyBag->Read(L"LayoutRTL", &v, pErrorLog)))
  989. {
  990. if(v.bstrVal)
  991. {
  992. // convert the value to ANSI
  993. //
  994. char szValue[32];
  995. WideCharToMultiByte(CP_ACP, 0, v.bstrVal, -1, szValue, sizeof(szValue), NULL, NULL);
  996. szValue[sizeof(szValue) - 1] = 0;
  997. VariantClear(&v);
  998. if(!stricmp(szValue, "TRUE"))
  999. {
  1000. // turn on RTL styles
  1001. //
  1002. g_RTL_Mirror_Style = 0;
  1003. g_RTL_Style = WS_EX_RTLREADING | WS_EX_RIGHT;
  1004. g_fuBiDiMessageBox = MB_RIGHT | MB_RTLREADING;
  1005. g_fBiDi = TRUE;
  1006. }
  1007. }
  1008. }
  1009. }
  1010. else if (isSameString(psz, txtHhCtrlVersion)) {
  1011. m_action = ACT_HHCTRL_VERSION;
  1012. }
  1013. else if (isSameString(psz, txtSplash)) {
  1014. m_action = ACT_SPLASH;
  1015. }
  1016. else if (isSameString(psz, txtTCard)) {
  1017. m_action = ACT_TCARD;
  1018. }
  1019. else if (isSameString(psz, txtClose)) {
  1020. m_action = ACT_CLOSE;
  1021. }
  1022. else if (isSameString(psz, txtHHWinPrint)) {
  1023. m_action = ACT_HHWIN_PRINT;
  1024. }
  1025. else if (isSameString(psz, txtMinimize)) {
  1026. m_action = ACT_MINIMIZE;
  1027. }
  1028. else if (isSameString(psz, txtMaximize)) {
  1029. m_action = ACT_MAXIMIZE;
  1030. }
  1031. else if (isSameString(psz, txtAboutBox)) {
  1032. // Let author know we're initialized
  1033. m_action = ACT_ABOUT_BOX;
  1034. SetActionData(psz);
  1035. }
  1036. else {
  1037. AuthorMsg(IDS_INVALID_INITIALIZER, psz);
  1038. return E_INVALIDARG;
  1039. }
  1040. //
  1041. // DANGER! DANGER! DANGER! DANGER! DANGER! DANGER! DANGER!
  1042. //
  1043. // [PaulTi] so far the code block below has been accidently
  1044. // removed twice with new checkins and has totally broken A/KLinks.
  1045. //
  1046. // Before ANYONE changes this code you must check with PaulTi
  1047. // to make sure you have not caused this code to break again
  1048. // (three strikes and you are out!).
  1049. //
  1050. // get the remaining arguments
  1051. PSTR pszArguments = StrChr(psz, ',');
  1052. if( pszArguments && *pszArguments == ',' ) // skip over the comma
  1053. pszArguments++;
  1054. pszArguments = FirstNonSpace(pszArguments); // skip over whitespace
  1055. while (pszArguments && *pszArguments) {
  1056. if (isSameString(pszArguments, txtBitmap)) {
  1057. // Skip to the filename
  1058. PSTR pszFile = FirstNonSpace(pszArguments + strlen(txtBitmap));
  1059. pszArguments = StrChr(pszFile, ',');
  1060. if( *pszArguments == ',' )
  1061. pszArguments++; // skip over the comma
  1062. if (pszArguments) {
  1063. *pszArguments = '\0';
  1064. pszArguments = FirstNonSpace(pszArguments + 1);
  1065. }
  1066. RemoveTrailingSpaces(pszFile);
  1067. m_pszBitmap = lcStrDup(pszFile);
  1068. }
  1069. // BUGBUG: finish processing the rest of the commands
  1070. else {
  1071. if( pszArguments ) {
  1072. pszArguments = StrChr(pszArguments, ',');
  1073. if( pszArguments && *pszArguments == ',' ) // skip over the comma
  1074. pszArguments++;
  1075. pszArguments = FirstNonSpace(pszArguments);
  1076. }
  1077. }
  1078. }
  1079. }
  1080. else { // Command not specified
  1081. AuthorMsg(IDS_MISSING_COMMAND, "");
  1082. return E_INVALIDARG;
  1083. }
  1084. // shanemc 7883 - Support bgcolor for index
  1085. if (ACT_INDEX == m_action)
  1086. {
  1087. VARIANT v;
  1088. ZeroMemory(&v, sizeof(VARIANT));
  1089. VariantInit(&v);
  1090. v.vt = VT_BSTR;
  1091. v.bstrVal = NULL;
  1092. // Get the background color
  1093. HRESULT hr = pPropertyBag->Read(txtwBgColor, &v, pErrorLog);
  1094. if (SUCCEEDED(hr) && (v.vt == VT_BSTR)) {
  1095. MAKE_ANSIPTR_FROMWIDE(psz, v.bstrVal);
  1096. VariantClear(&v); // Delete memory allocated for BSTR
  1097. // default to button face color
  1098. ULONG ulColor = GetSysColor(COLOR_BTNFACE);
  1099. // HACK for special case requested by Millennium team: Check for button face color.
  1100. // Really we should check for all the system and named colors supported by IE, but
  1101. // this isn't an ideal world.
  1102. if (strcmpi(psz, "buttonface") == 0) {
  1103. // Don't do anything; default is correct color
  1104. }
  1105. else {
  1106. // Format is like Web--6 hex digits
  1107. if ('#' == *psz) psz++; // skip optional #
  1108. // Only override default if we get a valid number.
  1109. if (isxdigit(*psz)) {
  1110. ulColor = strtoul(psz, NULL, 16);
  1111. // Need to flip the bytes from BGR to RGB
  1112. BYTE bB = static_cast<BYTE>(ulColor & 0xff);
  1113. BYTE bG = static_cast<BYTE>((ulColor >> 8) & 0xff);
  1114. BYTE bR = static_cast<BYTE>(ulColor >> 16);
  1115. ulColor = RGB(bR, bG, bB);
  1116. }
  1117. }
  1118. if (m_hbrBackGround) DeleteObject((HGDIOBJ) m_hbrBackGround);
  1119. m_hbrBackGround = CreateSolidBrush(ulColor);
  1120. m_clrFontHover = ulColor; // HACK!!! this color not used for Index
  1121. // (I don't want to change hhctrl.h to add new var)
  1122. }
  1123. }
  1124. // end shanemc 7883
  1125. // Read all item data starting with Item1, then Item2, etc. until
  1126. // an item isn't found.
  1127. char szBuf[20];
  1128. int iItem = 1;
  1129. for (;;) {
  1130. wsprintf(szBuf, txtItem, iItem++);
  1131. WCHAR uniBuf[sizeof(szBuf) * 2];
  1132. MultiByteToWideChar(CP_ACP, 0, szBuf, -1, uniBuf, sizeof(uniBuf));
  1133. // REVIEW: Do we need to convert to unicode?
  1134. hr = pPropertyBag->Read(uniBuf, &v, pErrorLog);
  1135. if (SUCCEEDED(hr)) {
  1136. // Choose the amount of memory the CTable needs to reserve based
  1137. // on the command
  1138. if (m_ptblItems == NULL) {
  1139. switch (m_action) {
  1140. case ACT_ABOUT_BOX:
  1141. case ACT_CONTENTS:
  1142. case ACT_INDEX:
  1143. case ACT_WINHELP:
  1144. case ACT_SPLASH:
  1145. case ACT_SHORTCUT:
  1146. m_ptblItems = new CTable(4096);
  1147. break;
  1148. case ACT_CLOSE:
  1149. case ACT_MINIMIZE:
  1150. case ACT_MAXIMIZE:
  1151. case ACT_TCARD: // data stored in m_pszActionData, not m_ptblItems
  1152. case ACT_HHWIN_PRINT:
  1153. break;
  1154. case ACT_KLINK:
  1155. case ACT_ALINK:
  1156. m_ptblItems = new CTable(1024 * 1024);
  1157. break;
  1158. case ACT_RELATED_TOPICS:
  1159. case ACT_KEYWORD_SEARCH:
  1160. case ACT_TEXT_POPUP:
  1161. default:
  1162. m_ptblItems = new CTable(256 * 1024);
  1163. break;
  1164. }
  1165. }
  1166. CStr csz(v.bstrVal);
  1167. if ( !g_fIE3 ) // fix for bug 5661 ...
  1168. VariantClear(&v); // Delete memory allocated for BSTR
  1169. if (m_action == ACT_RELATED_TOPICS) {
  1170. // Format is "title;url1;url2
  1171. PSTR pszUrl = StrChr(csz, ';');
  1172. if (pszUrl)
  1173. *pszUrl++ = '\0';
  1174. SITEMAP_ENTRY* pSiteMapEntry = m_pSiteMap->AddEntry();
  1175. if (pSiteMapEntry != NULL)
  1176. {
  1177. ClearMemory(pSiteMapEntry, sizeof(SITEMAP_ENTRY));
  1178. pSiteMapEntry->pszText = m_pSiteMap->StrDup((csz));
  1179. if (pszUrl) {
  1180. CSiteEntryUrl SiteUrl( sizeof(SITE_ENTRY_URL) );
  1181. PSTR psz = pszUrl;
  1182. pszUrl = StrChr(psz, ';');
  1183. if (pszUrl)
  1184. *pszUrl++ = '\0';
  1185. SiteUrl.m_pUrl->urlPrimary = m_pSiteMap->AddUrl(psz);
  1186. if (pszUrl)
  1187. SiteUrl.m_pUrl->urlSecondary = m_pSiteMap->AddUrl(pszUrl);
  1188. SiteUrl.SaveUrlEntry(m_pSiteMap, pSiteMapEntry);
  1189. }
  1190. }
  1191. else
  1192. break;
  1193. }
  1194. else if (m_action == ACT_TCARD) {
  1195. if(!m_pszActionData)
  1196. csz.TransferPointer(&m_pszActionData);
  1197. }
  1198. else if (m_ptblItems) { // not a related topic, so treat normally
  1199. //
  1200. // DANGER! DANGER! DANGER! DANGER! DANGER! DANGER! DANGER!
  1201. //
  1202. // [PaulTi] so far the code block below has been accidently
  1203. // removed twice with new checkins and has totally broken A/KLinks.
  1204. //
  1205. // Before ANYONE changes this code you must check with PaulTi
  1206. // to make sure you have not caused this code to break again
  1207. // (three strikes and you are out!).
  1208. //
  1209. LPSTR psz = FirstNonSpace(csz);
  1210. m_ptblItems->AddString(psz?psz:""); // Save the item
  1211. }
  1212. /* csz can be significantly larger than 512 characters.
  1213. #ifdef _DEBUG
  1214. if (csz.psz) {
  1215. char szMsg[512];
  1216. wsprintf(szMsg, "%s: %s\r\n", szBuf, csz.psz);
  1217. SendStringToParent(szMsg);
  1218. }
  1219. #endif
  1220. */
  1221. }
  1222. else
  1223. break;
  1224. }
  1225. if (m_action != ACT_CONTENTS && m_action != ACT_INDEX) {
  1226. hr = pPropertyBag->Read(txtwButton, &v, pErrorLog);
  1227. if (SUCCEEDED(hr)) {
  1228. CStr csz(v.bstrVal);
  1229. int cb;
  1230. if ((cb = CompareSz(csz, txtText)))
  1231. m_pwszButtonText = lcStrDupW(v.bstrVal + cb);
  1232. else if ((cb = CompareSz(csz, txtBitmap))) {
  1233. m_pszBitmap = lcStrDup(FirstNonSpace(csz.psz + cb));
  1234. m_flags[1] |= BS_BITMAP;
  1235. m_fIcon = FALSE;
  1236. }
  1237. else if ((cb = CompareSz(csz, txtIcon))) {
  1238. m_pszBitmap = lcStrDup(FirstNonSpace(csz.psz + cb));
  1239. m_flags[1] |= BS_ICON;
  1240. m_fIcon = TRUE;
  1241. }
  1242. else // default to a text button
  1243. m_pwszButtonText = lcStrDupW(v.bstrVal);
  1244. m_fButton = TRUE;
  1245. m_imgType = IMG_BUTTON;
  1246. VariantClear(&v); // Delete memory allocated for BSTR
  1247. }
  1248. else { // Button, Text and Icon are mutually exclusive
  1249. hr = pPropertyBag->Read(txtwText, &v, pErrorLog);
  1250. if (SUCCEEDED(hr)) {
  1251. MAKE_ANSIPTR_FROMWIDE(psz, v.bstrVal);
  1252. int cb;
  1253. if ((cb = CompareSz(psz, txtText)))
  1254. {
  1255. WCHAR* pwsz = v.bstrVal + cb;
  1256. while ( *pwsz == L' ' )
  1257. ++pwsz;
  1258. m_pwszButtonText = lcStrDupW(pwsz);
  1259. }
  1260. else if ((cb = CompareSz(psz, txtBitmap))) {
  1261. m_pszBitmap = lcStrDup(FirstNonSpace(psz + cb));
  1262. m_fIcon = FALSE;
  1263. m_flags[1] |= SS_BITMAP;
  1264. }
  1265. else if ((cb = CompareSz(psz, txtIcon))) {
  1266. m_pszBitmap = lcStrDup(FirstNonSpace(psz + cb));
  1267. m_fIcon = TRUE;
  1268. m_flags[1] |= SS_ICON;
  1269. }
  1270. else if (*psz) // no text is a chiclet button
  1271. AuthorMsg(IDS_INVALID_BUTTON_CMD, psz);
  1272. m_fButton = TRUE;
  1273. m_imgType = IMG_TEXT;
  1274. m_flags[1] |= SS_NOTIFY | (m_pszBitmap ? 0 : SS_OWNERDRAW);
  1275. VariantClear(&v); // Delete memory allocated for BSTR
  1276. }
  1277. }
  1278. }
  1279. hr = pPropertyBag->Read(txtwImage, &v, pErrorLog);
  1280. if (SUCCEEDED(hr)) {
  1281. CStr csz(v.bstrVal);
  1282. VariantClear(&v); // Delete memory allocated for BSTR
  1283. SzTrimSz(csz);
  1284. if (m_pszBitmap)
  1285. lcFree(m_pszBitmap);
  1286. csz.TransferPointer(&m_pszBitmap);
  1287. }
  1288. hr = pPropertyBag->Read(txtwWebMap, &v, pErrorLog);
  1289. if (SUCCEEDED(hr)) {
  1290. MAKE_ANSIPTR_FROMWIDE(psz, v.bstrVal);
  1291. VariantClear(&v); // Delete memory allocated for BSTR
  1292. if (m_pszWebMap)
  1293. lcFree(m_pszWebMap);
  1294. m_pszWebMap = lcStrDup(FirstNonSpace(psz));
  1295. RemoveTrailingSpaces((PSTR) m_pszWebMap);
  1296. }
  1297. hr = pPropertyBag->Read(txtwFont, &v, pErrorLog);
  1298. if (SUCCEEDED(hr)) {
  1299. MAKE_ANSIPTR_FROMWIDE(psz, v.bstrVal);
  1300. VariantClear(&v); // Delete memory allocated for BSTR
  1301. if (m_hfont)
  1302. DeleteObject(m_hfont);
  1303. m_hfont = CreateUserFont(psz, &m_clrFont, NULL, m_Charset);
  1304. lstrcpy(m_szFontSpec, psz);
  1305. }
  1306. /*
  1307. * Flags should be read after any command, since commands may set
  1308. * default flag values.
  1309. */
  1310. hr = pPropertyBag->Read(txtwFlags, &v, pErrorLog);
  1311. if ( SUCCEEDED(hr) && (v.vt == VT_BSTR) ) {
  1312. MAKE_ANSIPTR_FROMWIDE(psz, v.bstrVal);
  1313. VariantClear(&v); // Delete memory allocated for BSTR
  1314. for (int i = 0; i < MAX_FLAGS; i++) {
  1315. while (*psz && (*psz < '0' || *psz > '9') && *psz != ',')
  1316. psz++;
  1317. if (!*psz)
  1318. break;
  1319. if (*psz != ',')
  1320. m_flags[i] = Atoi(psz);
  1321. psz = strchr(psz, ',');
  1322. if (!psz)
  1323. break;
  1324. psz = FirstNonSpace(psz + 1);
  1325. }
  1326. if (m_flags[2] != (DWORD) -1 && m_action != ACT_KLINK && m_action != ACT_ALINK) {
  1327. if (m_hbrBackGround)
  1328. DeleteObject((HGDIOBJ) m_hbrBackGround);
  1329. m_hbrBackGround = CreateSolidBrush(m_flags[2]);
  1330. }
  1331. }
  1332. hr = pPropertyBag->Read(txtwFrame, &v, pErrorLog);
  1333. if (SUCCEEDED(hr)) {
  1334. CStr csz(v.bstrVal);
  1335. VariantClear(&v); // Delete memory allocated for BSTR
  1336. if (m_pSiteMap)
  1337. m_pSiteMap->SetFrameName(csz);
  1338. else {
  1339. if (m_pszFrame)
  1340. lcFree(m_pszFrame);
  1341. csz.TransferPointer(&m_pszFrame);
  1342. }
  1343. }
  1344. hr = pPropertyBag->Read(txtwWindow, &v, pErrorLog);
  1345. if (SUCCEEDED(hr)) {
  1346. CStr csz(v.bstrVal);
  1347. VariantClear(&v); // Delete memory allocated for BSTR
  1348. if (m_pSiteMap)
  1349. m_pSiteMap->SetWindowName(csz);
  1350. else {
  1351. if (m_pszWindow)
  1352. lcFree(m_pszWindow);
  1353. csz.TransferPointer(&m_pszWindow);
  1354. }
  1355. }
  1356. hr = pPropertyBag->Read(txtwDefaultTopic, &v, pErrorLog);
  1357. if (SUCCEEDED(hr)) {
  1358. CStr csz(v.bstrVal);
  1359. VariantClear(&v); // Delete memory allocated for BSTR
  1360. csz.TransferPointer(&m_pszDefaultTopic);
  1361. }
  1362. //
  1363. // We need to create an appropiate font for the display of alinks/klinks/dynalinks. This
  1364. // needs to be a content font rather than a UI font.
  1365. //
  1366. if (! m_hfont )
  1367. {
  1368. if ( phh )
  1369. {
  1370. m_hfont = phh->GetContentFont();
  1371. bSharedFont = TRUE;
  1372. }
  1373. if (! m_hfont ) // This code asks our container (IE) for a resolable font.
  1374. {
  1375. if ( GetAmbientFont(&m_pIFont) )
  1376. {
  1377. m_pIFont->get_hFont(&m_hfont);
  1378. m_pIFont->AddRefHfont(m_hfont);
  1379. #ifdef _DEBUG
  1380. LOGFONT lf ;
  1381. int r = GetObject(m_hfont, sizeof(lf), &lf) ;
  1382. #endif
  1383. }
  1384. }
  1385. }
  1386. if (! m_hfont )
  1387. m_hfont = CreateUserFont(GetStringResource(IDS_DEFAULT_CONTENT_FONT)); // Last resort!
  1388. //
  1389. // Now figure out a charset identifier and codepage...
  1390. //
  1391. CHARSETINFO cs;
  1392. if ( phh )
  1393. {
  1394. m_Charset = phh->GetContentCharset();
  1395. if ( TranslateCharsetInfo ((DWORD *)(DWORD_PTR)MAKELONG(m_Charset, 0), &cs, TCI_SRCCHARSET) )
  1396. m_CodePage = cs.ciACP;
  1397. else
  1398. m_CodePage = CP_ACP;
  1399. }
  1400. else
  1401. {
  1402. TEXTMETRIC tm;
  1403. HDC hDC;
  1404. HFONT hFontOrig;
  1405. hDC = GetDC(NULL);
  1406. hFontOrig = (HFONT)SelectObject(hDC, m_hfont);
  1407. GetTextMetrics (hDC, &tm);
  1408. if ( TranslateCharsetInfo ((DWORD *)(DWORD_PTR)MAKELONG(tm.tmCharSet, 0), &cs, TCI_SRCCHARSET) )
  1409. m_CodePage = cs.ciACP;
  1410. else
  1411. m_CodePage = CP_ACP;
  1412. m_Charset = tm.tmCharSet;
  1413. SelectObject(hDC, hFontOrig);
  1414. ReleaseDC(NULL, hDC);
  1415. }
  1416. _Module.SetCodePage(m_CodePage);
  1417. return S_OK;
  1418. }
  1419. //=--------------------------------------------------------------------------=
  1420. // CHtmlHelpControl::SetActionData
  1421. //=--------------------------------------------------------------------------=
  1422. //
  1423. void CHtmlHelpControl::SetActionData(PCSTR psz)
  1424. {
  1425. m_pszActionData = StrChr(psz, ',');
  1426. if (m_pszActionData) {
  1427. m_pszActionData = lcStrDup(FirstNonSpace(m_pszActionData + 1));
  1428. }
  1429. }
  1430. //=--------------------------------------------------------------------------=
  1431. // CHtmlHelpControl::ProcessPadding
  1432. //=--------------------------------------------------------------------------=
  1433. //
  1434. void CHtmlHelpControl::ProcessPadding(PCSTR pszPad)
  1435. {
  1436. if (IsEmptyString(pszPad))
  1437. return;
  1438. PCSTR psz = stristr(pszPad, txtHPad);
  1439. if (psz) {
  1440. psz = FirstNonSpace(psz + strlen(txtHPad));
  1441. m_hpadding = Atoi(psz);
  1442. }
  1443. psz = stristr(pszPad, txtVPad);
  1444. if (psz) {
  1445. psz = FirstNonSpace(psz + strlen(txtVPad));
  1446. m_vpadding = Atoi(psz);
  1447. }
  1448. }
  1449. //=--------------------------------------------------------------------------=
  1450. // CHtmlHelpControl::SaveTextState
  1451. //=--------------------------------------------------------------------------=
  1452. // saves properties using IPropertyBag.
  1453. //
  1454. // Parameters:
  1455. // IPropertyBag * - [in] stream to write to.
  1456. // fWriteDefault - [in] ?
  1457. //
  1458. // Output:
  1459. // HRESULT
  1460. //
  1461. // Notes:
  1462. //
  1463. STDMETHODIMP CHtmlHelpControl::SaveTextState(IPropertyBag *pPropertyBag, BOOL fWriteDefault)
  1464. {
  1465. // Save the state of various properties.
  1466. WCHAR uniBufProperty[MAX_URL];
  1467. WCHAR uniBufValue[MAX_URL];
  1468. VARIANT v;
  1469. char szBuf[20];
  1470. char szTmp[MAX_URL];
  1471. int iItem = 1;
  1472. HRESULT hr = S_OK;
  1473. CHECK_POINTER(pPropertyBag);
  1474. //
  1475. // Remember the action data. i.e. ACT_KLINK, ACT_SAMPLE, ect.
  1476. //
  1477. MultiByteToWideChar(CP_ACP, 0, m_szRawAction, -1, uniBufValue, MAX_URL); // Value.
  1478. v.vt = VT_BSTR;
  1479. v.bstrVal = SysAllocString(uniBufValue);
  1480. pPropertyBag->Write(txtwCommand, &v);
  1481. VariantClear(&v);
  1482. //
  1483. // Now remember all the parameters we put into the CTable...
  1484. //
  1485. while ( m_ptblItems && m_ptblItems->GetString(szTmp, iItem) )
  1486. {
  1487. wsprintf(szBuf, txtItem, iItem++);
  1488. MultiByteToWideChar(CP_ACP, 0, szBuf, -1, uniBufProperty, MAX_URL); // Property.
  1489. MultiByteToWideChar(CP_ACP, 0, szTmp, -1, uniBufValue, MAX_URL); // Value.
  1490. v.vt = VT_BSTR;
  1491. v.bstrVal = SysAllocString(uniBufValue);
  1492. pPropertyBag->Write(uniBufProperty, &v);
  1493. VariantClear(&v);
  1494. }
  1495. //
  1496. // Lastly, restore the button text and font.
  1497. //
  1498. if ( m_pwszButtonText )
  1499. {
  1500. v.vt = VT_BSTR;
  1501. v.bstrVal = SysAllocString(m_pwszButtonText);
  1502. pPropertyBag->Write(txtwButton, &v);
  1503. VariantClear(&v);
  1504. }
  1505. if ( m_szFontSpec[0] )
  1506. {
  1507. MultiByteToWideChar(CP_ACP, 0, m_szFontSpec, -1, uniBufValue, MAX_URL); // Value.
  1508. v.vt = VT_BSTR;
  1509. v.bstrVal = SysAllocString(uniBufValue);
  1510. pPropertyBag->Write(txtwFont, &v);
  1511. VariantClear(&v);
  1512. }
  1513. return hr;
  1514. }
  1515. //=--------------------------------------------------------------------------=
  1516. // CHtmlHelpControl::LoadBinaryState
  1517. //=--------------------------------------------------------------------------=
  1518. // loads in our binary state using streams.
  1519. //
  1520. // Parameters:
  1521. // IStream * - [in] stream to write to.
  1522. //
  1523. // Output:
  1524. // HRESULT
  1525. //
  1526. // Notes:
  1527. //
  1528. STDMETHODIMP CHtmlHelpControl::LoadBinaryState(IStream *pStream)
  1529. {
  1530. DWORD sh;
  1531. HRESULT hr;
  1532. // first read in the streamhdr, and make sure we like what we're getting
  1533. hr = pStream->Read(&sh, sizeof(sh), NULL);
  1534. RETURN_ON_FAILURE(hr);
  1535. // sanity check
  1536. if (sh != STREAMHDR_MAGIC)
  1537. return E_UNEXPECTED;
  1538. hr = pStream->Read(&(m_state.endDate), sizeof(m_state.endDate), NULL);
  1539. return(SetBmpPath(pStream));
  1540. }
  1541. //=--------------------------------------------------------------------------=
  1542. // CHtmlHelpControl::SaveBinaryState
  1543. //=--------------------------------------------------------------------------=
  1544. //
  1545. STDMETHODIMP CHtmlHelpControl::SaveBinaryState(IStream *pStream)
  1546. {
  1547. return S_OK;
  1548. }
  1549. //=--------------------------------------------------------------------------=
  1550. // CHtmlHelpControl::SetClientSite [IOleObject]
  1551. //=--------------------------------------------------------------------------=
  1552. // informs the embedded object [control] of it's client site [display
  1553. // location] within it's container
  1554. //
  1555. // Parameters:
  1556. // IOleClientSite * - [in] pointer to client site.
  1557. //
  1558. // Output:
  1559. // HRESULT - S_OK, E_UNEXPECTED
  1560. STDMETHODIMP CHtmlHelpControl::SetClientSite(IOleClientSite* pClientSite)
  1561. {
  1562. // Call the base class implementation first.
  1563. HRESULT hr = CInternetControl::SetClientSite(pClientSite);
  1564. LPSERVICEPROVIDER pISP;
  1565. if (m_pClientSite != NULL)
  1566. {
  1567. hr = m_pClientSite->QueryInterface(IID_IServiceProvider, (LPVOID*)&pISP);
  1568. if (SUCCEEDED(hr))
  1569. {
  1570. LPDISPATCH pIEDisp = NULL;
  1571. hr = pISP->QueryService(IID_IWebBrowserApp, IID_IDispatch, (LPVOID*)&pIEDisp);
  1572. if (SUCCEEDED(hr))
  1573. {
  1574. m_pWebBrowserApp = new IWebBrowserAppImpl(pIEDisp);
  1575. }
  1576. #ifdef _DEBUG
  1577. if (FAILED(hr))
  1578. OutputDebugString("Failed to get a pointer to IE's IDispatch\n");
  1579. #endif
  1580. pISP->Release();
  1581. return S_OK; // It's ok to fail the IWebBrowserApp wireing when we're printing.
  1582. }
  1583. }
  1584. return hr;
  1585. }
  1586. //=--------------------------------------------------------------------------=
  1587. // CHtmlHelpControl::OnDraw
  1588. //=--------------------------------------------------------------------------=
  1589. //
  1590. // Parameters:
  1591. // DWORD - [in] drawing aspect
  1592. // HDC - [in] HDC to draw to
  1593. // LPCRECTL - [in] rect we're drawing to
  1594. // LPCRECTL - [in] window extent and origin for meta-files
  1595. // HDC - [in] HIC for target device
  1596. // BOOL - [in] can we optimize dc handling?
  1597. HRESULT CHtmlHelpControl::OnDraw(DWORD dvaaspect, HDC hdcDraw,
  1598. LPCRECTL prcBounds, LPCRECTL prcWBounds, HDC hicTargetDevice,
  1599. BOOL fOptimize)
  1600. {
  1601. if (DesignMode()) {
  1602. HBRUSH hBrush = (HBRUSH)GetStockObject(BLACK_BRUSH);
  1603. FillRect(hdcDraw, (LPRECT)prcBounds, hBrush);
  1604. return S_OK;
  1605. }
  1606. if (prcWBounds != NULL) { // printing to a metafile ?
  1607. DBWIN("Metafile Printing not currently supported. <mikecole>");
  1608. return S_OK;
  1609. }
  1610. // Are we printing to a printer DC ?
  1611. //
  1612. if ( GetDeviceCaps(hdcDraw, TECHNOLOGY) == DT_RASPRINTER )
  1613. {
  1614. // On IE4 we have to do the printing ourselves.
  1615. //
  1616. if ( m_imgType != IMG_BITMAP && m_pwszButtonText && *m_pwszButtonText )
  1617. {
  1618. HFONT hfont;
  1619. if ( m_szFontSpec[0] )
  1620. hfont = CreateUserFont(m_szFontSpec, NULL, hdcDraw, m_Charset);
  1621. else
  1622. hfont = _Resource.DefaultPrinterFont(hdcDraw);
  1623. HFONT hfontOld = (HFONT) SelectObject(hdcDraw, hfont);
  1624. IntlExtTextOutW(hdcDraw, prcBounds->left, prcBounds->top, 0, NULL, m_pwszButtonText, lstrlenW(m_pwszButtonText), NULL);
  1625. SelectObject(hdcDraw, hfontOld);
  1626. DeleteObject(hfont);
  1627. }
  1628. return S_OK;
  1629. }
  1630. switch(m_imgType) {
  1631. case IMG_CHILD_WINDOW:
  1632. return S_OK; // no background to redraw
  1633. case IMG_TEXT:
  1634. case IMG_BUTTON:
  1635. return S_OK;
  1636. }
  1637. if ( (m_idBitmap == 0 || m_idBitmap == -1) && m_pszBitmap == NULL)
  1638. {
  1639. SIZEL szl;
  1640. szl.cx = 0;
  1641. szl.cy = 0;
  1642. SetControlSize(&szl);
  1643. }
  1644. else
  1645. {
  1646. HDC hdcTemp = CreateCompatibleDC(hdcDraw);
  1647. HBITMAP hBitmap = LoadBitmap(_Module.GetResourceInstance(), "shortcut");
  1648. HBITMAP hOld = (HBITMAP) SelectObject(hdcTemp, hBitmap);
  1649. BITMAP bm;
  1650. GetObject(hBitmap, sizeof(BITMAP), (LPSTR) &bm);
  1651. POINT ptSize;
  1652. ptSize.x = bm.bmWidth; // Get width of bitmap
  1653. ptSize.y = bm.bmHeight; // Get height of bitmap
  1654. DPtoLP(hdcTemp, &ptSize, 1); // Convert from device
  1655. // to logical points
  1656. SIZEL szl;
  1657. szl.cx = bm.bmWidth;
  1658. szl.cy = bm.bmHeight;
  1659. SetControlSize(&szl);
  1660. SelectObject(hdcTemp,hOld);
  1661. DeleteDC( hdcTemp );
  1662. DeleteObject(hBitmap);
  1663. }
  1664. return S_OK;
  1665. }
  1666. //=--------------------------------------------------------------------------=
  1667. // CHtmlHelpControl::WindowProc
  1668. //=--------------------------------------------------------------------------=
  1669. //
  1670. LRESULT CHtmlHelpControl::WindowProc(UINT msg, WPARAM wParam, LPARAM lParam)
  1671. {
  1672. switch(msg) {
  1673. case WM_ERASEBKGND:
  1674. {
  1675. // shanemc 7883: Support non-transparent index
  1676. if (ACT_INDEX == m_action && m_hbrBackGround != NULL) {
  1677. RECT rc;
  1678. GetClipBox((HDC) wParam, &rc);
  1679. FillRect((HDC) wParam, &rc, m_hbrBackGround);
  1680. return TRUE;
  1681. }
  1682. // end shanemc 7883
  1683. // Make the parent draw our background.
  1684. /*
  1685. * REVIEW: We could take advantage of this by having a flag
  1686. * set that would grab the pixel in the upper left corner and
  1687. * convert that into a background brush (m_hbrBackGround) that
  1688. * all of our transparent controls would use. That would save
  1689. * them from having to specify the background color in the
  1690. * object tag.
  1691. */
  1692. HWND hwndParent = GetParent(m_hwnd);
  1693. if (hwndParent) {
  1694. // Adjust the origin so the parent paints in the right place
  1695. POINT pt;
  1696. ZERO_STRUCTURE(pt);
  1697. MapWindowPoints(m_hwnd, hwndParent, &pt, 1);
  1698. OffsetWindowOrgEx((HDC) wParam, pt.x, pt.y, &pt);
  1699. LRESULT lres = SendMessage(hwndParent, msg, wParam, lParam);
  1700. SetWindowOrgEx((HDC) wParam, pt.x, pt.y, NULL);
  1701. if (lres)
  1702. return lres;
  1703. }
  1704. }
  1705. break;
  1706. case WM_WINDOWPOSCHANGING: // bug HH 4281
  1707. RECT rect;
  1708. GetWindowRect(m_hwnd, &rect);
  1709. if ( memcmp((void*)&m_rect, (void*)&rect, sizeof(RECT)) != 0 )
  1710. InvalidateRect(m_hwnd, NULL, WM_ERASEBKGND);
  1711. m_rect = rect;
  1712. break;
  1713. case WM_CTLCOLORBTN:
  1714. if (m_hbrBackGround && m_hwndDisplayButton != (HWND) lParam)
  1715. return (LRESULT) m_hbrBackGround;
  1716. break;
  1717. case WM_CTLCOLOREDIT:
  1718. if (m_hbrBackGround && m_ptoc && IsValidWindow(m_ptoc->m_hwndTree))
  1719. return (LRESULT) m_hbrBackGround;
  1720. break;
  1721. case WM_CTLCOLORSTATIC:
  1722. if (m_hbrBackGround) {
  1723. // shanemc 7883 - Set the background color if Index
  1724. if (ACT_INDEX == m_action) {
  1725. SetBkColor((HDC)wParam, m_clrFontHover);
  1726. // Note hack of using FontHover color which to hold BkColor.
  1727. // FontHover color isn't used by Index and I don't want to change
  1728. // hhctrl.h if I can avoid it.
  1729. // shanemc 7924
  1730. // Setting the background color apparently changes the system's
  1731. // default foreground color to be black instead of window text color.
  1732. // This breaks readability. Unfortunately, we don't really know (at this
  1733. // point) whether the caller asked for the button background color or some
  1734. // other specific color. But we do know that Millennium will always ask
  1735. // for button face, so we'll do the following:
  1736. // 1) Assume btnface is the background color.
  1737. // 2) Assume btntext is the best foreground color.
  1738. // 3) Confirm that the background color isn't the same as the
  1739. // button text color
  1740. // 4) If they are the same, use windowtext, black, or white
  1741. // (whichever doesn't match)
  1742. COLORREF clrText = GetSysColor(COLOR_BTNTEXT);
  1743. if (clrText == m_clrFontHover) {
  1744. clrText = GetSysColor(COLOR_WINDOWTEXT);
  1745. if (clrText == m_clrFontHover) {
  1746. clrText = RGB(0,0,0);
  1747. }
  1748. if (clrText == m_clrFontHover) {
  1749. clrText = RGB(255,255,255);
  1750. }
  1751. }
  1752. SetTextColor((HDC)wParam, clrText);
  1753. // end shanemc 7924
  1754. }
  1755. // end shanemc 7883
  1756. return (LRESULT) m_hbrBackGround;
  1757. }
  1758. break;
  1759. case WMP_AUTHOR_MSG:
  1760. AuthorMsg((UINT)wParam, (PCSTR) lParam);
  1761. lcFree((void*) lParam);
  1762. return 0;
  1763. case WMP_USER_MSG:
  1764. if (lParam) {
  1765. char szMsg[512];
  1766. wsprintf(szMsg, GetStringResource((int)wParam), (PCSTR) lParam);
  1767. ModalDialog(TRUE);
  1768. MessageBox(GetParent(m_hwnd), szMsg, "", MB_OK | MB_ICONHAND);
  1769. ModalDialog(FALSE);
  1770. lcFree((void*) lParam);
  1771. }
  1772. else {
  1773. ModalDialog(TRUE);
  1774. MessageBox(GetParent(m_hwnd), GetStringResource((int)wParam), "",
  1775. MB_OK | MB_ICONHAND);
  1776. ModalDialog(FALSE);
  1777. }
  1778. return 0;
  1779. case WM_NOTIFY:
  1780. if (m_action == ACT_CONTENTS)
  1781. return m_ptoc->TreeViewMsg((NM_TREEVIEW*) lParam);
  1782. else if (m_action == ACT_INDEX)
  1783. {
  1784. if ( wParam == IDC_KWD_VLIST )
  1785. m_pindex->OnVKListNotify((NMHDR*)lParam);
  1786. return 0;
  1787. }
  1788. break;
  1789. case WM_DRAWITEM:
  1790. if (m_imgType == IMG_TEXT) {
  1791. OnDrawStaticText((DRAWITEMSTRUCT*) lParam);
  1792. break;
  1793. }
  1794. switch (m_action) {
  1795. case ACT_INDEX:
  1796. // m_pindex->OnDrawItem(wParam, (LPDRAWITEMSTRUCT) lParam);
  1797. return 0;
  1798. }
  1799. break;
  1800. case WM_SETFOCUS:
  1801. HWND hWndButton;
  1802. if ( m_fButton && (hWndButton = ::GetWindow(m_hwnd, GW_CHILD)) )
  1803. {
  1804. ::SetFocus(hWndButton);
  1805. return 0;
  1806. }
  1807. else if ( (m_action == ACT_INDEX) && m_pindex)
  1808. {
  1809. m_pindex->SetDefaultFocus();
  1810. return 0;
  1811. }
  1812. break;
  1813. case WM_COMMAND:
  1814. // BN_CLICKED and STN_CLICKED have the same value
  1815. switch (HIWORD(wParam))
  1816. {
  1817. case BN_SETFOCUS:
  1818. ::SendMessage((HWND)lParam, BM_SETSTYLE, (BS_DEFPUSHBUTTON | BS_NOTIFY), 1L);
  1819. return 0;
  1820. case BN_KILLFOCUS:
  1821. ::SendMessage((HWND)lParam, BM_SETSTYLE, (BS_PUSHBUTTON | BS_NOTIFY), 1L);
  1822. return 0;
  1823. case BN_CLICKED:
  1824. case BN_DOUBLECLICKED:
  1825. if ( m_fButton && LOWORD(wParam) < ID_VIEW_ENTRY )
  1826. {
  1827. #ifdef _DEBUG
  1828. if (LOWORD(wParam) == ID_VIEW_MEMORY) {
  1829. OnReportMemoryUsage();
  1830. return 0;
  1831. }
  1832. #endif
  1833. if (LOWORD(wParam) >= IDM_RELATED_TOPIC && LOWORD(wParam) <= IDM_RELATED_TOPIC + 100) {
  1834. OnRelatedCommand(LOWORD(wParam));
  1835. }
  1836. else {
  1837. OnClick();
  1838. }
  1839. return 0;
  1840. }
  1841. // Hmmm, I wonder if a fall through is intended here ?
  1842. default:
  1843. switch (m_action) {
  1844. case ACT_INDEX:
  1845. return m_pindex->OnCommand(m_hwnd, LOWORD(wParam), HIWORD(wParam), lParam);
  1846. case ACT_CONTENTS:
  1847. {
  1848. LRESULT lr = m_ptoc->OnCommand(m_hwnd, LOWORD(wParam), HIWORD(wParam), lParam);
  1849. #if 0
  1850. // Since SendEvent() has to be a member of CHtmlHelpControl, it's called
  1851. // at this point.
  1852. SendEvent();
  1853. #endif
  1854. return lr;
  1855. }
  1856. case ACT_RELATED_TOPICS:
  1857. case ACT_ALINK:
  1858. case ACT_KLINK:
  1859. OnRelatedCommand(LOWORD(wParam));
  1860. return 0;
  1861. }
  1862. }
  1863. break;
  1864. case WM_CONTEXTMENU:
  1865. switch (m_action) {
  1866. case ACT_RELATED_TOPICS:
  1867. case ACT_INDEX:
  1868. if (IsHelpAuthor(GetParent(m_hwnd))) {
  1869. HMENU hmenu = CreatePopupMenu();
  1870. if (!hmenu)
  1871. break;
  1872. if (m_action == ACT_RELATED_TOPICS) {
  1873. CStr csz;
  1874. for (int i = 1; i <= m_pSiteMap->Count(); i++) {
  1875. csz = GetStringResource(IDS_VIEW_RELATED);
  1876. csz += m_pSiteMap->GetSiteMapEntry(i)->pszText;
  1877. HxAppendMenu(hmenu, MF_STRING, ID_VIEW_ENTRY + i,
  1878. csz);
  1879. }
  1880. }
  1881. else {
  1882. HxAppendMenu(hmenu, MF_STRING, ID_VIEW_ENTRY,
  1883. pGetDllStringResource(IDS_VIEW_ENTRY));
  1884. }
  1885. #ifdef _DEBUG
  1886. HxAppendMenu(hmenu, MF_STRING, ID_VIEW_MEMORY,
  1887. "Debug: memory usage...");
  1888. #endif
  1889. POINT pt;
  1890. GetCursorPos(&pt);
  1891. TrackPopupMenu(hmenu,
  1892. TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON,
  1893. pt.x, pt.y, 0, m_hwnd, NULL);
  1894. }
  1895. break;
  1896. }
  1897. break;
  1898. }
  1899. return OcxDefWindowProc(msg, wParam, lParam);
  1900. }
  1901. //=--------------------------------------------------------------------------=
  1902. // CHtmlHelpControl::SetObjectRects
  1903. //=--------------------------------------------------------------------------=
  1904. //
  1905. STDMETHODIMP CHtmlHelpControl::SetObjectRects(LPCRECT prcPos, LPCRECT prcClip)
  1906. {
  1907. BOOL fRemoveWindowRgn;
  1908. // verify our information
  1909. // This assertion doesn't seem valid because the container (IE 3) never
  1910. // calls SetExtent().
  1911. // ASSERT_COMMENT(m_Size.cx == (prcPos->right - prcPos->left) && m_Size.cy == (prcPos->bottom - prcPos->top), "Somebody called SetObjectRects without first setting the extent");
  1912. /*
  1913. * Move our window to the new location and handle clipping. Not
  1914. * applicable for windowless controls, since the container will be
  1915. * responsible for all clipping.
  1916. */
  1917. if (m_hwnd) {
  1918. fRemoveWindowRgn = m_fUsingWindowRgn;
  1919. if (prcClip) {
  1920. // the container wants us to clip, so figure out if we really
  1921. // need to
  1922. RECT rcIXect;
  1923. if (IntersectRect(&rcIXect, prcPos, prcClip)) {
  1924. if (!EqualRect(&rcIXect, prcPos)) {
  1925. OffsetRect(&rcIXect, -(prcPos->left), -(prcPos->top));
  1926. SetWindowRgn(m_hwnd, CreateRectRgnIndirect(&rcIXect), TRUE);
  1927. m_fUsingWindowRgn = TRUE;
  1928. fRemoveWindowRgn = FALSE;
  1929. }
  1930. }
  1931. }
  1932. if (fRemoveWindowRgn) {
  1933. SetWindowRgn(m_hwnd, NULL, TRUE);
  1934. m_fUsingWindowRgn = FALSE;
  1935. }
  1936. // set our control's location and size
  1937. // [people for whom zooming is important should set that up here]
  1938. // if (!EqualRect(prcPos, &m_rcLocation)) {
  1939. m_Size.cx = RECT_WIDTH(prcPos);
  1940. m_Size.cy = RECT_HEIGHT(prcPos);
  1941. SetWindowPos(m_hwnd, NULL, prcPos->left, prcPos->top, m_Size.cx, m_Size.cy, SWP_NOZORDER | SWP_NOACTIVATE);
  1942. CopyRect(&m_rcLocation, prcPos);
  1943. switch (m_action) {
  1944. case ACT_CONTENTS:
  1945. if(m_ptoc)
  1946. m_ptoc->ResizeWindow();
  1947. return S_OK;
  1948. case ACT_INDEX:
  1949. if(m_pindex)
  1950. m_pindex->ResizeWindow();
  1951. // OnSizeIndex(&m_rcLocation);
  1952. return S_OK;
  1953. }
  1954. return S_OK;
  1955. // }
  1956. }
  1957. // save out our current location. windowless controls want this more
  1958. // then windowed ones do, but everybody can have it just in case
  1959. // BUGBUG: 20-Apr-1997 [ralphw] why do we care about this for
  1960. // windowless controls
  1961. CopyRect(&m_rcLocation, prcPos);
  1962. return S_OK;
  1963. }
  1964. //=--------------------------------------------------------------------------=
  1965. // CHtmlHelpControl::JumpToUrl
  1966. //=--------------------------------------------------------------------------=
  1967. //
  1968. void CHtmlHelpControl::JumpToUrl(SITEMAP_ENTRY* pSiteMapEntry, CSiteMap* pSiteMap, SITE_ENTRY_URL* pUrl)
  1969. {
  1970. // REVIEW: we should make this an array of m_hwndHelp to handle more then
  1971. // on help window open at once.
  1972. HWND hwnd = ::JumpToUrl(m_pUnkOuter, m_hwndParent, pSiteMapEntry, m_pInfoType, pSiteMap, pUrl);
  1973. // if (hwnd) {
  1974. // if (m_hwndHelp && hwnd != m_hwndHelp)
  1975. // DestroyWindow(m_hwndHelp);
  1976. // m_hwndHelp = hwnd;
  1977. // }
  1978. }
  1979. //=--------------------------------------------------------------------------=
  1980. // CHtmlHelpControl::OnSpecialKey
  1981. //
  1982. // Function is called from COleControl::TranslateAccelerator() and should
  1983. // return TRUE if the key has been handled.
  1984. //
  1985. //=--------------------------------------------------------------------------=
  1986. BOOL CHtmlHelpControl::OnSpecialKey(LPMSG pmsg)
  1987. {
  1988. static int sDisplayAccel = 'd';
  1989. static int sEditAccel = 'w';
  1990. static BOOL sbIsAccelsSet = FALSE;
  1991. DBWIN("OnSpecialKey");
  1992. // Get the current state of the SHIFT key.
  1993. BOOL fShiftDown = (GetKeyState(VK_SHIFT) < 0);
  1994. if (m_action == ACT_CONTENTS) {
  1995. if (GetFocus() == m_hwnd)
  1996. ::SetFocus(m_ptoc->m_hwndTree);
  1997. // If the user pressed the Tab key, let the container
  1998. // process it so it can set focus to the appropriate object.
  1999. if (pmsg->wParam == VK_TAB &&
  2000. (pmsg->message == WM_KEYUP || pmsg->message == WM_KEYDOWN))
  2001. return FALSE;
  2002. SendMessage(m_ptoc->m_hwndTree, pmsg->message, pmsg->wParam, pmsg->lParam);
  2003. return TRUE;
  2004. }
  2005. if (m_action == ACT_INDEX) {
  2006. // The main control window shouldn't have the focus; so if it
  2007. // does, move it to the appropriate control depending on the
  2008. // state of the SHIFT key. (Tabbing to the control on an HTML
  2009. // page will set the focus to the main window.)
  2010. if (pmsg->message == WM_SYSKEYDOWN)
  2011. {
  2012. if (sbIsAccelsSet == FALSE)
  2013. {
  2014. sbIsAccelsSet = TRUE;
  2015. PCSTR psz = StrChr(GetStringResource(IDS_ENGLISH_DISPLAY), '&');
  2016. if (psz)
  2017. sDisplayAccel = ToLower(psz[1]);
  2018. psz = StrChr(GetStringResource(IDS_TYPE_KEYWORD), '&');
  2019. if (psz)
  2020. sEditAccel = ToLower(psz[1]);
  2021. }
  2022. if (ToLower((char)pmsg->wParam) == sEditAccel)
  2023. {
  2024. ::SetFocus(m_pindex->m_hwndEditBox);
  2025. return TRUE;
  2026. }
  2027. else if (ToLower((char)pmsg->wParam) == sDisplayAccel)
  2028. {
  2029. ::SendMessage(GetParent(m_pindex->m_hwndDisplayButton), WM_COMMAND, MAKELONG(IDBTN_DISPLAY, BN_CLICKED), (LPARAM)m_pindex->m_hwndDisplayButton);
  2030. return TRUE;
  2031. }
  2032. }
  2033. if (GetFocus() == m_hwnd){
  2034. if (fShiftDown)
  2035. ::SetFocus(m_pindex->m_hwndDisplayButton);
  2036. else
  2037. ::SetFocus(m_pindex->m_hwndEditBox);
  2038. return TRUE;
  2039. }
  2040. if (GetFocus() == m_pindex->m_hwndEditBox) {
  2041. if ((pmsg->message == WM_KEYUP || pmsg->message == WM_KEYDOWN) &&
  2042. pmsg->wParam == VK_TAB) {
  2043. if (fShiftDown) {
  2044. return FALSE; // Let the container handle this.
  2045. }
  2046. else {
  2047. // The focus only needs to be set once on WM_KEYDOWN.
  2048. if (pmsg->message == WM_KEYDOWN)
  2049. ::SetFocus(m_pindex->m_hwndListBox);
  2050. return TRUE;
  2051. }
  2052. }
  2053. else
  2054. {
  2055. if ( pmsg->message == WM_KEYDOWN && (pmsg->wParam >= VK_PRIOR && pmsg->wParam <= VK_DOWN))
  2056. {
  2057. SendMessage(m_pindex->m_hwndEditBox, pmsg->message, pmsg->wParam, pmsg->lParam);
  2058. return TRUE;
  2059. }
  2060. else
  2061. return FALSE;
  2062. }
  2063. }
  2064. else if (GetFocus() == m_pindex->m_hwndListBox) {
  2065. if ((pmsg->message == WM_KEYUP || pmsg->message == WM_KEYDOWN) &&
  2066. pmsg->wParam == VK_TAB) {
  2067. if (fShiftDown) {
  2068. if (pmsg->message == WM_KEYUP)
  2069. ::SetFocus(m_pindex->m_hwndEditBox);
  2070. return TRUE;
  2071. }
  2072. else {
  2073. if (pmsg->message == WM_KEYDOWN)
  2074. ::SetFocus(m_pindex->m_hwndDisplayButton);
  2075. return TRUE;
  2076. }
  2077. }
  2078. else {
  2079. // DonDr - Return TRUE instead of !SendMessage because it was causing double
  2080. // scrolls if there was no scroll bar in IE.
  2081. SendMessage(m_pindex->m_hwndListBox, pmsg->message, pmsg->wParam, pmsg->lParam);
  2082. return TRUE;
  2083. }
  2084. }
  2085. else if (GetFocus() == m_pindex->m_hwndDisplayButton) {
  2086. if ((pmsg->message == WM_KEYUP || pmsg->message == WM_KEYDOWN) &&
  2087. pmsg->wParam == VK_TAB) {
  2088. if (fShiftDown) {
  2089. if (pmsg->message == WM_KEYDOWN)
  2090. ::SetFocus(m_pindex->m_hwndListBox);
  2091. return TRUE;
  2092. }
  2093. else {
  2094. return FALSE;
  2095. }
  2096. }
  2097. }
  2098. }
  2099. return FALSE;
  2100. }
  2101. //=--------------------------------------------------------------------------=
  2102. // CHtmlHelpControl::OnSetExtent
  2103. //=--------------------------------------------------------------------------=
  2104. //
  2105. BOOL CHtmlHelpControl::OnSetExtent(const SIZE* pSize)
  2106. {
  2107. BOOL bRet = TRUE;
  2108. if ( m_fButton )
  2109. {
  2110. if ( IsValidWindow(m_hwndDisplayButton) )
  2111. {
  2112. m_Size.cx = RECT_WIDTH(m_rcButton);
  2113. m_Size.cy = RECT_HEIGHT(m_rcButton);
  2114. bRet = FALSE;
  2115. }
  2116. else if ( m_pwszButtonText && m_pwszButtonText[0] )
  2117. {
  2118. // Compute the rect for the text. NOTE: This code will only be entered at print time.
  2119. // for buttons that contain text.
  2120. //
  2121. HDC hDC;
  2122. SIZE Size;
  2123. if ( (hDC = GetDC(NULL)) )
  2124. {
  2125. HFONT hfontOld = (HFONT) SelectObject(hDC, m_hfont);
  2126. IntlGetTextExtentPoint32W(hDC, m_pwszButtonText, lstrlenW(m_pwszButtonText), &Size);
  2127. SelectObject(hDC, hfontOld);
  2128. m_Size.cx = Size.cx + 2; // The two pel "fudge factor" is a lazy way to avoid potential ABC spacing problems.
  2129. m_Size.cy = Size.cy + 2;
  2130. if ( m_imgType == IMG_BUTTON )
  2131. m_Size.cy += 12;
  2132. bRet = FALSE;
  2133. ReleaseDC(NULL, hDC);
  2134. }
  2135. }
  2136. }
  2137. return bRet;
  2138. }
  2139. //=--------------------------------------------------------------------------=
  2140. // CHtmlHelpControl::get_Image
  2141. //=--------------------------------------------------------------------------=
  2142. //
  2143. STDMETHODIMP CHtmlHelpControl::get_Image(BSTR* path)
  2144. {
  2145. CHECK_POINTER(path);
  2146. BSTR * pbstrPath = path;
  2147. *pbstrPath = (m_state.bmpPath && *(m_state.bmpPath)) ? BSTRFROMANSI(m_state.bmpPath) : SysAllocString(L"");
  2148. return (*pbstrPath) ? S_OK : E_OUTOFMEMORY;
  2149. }
  2150. //=--------------------------------------------------------------------------=
  2151. // CHtmlHelpControl::put_Image
  2152. //=--------------------------------------------------------------------------=
  2153. //
  2154. STDMETHODIMP CHtmlHelpControl::put_Image(BSTR path)
  2155. {
  2156. char * tmp = 0;
  2157. if (m_state.bmpPath)
  2158. delete m_state.bmpPath;
  2159. int len = wcslen(path);
  2160. HRESULT hr;
  2161. tmp = new char[len+1];
  2162. if (!tmp) {
  2163. FAIL("No memory");
  2164. hr = E_OUTOFMEMORY;
  2165. }
  2166. else if (WideCharToMultiByte(CP_ACP, 0, path, len, tmp, len, NULL, NULL) == 0)
  2167. return E_FAIL;
  2168. *(tmp + len) = '\0';
  2169. // if it hasn't changed, don't waste any time.
  2170. if(m_state.bmpPath)
  2171. {
  2172. if (!strcmp(m_state.bmpPath, tmp))
  2173. return S_OK;
  2174. }
  2175. if (m_state.bmpPath)
  2176. delete m_state.bmpPath;
  2177. m_state.bmpPath = tmp;
  2178. UpdateImage();
  2179. return(hr);
  2180. }
  2181. //=--------------------------------------------------------------------------=
  2182. // CHtmlHelpControl::Click
  2183. //=--------------------------------------------------------------------------=
  2184. //
  2185. // This is called from scripting in the browser
  2186. //
  2187. STDMETHODIMP CHtmlHelpControl::Click()
  2188. {
  2189. OnClick();
  2190. return S_OK;
  2191. }
  2192. //=--------------------------------------------------------------------------=
  2193. // CHtmlHelpControl::HHClick
  2194. //=--------------------------------------------------------------------------=
  2195. //
  2196. // HHClick is a duplicate of Click() because in IE 4, VBScript decided to
  2197. // implement a Click command that overrides the OCX.
  2198. //
  2199. STDMETHODIMP CHtmlHelpControl::HHClick()
  2200. {
  2201. OnClick();
  2202. return S_OK;
  2203. }
  2204. //=--------------------------------------------------------------------------=
  2205. // CHtmlHelpControl::syncURL
  2206. //=--------------------------------------------------------------------------=
  2207. //
  2208. STDMETHODIMP CHtmlHelpControl::syncURL(BSTR pszUrl)
  2209. {
  2210. if (pszUrl != NULL && m_ptoc)
  2211. {
  2212. CStr cszUrl((WCHAR*) pszUrl);
  2213. m_ptoc->Synchronize(cszUrl);
  2214. }
  2215. return S_OK;
  2216. }
  2217. //=--------------------------------------------------------------------------=
  2218. // CHtmlHelpControl::TCard
  2219. //=--------------------------------------------------------------------------=
  2220. //
  2221. STDMETHODIMP CHtmlHelpControl::TCard(WPARAM wParam, LPARAM lParam)
  2222. {
  2223. HWND hwndParent = FindTopLevelWindow(GetParent(m_hwnd));
  2224. if (hwndParent) {
  2225. SendMessage(hwndParent, WM_TCARD, wParam, lParam);
  2226. return S_OK;
  2227. }
  2228. else
  2229. return S_FALSE;
  2230. }
  2231. //=--------------------------------------------------------------------------=
  2232. // CHtmlHelpControl::Print
  2233. //=--------------------------------------------------------------------------=
  2234. //
  2235. STDMETHODIMP CHtmlHelpControl::Print()
  2236. {
  2237. HRESULT hr = S_OK;
  2238. if (m_pWebBrowserApp->m_lpDispatch != NULL &&
  2239. m_ptoc != NULL)
  2240. {
  2241. PostMessage(m_hwnd, WM_COMMAND, ID_PRINT, 0);
  2242. #if 0
  2243. int action = PRINT_CUR_TOPIC;
  2244. HTREEITEM hitem = TreeView_GetSelection(m_ptoc->m_hwndTree);
  2245. if (hitem) {
  2246. CPrint prt(m_hwndParent);
  2247. prt.SetAction(action);
  2248. if (!prt.DoModal())
  2249. return hr;
  2250. action = prt.GetAction();
  2251. }
  2252. PrintTopics(action, m_ptoc, m_pWebBrowserApp);
  2253. #endif
  2254. }
  2255. else
  2256. hr = E_FAIL;
  2257. return hr;
  2258. }
  2259. //=--------------------------------------------------------------------------=
  2260. // CHtmlHelpControl::TextPopup
  2261. //=--------------------------------------------------------------------------=
  2262. //
  2263. STDMETHODIMP CHtmlHelpControl::TextPopup(BSTR pszText, BSTR pszFont,
  2264. int horzMargins, int vertMargins, COLORREF clrForeground, COLORREF clrBackground)
  2265. {
  2266. if (pszText != NULL) {
  2267. HH_POPUP popup;
  2268. popup.cbStruct = sizeof(HH_POPUP);
  2269. popup.hinst = NULL; // This should be zero if idString is zero.
  2270. popup.idString = 0;
  2271. popup.pszText = (PCSTR) pszText;
  2272. GetCursorPos(&popup.pt);
  2273. popup.clrForeground = clrForeground;
  2274. popup.clrBackground = clrBackground;
  2275. popup.rcMargins.left = horzMargins;
  2276. popup.rcMargins.top = vertMargins;
  2277. popup.rcMargins.right = horzMargins;
  2278. popup.rcMargins.bottom = vertMargins;
  2279. popup.pszFont = (PCSTR) pszFont;
  2280. xHtmlHelpW(FindTopLevelWindow(GetParent(m_hwnd)), NULL,
  2281. HH_DISPLAY_TEXT_POPUP, (DWORD_PTR) &popup);
  2282. return S_OK;
  2283. }
  2284. else
  2285. return S_FALSE;
  2286. }
  2287. //=--------------------------------------------------------------------------=
  2288. // CHtmlHelpControl::SetBmpPath
  2289. //=--------------------------------------------------------------------------=
  2290. //
  2291. HRESULT CHtmlHelpControl::SetBmpPath(IStream * strm)
  2292. {
  2293. CHECK_POINTER(strm);
  2294. char * tmp = 0;
  2295. if (m_state.bmpPath)
  2296. delete m_state.bmpPath;
  2297. DWORD dw;
  2298. HRESULT hr = strm->Read(&dw, sizeof(dw), 0);
  2299. if (SUCCEEDED(hr)) {
  2300. if (!dw) {
  2301. hr = S_OK;
  2302. }
  2303. else {
  2304. tmp = new char[dw+1];
  2305. if (!tmp) {
  2306. FAIL("No memory");
  2307. hr = E_OUTOFMEMORY;
  2308. }
  2309. else {
  2310. hr = strm->Read(tmp, dw + 1, 0);
  2311. }
  2312. }
  2313. }
  2314. // if it hasn't changed, don't waste any time.
  2315. if ((!tmp && !m_state.bmpPath) || !strcmp(m_state.bmpPath, tmp))
  2316. return S_OK;
  2317. if (m_state.bmpPath)
  2318. delete m_state.bmpPath;
  2319. m_state.bmpPath = tmp;
  2320. UpdateImage();
  2321. return(hr);
  2322. }
  2323. //=--------------------------------------------------------------------------=
  2324. // CHtmlHelpControl::UpdateImage
  2325. //=--------------------------------------------------------------------------=
  2326. //
  2327. HRESULT CHtmlHelpControl::UpdateImage()
  2328. {
  2329. if (!m_hwnd)
  2330. return(S_OK);
  2331. if (!m_state.bmpPath)
  2332. return(S_OK);
  2333. FireReadyStateChange(READYSTATE_INTERACTIVE);
  2334. return(SetupDownload(OLESTRFROMANSI(m_state.bmpPath), DISPID_BMPPATH));
  2335. return S_OK;
  2336. }
  2337. //=--------------------------------------------------------------------------=
  2338. // CHtmlHelpControl::OnData
  2339. //=--------------------------------------------------------------------------=
  2340. //
  2341. HRESULT CHtmlHelpControl::OnData(DISPID propId, DWORD grfBSCF,
  2342. IStream * strm, DWORD dwSize)
  2343. {
  2344. HRESULT hr = NOERROR;
  2345. switch(m_readystate) {
  2346. case bdsNoBitsYet:
  2347. #if 0
  2348. if (dwSize >= sizeof(BITMAPFILEHEADER)) {
  2349. if( m_dibFile )
  2350. delete m_dibFile;
  2351. m_dibFile = new CDibFile;
  2352. if (!m_dibFile) {
  2353. hr = E_OUTOFMEMORY;
  2354. break;
  2355. }
  2356. hr = m_dibFile->GetFileHeader(strm);
  2357. if (FAILED(hr))
  2358. break;
  2359. m_readystate = bdsGotFileHeader;
  2360. // now FALL THRU!
  2361. }
  2362. else
  2363. #endif
  2364. break;
  2365. case bdsGotFileHeader:
  2366. #if 0
  2367. if (dwSize >= (m_dibFile->HeaderSize() + sizeof(BITMAPFILEHEADER)))
  2368. {
  2369. if (m_dibFile)
  2370. hr = m_dibFile->GetInfoHeader(strm);
  2371. else
  2372. hr = E_OUTOFMEMORY;
  2373. if (FAILED(hr))
  2374. break;
  2375. if (m_dib)
  2376. delete m_dib;
  2377. m_dib = new CDibSection;
  2378. if (!m_dib) {
  2379. hr = E_OUTOFMEMORY;
  2380. break;
  2381. }
  2382. m_dib->Setup(m_dc);
  2383. hr = m_dib->Create(*m_dibFile);
  2384. if (FAILED(hr))
  2385. break;
  2386. m_dib->ImageSize(m_dibFile->CalcImageSize());
  2387. m_readystate = bdsGotBitmapInfo;
  2388. // FALL THRU!
  2389. }
  2390. else
  2391. #endif
  2392. break;
  2393. case bdsGotBitmapInfo:
  2394. #if 0
  2395. SIZEL sz;
  2396. m_dib->GetSize(sz);
  2397. SetControlSize(&sz);
  2398. m_oldSize = (m_dibFile->HeaderSize() + sizeof(BITMAPFILEHEADER));
  2399. m_readystate = bdsGettingBits;
  2400. #endif
  2401. // FALL THRU
  2402. case bdsGettingBits:
  2403. #if 0
  2404. if (dwSize > m_oldSize) {
  2405. hr = m_dib->ReadFrom(strm, dwSize - m_oldSize);
  2406. if (FAILED(hr))
  2407. break;
  2408. ::RealizePalette(m_dc);
  2409. m_dib->PaintTo(m_dc);
  2410. m_oldSize = dwSize;
  2411. }
  2412. if (grfBSCF & BSCF_LASTDATANOTIFICATION)
  2413. m_readystate = bdsBitsAreDone;
  2414. else
  2415. #endif
  2416. break;
  2417. case bdsBitsAreDone:
  2418. #if 0
  2419. m_readystate = bdsNoBitsYet;
  2420. FireReadyStateChange(READYSTATE_COMPLETE);
  2421. InvalidateControl(0);
  2422. #endif
  2423. break;
  2424. }
  2425. return(hr);
  2426. }
  2427. #ifndef PPGS
  2428. //=--------------------------------------------------------------------------=
  2429. // CHtmlHelpControl::DoVerb
  2430. //=--------------------------------------------------------------------------=
  2431. //
  2432. STDMETHODIMP CHtmlHelpControl::DoVerb
  2433. (
  2434. LONG lVerb,
  2435. LPMSG pMsg,
  2436. IOleClientSite *pActiveSite,
  2437. LONG lIndex,
  2438. HWND hwndParent,
  2439. LPCRECT prcPosRect
  2440. )
  2441. {
  2442. switch (lVerb) {
  2443. case OLEIVERB_PRIMARY:
  2444. case CTLIVERB_PROPERTIES:
  2445. case OLEIVERB_PROPERTIES:
  2446. case OLEIVERB_OPEN:
  2447. case OLEIVERB_HIDE:
  2448. return S_OK;
  2449. #ifdef _DEBUG
  2450. case OLEIVERB_INPLACEACTIVATE:
  2451. case OLEIVERB_UIACTIVATE:
  2452. //DBWIN("ACTIVATE");
  2453. break;
  2454. #endif
  2455. }
  2456. return COleControl::DoVerb(lVerb, pMsg, pActiveSite, lIndex, hwndParent, prcPosRect);
  2457. }
  2458. #endif
  2459. //=--------------------------------------------------------------------------=
  2460. // CHtmlHelpControl::InternalQueryInterface
  2461. //=--------------------------------------------------------------------------=
  2462. // qi for things only we support.
  2463. //
  2464. // Parameters:
  2465. // Parameters:
  2466. // REFIID - [in] interface they want
  2467. // void ** - [out] where they want to put the resulting object ptr.
  2468. //
  2469. // Output:
  2470. // HRESULT - S_OK, E_NOINTERFACE
  2471. HRESULT CHtmlHelpControl::InternalQueryInterface(REFIID riid, void **ppvObjOut)
  2472. {
  2473. IUnknown *pUnk;
  2474. if (!ppvObjOut)
  2475. return E_INVALIDARG;
  2476. *ppvObjOut = NULL;
  2477. /*
  2478. * TODO: if you want to support any additional interrfaces, then you
  2479. * should indicate that here. never forget to call CInternetControl's
  2480. * version in the case where you don't support the given interface.
  2481. */
  2482. if (DO_GUIDS_MATCH(riid, IID_IHHCtrl)) {
  2483. pUnk = (IUnknown *)(IHHCtrl *)this;
  2484. } else{
  2485. return CInternetControl::InternalQueryInterface(riid, ppvObjOut);
  2486. }
  2487. pUnk->AddRef();
  2488. *ppvObjOut = (void *)pUnk;
  2489. return S_OK;
  2490. }
  2491. //=--------------------------------------------------------------------------=
  2492. // CHtmlHelpControl::ConvertToCacheFile
  2493. //=--------------------------------------------------------------------------=
  2494. //
  2495. BOOL CHtmlHelpControl::ConvertToCacheFile(PCSTR pszSrc, PSTR pszDst)
  2496. {
  2497. CStr cszTmp;
  2498. PSTR psz = stristr(pszSrc, txtSysRoot);
  2499. if (psz) {
  2500. char szPath[MAX_PATH];
  2501. GetRegWindowsDirectory(szPath);
  2502. strcat(szPath, psz + strlen(txtSysRoot));
  2503. cszTmp = szPath;
  2504. pszSrc = (PCSTR) cszTmp.psz;
  2505. }
  2506. TryThatAgain:
  2507. PCSTR pszChmSep = strstr(pszSrc, txtDoubleColonSep);
  2508. if (pszChmSep) {
  2509. if (pszSrc != cszTmp.psz) {
  2510. cszTmp = pszSrc;
  2511. int offset = (int)(pszChmSep - pszSrc);
  2512. pszSrc = cszTmp;
  2513. pszChmSep = pszSrc + offset;
  2514. }
  2515. *(PSTR) pszChmSep = '\0'; // Remove the separator
  2516. HRESULT hr = URLDownloadToCacheFile(m_pUnkOuter, pszSrc, pszDst, MAX_PATH, 0, NULL);
  2517. if (!SUCCEEDED(hr)) {
  2518. CStr cszNew;
  2519. ModalDialog(TRUE);
  2520. BOOL fResult = FindThisFile(m_hwnd, pszSrc, &cszNew, TRUE);
  2521. ModalDialog(FALSE);
  2522. if (fResult) {
  2523. strcpy(pszDst, cszNew.psz);
  2524. *(PSTR) pszChmSep = ':'; // Put the separator back
  2525. strcat(pszDst, pszChmSep);
  2526. return TRUE;
  2527. }
  2528. }
  2529. else { // we downloaded it, or have a pointer to it
  2530. *(PSTR) pszChmSep = ':'; // Put the separator back
  2531. strcat(pszDst, pszChmSep);
  2532. return TRUE;
  2533. }
  2534. }
  2535. // BUGBUG: need to get the current ULR -- if this is a "mk:" URL, then
  2536. // we need to change the path before this will work
  2537. HRESULT hr = URLDownloadToCacheFile(m_pUnkOuter, pszSrc, pszDst, MAX_PATH, 0, NULL);
  2538. if (!SUCCEEDED(hr)) {
  2539. if (!StrChr(pszSrc, ':')) { // no protocol, check current .CHM file
  2540. HWND hwndParent = FindTopLevelWindow(GetParent(m_hwnd));
  2541. char szClass[256];
  2542. GetClassName(hwndParent, szClass, sizeof(szClass));
  2543. if (IsSamePrefix(szClass, txtHtmlHelpWindowClass, -2)) {
  2544. PCSTR pszFile = (PCSTR) SendMessage(hwndParent,
  2545. WMP_GET_CUR_FILE, 0, 0);
  2546. if (IsNonEmptyString(pszFile)) {
  2547. cszTmp = pszFile;
  2548. cszTmp += txtDoubleColonSep;
  2549. cszTmp += pszSrc;
  2550. pszSrc = cszTmp;
  2551. goto TryThatAgain;
  2552. }
  2553. }
  2554. }
  2555. return FALSE;
  2556. }
  2557. return TRUE;
  2558. }
  2559. //=--------------------------------------------------------------------------=
  2560. // CHtmlHelpControl::SendEvent
  2561. //=--------------------------------------------------------------------------=
  2562. //
  2563. HRESULT CHtmlHelpControl::SendEvent(LPCTSTR pszEventString)
  2564. {
  2565. if (!IsEmptyString(pszEventString)) {
  2566. CWStr cwsz(pszEventString); // convert to WIDE
  2567. BSTR bstr;
  2568. if ((bstr = SysAllocString(cwsz)) != NULL)
  2569. FireEvent(&::rgHHCtrlEvents[HHCtrlEvent_Click], bstr);
  2570. SysFreeString(bstr);
  2571. }
  2572. return S_OK;
  2573. }
  2574. //=--------------------------------------------------------------------------=
  2575. // GetHtmlHelpFrameWindow
  2576. //=--------------------------------------------------------------------------=
  2577. //
  2578. /*
  2579. This function gets the HWND for HTML Helps frame. HTML Help (CContainer) contains IE.
  2580. IE contains an AKLink ActiveX contain (CHtmlHelpControl). This function gives CHtmlHelpControl
  2581. a way to get to the HWND of its big daddy.
  2582. */
  2583. HWND
  2584. CHtmlHelpControl::GetHtmlHelpFrameWindow()
  2585. {
  2586. HWND hWndReturn = NULL ;
  2587. if (m_pWebBrowserApp)
  2588. {
  2589. //--- Get a pointer to the container's IDispatch. This points to the IDispatch of CContainer (contain.cpp).
  2590. IDispatch* pDispatchContainer = m_pWebBrowserApp->GetContainer() ;
  2591. if (pDispatchContainer)
  2592. {
  2593. //--- Get the IOleWindow interface implemented by the container.
  2594. IOleWindow* pIOleWindow = NULL ;
  2595. HRESULT hr = pDispatchContainer->QueryInterface(IID_IOleWindow, (void**)&pIOleWindow) ;
  2596. if (SUCCEEDED(hr) && pIOleWindow)
  2597. {
  2598. //--- Get the window for this container.
  2599. HWND hWndTemp = NULL ;
  2600. hr = pIOleWindow->GetWindow(&hWndTemp) ;
  2601. if (SUCCEEDED(hr) && IsWindow(hWndTemp))
  2602. {
  2603. //--- We found the container window! Now, get the HTML Help Frame window from this.
  2604. CHHWinType* phh = FindHHWindowIndex(hWndTemp) ;
  2605. if (phh && IsWindow(phh->hwndHelp))
  2606. {
  2607. hWndReturn = phh->hwndHelp ;
  2608. }
  2609. }
  2610. // Clean up.
  2611. pIOleWindow->Release() ;
  2612. }
  2613. // Clean up some more.
  2614. pDispatchContainer->Release() ;
  2615. }
  2616. }
  2617. return hWndReturn ;
  2618. }