WinHelp.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include <HelpIntfs.hpp>
  5. #include <WinHelpViewer.hpp>
  6. #include <Common.h>
  7. #include <Tools.h>
  8. #include <TextsWin.h>
  9. //---------------------------------------------------------------------------
  10. #pragma package(smart_init)
  11. //---------------------------------------------------------------------------
  12. #define IUNKNOWN \
  13. virtual HRESULT __stdcall QueryInterface(const GUID& IID, void **Obj) \
  14. { \
  15. return TInterfacedObject::QueryInterface(IID, (void *)Obj); \
  16. } \
  17. \
  18. virtual ULONG __stdcall AddRef() \
  19. { \
  20. return TInterfacedObject::_AddRef(); \
  21. } \
  22. \
  23. virtual ULONG __stdcall Release() \
  24. { \
  25. return TInterfacedObject::_Release(); \
  26. }
  27. //---------------------------------------------------------------------------
  28. class TWebHelpSystem : public TInterfacedObject, public ICustomHelpViewer
  29. {
  30. public:
  31. virtual AnsiString __fastcall GetViewerName();
  32. virtual int __fastcall UnderstandsKeyword(const AnsiString HelpString);
  33. virtual TStringList * __fastcall GetHelpStrings(const AnsiString HelpString);
  34. virtual bool __fastcall CanShowTableOfContents();
  35. virtual void __fastcall ShowTableOfContents();
  36. virtual void __fastcall ShowHelp(const AnsiString HelpString);
  37. virtual void __fastcall NotifyID(const int ViewerID);
  38. virtual void __fastcall SoftShutDown();
  39. virtual void __fastcall ShutDown();
  40. void __fastcall InternalShutdown();
  41. int __fastcall ViewerID();
  42. IUNKNOWN
  43. private:
  44. int FViewerID;
  45. };
  46. //---------------------------------------------------------------------------
  47. class TWinHelpTester : public TInterfacedObject, public IWinHelpTester
  48. {
  49. public:
  50. virtual __fastcall ~TWinHelpTester();
  51. virtual bool __fastcall CanShowALink(const AnsiString ALink, const AnsiString FileName);
  52. virtual bool __fastcall CanShowTopic(const AnsiString Topic, const AnsiString FileName);
  53. virtual bool __fastcall CanShowContext(const int Context, const AnsiString FileName);
  54. virtual TStringList * __fastcall GetHelpStrings(const AnsiString ALink);
  55. virtual AnsiString __fastcall GetHelpPath();
  56. virtual AnsiString __fastcall GetDefaultHelpFile();
  57. IUNKNOWN
  58. };
  59. //---------------------------------------------------------------------------
  60. TWebHelpSystem * WebHelpSystem;
  61. _di_IHelpManager * PHelpManager = NULL;
  62. IUnknown * HelpManagerUnknown = NULL;
  63. TObjectList * ViewerList = NULL;
  64. ICustomHelpViewer * WinHelpViewer = NULL;
  65. //---------------------------------------------------------------------------
  66. void __fastcall InitializeWinHelp()
  67. {
  68. assert(PHelpManager == NULL);
  69. // workaround
  70. // _di_IHelpManager cannot be instantiated due to either bug in compiler or
  71. // VCL code
  72. PHelpManager = (_di_IHelpManager*)malloc(sizeof(_di_IHelpManager));
  73. WebHelpSystem = new TWebHelpSystem();
  74. // our own reference
  75. WebHelpSystem->AddRef();
  76. RegisterViewer(WebHelpSystem, *PHelpManager);
  77. HelpManagerUnknown = dynamic_cast<IUnknown *>(&**PHelpManager);
  78. // gross hack
  79. // Due to major bugs in VCL help system, unregister winhelp at all.
  80. // To do this we must call RegisterViewer first to get HelpManager.
  81. // Due to another bug, viewers must be unregistred in order reversed to
  82. // registration order, so we must unregister WebHelpSystem first and register
  83. // it again at the end
  84. WebHelpSystem->InternalShutdown();
  85. // 40 is offset from IHelpManager to THelpManager
  86. // 16 is offset from THelpManager to THelpManager::FViewerList
  87. ViewerList =
  88. *reinterpret_cast<TObjectList **>(reinterpret_cast<char *>(&**PHelpManager)
  89. - 40 + 16);
  90. assert(ViewerList->Count == 1);
  91. // 8 is offset from THelpViewerNode to THelpViewerNode::FViewer
  92. int WinHelpViewerID =
  93. *reinterpret_cast<int *>(reinterpret_cast<char *>(ViewerList->Items[0])
  94. + 8);
  95. // 4 is offset from THelpViewerNode to THelpViewerNode::FViewer
  96. WinHelpViewer =
  97. *reinterpret_cast<_di_ICustomHelpViewer *>(reinterpret_cast<char *>(ViewerList->Items[0])
  98. + 4);
  99. // our reference
  100. // we cannot release win help viewer completelly here as finalization code of
  101. // WinHelpViewer expect it to exist
  102. WinHelpViewer->AddRef();
  103. (**PHelpManager).Release(WinHelpViewerID);
  104. // remove forgoten 3 references of manager
  105. WinHelpViewer->Release();
  106. WinHelpViewer->Release();
  107. WinHelpViewer->Release();
  108. assert(ViewerList->Count == 0);
  109. // this clears reference to manager in TWinHelpViewer::FHelpManager,
  110. // preventing call to TWinHelpViewer::InternalShutdown from finalization code
  111. // of WinHelpViewer
  112. WinHelpViewer->ShutDown();
  113. RegisterViewer(WebHelpSystem, *PHelpManager);
  114. // we've got second reference to the same pointer here, release it
  115. HelpManagerUnknown->Release();
  116. assert(ViewerList->Count == 1);
  117. // now when winhelp is not registered, the tester is not used anyway
  118. // for any real work, but we use it as a hook to be called after
  119. // finalization of WinHelpViewer (see its finalization section)
  120. WinHelpTester = new TWinHelpTester();
  121. }
  122. //---------------------------------------------------------------------------
  123. void __fastcall FinalizeWinHelp()
  124. {
  125. if (WebHelpSystem != NULL)
  126. {
  127. // unregister ourselves to release both references
  128. WebHelpSystem->InternalShutdown();
  129. // our own reference
  130. WebHelpSystem->Release();
  131. }
  132. if (PHelpManager != NULL)
  133. {
  134. assert(ViewerList->Count == 0);
  135. // our reference
  136. HelpManagerUnknown->Release();
  137. free(PHelpManager);
  138. PHelpManager = NULL;
  139. HelpManagerUnknown = NULL;
  140. }
  141. }
  142. //---------------------------------------------------------------------------
  143. void __fastcall CleanUpWinHelp()
  144. {
  145. // WinHelpViewer finalization code should have been called by now already,
  146. // so we can safely remove the last reference to destroy it
  147. assert(WinHelpViewer != NULL);
  148. WinHelpViewer->Release();
  149. }
  150. //---------------------------------------------------------------------------
  151. AnsiString __fastcall TWebHelpSystem::GetViewerName()
  152. {
  153. return "Web";
  154. }
  155. //---------------------------------------------------------------------------
  156. int __fastcall TWebHelpSystem::ViewerID()
  157. {
  158. return FViewerID;
  159. }
  160. //---------------------------------------------------------------------------
  161. void __fastcall TWebHelpSystem::InternalShutdown()
  162. {
  163. assert(PHelpManager != NULL);
  164. if (PHelpManager != NULL)
  165. {
  166. // override conflict of two Release() methods by getting
  167. // IHelpManager explicitly using operator *
  168. (**PHelpManager).Release(FViewerID);
  169. // registration to help manager increases refcount by 2, but deregistration
  170. // by one only
  171. assert(RefCount > 0);
  172. Release();
  173. }
  174. }
  175. //---------------------------------------------------------------------------
  176. int __fastcall TWebHelpSystem::UnderstandsKeyword(const AnsiString HelpString)
  177. {
  178. // pretend that we know everyting
  179. return 1;
  180. }
  181. //---------------------------------------------------------------------------
  182. TStringList * __fastcall TWebHelpSystem::GetHelpStrings(const AnsiString HelpString)
  183. {
  184. TStringList * Result = new TStringList();
  185. Result->Add(GetViewerName() + " : " + HelpString);
  186. return Result;
  187. }
  188. //---------------------------------------------------------------------------
  189. bool __fastcall TWebHelpSystem::CanShowTableOfContents()
  190. {
  191. return true;
  192. }
  193. //---------------------------------------------------------------------------
  194. void __fastcall TWebHelpSystem::ShowTableOfContents()
  195. {
  196. OpenBrowser(LoadStr(DOCUMENTATION_URL));
  197. }
  198. //---------------------------------------------------------------------------
  199. void __fastcall TWebHelpSystem::ShowHelp(const AnsiString HelpString)
  200. {
  201. OpenBrowser(FMTLOAD(DOCUMENTATION_KEYWORD_URL, (HelpString)));
  202. }
  203. //---------------------------------------------------------------------------
  204. void __fastcall TWebHelpSystem::NotifyID(const int ViewerID)
  205. {
  206. FViewerID = ViewerID;
  207. }
  208. //---------------------------------------------------------------------------
  209. void __fastcall TWebHelpSystem::SoftShutDown()
  210. {
  211. }
  212. //---------------------------------------------------------------------------
  213. void __fastcall TWebHelpSystem::ShutDown()
  214. {
  215. }
  216. //---------------------------------------------------------------------------
  217. //---------------------------------------------------------------------------
  218. __fastcall TWinHelpTester::~TWinHelpTester()
  219. {
  220. CleanUpWinHelp();
  221. }
  222. //---------------------------------------------------------------------------
  223. bool __fastcall TWinHelpTester::CanShowALink(const AnsiString ALink,
  224. const AnsiString FileName)
  225. {
  226. assert(false);
  227. return !Application->HelpFile.IsEmpty();
  228. }
  229. //---------------------------------------------------------------------------
  230. bool __fastcall TWinHelpTester::CanShowTopic(const AnsiString Topic,
  231. const AnsiString FileName)
  232. {
  233. assert(false);
  234. return !Application->HelpFile.IsEmpty();
  235. }
  236. //---------------------------------------------------------------------------
  237. bool __fastcall TWinHelpTester::CanShowContext(const int /*Context*/,
  238. const AnsiString FileName)
  239. {
  240. assert(false);
  241. return !Application->HelpFile.IsEmpty();
  242. }
  243. //---------------------------------------------------------------------------
  244. TStringList * __fastcall TWinHelpTester::GetHelpStrings(const AnsiString ALink)
  245. {
  246. assert(false);
  247. TStringList * Result = new TStringList();
  248. Result->Add(ViewerName + ": " + ALink);
  249. return Result;
  250. }
  251. //---------------------------------------------------------------------------
  252. AnsiString __fastcall TWinHelpTester::GetHelpPath()
  253. {
  254. assert(false);
  255. // never called on windows anyway
  256. return ExtractFilePath(Application->HelpFile);
  257. }
  258. //---------------------------------------------------------------------------
  259. AnsiString __fastcall TWinHelpTester::GetDefaultHelpFile()
  260. {
  261. assert(false);
  262. return Application->HelpFile;
  263. }