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.

326 lines
11 KiB

  1. /*****************************************************************************
  2. * *
  3. * HELPCALL.C *
  4. * *
  5. * Copyright (C) Microsoft Corporation 1989. *
  6. * All Rights reserved. *
  7. * *
  8. ******************************************************************************
  9. * *
  10. * Program Description: Sample interface to windows help *
  11. * *
  12. ******************************************************************************
  13. * *
  14. * Revision History: Created by RKB 11/30/88 *
  15. * Revised to new API 1/12/88 (RKB) *
  16. * Added to USER 3/28/89 (BG) *
  17. * Slight update 6/15/89 (BG) *
  18. * Clean ugly code 10/30/89 (BG) *
  19. * GlobalFree if QUIT 1/26/90 (CRC) *
  20. * *
  21. ******************************************************************************
  22. */
  23. #define NO_REDEF_SENDMESSAGE
  24. #include "user.h"
  25. #define _WINGDIP_ // We need to define these to prevent
  26. #include "wowcmpat.h" // redefinition of the GACF flags
  27. #define WM_WINHELP 0x38
  28. DWORD API NotifyWow(WORD, LPBYTE);
  29. BOOL API
  30. Win32WinHelp(
  31. HWND hwndMain,
  32. LPCSTR lpszHelp,
  33. UINT usCommand,
  34. DWORD ulData
  35. );
  36. DWORD WINAPI
  37. GetWOWCompatFlagsEx(
  38. void
  39. );
  40. /* This must match its counterpart in mvdm\inc\wowusr.h */
  41. #define NW_WINHELP 6 // Internal
  42. WORD msgWinHelp = 0;
  43. char CODESEG szMS_WINHELP[] = "MS_WINHELP";
  44. /*
  45. Communicating with WinHelp involves using Windows SendMessage() function
  46. to pass blocks of information to WinHelp. The call looks like.
  47. SendMessage(hwndHelp, msgWinHelp, hwndMain, (LONG)hHlp);
  48. Where:
  49. hwndHelp - the window handle of the help application. This
  50. is obtained by enumerating all the windows in the
  51. system and sending them HELP_FIND commands. The
  52. application may have to load WinHelp.
  53. msgWinHelp - the value obtained from a RegisterWindowMessage()
  54. szWINHELP
  55. hwndMain - the handle to the main window of the application
  56. calling help
  57. hHlp - a handle to a block of data with a HLP structure
  58. at it head.
  59. The data in the handle will look like:
  60. +-------------------+
  61. | cbData |
  62. | usCommand |
  63. | ulTopic |
  64. | ulReserved |
  65. | offszHelpFile |\ - offsets measured from beginning
  66. / | offaData | \ of header.
  67. / +-------------------| /
  68. / | Help file name |/
  69. \ | and path |
  70. \ +-------------------+
  71. \ | Other data |
  72. | (keyword) |
  73. +-------------------+
  74. The defined commands are:
  75. HELP_CONTEXT 0x0001 Display topic in ulTopic
  76. HELP_KEY 0x0101 Display topic for keyword in offabData
  77. HELP_QUIT 0x0002 Terminate help
  78. */
  79. /*******************
  80. **
  81. ** Name: HFill
  82. **
  83. ** Purpose: Builds a data block for communicating with help
  84. **
  85. ** Arguments: lpszHelp - pointer to the name of the help file to use
  86. ** usCommand - command being set to help
  87. ** ulData - data for the command
  88. **
  89. ** Returns: a handle to the data block or hNIL if the the
  90. ** block could not be created.
  91. **
  92. *******************/
  93. HANDLE HFill(LPCSTR lpszHelp, WORD usCommand, DWORD ulData)
  94. {
  95. WORD cb; /* Size of the data block */
  96. HANDLE hHlp; /* Handle to return */
  97. BYTE bHigh; /* High byte of usCommand */
  98. LPHLP qhlp; /* Pointer to data block */
  99. /* Calculate size */
  100. if (lpszHelp)
  101. cb = sizeof(HLP) + lstrlen(lpszHelp) + 1;
  102. else
  103. cb = sizeof(HLP);
  104. bHigh = (BYTE)HIBYTE(usCommand);
  105. if (bHigh == 1)
  106. cb += lstrlen((LPSTR)ulData) + 1;
  107. else if (bHigh == 2)
  108. cb += *((int far *)ulData);
  109. /* Get data block */
  110. if (!(hHlp = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD)cb)))
  111. return NULL;
  112. if (!(qhlp = (LPHLP)GlobalLock(hHlp)))
  113. {
  114. GlobalFree(hHlp);
  115. return NULL;
  116. }
  117. qhlp->cbData = cb; /* Fill in info */
  118. qhlp->usCommand = usCommand;
  119. qhlp->ulReserved = 0;
  120. if (lpszHelp)
  121. {
  122. qhlp->offszHelpFile = sizeof(HLP);
  123. lstrcpy((LPSTR)(qhlp+1), lpszHelp);
  124. }
  125. else
  126. qhlp->offszHelpFile = 0;
  127. switch(bHigh)
  128. {
  129. case 0:
  130. qhlp->offabData = 0;
  131. qhlp->ulTopic = ulData;
  132. break;
  133. case 1:
  134. qhlp->offabData = sizeof(HLP) + lstrlen(lpszHelp) + 1;
  135. lstrcpy((LPSTR)qhlp + qhlp->offabData, (LPSTR)ulData);
  136. break;
  137. case 2:
  138. qhlp->offabData = sizeof(HLP) + lstrlen(lpszHelp) + 1;
  139. LCopyStruct((LPSTR)ulData, (LPSTR)qhlp + qhlp->offabData, *((int far *)ulData));
  140. break;
  141. }
  142. GlobalUnlock(hHlp);
  143. return hHlp;
  144. }
  145. char CODESEG szEXECHELP[] = "\\WINHELP -x";
  146. BOOL _fastcall LaunchHelper(LPSTR lpfile)
  147. {
  148. int len;
  149. len = lstrlen(lpfile);
  150. if (lpfile[len-1]=='\\')
  151. /* Are we at the root?? If so, skip over leading backslash in text
  152. * string. */
  153. lstrcat(lpfile, szEXECHELP+1);
  154. else
  155. lstrcat(lpfile, szEXECHELP);
  156. return ((HINSTANCE)WinExec(lpfile, SW_SHOW) > HINSTANCE_ERROR);
  157. }
  158. BOOL LaunchHelp(VOID)
  159. {
  160. char szFile[128];
  161. /* Search in windows directory */
  162. GetWindowsDirectory(szFile, sizeof(szFile));
  163. if (LaunchHelper(szFile))
  164. return(TRUE);
  165. /* Search system directory */
  166. GetSystemDirectory(szFile, sizeof(szFile));
  167. if (LaunchHelper(szFile))
  168. return(TRUE);
  169. /* Last ditch: simply let dos do it */
  170. lstrcpy(szFile, szEXECHELP+1);
  171. return ((HINSTANCE)WinExec(szFile, SW_SHOW) > HINSTANCE_ERROR);
  172. }
  173. /*******************
  174. **
  175. ** Name: WinHelp
  176. **
  177. ** Purpose: Displays help
  178. **
  179. ** Arguments:
  180. ** hwndMain handle to main window of application
  181. ** lpszHelp path (if not current directory) and file
  182. ** to use for help topic.
  183. ** usCommand Command to send to help
  184. ** ulData Data associated with command:
  185. ** HELP_QUIT - no data (undefined)
  186. ** HELP_LAST - no data (undefined)
  187. ** HELP_CONTEXT - context number to display
  188. ** HELP_KEY - string ('\0' terminated)
  189. ** use as keyword to topic
  190. ** to display
  191. ** HELP_FIND - no data (undefined)
  192. **
  193. ** Returns: TRUE iff success
  194. **
  195. *******************/
  196. BOOL API IWinHelp(hwndMain, lpszHelp, usCommand, ulData)
  197. HWND hwndMain;
  198. LPCSTR lpszHelp;
  199. UINT usCommand;
  200. DWORD ulData;
  201. {
  202. register HANDLE hHlp;
  203. DWORD dwHelpPid; /* loword is hwndHelp */
  204. /* hiword TRUE if hwndHelp is of this process */
  205. DWORD dwWOWCompatFlagsEx;
  206. /* RAID BUG 394455
  207. Some apps have problems loading their help files with 16 bit winhelp. Hard coded paths,
  208. 32 bit helper dlls, etc. These issues can be fixed by redirecting the call to winhelp32.
  209. Check to see if the compatibility bit has been set for this app. */
  210. dwWOWCompatFlagsEx = GetWOWCompatFlagsEx();
  211. if (dwWOWCompatFlagsEx & WOWCFEX_USEWINHELP32) {
  212. return Win32WinHelp(hwndMain, lpszHelp, usCommand, ulData);
  213. }
  214. if (msgWinHelp == 0) {
  215. /* Register private WinHelp message for communicating to WinHelp via
  216. * WinHelp api.
  217. */
  218. char static CODESEG szWM_WINHELP[] = "WM_WINHELP";
  219. msgWinHelp = RegisterWindowMessage(szWM_WINHELP);
  220. }
  221. /* Move Help file name to a handle */
  222. if (!(hHlp = HFill(lpszHelp, usCommand, ulData)))
  223. return(FALSE);
  224. if ((dwHelpPid = (DWORD)NotifyWow(NW_WINHELP, szMS_WINHELP)) == (DWORD)NULL)
  225. {
  226. if (usCommand == HELP_QUIT) /* Don't bother to load HELP just to*/
  227. {
  228. GlobalFree(hHlp);
  229. return(TRUE);
  230. }
  231. /* Can't find it --> launch it */
  232. if (!LaunchHelp() || ((dwHelpPid = (DWORD)NotifyWow(NW_WINHELP, szMS_WINHELP)) == (DWORD)NULL))
  233. {
  234. /* Can't find help, or not enough memory to load help.*/
  235. GlobalFree(hHlp);
  236. return(FALSE);
  237. }
  238. }
  239. // if winhelp.exe was launched from this process, normal sendmessage else
  240. // we need to thunk the data across WOWVDM processes and the format is
  241. // msg = WM_WINHELP, a private msg
  242. // wparam = 0 instead of hwndMain, (note 1)
  243. // lparam = LPHLP
  244. //
  245. // note 1: winhelp, calls GetWindowWord(wParam, GWW_HINSTANCE) when it receives HELP_QUIT
  246. // command. If this matches a value in its table and is the only registered instance
  247. // winhelp will close - this is quite ok undernormal circumstances (just one WOWVDM)
  248. // but under multiple WOWVDM, numeric value of hinstances could be same for different
  249. // hwnds.
  250. //
  251. // So we workaround this by passing a NULL hwnd in wParam and by not sending HELP_QUIT
  252. // message - which effectively implies that WinHelp will close only if there are no
  253. // references to it from the same WOWVDM (as itself).
  254. //
  255. // This is the best compromise I could comeup with for running "only one WinHelp for all
  256. // WOWVDMs".
  257. //
  258. // - nanduri
  259. if (HIWORD(dwHelpPid)) {
  260. SendMessage((HWND)LOWORD(dwHelpPid), msgWinHelp, (WPARAM)hwndMain, MAKELPARAM(hHlp, 0));
  261. }
  262. else {
  263. if (usCommand != HELP_QUIT) {
  264. SendMessage((HWND)LOWORD(dwHelpPid), WM_WINHELP, (WPARAM)0, (LPARAM)GlobalLock(hHlp));
  265. GlobalUnlock(hHlp);
  266. }
  267. }
  268. GlobalFree(hHlp);
  269. return(TRUE);
  270. }