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.

2389 lines
78 KiB

  1. // Copyright (C) Microsoft Corporation 1996-1997, All Rights reserved.
  2. #include "header.h"
  3. #ifdef _DEBUG
  4. #undef THIS_FILE
  5. static const char THIS_FILE[] = __FILE__;
  6. #endif
  7. #include "strtable.h"
  8. #include "hha_strtable.h"
  9. #include "resource.h"
  10. #include "contain.h"
  11. #include "system.h"
  12. #include "secwin.h"
  13. #include "popup.h"
  14. #include "highlite.h"
  15. // Get hhPreTranslateMessage
  16. #include "hhshell.h"
  17. // Internal API definitions.
  18. #include "hhpriv.h"
  19. // HH_GET_LAST_ERROR support
  20. #include "lasterr.h"
  21. /////////////////////////////////////////////////////////////////////
  22. //
  23. // Internal function prototypes.
  24. //
  25. HWND ReactivateDisplayTopic(HWND hwndCaller, LPCSTR pszFile, DWORD_PTR dwData) ;
  26. HWND InternalHelpContext(HWND hwndCaller, LPCSTR pszFile, DWORD_PTR id, HH_COLLECTION_CONTEXT* pContext);
  27. HWND OnHelpContextInCollection(HWND hwndCaller, LPCSTR pszColFile, DWORD_PTR dwData);
  28. bool SetGlobalProperty(HH_GLOBAL_PROPERTY* prop, CHHWinType*) ;
  29. bool GetNameAndWinType(LPCSTR pszFile, CStr& pszName, CStr& pszWindow) ;
  30. HWND OnReloadNavData(HWND hwndCaller, LPCSTR pszFile, HH_NAVDATA* pNavData) ;
  31. bool GetBrowserInterface(HWND hWndBrowserParent, IDispatch** ppWebBrowser);
  32. // Used by hh.cpp
  33. bool InitializeSession(UNALIGNED DWORD_PTR* pCookie) ;
  34. bool UninitializeSession(DWORD_PTR Cookie) ;
  35. /////////////////////////////////////////////////////////////////////
  36. //
  37. // Constants
  38. //
  39. static const char txtWinHelpFileExt[] = ".hlp";
  40. static const char txtForceWindowType[] = "$Lee";
  41. // Pointer to global array of window types.
  42. HWND xHtmlHelpW(HWND hwndCaller, LPCWSTR pszFile, UINT uCommand, DWORD_PTR dwData)
  43. {
  44. CStr cszFile;
  45. if (pszFile)
  46. cszFile = (WCHAR*) pszFile;
  47. switch (uCommand) {
  48. case HH_DISPLAY_TEXT_POPUP:
  49. {
  50. HH_POPUP* ppopup = (HH_POPUP*) dwData;
  51. CStr cszString;
  52. if (!ppopup->idString) {
  53. cszString = (WCHAR*) ppopup->pszText;
  54. ppopup->pszText = cszString.psz;
  55. }
  56. CStr cszFont;
  57. if (ppopup->pszFont) {
  58. cszFont = (WCHAR*) ppopup->pszFont;
  59. ppopup->pszFont = cszFont.psz;
  60. }
  61. return xHtmlHelpA(hwndCaller, cszFile, uCommand, dwData);
  62. }
  63. case HH_DISPLAY_INDEX:
  64. case HH_GET_WIN_HANDLE:
  65. case HH_DISPLAY_TOPIC:
  66. if (dwData && !IsBadReadPtr((LPCSTR) dwData, sizeof(LPCSTR))) {
  67. char szURL[MAX_PATH];
  68. szURL[WideCharToMultiByte(CP_ACP, 0,
  69. (const WCHAR*) dwData, -1,
  70. szURL, MAX_PATH, NULL, NULL)] = '\0';
  71. return xHtmlHelpA(hwndCaller, cszFile, uCommand, (DWORD_PTR) szURL);
  72. }
  73. else
  74. return xHtmlHelpA(hwndCaller, cszFile, uCommand, dwData);
  75. case HH_KEYWORD_LOOKUP:
  76. {
  77. HH_AKLINK* pakLink = (HH_AKLINK*) dwData;
  78. if (IsBadReadPtr(pakLink, sizeof(HH_AKLINK*)))
  79. // BUGBUG: nag the help author
  80. return NULL;
  81. pakLink->fReserved = TRUE;
  82. return xHtmlHelpA(hwndCaller, cszFile, uCommand, dwData);
  83. }
  84. case HH_SET_INFO_TYPE:
  85. {
  86. PHH_SET_INFOTYPE pSetInfoType = *(PHH_SET_INFOTYPE *)dwData;
  87. CStr cszType;
  88. CStr cszCat;
  89. if (*pSetInfoType->pszCatName != NULL) {
  90. cszCat = (WCHAR*) pSetInfoType->pszCatName;
  91. pSetInfoType->pszCatName = cszCat.psz;
  92. }
  93. if (*pSetInfoType->pszInfoTypeName != NULL) {
  94. cszType = (WCHAR*) pSetInfoType->pszInfoTypeName;
  95. pSetInfoType->pszInfoTypeName = cszType.psz;
  96. }
  97. return xHtmlHelpA(hwndCaller, cszFile, uCommand, dwData);
  98. }
  99. case HH_ENUM_INFO_TYPE:
  100. {
  101. PHH_ENUM_IT penumIT;
  102. penumIT = (PHH_ENUM_IT)(*(PHH_ENUM_IT*)dwData);
  103. HWND ret = xHtmlHelpA(hwndCaller, cszFile, uCommand, dwData);
  104. if ( ret != (HWND)-1 )
  105. {
  106. CHmData* phmData = FindCurFileData( cszFile.psz);
  107. if ( phmData == NULL )
  108. return (HWND)-1;
  109. phmData->PopulateUNICODETables();
  110. penumIT->pszITName = phmData->m_ptblIT->GetPointer((int)(DWORD_PTR)ret);
  111. penumIT->pszITDescription = phmData->m_ptblIT_Desc->GetPointer((int)(DWORD_PTR)ret);
  112. }
  113. return ret;
  114. }
  115. case HH_ENUM_CATEGORY:
  116. {
  117. PHH_ENUM_CAT penumCat;
  118. HWND ret = xHtmlHelpA(hwndCaller, cszFile, uCommand, dwData);
  119. if ( ret != (HWND)-1 )
  120. {
  121. penumCat = *(PHH_ENUM_CAT*) dwData;
  122. CHmData* phmData = FindCurFileData( cszFile.psz);
  123. if ( phmData == NULL )
  124. return (HWND)-1;
  125. phmData->PopulateUNICODETables();
  126. penumCat->pszCatName = phmData->m_ptblCat->GetPointer((int)(DWORD_PTR)ret+1);
  127. penumCat->pszCatDescription = phmData->m_ptblCat_Desc->GetPointer((int)(DWORD_PTR)ret+1);
  128. }
  129. return ret;
  130. }
  131. case HH_ENUM_CATEGORY_IT:
  132. {
  133. PHH_ENUM_IT penumIT;
  134. CStr csz;
  135. penumIT = *(PHH_ENUM_IT*)dwData;
  136. csz = (WCHAR*) penumIT->pszCatName;
  137. penumIT->pszCatName = csz.psz;
  138. HWND ret = xHtmlHelpA(hwndCaller, cszFile, uCommand, dwData);
  139. if ( ret != (HWND)-1 )
  140. {
  141. CHmData* phmData = FindCurFileData( cszFile.psz);
  142. if ( phmData == NULL )
  143. return (HWND)-1;
  144. phmData->PopulateUNICODETables();
  145. penumIT->pszITName = phmData->m_ptblIT->GetPointer((int)(DWORD_PTR)ret);
  146. penumIT->pszITDescription = phmData->m_ptblIT_Desc->GetPointer((int)(DWORD_PTR)ret);
  147. }
  148. return ret;
  149. }
  150. case HH_SET_GUID:
  151. {
  152. // Set all CHM files matching this process ID to use this GUID
  153. // BUGBUG: should NOT be using a global for this -- breaks
  154. // the moment you share instances of HHCTRL accross processes
  155. if (g_pszDarwinGuid)
  156. lcFree(g_pszDarwinGuid);
  157. // Convert to ANSI
  158. CStr pszGuid((LPCWSTR) dwData);
  159. // Save pointer.
  160. pszGuid.TransferPointer(&g_pszDarwinGuid ) ;
  161. }
  162. return NULL;
  163. case HH_SET_BACKUP_GUID:
  164. {
  165. // Set all CHM files matching this process ID to use this GUID
  166. // BUGBUG: should NOT be using a global for this -- breaks
  167. // the moment you share instances of HHCTRL accross processes
  168. if (g_pszDarwinBackupGuid)
  169. lcFree(g_pszDarwinBackupGuid);
  170. // Convert to ANSI
  171. CStr pszGuid((LPCWSTR) dwData);
  172. // Save pointer.
  173. pszGuid.TransferPointer(&g_pszDarwinBackupGuid) ;
  174. }
  175. return NULL;
  176. default:
  177. return xHtmlHelpA(hwndCaller, cszFile, uCommand, dwData);
  178. }
  179. return NULL;
  180. }
  181. HWND xHtmlHelpA(HWND hwndCaller, LPCSTR pszFile, UINT uCommand, DWORD_PTR dwData)
  182. {
  183. #if 0
  184. #ifdef _DEBUG
  185. static int count = 0;
  186. if (!count)
  187. DebugBreak();
  188. count++;
  189. #endif
  190. #endif
  191. switch (uCommand) {
  192. case HH_RESERVED1: // this is a WinHelp HELP_CONTEXTMENU call
  193. WinHelp(hwndCaller, pszFile, HELP_CONTEXTMENU, dwData);
  194. return NULL;
  195. case HH_RESERVED2: // this is a WinHelp HELP_FINDER call
  196. WinHelp(hwndCaller, pszFile, HELP_FINDER, 0);
  197. return NULL;
  198. case HH_RESERVED3: // this is a WinHelp HELP_WM_HELP call
  199. WinHelp(hwndCaller, pszFile, HELP_WM_HELP, dwData);
  200. return NULL;
  201. case HH_DISPLAY_TOPIC:
  202. DBWIN("HH_DISPLAY_TOPIC");
  203. return OnDisplayTopic(hwndCaller, pszFile, dwData);
  204. case HH_SET_WIN_TYPE:
  205. DBWIN("HH_SET_WIN_TYPE");
  206. return SetWinType(pszFile, (HH_WINTYPE*) dwData) ;
  207. case HH_GET_WIN_TYPE:
  208. DBWIN("HH_GET_WIN_TYPE");
  209. return GetWinType(hwndCaller, pszFile, (HH_WINTYPE**)dwData) ;
  210. case HH_DISPLAY_SEARCH:
  211. DBWIN("HH_DISPLAY_SEARCH");
  212. return doDisplaySearch(hwndCaller, pszFile, (HH_FTS_QUERY*) dwData) ;
  213. case HH_DISPLAY_INDEX:
  214. DBWIN("HH_DISPLAY_INDEX");
  215. return doDisplayIndex(hwndCaller, pszFile, (LPCTSTR)dwData);
  216. case HH_DISPLAY_TOC:
  217. DBWIN("HH_DISPLAY_TOC");
  218. if (IsThisAWinHelpFile(hwndCaller, pszFile)) {
  219. WinHelp(hwndCaller, pszFile, HELP_CONTEXT, dwData);
  220. return NULL;
  221. }
  222. return doDisplayToc(hwndCaller, pszFile, dwData);
  223. case HH_DISPLAY_TEXT_POPUP:
  224. DBWIN("HH_DISPLAY_TEXT_POPUP");
  225. return doDisplayTextPopup(hwndCaller, pszFile, (HH_POPUP*)dwData) ;
  226. case HH_TP_HELP_WM_HELP:
  227. DBWIN("HH_TP_HELP_WM_HELP");
  228. if (IsThisAWinHelpFile(hwndCaller, pszFile)) {
  229. WinHelp(hwndCaller, pszFile, HELP_WM_HELP, dwData);
  230. return NULL;
  231. }
  232. return doTpHelpWmHelp(hwndCaller, pszFile, dwData);
  233. case HH_TP_HELP_CONTEXTMENU:
  234. DBWIN("HH_TP_HELP_CONTEXTMENU");
  235. if (IsThisAWinHelpFile(hwndCaller, pszFile)) {
  236. WinHelp(hwndCaller, pszFile, HELP_CONTEXTMENU, dwData);
  237. return NULL;
  238. }
  239. return doTpHelpContextMenu(hwndCaller, pszFile, dwData);
  240. case HH_GET_WIN_HANDLE:
  241. {
  242. DBWIN("HH_GET_WIN_HANDLE");
  243. if (!dwData || IsBadReadPtr((LPCSTR) dwData, sizeof(LPCSTR)))
  244. {
  245. return NULL;
  246. }
  247. if (!pszFile || IsEmptyString(pszFile))
  248. {
  249. return NULL ;
  250. }
  251. // Need to include compiled filename with window lookup
  252. // since there can be two or more .CHM files with identical window type
  253. // names, but different definitions
  254. CHHWinType* phh = FindWindowType(FirstNonSpace((PCSTR) dwData), hwndCaller, pszFile);
  255. if (!phh)
  256. {
  257. return NULL;
  258. }
  259. return phh->GetHwnd();
  260. }
  261. case HH_SYNC:
  262. {
  263. DBWIN("HH_SYNC");
  264. // pszFile has two pieces of information which we need. The filename and the window type name.
  265. // Window type provided?
  266. CStr cszChmName ;
  267. CStr cszWindow ;
  268. if (!GetNameAndWinType(pszFile, cszChmName, cszWindow))
  269. {
  270. return NULL;
  271. }
  272. /*
  273. REVIEW: 27 Apr 98 [dalero] - I'm adding the code to make FindOrCreateWindowSlot
  274. take a filename parameter, and I have to say that this function makes no sense to me.
  275. Why does HH_SYNC require a window type? Shouldn't it figure one out if you don't give
  276. it one? Leave as is for now...
  277. */
  278. CHHWinType* phh = FindWindowType(cszWindow, hwndCaller, cszChmName);
  279. if (phh->m_aNavPane[HH_TAB_CONTENTS])
  280. {
  281. CStr cszUrl((PCSTR) dwData);
  282. CToc* ptoc = reinterpret_cast<CToc*>(phh->m_aNavPane[HH_TAB_CONTENTS]) ; // HACKHACK: Should use dynamic cast.
  283. ptoc->Synchronize(cszUrl);
  284. }
  285. return phh->GetHwnd();
  286. }
  287. case HH_KEYWORD_LOOKUP:
  288. DBWIN("HH_KEYWORD_LOOKUP");
  289. return OnKeywordSearch(hwndCaller, pszFile, (HH_AKLINK*) dwData);
  290. case HH_ALINK_LOOKUP:
  291. DBWIN("HH_ALINK_LOOKUP");
  292. return OnKeywordSearch(hwndCaller, pszFile, (HH_AKLINK*) dwData, FALSE);
  293. case HH_HELP_CONTEXT:
  294. DBWIN("HH_HELP_CONTEXT");
  295. return OnHelpContext(hwndCaller, pszFile, dwData);
  296. case HH_CLOSE_ALL:
  297. {
  298. DBWIN("HH_CLOSE_ALL");
  299. DeleteWindows() ; // This deletes everything. Windows and chm data.
  300. }
  301. return NULL;
  302. case HH_GET_LAST_ERROR:
  303. DBWIN("HH_GET_LAST_ERROR");
  304. if (SUCCEEDED(hhGetLastError((HH_LAST_ERROR*)(dwData))))
  305. return (HWND)TRUE;
  306. else
  307. return NULL;
  308. case HH_ENUM_INFO_TYPE:
  309. {
  310. DBWIN("HH_ENUM_INFO_TYPE");
  311. static HH_ENUM_IT ITData;
  312. static PHH_ENUM_IT pITData=&ITData;
  313. CHmData* phmData = FindCurFileData( pszFile ) ;
  314. if ( phmData == NULL )
  315. return (HWND)-1;
  316. if ( phmData->m_cur_IT == 0 )
  317. phmData->m_cur_IT = 1;
  318. if ( !phmData->m_pInfoType )
  319. {
  320. phmData->m_pInfoType = new CInfoType();
  321. phmData->m_pInfoType->CopyTo( phmData );
  322. }
  323. // get the information type
  324. if ( phmData->m_cur_IT > phmData->m_pInfoType->HowManyInfoTypes() )
  325. {
  326. phmData->m_cur_IT = 0;
  327. return (HWND)-1;
  328. }
  329. ITData.iType = IT_INCLUSIVE;
  330. if ( phmData->m_pInfoType->IsHidden( phmData->m_cur_IT) )
  331. ITData.iType = IT_HIDDEN;
  332. else
  333. if ( phmData->m_pInfoType->IsExclusive( phmData->m_cur_IT ) )
  334. ITData.iType = IT_EXCLUSIVE;
  335. ITData.pszITName = phmData->m_pInfoType->GetInfoTypeName(phmData->m_cur_IT);
  336. ITData.pszITDescription = phmData->m_pInfoType->GetInfoTypeDescription(phmData->m_cur_IT);
  337. ITData.cbStruct = sizeof(HH_ENUM_IT);
  338. memcpy(*(PHH_ENUM_IT*)dwData, (PHH_ENUM_IT)(pITData), sizeof(HH_ENUM_IT) );
  339. phmData->m_cur_IT++;
  340. return reinterpret_cast<HWND>((DWORD_PTR)(phmData->m_cur_IT-1));
  341. }
  342. case HH_SET_INFO_TYPE:
  343. DBWIN("HH_SET_INFO_TYPE");
  344. if (IsThisAWinHelpFile(hwndCaller, pszFile)) {
  345. WinHelp(hwndCaller, pszFile, HELP_CONTEXTPOPUP, dwData);
  346. return NULL;
  347. }
  348. {
  349. HH_SET_INFOTYPE set_type;
  350. CStr cszIT;
  351. CHmData* phmData = FindCurFileData( pszFile );
  352. if ( phmData == NULL )
  353. return (HWND)-1;
  354. memcpy(&set_type, *(PHH_SET_INFOTYPE*)dwData, (int)(**(int**)dwData));
  355. if ( set_type.pszCatName && *set_type.pszCatName!= NULL)
  356. {
  357. cszIT = set_type.pszCatName;
  358. cszIT+=":";
  359. }
  360. if ( set_type.pszInfoTypeName )
  361. if ( cszIT.IsEmpty() )
  362. cszIT = set_type.pszInfoTypeName;
  363. else
  364. cszIT += set_type.pszInfoTypeName;
  365. else
  366. return (HWND)-1;
  367. if ( !phmData->m_pInfoType )
  368. {
  369. phmData->m_pInfoType = new CInfoType();
  370. phmData->m_pInfoType->CopyTo( phmData );
  371. }
  372. int IT = phmData->m_pInfoType->GetInfoType( cszIT.psz );
  373. if ( IT <= 0 )
  374. return (HWND)-1;
  375. if (!phmData->m_pAPIInfoTypes )
  376. phmData->m_pAPIInfoTypes = (INFOTYPE*)lcCalloc(phmData->m_pInfoType->InfoTypeSize());
  377. AddIT(IT, phmData->m_pAPIInfoTypes);
  378. return reinterpret_cast<HWND>((DWORD_PTR)(IT));
  379. }
  380. case HH_ENUM_CATEGORY:
  381. DBWIN("HH_ENUM_CATEGORY");
  382. {
  383. static HH_ENUM_CAT ITData;
  384. static PHH_ENUM_CAT pITData = &ITData;
  385. CHmData* phmData = FindCurFileData( pszFile );
  386. if ( phmData == NULL )
  387. return (HWND)-1;
  388. if ( !phmData->m_pInfoType )
  389. {
  390. phmData->m_pInfoType = new CInfoType();
  391. phmData->m_pInfoType->CopyTo( phmData );
  392. }
  393. if ( phmData->m_cur_Cat+1 > phmData->m_pInfoType->HowManyCategories() )
  394. {
  395. phmData->m_cur_Cat = 0;
  396. return (HWND)-1;
  397. }
  398. ITData.pszCatName = phmData->m_pInfoType->GetCategoryString(phmData->m_cur_Cat+1);
  399. ITData.pszCatDescription = phmData->m_pInfoType->GetCategoryDescription(phmData->m_cur_Cat+1);
  400. ITData.cbStruct = sizeof(HH_ENUM_CAT);
  401. memcpy(*(PHH_ENUM_CAT*)dwData, (PHH_ENUM_CAT)(pITData), sizeof(HH_ENUM_CAT) );
  402. phmData->m_cur_Cat++;
  403. return reinterpret_cast<HWND>((DWORD_PTR)(phmData->m_cur_Cat-1));
  404. }
  405. case HH_ENUM_CATEGORY_IT:
  406. {
  407. DBWIN("HH_ENUM_CATEGORY_IT");
  408. static HH_ENUM_IT ITData;
  409. static PHH_ENUM_IT pITData = &ITData;
  410. CHmData* phmData = FindCurFileData( pszFile );
  411. if ( phmData == NULL )
  412. return (HWND)-1;
  413. if ( phmData->m_cur_IT == -1 )
  414. {
  415. phmData->m_cur_Cat = 0;
  416. phmData->m_cur_IT = 0;
  417. }
  418. if ( !phmData->m_pInfoType )
  419. {
  420. phmData->m_pInfoType = new CInfoType();
  421. phmData->m_pInfoType->CopyTo( phmData );
  422. }
  423. if ( !dwData )
  424. return (HWND)-1;
  425. memcpy(&ITData, *(PHH_ENUM_IT*)dwData, (int)(**(int**)dwData));
  426. phmData->m_cur_Cat = phmData->m_pInfoType->GetCatPosition(ITData.pszCatName);
  427. if( phmData->m_cur_Cat == -1 )
  428. return (HWND)-1;
  429. if ( phmData->m_cur_IT ==0 )
  430. phmData->m_cur_IT = phmData->m_pInfoType->GetFirstCategoryType( phmData->m_cur_Cat-1 );
  431. else
  432. phmData->m_cur_IT = phmData->m_pInfoType->GetNextITinCategory( );
  433. if ( phmData->m_cur_IT == -1 )
  434. return (HWND)-1;
  435. ITData.iType = IT_INCLUSIVE;
  436. if ( phmData->m_pInfoType->IsHidden( phmData->m_cur_IT) )
  437. ITData.iType = IT_HIDDEN;
  438. else
  439. if ( phmData->m_pInfoType->IsExclusive( phmData->m_cur_IT ) )
  440. ITData.iType = IT_EXCLUSIVE;
  441. ITData.pszITName = phmData->m_pInfoType->GetInfoTypeName( phmData->m_cur_IT );
  442. ITData.pszITDescription = phmData->m_pInfoType->GetInfoTypeDescription( phmData->m_cur_IT );
  443. memcpy(*(PHH_ENUM_IT*)dwData, (PHH_ENUM_IT)(pITData), sizeof(HH_ENUM_IT) );
  444. return reinterpret_cast<HWND>((DWORD_PTR)(phmData->m_cur_IT));
  445. }
  446. case HH_SET_INCLUSIVE_FILTER:
  447. DBWIN("HH_SET_INCLUSIVE_FILTER");
  448. {
  449. CHmData* phmData=NULL;
  450. phmData = FindCurFileData( pszFile );
  451. if ( phmData == NULL )
  452. return (HWND)-1;
  453. if ( !phmData->m_pInfoType )
  454. {
  455. phmData->m_pInfoType = new CInfoType();
  456. phmData->m_pInfoType->CopyTo( phmData );
  457. }
  458. if ( !phmData->m_pAPIInfoTypes )
  459. return (HWND)-1;
  460. *phmData->m_pAPIInfoTypes &= ~1L; // turn bit zero off for inclusive filtering; ie to 0.
  461. return NULL;
  462. }
  463. break;
  464. case HH_SET_EXCLUSIVE_FILTER:
  465. DBWIN("HH_SET_EXCLUSIVE_FILTER");
  466. {
  467. CHmData* phmData=NULL;
  468. phmData = FindCurFileData( pszFile );
  469. if ( phmData == NULL )
  470. return (HWND)-1;
  471. if ( !phmData->m_pInfoType )
  472. {
  473. phmData->m_pInfoType = new CInfoType();
  474. phmData->m_pInfoType->CopyTo( phmData );
  475. }
  476. if ( !phmData->m_pAPIInfoTypes )
  477. return (HWND)-1;
  478. *phmData->m_pAPIInfoTypes |= 1L; // turn bit zero on for exclusive filtering; ie to 1.
  479. return NULL;
  480. }
  481. break;
  482. case HH_RESET_IT_FILTER:
  483. DBWIN("HH_RESET_IT_FILTER");
  484. {
  485. CHmData* phmData=NULL;
  486. BOOL fExclusive;
  487. phmData = FindCurFileData( pszFile );
  488. if ( phmData == NULL )
  489. return (HWND)-1;
  490. if ( !phmData->m_pInfoType )
  491. {
  492. phmData->m_pInfoType = new CInfoType();
  493. phmData->m_pInfoType->CopyTo( phmData );
  494. }
  495. if ( !phmData->m_pAPIInfoTypes )
  496. return NULL;
  497. if ( *phmData->m_pAPIInfoTypes & 1L )
  498. fExclusive = TRUE;
  499. memset(phmData->m_pAPIInfoTypes, '\0', phmData->m_pInfoType->InfoTypeSize() );
  500. if ( fExclusive )
  501. *phmData->m_pAPIInfoTypes |= 1L; // turn bit zero on for exclusive filtering; ie to 1.
  502. return NULL;
  503. }
  504. case HH_INITIALIZE:
  505. return (HWND)(DWORD_PTR)InitializeSession(reinterpret_cast<DWORD_PTR*>(dwData)) ;
  506. case HH_UNINITIALIZE:
  507. return (HWND)(DWORD_PTR)UninitializeSession(dwData) ;
  508. //--- These were internal and are now external.
  509. case HH_PRETRANSLATEMESSAGE:
  510. return (HWND)(DWORD_PTR)hhPreTranslateMessage((MSG*)dwData) ;
  511. case HH_SET_GLOBAL_PROPERTY:
  512. {
  513. CHHWinType *phh = FindCurWindow( );
  514. return (HWND)SetGlobalProperty(reinterpret_cast<HH_GLOBAL_PROPERTY*>(dwData), phh) ;
  515. }
  516. //--- Internal HH Commands.
  517. case HH_TITLE_PATHNAME : // Get the location of the title from its tag.
  518. DBWIN("HH_TITLE_PATHNAME");
  519. return reinterpret_cast<HWND>((DWORD_PTR)(GetLocationFromTitleTag(NULL/*pszFile*/, reinterpret_cast<HH_TITLE_FULLPATH*>(dwData)))) ;
  520. case HH_PRETRANSLATEMESSAGE2:
  521. return (HWND)(DWORD_PTR)hhPreTranslateMessage((MSG*)dwData, hwndCaller);
  522. case HH_HELP_CONTEXT_COLLECTION:
  523. DBWIN("HH_HELP_CONTEXT_COLLECTION");
  524. return OnHelpContextInCollection(hwndCaller, pszFile, dwData) ;
  525. case HH_RELOAD_NAV_DATA:
  526. {
  527. return OnReloadNavData(hwndCaller, pszFile, reinterpret_cast<HH_NAVDATA*>(dwData)) ;
  528. }
  529. case HH_GET_BROWSER_INTERFACE:
  530. {
  531. return reinterpret_cast<HWND>(GetBrowserInterface(hwndCaller, reinterpret_cast<IDispatch**>(dwData))) ;
  532. }
  533. default:
  534. DBWIN("Unsupported API call");
  535. return NULL;
  536. }
  537. }
  538. // <mc> As per HH bug 7487 NT5 bug 303099 I am placing a check here to see if we
  539. // appear to have a valid IE intallation. <mc/>
  540. //
  541. BOOL ValidateIE()
  542. {
  543. BOOL bRet = FALSE;
  544. HKEY hkey;
  545. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Internet Explorer", 0, KEY_READ, &hkey) == ERROR_SUCCESS)
  546. {
  547. char szVersion[MAX_URL];
  548. DWORD cbPath = sizeof(szVersion);
  549. if ( (RegQueryValueEx(hkey, "Version", NULL, NULL, (LPBYTE) szVersion, &cbPath) == ERROR_SUCCESS) )
  550. bRet = TRUE;
  551. else if ( (RegQueryValueEx(hkey, "IVer", NULL, NULL, (LPBYTE) szVersion, &cbPath) == ERROR_SUCCESS) )
  552. bRet = TRUE;
  553. else if ( (RegQueryValueEx(hkey, "Build", NULL, NULL, (LPBYTE) szVersion, &cbPath) == ERROR_SUCCESS) )
  554. bRet = TRUE;
  555. RegCloseKey(hkey);
  556. }
  557. return bRet;
  558. }
  559. /***************************************************************************
  560. FUNCTION: OnDisplayTopic
  561. PURPOSE: Display topic in current or specified window, creating the
  562. window if necessary.
  563. PARAMETERS:
  564. hwndCaller -- window requesting this topic
  565. pszFile -- file and optionally the window to display
  566. dwData -- optional data
  567. RETURNS:
  568. Window handle on success
  569. NULL on failure
  570. COMMENTS:
  571. A window name is specified by following the filename (if any) with
  572. a '>' character immediately followed by the window name:
  573. foo.hh>proc4
  574. If a window of the specified type isn't currently created, it will
  575. be created and activated. If the window type has been created, but
  576. is not active, it will be activated and the topic displayed in that
  577. window.
  578. MODIFICATION DATES:
  579. 27-Feb-1996 [ralphw]
  580. ***************************************************************************/
  581. HWND OnDisplayTopic(HWND hwndCaller, LPCSTR pszFile, DWORD_PTR dwData)
  582. {
  583. if (dwData && IsBadReadPtr((LPCSTR) dwData, sizeof(LPCSTR)))
  584. return NULL ;
  585. // <mc> As per HH bug 7487 NT5 bug 303099 I am placing a check here to see if we
  586. // appear to have a valid IE intallation. <mc/>
  587. //
  588. if ( ! ValidateIE() )
  589. return NULL;
  590. //--- If name has string %SystemRoot% add the windows directory.
  591. CStr cszTmp;
  592. PSTR psz = stristr(pszFile, txtSysRoot);
  593. if (psz) {
  594. char szPath[MAX_PATH];
  595. GetRegWindowsDirectory(szPath);
  596. strcat(szPath, psz + strlen(txtSysRoot));
  597. cszTmp = szPath;
  598. pszFile = (PCSTR) cszTmp.psz;
  599. }
  600. //--- Find the window name.
  601. CStr cszFile(pszFile);
  602. CStr cszWindow;
  603. PSTR pszWindow = StrChr(cszFile, WINDOW_SEPARATOR);
  604. if (pszWindow != NULL) {
  605. *pszWindow = '\0';
  606. RemoveTrailingSpaces(cszFile);
  607. cszWindow = FirstNonSpace(pszWindow + 1);
  608. }
  609. // Is the file a collection?
  610. BOOL bCollection = IsCollectionFile(pszFile);
  611. //--- dwData can point to a particular topic to which to jump. Add this topic.
  612. CStr cszExternal;
  613. if (dwData) {
  614. if (cszFile.IsEmpty())
  615. cszFile = (LPCSTR) dwData;
  616. else
  617. {
  618. //--- Hack: If there is a '::' assume we are specifying a chm file...
  619. PCSTR psz = (LPCSTR) dwData;
  620. if (bCollection && strstr(psz, "::"))
  621. {
  622. // Only valid if we are passing in a collection.
  623. cszExternal = psz;
  624. // If there is a window type at the end, remove it. We get the window type from the collection.
  625. PSTR pszWindowType = StrChr(cszExternal, WINDOW_SEPARATOR);
  626. if (pszWindowType != NULL)
  627. {
  628. *pszWindowType = '\0';
  629. }
  630. }
  631. else
  632. {
  633. cszFile += txtSepBack;
  634. cszFile += (*psz == '/' ? psz + 1 : psz);
  635. }
  636. }
  637. }
  638. //--- CHmData used by the CreateWindow call
  639. CHmData* pHmDataCreateWindow = NULL ;
  640. //--- We have a filename from which we can get the file.
  641. CHHWinType* phh = NULL;
  642. if (bCollection || IsCompiledHtmlFile(cszFile, &cszFile))
  643. {
  644. //--- Initialize the CHmData structure.
  645. CStr cszCompressed;
  646. PCSTR pszFilePortion = GetCompiledName(cszFile, &cszCompressed); // pszFilePortion is everything is cszFile after the '::', in other words the topic path.
  647. if (!FindThisFile(hwndCaller, cszCompressed, &cszCompressed, FALSE))
  648. {
  649. //TODO: Move error message into FindThisFile.
  650. g_LastError.Set(HH_E_FILENOTFOUND) ;
  651. return NULL;
  652. }
  653. CHmData* phmData = NULL;
  654. CExCollection* pCollection = GetCurrentCollection(NULL, pszFile);
  655. //
  656. // if ( .COL file AND g_Col != returned col ) OR ( .CHM file and g_col == returned col )
  657. //
  658. if ( !pCollection
  659. || ((bCollection && (pCollection != g_pCurrentCollection))
  660. || (!bCollection && (pCollection == g_pCurrentCollection))
  661. || (!bCollection && (pCollection == g_phmData[0]->m_pTitleCollection)))) //Bug:: May not have been loaded!!!
  662. {
  663. phmData = FindCurFileData(cszCompressed);
  664. }
  665. else
  666. {
  667. phmData = pCollection->m_phmData;
  668. }
  669. if (phmData == NULL)
  670. {
  671. g_LastError.Set(HH_E_INVALIDHELPFILE) ; // TODO: FindCurFileData should set this.
  672. return NULL;
  673. }
  674. ASSERT(phmData) ; // See the previous if statement!
  675. // IsCompiledHtmlFile has numerous side effects. We need those effects.
  676. if (bCollection)
  677. {
  678. // Get the name of the master chm.
  679. cszFile = phmData->GetCompiledFile();
  680. // Parse it to get the various pieces.
  681. IsCompiledHtmlFile(cszFile, &cszFile);
  682. }
  683. // Get the CHmData associated with the specified window type.
  684. if (cszWindow.IsNonEmpty()
  685. && !IsGlobalWinType(cszWindow.psz)) // Only use the information from window type if its non-global. Currently, means get the default topic from CHM passed in.
  686. {
  687. phh = FindWindowType(cszWindow, hwndCaller, cszFile);
  688. if (phh)
  689. {
  690. if (phh->m_phmData) // Bug 6799 - This is NULL until the window is created...
  691. {
  692. phmData = phh->m_phmData; //Review: Is the FindCurFileData above a waste in this case?
  693. }
  694. }
  695. else if (strcmp(cszWindow, txtDefWindow + 1) != 0 && strcmp(cszWindow, txtForceWindowType) != 0)
  696. {
  697. AuthorMsg(IDSHHA_NO_HH_GET_WIN_TYPE, cszWindow, hwndCaller, NULL);
  698. // Get the CHmData associated with the default window.
  699. // We could do this in the section outside the outer if, but I'm paranoid about breaking things...
  700. // The default window type is used only if it exists. Therefore, if we have to create a window,
  701. // will use the correct name.
  702. if (phmData->GetDefaultWindow() &&
  703. FindWindowType(phmData->GetDefaultWindow(), hwndCaller, cszFile))
  704. {
  705. AuthorMsg(IDSHHA_NO_HH_GET_WIN_TYPE, cszWindow, hwndCaller, NULL);
  706. cszWindow = phmData->GetDefaultWindow();
  707. }
  708. }
  709. }
  710. // Get the CHmData associated with the default window.
  711. if (cszWindow.IsEmpty() && phmData->GetDefaultWindow())
  712. cszWindow = phmData->GetDefaultWindow();
  713. //--- If the user didn't supply a topic, try and find one...
  714. if (pszFilePortion)
  715. {
  716. // If we have a topic, make sure that the slashes are correct.
  717. ConvertBackSlashToForwardSlash(const_cast<LPSTR>(pszFilePortion)) ; // Danger! Danger! Will Robinson! Casting away const on a pointer inside of a CStr...
  718. }
  719. else
  720. {
  721. LPCTSTR pTopic = NULL ;
  722. if (phh && phh->pszFile) // the window type has a topic
  723. {
  724. pTopic = phh->pszFile ;
  725. }
  726. else if (phmData && phmData->GetDefaultHtml()) // the CHmData struct's default html page.
  727. {
  728. pTopic = phmData->GetDefaultHtml() ;
  729. }
  730. if (pTopic)
  731. {
  732. if (*pTopic == '/') // Look for an initial separator.
  733. {
  734. pTopic++ ; // Skip the initial separator.
  735. }
  736. cszFile += txtSepBack;
  737. cszFile += pTopic ;
  738. }
  739. }
  740. // Get the CHmData structure we want to use with the window.
  741. if (cszExternal.IsEmpty())
  742. pHmDataCreateWindow = g_phmData[g_curHmData] ;
  743. else
  744. pHmDataCreateWindow = phmData ; // CHmdata for the collection.
  745. } // if IsCompiledFile.
  746. if (cszWindow.IsEmpty() && (!phh || phh->m_pCIExpContainer == NULL))
  747. cszWindow = txtForceWindowType;
  748. //--- The user supplied a window type or we have a default window type.
  749. if (cszWindow.IsNonEmpty())
  750. {
  751. CStr cszChmFile;
  752. if (cszFile.IsNonEmpty())
  753. GetCompiledName(cszFile, &cszChmFile); //Have to call this again, because pszFile was built back up.
  754. phh = FindWindowType(cszWindow, hwndCaller, cszChmFile); // Review: We may have already gotten the window type.
  755. if (!phh) // Can't find the window type, so create it.
  756. {
  757. if (strcmp(cszWindow, txtDefWindow + 1) != 0 && strcmp(cszWindow, txtForceWindowType) != 0)
  758. AuthorMsg(IDSHHA_NO_HH_GET_WIN_TYPE, cszWindow, hwndCaller, NULL);
  759. CreateDefaultWindowType(cszChmFile.IsEmpty() ?
  760. txtZeroLength : cszChmFile.psz, cszWindow); // This only does a HH_SET_WIN_TYPE
  761. phh = FindWindowType(cszWindow, hwndCaller, pszFile); // Try again to get the window type.
  762. }
  763. // We still don't have a valid window type or we don't have a valid window.
  764. if (!phh || !IsValidWindow(phh->GetHwnd()))
  765. {
  766. // Create the help window. This does a lot of work.
  767. phh = CreateHelpWindow(cszWindow, cszChmFile, hwndCaller, pHmDataCreateWindow);
  768. if (!phh)
  769. {
  770. g_LastError.Set(HH_E_INVALIDHELPFILE) ; // TODO: FindCurFileData should set this.
  771. return NULL ;
  772. }
  773. RECT rc;
  774. GetClientRect(phh->GetHwnd(), &rc);
  775. SendMessage(phh->GetHwnd(), WM_SIZE, SIZE_RESTORED, MAKELONG(RECT_WIDTH(rc),RECT_HEIGHT(rc)));
  776. // HTML Help Bug 6334 - For some reason on win95, we have a problem with coming up in the background.
  777. // Not sure why, however the following code which is basically what happens if we don't have
  778. // a window fixes the issue.
  779. if (!IsIconic(phh->GetHwnd()))
  780. {
  781. phh->SetActiveHelpWindow();
  782. }
  783. }
  784. else
  785. {
  786. // Bring the existing window to the front and restore if needed.
  787. phh->SetActiveHelpWindow();
  788. }
  789. ASSERT(phh) ; // This has to be true by now.
  790. // Still futzing with the filename. Review: Reduce the futzing.
  791. if (cszFile.IsEmpty())
  792. {
  793. if (phh->pszFile)
  794. cszFile = phh->pszFile;
  795. }
  796. }
  797. // If we are displaying the file in the collection space, just use the string passed in
  798. // the dwData parameter.
  799. return ChangeHtmlTopic(cszExternal.IsNonEmpty() ? cszExternal : cszFile, phh->GetHwnd());
  800. }
  801. HWND ChangeHtmlTopic(PCSTR pszFile, HWND hwndChild, BOOL bHighlight)
  802. {
  803. if (IsEmptyString(pszFile))
  804. return NULL;
  805. CHHWinType* phh;
  806. ASSERT_COMMENT(hwndChild, "It is not valid to call ChangeHtmlTopic with NULL for the calling window handle");
  807. phh = FindHHWindowIndex(hwndChild);
  808. CStr cszTmp;
  809. if ( IsCompiledURL( pszFile ) ) {
  810. if (!strstr(pszFile, txtDoubleColonSep)) {
  811. cszTmp = pszFile;
  812. cszTmp += txtDefFile;
  813. pszFile = cszTmp;
  814. }
  815. }
  816. if (phh->m_pCIExpContainer) {
  817. phh->m_fHighlight = bHighlight;
  818. phh->m_pCIExpContainer->m_pWebBrowserApp->Navigate(pszFile, NULL, NULL, NULL, NULL);
  819. #if 0
  820. if (phh->IsProperty(HHWIN_PROP_AUTO_SYNC))
  821. {
  822. if (phh->m_aNavPane[HH_TAB_CONTENTS])
  823. {
  824. cszTmp = pszFile;
  825. CToc* ptoc = reinterpret_cast<CToc*>(phh->m_aNavPane[HH_TAB_CONTENTS]) ; // HACKHACK: Should use dynamic cast.
  826. ptoc->Synchronize(cszTmp);
  827. }
  828. }
  829. #endif
  830. if (IsValidWindow(phh->GetHwnd())) {
  831. DBWIN("Bringing window to the front");
  832. SetWindowPos(phh->GetHwnd(), HWND_TOP, 0, 0, 0, 0,
  833. SWP_NOMOVE | SWP_NOSIZE);
  834. }
  835. #ifdef DEBUG
  836. else
  837. DBWIN("Invalid window handle");
  838. #endif
  839. return phh->GetHwnd();
  840. }
  841. return NULL;
  842. }
  843. BOOL ConvertToCacheFile(PCSTR pszSrc, PSTR pszDst)
  844. {
  845. if (!pszSrc)
  846. return FALSE;
  847. CStr cszTmp;
  848. PSTR psz = stristr(pszSrc, txtSysRoot);
  849. if (psz) {
  850. char szPath[MAX_PATH];
  851. GetRegWindowsDirectory(szPath);
  852. strcat(szPath, psz + strlen(txtSysRoot));
  853. cszTmp = szPath;
  854. pszSrc = (PCSTR) cszTmp.psz;
  855. }
  856. if ( IsCompiledURL( pszSrc ) )
  857. {
  858. strcpy(pszDst, pszSrc);
  859. if ( (GetURLType(pszDst) == HH_URL_UNQUALIFIED) )
  860. {
  861. // We need to qualify the .CHM filespec.
  862. //
  863. CExCollection *pCollection;
  864. CExTitle *pTitle;
  865. PSTR pszSep;
  866. if( (pCollection = GetCurrentCollection(NULL, pszDst)) )
  867. {
  868. if ( (SUCCEEDED(pCollection->URL2ExTitle(pszDst, &pTitle))) && pTitle )
  869. {
  870. if ( (pszSep = stristr(pszDst, txtDoubleColonSep)) )
  871. {
  872. while ( ((*(--pszSep) != ':')) && (pszSep != pszDst) );
  873. if ( *pszSep == ':' )
  874. *(++pszSep) = '\0';
  875. lstrcat(pszDst, pTitle->GetContentFileName());
  876. pszSep = stristr(pszSrc, txtDoubleColonSep);
  877. lstrcat(pszDst, pszSep);
  878. return TRUE;
  879. }
  880. }
  881. }
  882. }
  883. else
  884. return TRUE;
  885. }
  886. PCSTR pszChmSep = strstr(pszSrc, txtDoubleColonSep);
  887. if (pszChmSep) {
  888. if (pszSrc != cszTmp.psz) {
  889. cszTmp = pszSrc;
  890. int offset = (int)(pszChmSep - pszSrc);
  891. pszSrc = cszTmp;
  892. pszChmSep = pszSrc + offset;
  893. }
  894. *(PSTR) pszChmSep = '\0'; // Remove the separator
  895. HRESULT hr = URLDownloadToCacheFile(NULL, pszSrc, pszDst, MAX_PATH, 0, NULL);
  896. if (!SUCCEEDED(hr)) {
  897. CStr cszNew;
  898. BOOL fResult = FindThisFile(NULL, pszSrc, &cszNew, FALSE);
  899. if (fResult) {
  900. strcpy(pszDst, cszNew.psz);
  901. *(PSTR) pszChmSep = ':'; // Put the separator back
  902. strcat(pszDst, pszChmSep);
  903. return TRUE;
  904. }
  905. }
  906. else { // we downloaded it, or have a pointer to it
  907. *(PSTR) pszChmSep = ':'; // Put the separator back
  908. strcat(pszDst, pszChmSep);
  909. return TRUE;
  910. }
  911. }
  912. HRESULT hr = URLDownloadToCacheFile(NULL, pszSrc, pszDst, MAX_PATH, 0, NULL);
  913. if (!SUCCEEDED(hr)) {
  914. #if 0
  915. if (MessageBox(NULL, pszSrc, "URLDownloadToCacheFile failure", MB_RETRYCANCEL) == IDRETRY)
  916. DebugBreak();
  917. #endif
  918. return FALSE;
  919. }
  920. return TRUE;
  921. }
  922. void doAuthorMsg(UINT idStringFormatResource, PCSTR pszSubString);
  923. int (STDCALL *pHhaChangeParentWindow)(HWND hwndNewParent);
  924. extern "C" void AuthorMsg(UINT idStringFormatResource, PCSTR pszSubString, HWND hwndParent, void* phhctrl)
  925. {
  926. if (g_hmodHHA == NULL) {
  927. if (g_fTriedHHA || !LoadHHA(hwndParent, _Module.GetModuleInstance()))
  928. return; // no HHA.dll, so not a help author
  929. }
  930. if (!pHhaChangeParentWindow) {
  931. (FARPROC&) pHhaChangeParentWindow = GetProcAddress(g_hmodHHA, MAKEINTATOM(311));
  932. if (!pHhaChangeParentWindow)
  933. return;
  934. }
  935. pHhaChangeParentWindow(hwndParent);
  936. if (phhctrl)
  937. ((CHtmlHelpControl*)phhctrl)->ModalDialog(TRUE);
  938. doAuthorMsg(idStringFormatResource, pszSubString);
  939. if (phhctrl)
  940. ((CHtmlHelpControl*)phhctrl)->ModalDialog(FALSE);
  941. }
  942. void CreateDefaultWindowType(PCSTR pszCompiledFile, PCSTR pszWindow)
  943. {
  944. HH_WINTYPE hhWinType;
  945. ZERO_STRUCTURE(hhWinType);
  946. hhWinType.cbStruct = sizeof(HH_WINTYPE);
  947. hhWinType.fsToolBarFlags = HHWIN_DEF_BUTTONS;
  948. hhWinType.pszType = pszWindow;
  949. CStr cszToc; // use CStr so we automatically free the memory
  950. CStr cszIndex;
  951. bool bFail = true ;
  952. if (!IsEmptyString(pszCompiledFile) &&
  953. g_phmData && g_phmData[g_curHmData])
  954. {
  955. bool bHasFTS = !((g_phmData[g_curHmData]->m_sysflags.fFTI) == 0) == TRUE;
  956. bool bHasToc = IsNonEmptyString(g_phmData[g_curHmData]->GetDefaultToc()) == TRUE;
  957. bool bHasIndex = IsNonEmptyString(g_phmData[g_curHmData]->GetDefaultIndex()) == TRUE;
  958. bool bHasNavData = (bHasFTS || bHasToc || bHasIndex) ;
  959. if (bHasNavData)
  960. {
  961. hhWinType.fsToolBarFlags |= HHWIN_BUTTON_EXPAND;
  962. hhWinType.fsValidMembers |= HHWIN_PARAM_PROPERTIES | HHWIN_PARAM_TB_FLAGS;
  963. hhWinType.fsWinProperties |= HHWIN_PROP_CHANGE_TITLE | HHWIN_PROP_TRI_PANE ;
  964. if (bHasFTS)
  965. {
  966. hhWinType.fsWinProperties |= HHWIN_PROP_TAB_SEARCH;
  967. }
  968. if (bHasToc)
  969. {
  970. cszToc = pszCompiledFile;
  971. cszToc += "::/";
  972. cszToc += g_phmData[g_curHmData]->GetDefaultToc();
  973. hhWinType.pszToc = cszToc.psz;
  974. hhWinType.fsWinProperties |= HHWIN_PROP_AUTO_SYNC ;
  975. }
  976. if (bHasIndex)
  977. {
  978. cszIndex = pszCompiledFile;
  979. cszIndex += "::/";
  980. cszIndex += g_phmData[g_curHmData]->GetDefaultIndex();
  981. hhWinType.pszIndex = cszIndex.psz;
  982. if (!bHasToc) // REVIEW: 30 Jun 98 : Can this be removed? [dalero]
  983. {
  984. hhWinType.curNavType = HHWIN_NAVTYPE_INDEX;
  985. hhWinType.fsValidMembers |= HHWIN_PARAM_TABPOS;
  986. }
  987. }
  988. if (IsNonEmptyString(g_phmData[g_curHmData]->GetDefaultHtml()))
  989. {
  990. CStr csz, cszFull;
  991. csz = g_phmData[g_curHmData]->GetDefaultHtml();
  992. if (!stristr(csz, txtDoubleColonSep) &&
  993. !stristr(csz, txtFileHeader) && !stristr(csz, txtHttpHeader))
  994. {
  995. cszFull = g_phmData[g_curHmData]->GetCompiledFile();
  996. cszFull += txtSepBack;
  997. cszFull += csz.psz;
  998. cszFull.TransferPointer(&hhWinType.pszHome);
  999. }
  1000. else
  1001. csz.TransferPointer(&hhWinType.pszHome);
  1002. }
  1003. if (IsNonEmptyString(g_phmData[g_curHmData]->GetDefaultCaption()))
  1004. hhWinType.pszCaption = g_phmData[g_curHmData]->GetDefaultCaption();
  1005. else
  1006. hhWinType.pszCaption = lcStrDup(GetStringResource(IDS_DEF_WINDOW_CAPTION));
  1007. // We've made a nice default window type.
  1008. bFail = false ;
  1009. }
  1010. }
  1011. if (bFail)
  1012. {
  1013. hhWinType.pszCaption = lcStrDup(GetStringResource(IDS_DEF_WINDOW_CAPTION));
  1014. }
  1015. xHtmlHelpA(NULL, pszCompiledFile, HH_SET_WIN_TYPE, (DWORD_PTR) &hhWinType);
  1016. }
  1017. BOOL IsThisAWinHelpFile(HWND hwndCaller, PCSTR pszFile)
  1018. {
  1019. if (stristr(pszFile, txtWinHelpFileExt)) {
  1020. CStr cszFile;
  1021. if (FindThisFile(hwndCaller, pszFile, &cszFile, FALSE)) {
  1022. HFILE hf = _lopen(cszFile, OF_READ);
  1023. if (hf != HFILE_ERROR) {
  1024. BYTE aMagic[2];
  1025. _lread(hf, aMagic, sizeof(aMagic));
  1026. _lclose(hf);
  1027. if (aMagic[0] == '?' && aMagic[1] == '_') { // yep, this is a WinHelp file
  1028. return TRUE;
  1029. }
  1030. }
  1031. }
  1032. }
  1033. return FALSE;
  1034. }
  1035. ///////////////////////////////////////////////////////////////////////////////
  1036. //
  1037. // This does a Context ID lookup in the CollectionSpace.
  1038. //
  1039. HWND OnHelpContextInCollection(HWND hwndCaller,
  1040. LPCSTR pszColFile,
  1041. DWORD_PTR dwData)
  1042. {
  1043. HH_COLLECTION_CONTEXT* pContext = reinterpret_cast<HH_COLLECTION_CONTEXT*>(dwData);
  1044. //TODO: Validate.
  1045. if (!pContext)
  1046. {
  1047. return NULL ;
  1048. }
  1049. HWND hwndReturn = InternalHelpContext(hwndCaller, pszColFile, pContext->id, pContext);
  1050. if (!hwndReturn)
  1051. {
  1052. // We can be left in weird states after failures.
  1053. // So, we are going to be very aggresive about this and dump all the Hmdata if we don't end up
  1054. // with a window. We do this by deleting all of the CHHWinType structures.
  1055. // This is somewhat overkill, but the safest solution.
  1056. DeleteWindows() ;
  1057. }
  1058. return hwndReturn ;
  1059. }
  1060. ///////////////////////////////////////////////////////////////////////////////
  1061. //
  1062. // This is the original OnHelpContext
  1063. //
  1064. HWND OnHelpContext(HWND hwndCaller, LPCSTR pszFile, DWORD_PTR dwData)
  1065. {
  1066. return InternalHelpContext(hwndCaller, pszFile, dwData, NULL);
  1067. }
  1068. ///////////////////////////////////////////////////////////////////////////////
  1069. //
  1070. // Do the actual lookup.
  1071. //
  1072. HWND InternalHelpContext(HWND hwndCaller,
  1073. LPCSTR pszFile,
  1074. DWORD_PTR dwData,
  1075. HH_COLLECTION_CONTEXT* pContext)
  1076. {
  1077. CExTitle* pExTitle;
  1078. PSTR pszJumpFile;
  1079. char szMsg[256];
  1080. // Is this a WinHelp file?
  1081. if (IsThisAWinHelpFile(hwndCaller, pszFile)) {
  1082. WinHelp(hwndCaller, pszFile, HELP_CONTEXT, dwData);
  1083. return NULL;
  1084. }
  1085. PSTR psz = stristr(pszFile, txtSysRoot);
  1086. CStr cszTmp;
  1087. if (psz) {
  1088. char szPath[MAX_PATH];
  1089. GetRegWindowsDirectory(szPath);
  1090. strcat(szPath, psz + strlen(txtSysRoot));
  1091. cszTmp = szPath;
  1092. pszFile = (PCSTR) cszTmp.psz;
  1093. }
  1094. CStr cszFile(pszFile); // copy it so we can modify it
  1095. CStr cszWindow;
  1096. PSTR pszWindow = StrChr(cszFile, WINDOW_SEPARATOR);
  1097. if (pszWindow != NULL) {
  1098. *pszWindow = '\0';
  1099. RemoveTrailingSpaces(cszFile);
  1100. cszWindow = FirstNonSpace(pszWindow + 1);
  1101. }
  1102. //--- We want to be able to do a lookup in the context of a CHM.
  1103. BOOL bCollection = IsCollectionFile(cszFile);
  1104. if ((bCollection && pContext) // Only allow lookup in the collection space with valid pContext structure.
  1105. || IsCompiledHtmlFile(cszFile, &cszFile))
  1106. {
  1107. CStr cszCompressed;
  1108. PCSTR pszFilePortion = GetCompiledName(cszFile, &cszCompressed);
  1109. if (!FindThisFile(hwndCaller, cszCompressed, &cszCompressed))
  1110. {
  1111. g_LastError.Set(HH_E_FILENOTFOUND) ; // Let FindThisFile do this when it gets a process id.
  1112. return NULL;
  1113. }
  1114. CHmData* phmData = FindCurFileData(cszCompressed);
  1115. if (!phmData)
  1116. {
  1117. g_LastError.Set(HH_E_INVALIDHELPFILE) ; // TODO: FindCurFileData should set this.
  1118. return NULL ;
  1119. }
  1120. // Handle if we have a collection.
  1121. if ( bCollection )
  1122. {
  1123. // We have to have the tag name.
  1124. if (IsEmptyString(pContext->szTag))
  1125. {
  1126. // TODO: use pszFilePortion...((*pszFilePortion == '/') ? pszFilePortion+1 : pszFilePortion
  1127. return NULL ;
  1128. }
  1129. //---Get the path to the CHM.
  1130. pExTitle = phmData->m_pTitleCollection->FindTitleNonExact(pContext->szTag,
  1131. LANGIDFROMLCID(pContext->lcid)) ;
  1132. if (!pExTitle)
  1133. {
  1134. return NULL ;
  1135. }
  1136. //
  1137. // We're setting cszFile to the FQ .CHM name for use later in this function (only in the collection case).
  1138. //
  1139. cszFile = pExTitle->GetFileName();
  1140. //
  1141. // Yes, This has a side affect we're relying on. We want IsCompiledHtmlFile to decorate the URL for us.
  1142. //
  1143. //IsCompiledHtmlFile(cszFile, &cszFile); // Doesn't work in CD swaping case.
  1144. char szTmp[MAX_PATH*4]; //REVIEW:: Inefficient
  1145. wsprintf(szTmp, "%s%s", (g_bMsItsMonikerSupport ? txtMsItsMoniker : txtMkStore), //TODO: We are adding moniker information. This should be centralized.
  1146. cszFile.psz);
  1147. cszFile = szTmp ;
  1148. }
  1149. else
  1150. {
  1151. if (! phmData->m_pTitleCollection->IsSingleTitle() )
  1152. {
  1153. g_LastError.Set(HH_E_INVALIDHELPFILE) ; // TODO: FindCurFileData should set this.
  1154. return NULL;
  1155. }
  1156. pExTitle = phmData->GetExTitle();
  1157. }
  1158. //
  1159. // Now translate the context hash int a URL so we can jump!
  1160. //
  1161. HRESULT hr = pExTitle->ResolveContextId((DWORD)dwData, &pszJumpFile);
  1162. if ( hr != S_OK )
  1163. {
  1164. g_LastError.Set(hr);
  1165. if (IsHelpAuthor(NULL))
  1166. {
  1167. if ( hr == HH_E_NOCONTEXTIDS )
  1168. doAuthorMsg(IDS_HHA_NO_MAP_SECTION, "");
  1169. else if ( hr == HH_E_CONTEXTIDDOESNTEXIT )
  1170. {
  1171. wsprintf(szMsg, pGetDllStringResource(IDS_HHA_MISSING_MAP_ID), dwData, cszFile.psz);
  1172. SendStringToParent(szMsg);
  1173. }
  1174. }
  1175. return NULL;
  1176. }
  1177. #if 0 // TEST TEST TEST
  1178. CStr test("vbcmn98.chm::/html\\vbproMaxMinPropertiesActiveXControls.htm") ;
  1179. pszJumpFile = test ;
  1180. #endif //TEST TEST TEST
  1181. BOOL fIsInterFileJump = IsCompiledHtmlFile(pszJumpFile);
  1182. char szUrl[MAX_PATH*4];
  1183. if (bCollection & fIsInterFileJump)
  1184. {
  1185. //--- This is an interfile jump in the context of the collection.
  1186. // We need a full path to this file so that we can find it.
  1187. CStr pszChmName;
  1188. PCSTR pszTopic = GetCompiledName(pszJumpFile, &pszChmName);
  1189. // Remove the extension.
  1190. PSTR pszExt = stristr(pszChmName, txtDefExtension); // case insensitive search.
  1191. if (pszExt)
  1192. *pszExt = '\0' ;
  1193. // Look in the global col file for this chm.
  1194. HH_TITLE_FULLPATH tf ;
  1195. tf.lcid = pContext->lcid ;
  1196. tf.szTag = pszChmName ;
  1197. tf.fullpathname = NULL;
  1198. if (GetLocationFromTitleTag(NULL/*cszCompressed*/, &tf))
  1199. {
  1200. // Found it.
  1201. CStr full(tf.fullpathname) ; // Convert.
  1202. wsprintf(szUrl, "%s%s::%s", (g_bMsItsMonikerSupport ? txtMsItsMoniker : txtMkStore), //TODO: We are adding moniker information. This should be centralized.
  1203. full.psz,
  1204. pszTopic);
  1205. ::SysFreeString(tf.fullpathname); // cleanup.
  1206. }
  1207. else
  1208. {
  1209. // Didn't find it. hope for the best...maybe its in the windows help directory.
  1210. strcpy(szUrl, pszJumpFile);
  1211. }
  1212. }
  1213. else if (fIsInterFileJump)
  1214. {
  1215. // On an interfile jump we are given the name of the chm and the topic: "help.chm::topic.htm"
  1216. // So we don't combine the two together.
  1217. // BUGBUG: This will rarely work, since we will not have a fullpath to the chm.
  1218. // To work, it must be in the windows help directory.
  1219. strcpy(szUrl, pszJumpFile);
  1220. }
  1221. else
  1222. {
  1223. // Combine the chm name with the topic name.
  1224. wsprintf(szUrl, "%s::/%s", cszFile.psz, pszJumpFile);
  1225. }
  1226. // Add on the window.
  1227. if (cszWindow.IsNonEmpty()) {
  1228. strcat(szUrl, ">");
  1229. strcat(szUrl, cszWindow);
  1230. }
  1231. if (IsHelpAuthor(NULL)) {
  1232. wsprintf(szMsg, pGetDllStringResource(IDS_HHA_HH_HELP_CONTEXT),
  1233. fIsInterFileJump ? "" : cszFile.psz, dwData, pszJumpFile);
  1234. SendStringToParent(szMsg);
  1235. }
  1236. // Send the COL file to HH_DISPLAY_TOPIC. Also send the chm::htm string.
  1237. if (bCollection)
  1238. {
  1239. return OnDisplayTopic(hwndCaller, cszCompressed, (DWORD_PTR)szUrl);
  1240. }
  1241. else
  1242. {
  1243. return OnDisplayTopic(hwndCaller, szUrl, NULL);
  1244. }
  1245. }
  1246. else
  1247. {
  1248. return NULL ;
  1249. }
  1250. }
  1251. /***************************************************************************
  1252. FUNCTION: SetWinType
  1253. PURPOSE:
  1254. PARAMETERS:
  1255. hwndCaller -- window requesting this topic
  1256. pszFile -- file and window
  1257. bFindCurdata -- if true, it will call FindCurFileData.
  1258. Only ReadSystemFiles should call this with True. Its main purpose is to prevent
  1259. re-entering ReadSystemFiles.
  1260. RETURNS:
  1261. COMMENTS:
  1262. MODIFICATION DATES:
  1263. 27-Apr-98
  1264. ***************************************************************************/
  1265. HWND
  1266. SetWinType(LPCSTR pszFile, HH_WINTYPE* phhWinType, CHmData* phmDataOrg /*= NULL*/)
  1267. {
  1268. // Check for uninitialized or invalid pointers
  1269. if (IsBadReadPtr(phhWinType, sizeof(HH_WINTYPE*)))
  1270. // BUGBUG: nag the help author
  1271. return FALSE;
  1272. if (IsBadReadPtr(phhWinType->pszType, sizeof(PCSTR)) || IsEmptyString(phhWinType->pszType))
  1273. // BUGBUG: nag the help author
  1274. return FALSE;
  1275. if (IsNonEmptyString(pszFile))
  1276. {
  1277. // If a CHM happens to have a global window type in it, we do not want to re-load the window type information
  1278. // from the CHM if it has already been loaded. Bug 1.1c 5175
  1279. if (IsGlobalWinType(phhWinType->pszType))
  1280. {
  1281. // We are attempting to load the win type information from the CHM.
  1282. // Check to see if it has already been loaded.
  1283. CHHWinType* phh = FindWindowType(phhWinType->pszType, NULL, NULL);
  1284. if (phh)
  1285. {
  1286. // Don't over write the window type.
  1287. return FALSE ;
  1288. }
  1289. }
  1290. // Window types are owned by a particular chm. Unless they are global....
  1291. if (!phmDataOrg)
  1292. {
  1293. FindCurFileData(pszFile); // We aren't getting loaded by SetWinType. So we don't have an Org file...
  1294. }
  1295. }
  1296. else
  1297. {
  1298. // No filename specified. Must be a global window type.
  1299. if (!IsGlobalWinType(phhWinType->pszType))
  1300. {
  1301. // Force it to be a global window type.
  1302. _Module.m_GlobalWinTypes.Add(phhWinType->pszType) ;
  1303. }
  1304. }
  1305. // The following code will over write any current definitions of this window type.
  1306. CHHWinType* phh = FindOrCreateWindowSlot(phhWinType->pszType, pszFile);
  1307. if (!phh)
  1308. return FALSE ;
  1309. CHHWinType* phhNew = (CHHWinType*) phhWinType;
  1310. phh->SetUniCodeStrings(phhWinType);
  1311. phh->SetCaption(phhWinType);
  1312. phh->SetToc(phhWinType);
  1313. phh->SetIndex(phhWinType);
  1314. phh->SetFile(phhWinType);
  1315. phh->SetValidMembers(phhWinType);
  1316. phh->SetProperties(phhWinType);
  1317. phh->SetStyles(phhWinType);
  1318. phh->SetExStyles(phhWinType);
  1319. phh->SetWindowRect(phhWinType);
  1320. phh->SetDisplayState(phhWinType);
  1321. phh->SetNavExpansion(phhWinType);
  1322. phh->SetNavWidth(phhWinType);
  1323. phh->SetCaller(phhWinType);
  1324. phh->SetHome(phhWinType);
  1325. phh->SetToolBar(phhWinType);
  1326. phh->SetTabPos(phhWinType);
  1327. phh->SetTabOrder(phhWinType);
  1328. phh->SetJump1(phhWinType);
  1329. phh->SetJump2(phhWinType);
  1330. phh->SetCurNavType(phhWinType);
  1331. phh->idNotify = phhWinType->idNotify;
  1332. if (phmDataOrg)
  1333. {
  1334. /*
  1335. We are being loaded from ReadSystemFiles. We need to store the CHMDATA from which we are created,
  1336. so that we get the custom tab information from the [options] sections of the correct CHM. The
  1337. m_pChmData paramter isn't good enough since it is arbitarily set during create window and is over written
  1338. as a result of the HH_RELOAD_NAV_DATA.
  1339. */
  1340. phh->m_phmDataOrg = phmDataOrg ;
  1341. }
  1342. // If there isn't a table of contents, turn off various parameters.
  1343. if (!phh->IsValidNavPane(HH_TAB_CONTENTS))
  1344. {
  1345. if (phh->IsValidMember(HHWIN_PARAM_TB_FLAGS))
  1346. {
  1347. phh->fsToolBarFlags &= ~HHWIN_BUTTON_TOC_PREV ;
  1348. phh->fsToolBarFlags &= ~HHWIN_BUTTON_TOC_NEXT ;
  1349. }
  1350. }
  1351. // If we are a tri-pane window with nothing to expand,
  1352. // then shut off the automatic expansion
  1353. if (!phh->AnyValidNavPane())
  1354. {
  1355. phh->fNotExpanded = TRUE;
  1356. // Bug 1084 Disable the Expand button also.
  1357. phh->fsToolBarFlags &= ~HHWIN_BUTTON_EXPAND ;
  1358. }
  1359. #ifdef _DEBUG
  1360. DWORD dwOldStyle;
  1361. #endif
  1362. // Does this window type name already exist.
  1363. if (!phh->GetTypeName())
  1364. {
  1365. phh->SetTypeName(phhWinType);
  1366. return phh->GetHwnd();
  1367. }
  1368. else
  1369. {
  1370. // Change the existing window type.
  1371. // REVIEW: IsValidWindow(phh->GetHwnd() is called TOO often
  1372. // Set Caption
  1373. if (phhNew->GetCaption() && IsValidWindow(phh->GetHwnd()))
  1374. SetWindowText(phh->GetHwnd(), phh->GetCaption());
  1375. // Set window styles
  1376. bool bStyleChanged = false ;
  1377. if (phhNew->IsValidMember(HHWIN_PARAM_STYLES))
  1378. {
  1379. phh->AddStyle(WS_VISIBLE | WS_CLIPSIBLINGS); //REVIEW: Why isn't this part of DEFAULT_STYLE?
  1380. if (IsValidWindow(phh->GetHwnd()))
  1381. {
  1382. #ifdef _DEBUG
  1383. dwOldStyle = GetWindowLong(*phh, GWL_STYLE);
  1384. #endif
  1385. SetWindowLong(*phh, GWL_STYLE, phh->GetStyles());
  1386. bStyleChanged = true;
  1387. }
  1388. }
  1389. // Change extended window styles.
  1390. if (phhNew->IsValidMember(HHWIN_PARAM_EXSTYLES))
  1391. {
  1392. if (!(phhNew->IsProperty(HHWIN_PROP_NODEF_EXSTYLES)))
  1393. {
  1394. if (IsValidWindow(phh->GetHwnd()))
  1395. phh->AddStyle(GetWindowLong(phh->GetHwnd(), GWL_EXSTYLE));
  1396. if (phhWinType->fsWinProperties & HHWIN_PROP_ONTOP)
  1397. phh->AddStyle(WS_EX_TOPMOST);
  1398. }
  1399. if (IsValidWindow(phh->GetHwnd())) {
  1400. #ifdef _DEBUG
  1401. dwOldStyle = GetWindowLong(phh->GetHwnd(), GWL_EXSTYLE);
  1402. #endif
  1403. SetWindowLong(phh->GetHwnd(), GWL_EXSTYLE, phh->GetExStyles());
  1404. bStyleChanged = true;
  1405. }
  1406. }
  1407. if (bStyleChanged)
  1408. {
  1409. // Must call this for SetWindowLong to take affect. See docs for SetWindowPos and SetWindowLong.
  1410. SetWindowPos(phh->GetHwnd(), NULL, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED) ;
  1411. }
  1412. // Change the rect.
  1413. if (phhNew->IsValidMember(HHWIN_PARAM_RECT))
  1414. {
  1415. phh->GetWindowRect();
  1416. if (phhNew->GetLeft() >= 0)
  1417. phh->rcWindowPos.left = phhNew->GetLeft();
  1418. if (phhNew->GetRight() >= 0)
  1419. phh->rcWindowPos.right = phhNew->GetRight();
  1420. if (phhNew->GetTop() >= 0)
  1421. phh->rcWindowPos.top = phhNew->GetTop();
  1422. if (phhNew->GetBottom() >= 0)
  1423. phh->rcWindowPos.bottom = phhNew->GetBottom();
  1424. if (IsValidWindow(*phh))
  1425. MoveWindow(*phh, phh->GetLeft(), phh->GetTop(),
  1426. phh->GetWidth(), phh->GetHeight(), TRUE);
  1427. }
  1428. // Change the show state.
  1429. if (phhNew->IsValidMember(HHWIN_PARAM_SHOWSTATE))
  1430. {
  1431. if (IsValidWindow(phh->GetHwnd()))
  1432. ShowWindow(phh->GetHwnd(), phh->GetShowState());
  1433. }
  1434. return phh->GetHwnd();
  1435. }
  1436. }
  1437. /***************************************************************************
  1438. FUNCTION: GetWinType
  1439. PURPOSE:
  1440. PARAMETERS:
  1441. hwndCaller -- window requesting this topic
  1442. pszFile -- file and window
  1443. RETURNS:
  1444. COMMENTS:
  1445. MODIFICATION DATES:
  1446. 27-Apr-98
  1447. ***************************************************************************/
  1448. HWND
  1449. GetWinType(HWND hwndCaller, LPCSTR pszFile, HH_WINTYPE** pphh)
  1450. {
  1451. CStr cszChmName ;
  1452. CStr cszWindow ;
  1453. // Support global window types
  1454. //
  1455. if(pszFile)
  1456. {
  1457. LPCSTR pszWinType = pszFile;
  1458. if(pszWinType[0]=='>')
  1459. pszWinType++;
  1460. if(pszWinType && IsGlobalWinType(pszWinType))
  1461. {
  1462. CHHWinType* phh = FindWindowType(pszWinType, hwndCaller, cszChmName);
  1463. if (!phh)
  1464. return (HWND) -1;
  1465. *pphh = phh;
  1466. return phh->GetHwnd();
  1467. }
  1468. }
  1469. // A filename and window type name are required to get the window type.
  1470. if (!GetNameAndWinType(pszFile, cszChmName, cszWindow))
  1471. {
  1472. return (HWND) -1;
  1473. }
  1474. // Read in the chm information.
  1475. if (!IsCompiledHtmlFile(cszChmName, &cszChmName))
  1476. {
  1477. return (HWND) -1;
  1478. }
  1479. CStr cszCompressed ;
  1480. GetCompiledName(cszChmName, &cszCompressed);
  1481. CHmData* phm = FindCurFileData(cszCompressed);
  1482. if (!phm)
  1483. {
  1484. return (HWND) -1;
  1485. }
  1486. // Need to include compiled filename with window lookup
  1487. // since there can be two or more .CHM files with identical window type
  1488. // names, but different definitions
  1489. CHHWinType* phh = FindWindowType(cszWindow, hwndCaller, cszChmName);
  1490. if (!phh)
  1491. {
  1492. //BUG 5004: Not sure what the purpose of all of this stuff is. However,
  1493. // cszWindow doesn't have the '>' prefix and txtDefWindow does...[dalero]
  1494. if (strcmp(cszWindow, (txtDefWindow+1)) != 0)
  1495. {
  1496. AuthorMsg(IDSHHA_NO_HH_GET_WIN_TYPE, cszWindow, hwndCaller, NULL);
  1497. }
  1498. return (HWND) -1;
  1499. }
  1500. *pphh = phh;
  1501. return phh->GetHwnd();
  1502. }
  1503. /***************************************************************************
  1504. FUNCTION: doDisplaySearch
  1505. PURPOSE: Save as HH_DISPLAY_TOPIC, but forces search tab to front.
  1506. PARAMETERS:
  1507. hwndCaller -- window requesting this topic
  1508. pszFile -- file and optionally the window to display
  1509. pFtsQuery -- the query information structure.
  1510. RETURNS:
  1511. Window handle on success
  1512. NULL on failure
  1513. COMMENTS:
  1514. MODIFICATION DATES:
  1515. 26-Jun-97
  1516. ***************************************************************************/
  1517. HWND doDisplaySearch(HWND hwndCaller, LPCSTR pszFile, HH_FTS_QUERY* pFtsQuery)
  1518. {
  1519. //
  1520. // Pre-conditions
  1521. //
  1522. // Null pointers
  1523. ASSERT(IsNonEmptyString(pszFile));
  1524. ASSERT(pFtsQuery);
  1525. if (IsEmptyString(pszFile) || IsBadReadPtr(pFtsQuery, sizeof(HH_FTS_QUERY*)))
  1526. {
  1527. FAIL("HH_DISPLAY_SEARCH: pszFile or pFtsQuery is invalid.") ;
  1528. return NULL;
  1529. }
  1530. // Incorrect structure size.
  1531. if (pFtsQuery->cbStruct != sizeof(HH_FTS_QUERY))
  1532. {
  1533. // REVIEW: means all previous versions fail the instant we change the
  1534. // structure size. We should just fill in the parts of the structure
  1535. // we don't know about.
  1536. FAIL("HH_DISPLAY_SEARCH: pFtsQuery points to structure with incorrect size.");
  1537. return NULL ;
  1538. }
  1539. //
  1540. // Handle parameters.
  1541. //
  1542. // String pointer can be NULL, if search is not seeded.
  1543. // TODO - Query string.
  1544. // Change Proximity
  1545. if (pFtsQuery->iProximity != HH_FTS_DEFAULT_PROXIMITY)
  1546. {
  1547. }
  1548. // Convert Strings
  1549. if (pFtsQuery->fUniCodeStrings)
  1550. {
  1551. FAIL("HH_DISPLAY_SEARCH: fUniCodeStrings is not yet implemented. Ignoring.") ;
  1552. }
  1553. // Manipulate options
  1554. if (pFtsQuery->fStemmedSearch)
  1555. {
  1556. FAIL("HH_DISPLAY_SEARCH: fStemmedSearch is not yet implemented. Ignoring.") ;
  1557. }
  1558. if (pFtsQuery->fTitleOnly)
  1559. {
  1560. FAIL("HH_DISPLAY_SEARCH: fTitleOnly is not yet implemented. Ignoring.") ;
  1561. }
  1562. // Can only Execute if there is a search string.
  1563. if (pFtsQuery->fExecute)
  1564. {
  1565. FAIL("HH_DISPLAY_SEARCH: fExecute is not yet implemented. Ignoring.") ;
  1566. }
  1567. // Merge the window with the filename.
  1568. CStr cszFile(pszFile);
  1569. if (!IsEmptyString(pFtsQuery->pszWindow))
  1570. {
  1571. cszFile += ">";
  1572. // BUGBUG: Doesn't handle UNICODE
  1573. cszFile += pFtsQuery->pszWindow;
  1574. }
  1575. // Display the topic
  1576. HWND hwnd = ReactivateDisplayTopic(hwndCaller, pszFile, 0);
  1577. // Did it succeed?
  1578. if (!hwnd || !IsValidWindow(hwnd))
  1579. {
  1580. FAIL("HH_DISPLAY_SEARCH: Could not start help system.") ;
  1581. return NULL ;
  1582. }
  1583. // BUGBUG: 19-Jun-1997 [ralphw] Why are we doing this? It's already on top
  1584. // Bring help window to front.
  1585. ::BringWindowToTop(hwnd);
  1586. // Change the current tab.
  1587. CHHWinType* phh = FindHHWindowIndex(hwnd);
  1588. ASSERT(phh);
  1589. phh->doSelectTab(HH_TAB_SEARCH) ;
  1590. // TODO: Seed edit box.
  1591. // Done
  1592. return hwnd;
  1593. }
  1594. /***************************************************************************
  1595. FUNCTION: doDisplayIndex
  1596. PURPOSE: Does a DISPLAY_TOPIC but ensures that the Index tab is selected.
  1597. PARAMETERS:
  1598. hwndCaller -- window requesting this topic
  1599. pszFile -- file and optionally the window to display
  1600. pszKeyword -- keyword with which to seed edit control
  1601. RETURNS:
  1602. Window handle on success
  1603. NULL on failure
  1604. COMMENTS:
  1605. MODIFICATION DATES:
  1606. 26-Jun-97 [dalero] created.
  1607. ***************************************************************************/
  1608. HWND doDisplayIndex(HWND hwndCaller, LPCSTR pszFile, LPCSTR pszKeyword)
  1609. {
  1610. //
  1611. // Pre-conditions
  1612. //
  1613. // Null pointers
  1614. ASSERT(IsNonEmptyString(pszFile));
  1615. if (IsEmptyString(pszFile))
  1616. {
  1617. FAIL("HH_DISPLAY_SEARCH: pszFile or pFtsQuery is invalid.") ;
  1618. return NULL;
  1619. }
  1620. // Display the topic
  1621. HWND hwnd = ReactivateDisplayTopic(hwndCaller, pszFile, 0);
  1622. // Did it succeed?
  1623. if (!hwnd || !IsValidWindow(hwnd))
  1624. {
  1625. FAIL("HH_DISPLAY_SEARCH: Could not start help system.") ;
  1626. return NULL ;
  1627. }
  1628. // Bring help window to front.
  1629. ::BringWindowToTop(hwnd);
  1630. // Change the current tab.
  1631. CHHWinType* phh = FindHHWindowIndex(hwnd);
  1632. ASSERT(phh);
  1633. phh->doSelectTab(HH_TAB_INDEX) ;
  1634. #define _SEED_ON_
  1635. #ifdef _SEED_ON_
  1636. // Seed Edit Control
  1637. //ASSERT(phh->m_pindex != NULL) ;
  1638. if ((phh->m_aNavPane[HH_TAB_INDEX] != NULL) && pszKeyword )
  1639. {
  1640. phh->m_aNavPane[HH_TAB_INDEX]->Seed(pszKeyword) ;
  1641. }
  1642. #endif
  1643. // Done
  1644. return hwnd;
  1645. }
  1646. /***************************************************************************
  1647. FUNCTION: doDisplayToc
  1648. PURPOSE: Does a DISPLAY_TOPIC but ensures that the TOC tab is selected.
  1649. PARAMETERS:
  1650. hwndCaller -- window requesting this topic
  1651. pszFile -- file and optionally the window to display
  1652. RETURNS:
  1653. Window handle on success
  1654. NULL on failure
  1655. COMMENTS:
  1656. MODIFICATION DATES:
  1657. 26-Jun-97 [dalero] created.
  1658. ***************************************************************************/
  1659. HWND doDisplayToc(HWND hwndCaller, LPCSTR pszFile, DWORD_PTR dwData)
  1660. {
  1661. //
  1662. // Pre-conditions
  1663. //
  1664. // Null pointers
  1665. ASSERT(IsNonEmptyString(pszFile));
  1666. if (IsEmptyString(pszFile))
  1667. {
  1668. FAIL("HH_DISPLAY_SEARCH: pszFile or pFtsQuery is invalid.") ;
  1669. return NULL;
  1670. }
  1671. HWND hwnd = ReactivateDisplayTopic(hwndCaller, pszFile, dwData);
  1672. // Did it succeed?
  1673. if (!hwnd || !IsValidWindow(hwnd))
  1674. {
  1675. FAIL("HH_DISPLAY_SEARCH: Could not start help system.") ;
  1676. return NULL ;
  1677. }
  1678. // Bring help window to front.
  1679. ::BringWindowToTop(hwnd);
  1680. // Change the current tab.
  1681. CHHWinType* phh = FindHHWindowIndex(hwnd);
  1682. ASSERT(phh);
  1683. phh->doSelectTab(HH_TAB_CONTENTS) ;
  1684. // Done
  1685. return hwnd;
  1686. }
  1687. /***************************************************************************
  1688. FUNCTION: GetLocationFromTitleTag
  1689. PURPOSE: Looks in the global col to find the location for this TitleTag
  1690. PARAMETERS:
  1691. pszFile --- Filename of the collection to look in. NULL for global.col
  1692. HH_TITLE_FULLPATH pTitleFullPath
  1693. RETURNS:
  1694. NULL on failure
  1695. COMMENTS:
  1696. MODIFICATION DATES:
  1697. 31-Oct-97 [dalero] created.
  1698. 03-Apr-98 [dalero] the szCollection parameter is currently not used.
  1699. ***************************************************************************/
  1700. int
  1701. GetLocationFromTitleTag(LPCSTR szCollection, HH_TITLE_FULLPATH* pTitleFullPath)
  1702. {
  1703. int iReturn = false ;
  1704. // Open a dummy collection.
  1705. CCollection collection ;
  1706. DWORD e = collection.Open(szCollection ? szCollection : "placeholder") ;
  1707. if (e == F_OK)
  1708. {
  1709. // Locates a title based on id
  1710. CTitle* pTitle = collection.FindTitleNonExact(pTitleFullPath->szTag, LANGIDFROMLCID(pTitleFullPath->lcid)) ;
  1711. if (pTitle)
  1712. {
  1713. // Always get the last one.
  1714. LOCATIONHISTORY* pLocationHistory = pTitle->m_pTail;//LOCATIONHISTORY* pLocationHistory = pTitle->GetLocation(/*DWORD Index*/0);
  1715. if (pLocationHistory && pLocationHistory->FileName)
  1716. {
  1717. CWStr wide(pLocationHistory->FileName) ;
  1718. pTitleFullPath->fullpathname = ::SysAllocString(wide) ;
  1719. iReturn = true ;
  1720. }
  1721. }
  1722. }
  1723. return iReturn ;
  1724. }
  1725. /***************************************************************************
  1726. FUNCTION: ReactivateDisplayTopic
  1727. PURPOSE: If default window type exists, returns HWND.
  1728. Otherwise, does an OnDisplayTopic.
  1729. This allows OnDisplayToc and others to not change the current topic when changing the tab.
  1730. PARAMETERS:
  1731. RETURNS:
  1732. NULL on failure
  1733. COMMENTS:
  1734. MODIFICATION DATES:
  1735. 13 Jan 98 [dalero] created.
  1736. ***************************************************************************/
  1737. HWND ReactivateDisplayTopic(HWND hwndCaller, LPCSTR pszFile, DWORD_PTR dwData)
  1738. {
  1739. // A lot of this is copied from OnDisplayTopic...
  1740. CStr cszFile(pszFile);
  1741. CStr cszCompressed ;
  1742. GetCompiledName(cszFile, &cszCompressed);
  1743. if (FindThisFile(hwndCaller, cszCompressed, &cszCompressed, FALSE))
  1744. {
  1745. // Get the CHmData for this file.
  1746. CHmData* phmData = FindCurFileData(cszCompressed); // Get the
  1747. if (phmData)
  1748. {
  1749. // Get the info for the default window type structure.
  1750. CHHWinType* phh = FindWindowType(phmData->GetDefaultWindow(), hwndCaller, cszCompressed);
  1751. if (phh && phh->GetHwnd() && IsWindow(phh->GetHwnd()))
  1752. {
  1753. WINDOWPLACEMENT wp;
  1754. wp.length = sizeof(WINDOWPLACEMENT);
  1755. GetWindowPlacement(phh->GetHwnd(), &wp);
  1756. if (wp.showCmd == SW_SHOWMINIMIZED)
  1757. {
  1758. ShowWindow(phh->GetHwnd(), SW_RESTORE);
  1759. }
  1760. SetForegroundWindow(phh->GetHwnd());
  1761. return phh->GetHwnd() ;
  1762. }
  1763. }
  1764. }
  1765. // Display the topic
  1766. return OnDisplayTopic(hwndCaller, pszFile, 0);
  1767. }
  1768. /***************************************************************************
  1769. FUNCTION: ReactivateDisplayTopic
  1770. PURPOSE: If default window type exists, returns HWND.
  1771. Otherwise, does an OnDisplayTopic.
  1772. This allows OnDisplayToc and others to not change the current topic when changing the tab.
  1773. PARAMETERS:
  1774. RETURNS:
  1775. NULL on failure
  1776. COMMENTS:
  1777. MODIFICATION DATES:
  1778. 13 Jan 98 [dalero] created.
  1779. ***************************************************************************/
  1780. bool
  1781. SetGlobalProperty(HH_GLOBAL_PROPERTY* prop, CHHWinType *phh)
  1782. {
  1783. bool bReturn = false ;
  1784. if (!prop)
  1785. return bReturn;
  1786. switch(prop->id)
  1787. {
  1788. case HH_GPROPID_SINGLETHREAD:
  1789. if (prop->var.vt == VT_BOOL)
  1790. {
  1791. g_fStandAlone = (prop->var.boolVal == VARIANT_TRUE) ;
  1792. bReturn = true ;
  1793. }
  1794. break ;
  1795. case HH_GPROPID_TOOLBAR_MARGIN:
  1796. if ( prop->var.vt == VT_UI4 || prop->var.vt == VT_UINT )
  1797. {
  1798. long L, R;
  1799. R = HIWORD( prop->var.ulVal );
  1800. L = LOWORD( prop->var.ulVal );
  1801. if ( (L == g_tbLeftMargin) && (R == g_tbRightMargin) )
  1802. return TRUE;
  1803. g_tbRightMargin = HIWORD( prop->var.ulVal );
  1804. g_tbLeftMargin = LOWORD( prop->var.ulVal );
  1805. if ( phh && phh->hwndToolBar )
  1806. {
  1807. ::SendMessage(phh->hwndHelp, WM_SIZE, SIZE_RESTORED, (LPARAM)0 );
  1808. // Due to a repaint bug in IE 3.02 Comctrl with the toolbar, we need to
  1809. // reapint the whole toolbar region including the margins on the left and right.
  1810. RECT rcvoid;
  1811. rcvoid.top = 0;
  1812. rcvoid.bottom = RECT_HEIGHT(phh->rcToolBar);
  1813. rcvoid.left = 0;
  1814. rcvoid.right = RECT_WIDTH(phh->rcWindowPos);
  1815. InvalidateRect(phh->hwndHelp, &rcvoid, TRUE);
  1816. UpdateWindow(phh->hwndHelp);
  1817. bReturn = true ;
  1818. }
  1819. }
  1820. break;
  1821. case HH_GPROPID_UI_LANGUAGE:// Set the language for hhctrl's ui.
  1822. {
  1823. LANGID request = NULL ;
  1824. // Convert the val to a LANGID.
  1825. if (prop->var.vt == VT_I4)
  1826. {
  1827. request = static_cast<LANGID>(prop->var.lVal) ;
  1828. }
  1829. else if (prop->var.vt = VT_I2)
  1830. {
  1831. request = prop->var.iVal ;
  1832. }
  1833. else if (prop->var.vt = VT_UI4)
  1834. {
  1835. request = prop->var.uiVal ;
  1836. }
  1837. else if (prop->var.vt = VT_UI2)
  1838. {
  1839. request = static_cast<LANGID>(prop->var.ulVal) ;
  1840. }
  1841. if (request)
  1842. {
  1843. // Request this langid.
  1844. LANGID result = _Module.m_Language.SetUiLanguage(request) ;
  1845. bReturn = (result == request) ;
  1846. }
  1847. }
  1848. break ;
  1849. case HH_GPROPID_CURRENT_SUBSET:
  1850. {
  1851. if ( prop->var.vt == VT_BSTR && prop->var.bstrVal && *(prop->var.bstrVal) )
  1852. {
  1853. WideCharToMultiByte(CP_ACP, 0, prop->var.bstrVal, -1, _Module.szCurSS, MAX_SS_NAME_LEN, NULL, NULL);
  1854. bReturn = true ; // TODO: Increase robustness!
  1855. }
  1856. }
  1857. break;
  1858. default:
  1859. ASSERT(0) ;
  1860. }
  1861. return bReturn ;
  1862. }
  1863. //////////////////////////////////////////////////////////////////////////
  1864. //
  1865. // GetNameAndWinType ---(from pszfile) Splits out the name and window type.
  1866. //
  1867. bool
  1868. GetNameAndWinType(LPCSTR pszFile, CStr& cszName, CStr& cszWindow)
  1869. {
  1870. if (IsEmptyString(pszFile))
  1871. {
  1872. return false ;
  1873. }
  1874. // Copy the string.
  1875. cszName = pszFile;
  1876. // Parse out window type.
  1877. PSTR pszWindow = StrChr(cszName, WINDOW_SEPARATOR);
  1878. if (pszWindow != NULL)
  1879. {
  1880. // Terminate the string.
  1881. *pszWindow = '\0';
  1882. RemoveTrailingSpaces(cszName);
  1883. cszWindow = FirstNonSpace(pszWindow + 1);
  1884. }
  1885. else
  1886. {
  1887. if(pszFile && IsGlobalWinType(pszFile))
  1888. cszWindow = pszFile;
  1889. }
  1890. // Must have a window type.
  1891. if (cszWindow.IsNonEmpty())
  1892. {
  1893. // Must either be a global window type, or have a filename.
  1894. if (IsGlobalWinType(cszWindow) || cszName.IsNonEmpty())
  1895. {
  1896. return true ;
  1897. }
  1898. }
  1899. return false;
  1900. }
  1901. //////////////////////////////////////////////////////////////////////////
  1902. //
  1903. // Reload the nav panes with data from a different CHM.
  1904. // NOTE: This is a dangerous Hack for Office.
  1905. //
  1906. HWND OnReloadNavData(HWND hwndCaller, LPCSTR pszFile, HH_NAVDATA* pNavData)
  1907. {
  1908. // Remember that the members of pNavData are unicode...
  1909. if (IsNonEmptyString(pszFile) // pszFile is not used
  1910. //|| !IsValidWindow(hwndCaller) --- Allows reparenting. See FindWindowType
  1911. || !pNavData
  1912. || IsEmptyStringW(pNavData->pszName)
  1913. || IsEmptyStringW(pNavData->pszFile)
  1914. || !IsGlobalWinTypeW(pNavData->pszName) // Window Type must be global!
  1915. )
  1916. {
  1917. return NULL ;
  1918. }
  1919. // Make sure that we have a compiled filename.
  1920. CStr cszFile(pNavData->pszFile) ; // Convert to ANSI.
  1921. if (!IsCompiledHtmlFile(cszFile, &cszFile))
  1922. {
  1923. return NULL ;
  1924. }
  1925. // Parse out all of the unnecessary bits...
  1926. GetCompiledName(cszFile, &cszFile);
  1927. if (cszFile.IsEmpty())
  1928. {
  1929. return NULL ;
  1930. }
  1931. // Get the CHmData structure for this file.
  1932. CHmData* phmdata = FindCurFileData(cszFile) ;
  1933. if (!phmdata)
  1934. {
  1935. return NULL;
  1936. }
  1937. // Find the window type.
  1938. CStr cszName(pNavData->pszName) ; // Convert to ANSI.
  1939. CHHWinType* phh = FindWindowType(cszName, hwndCaller, NULL) ; // WindowType must be global!
  1940. if (!phh)
  1941. {
  1942. // Couldn't find the window type. It must be defined.
  1943. return NULL ;
  1944. }
  1945. // Go do it!
  1946. phh->ReloadNavData(phmdata) ;
  1947. return phh->GetHwnd() ;
  1948. }
  1949. //////////////////////////////////////////////////////////////////////////
  1950. //
  1951. // CSession - This is a placeholder class. This will eventually do something.
  1952. //
  1953. // This should be moved to its own C++ file...
  1954. //
  1955. class CSession
  1956. {
  1957. public:
  1958. CSession();
  1959. ~CSession();
  1960. private:
  1961. DWORD* m_dwData ;
  1962. };
  1963. // Constructor
  1964. CSession::CSession()
  1965. : m_dwData(0)
  1966. {
  1967. //--- Initialize OLE. Competes with process detach/attach.
  1968. if ( !g_fCoInitialized )
  1969. {
  1970. if (S_FALSE == OleInitialize(NULL))
  1971. {
  1972. // shanemc/dalero
  1973. // If S_FALSE is returned OLE was already init'd. We don't want to uninit later
  1974. // because it can hose apps that have called OleInit (like IE).
  1975. OleUninitialize();
  1976. }
  1977. else
  1978. {
  1979. g_fCoInitialized = TRUE; // so that we call CoUninitialize() when dll is unloaded
  1980. }
  1981. }
  1982. }
  1983. // Destructor
  1984. CSession::~CSession()
  1985. {
  1986. //--- Unitialize OLE.
  1987. ASSERT(g_fCoInitialized); // Should never be FALSE here.
  1988. if (g_fCoInitialized)
  1989. {
  1990. OleUninitialize();
  1991. g_fCoInitialized = FALSE;
  1992. }
  1993. }
  1994. //////////////////////////////////////////////////////////////////////////
  1995. //
  1996. // Initializes everything we need initialized.
  1997. //
  1998. bool
  1999. InitializeSession(UNALIGNED DWORD_PTR* pCookie)
  2000. {
  2001. bool bReturn = false ;
  2002. if (pCookie)
  2003. {
  2004. //--- Create a session object.
  2005. CSession* p = new CSession() ;
  2006. // The session object is used as a cookie.
  2007. *pCookie = (DWORD_PTR)p;
  2008. // Initializing a session, implies standalone.
  2009. g_fStandAlone = TRUE ;
  2010. // A-ok
  2011. bReturn = true ;
  2012. }
  2013. return bReturn;
  2014. }
  2015. //////////////////////////////////////////////////////////////////////////
  2016. //
  2017. // Uninitalizes everything we need initialized.
  2018. //
  2019. bool
  2020. UninitializeSession(DWORD_PTR Cookie)
  2021. {
  2022. bool bReturn = false ;
  2023. ASSERT(g_fStandAlone) ; // Must be standalone.
  2024. //--- Need a valid cookie to uninitialize.
  2025. if (Cookie)
  2026. {
  2027. // Convert to a session pointer.
  2028. CSession* p = reinterpret_cast<CSession*>(Cookie) ;
  2029. // Do something useful.
  2030. bReturn = true ;
  2031. // Delete the session.
  2032. delete p ;
  2033. }
  2034. return bReturn ;
  2035. }
  2036. //////////////////////////////////////////////////////////////////////////
  2037. //
  2038. // Private function which returns the interface pointer to the embedded
  2039. // WebBrowser control given a particular window handle.
  2040. //
  2041. bool
  2042. GetBrowserInterface(HWND hWndBrowserParent, IDispatch** ppWebBrowser)
  2043. {
  2044. bool bReturn = false ;
  2045. if (IsWindow(hWndBrowserParent) && !IsBadReadPtr(ppWebBrowser, sizeof(IDispatch**)))
  2046. {
  2047. CHHWinType* phh = FindHHWindowIndex(hWndBrowserParent);
  2048. if (phh &&
  2049. phh->m_pCIExpContainer &&
  2050. phh->m_pCIExpContainer->m_pWebBrowserApp &&
  2051. phh->m_pCIExpContainer->m_pWebBrowserApp->m_lpDispatch)
  2052. {
  2053. *ppWebBrowser = phh->m_pCIExpContainer->m_pWebBrowserApp->m_lpDispatch;
  2054. bReturn = true ;
  2055. }
  2056. }
  2057. return bReturn ;
  2058. }