/***************************************************************************** * * * HELPCALL.C * * * * Copyright (C) Microsoft Corporation 1989. * * All Rights reserved. * * * ****************************************************************************** * * * Program Description: Sample interface to windows help * * * ****************************************************************************** * * * Revision History: Created by RKB 11/30/88 * * Revised to new API 1/12/88 (RKB) * * Added to USER 3/28/89 (BG) * * Slight update 6/15/89 (BG) * * Clean ugly code 10/30/89 (BG) * * GlobalFree if QUIT 1/26/90 (CRC) * * * ****************************************************************************** */ #define NO_REDEF_SENDMESSAGE #include "user.h" // // We define certain things here because including mvdm\inc\*.h files here // will lead to endless mess. // #define WM_WINHELP 0x38 DWORD API NotifyWow(WORD, LPBYTE); #define FUN_WINHELP 171 // WORD msgWinHelp = 0; char CODESEG szMS_WINHELP[] = "MS_WINHELP"; /* Communicating with WinHelp involves using Windows SendMessage() function to pass blocks of information to WinHelp. The call looks like. SendMessage(hwndHelp, msgWinHelp, hwndMain, (LONG)hHlp); Where: hwndHelp - the window handle of the help application. This is obtained by enumerating all the windows in the system and sending them HELP_FIND commands. The application may have to load WinHelp. msgWinHelp - the value obtained from a RegisterWindowMessage() szWINHELP hwndMain - the handle to the main window of the application calling help hHlp - a handle to a block of data with a HLP structure at it head. The data in the handle will look like: +-------------------+ | cbData | | usCommand | | ulTopic | | ulReserved | | offszHelpFile |\ - offsets measured from beginning / | offaData | \ of header. / +-------------------| / / | Help file name |/ \ | and path | \ +-------------------+ \ | Other data | | (keyword) | +-------------------+ The defined commands are: HELP_CONTEXT 0x0001 Display topic in ulTopic HELP_KEY 0x0101 Display topic for keyword in offabData HELP_QUIT 0x0002 Terminate help */ /******************* ** ** Name: HFill ** ** Purpose: Builds a data block for communicating with help ** ** Arguments: lpszHelp - pointer to the name of the help file to use ** usCommand - command being set to help ** ulData - data for the command ** ** Returns: a handle to the data block or hNIL if the the ** block could not be created. ** *******************/ HANDLE HFill(LPCSTR lpszHelp, WORD usCommand, DWORD ulData) { WORD cb; /* Size of the data block */ HANDLE hHlp; /* Handle to return */ BYTE bHigh; /* High byte of usCommand */ LPHLP qhlp; /* Pointer to data block */ /* Calculate size */ if (lpszHelp) cb = sizeof(HLP) + lstrlen(lpszHelp) + 1; else cb = sizeof(HLP); bHigh = (BYTE)HIBYTE(usCommand); if (bHigh == 1) cb += lstrlen((LPSTR)ulData) + 1; else if (bHigh == 2) cb += *((int far *)ulData); /* Get data block */ if (!(hHlp = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD)cb))) return NULL; if (!(qhlp = (LPHLP)GlobalLock(hHlp))) { GlobalFree(hHlp); return NULL; } qhlp->cbData = cb; /* Fill in info */ qhlp->usCommand = usCommand; qhlp->ulReserved = 0; if (lpszHelp) { qhlp->offszHelpFile = sizeof(HLP); lstrcpy((LPSTR)(qhlp+1), lpszHelp); } else qhlp->offszHelpFile = 0; switch(bHigh) { case 0: qhlp->offabData = 0; qhlp->ulTopic = ulData; break; case 1: qhlp->offabData = sizeof(HLP) + lstrlen(lpszHelp) + 1; lstrcpy((LPSTR)qhlp + qhlp->offabData, (LPSTR)ulData); break; case 2: qhlp->offabData = sizeof(HLP) + lstrlen(lpszHelp) + 1; LCopyStruct((LPSTR)ulData, (LPSTR)qhlp + qhlp->offabData, *((int far *)ulData)); break; } GlobalUnlock(hHlp); return hHlp; } char CODESEG szEXECHELP[] = "\\WINHELP -x"; BOOL _fastcall LaunchHelper(LPSTR lpfile) { int len; len = lstrlen(lpfile); if (lpfile[len-1]=='\\') /* Are we at the root?? If so, skip over leading backslash in text * string. */ lstrcat(lpfile, szEXECHELP+1); else lstrcat(lpfile, szEXECHELP); return ((HINSTANCE)WinExec(lpfile, SW_SHOW) > HINSTANCE_ERROR); } BOOL LaunchHelp(VOID) { char szFile[128]; /* Search in windows directory */ GetWindowsDirectory(szFile, sizeof(szFile)); if (LaunchHelper(szFile)) return(TRUE); /* Search system directory */ GetSystemDirectory(szFile, sizeof(szFile)); if (LaunchHelper(szFile)) return(TRUE); /* Last ditch: simply let dos do it */ lstrcpy(szFile, szEXECHELP+1); return ((HINSTANCE)WinExec(szFile, SW_SHOW) > HINSTANCE_ERROR); } /******************* ** ** Name: WinHelp ** ** Purpose: Displays help ** ** Arguments: ** hwndMain handle to main window of application ** lpszHelp path (if not current directory) and file ** to use for help topic. ** usCommand Command to send to help ** ulData Data associated with command: ** HELP_QUIT - no data (undefined) ** HELP_LAST - no data (undefined) ** HELP_CONTEXT - context number to display ** HELP_KEY - string ('\0' terminated) ** use as keyword to topic ** to display ** HELP_FIND - no data (undefined) ** ** Returns: TRUE iff success ** *******************/ BOOL API IWinHelp(hwndMain, lpszHelp, usCommand, ulData) HWND hwndMain; LPCSTR lpszHelp; WORD usCommand; DWORD ulData; { register HANDLE hHlp; DWORD dwHelpPid; /* loword is hwndHelp */ /* hiword TRUE if hwndHelp is of this process */ if (msgWinHelp == 0) { /* Register private WinHelp message for communicating to WinHelp via * WinHelp api. */ char static CODESEG szWM_WINHELP[] = "WM_WINHELP"; msgWinHelp = RegisterWindowMessage(szWM_WINHELP); } /* Move Help file name to a handle */ if (!(hHlp = HFill(lpszHelp, usCommand, ulData))) return(FALSE); if ((dwHelpPid = (DWORD)NotifyWow(FUN_WINHELP, szMS_WINHELP)) == (DWORD)NULL) { if (usCommand == HELP_QUIT) /* Don't bother to load HELP just to*/ { GlobalFree(hHlp); return(TRUE); } /* Can't find it --> launch it */ if (!LaunchHelp() || ((dwHelpPid = (DWORD)NotifyWow(FUN_WINHELP, szMS_WINHELP)) == (DWORD)NULL)) { /* Can't find help, or not enough memory to load help.*/ GlobalFree(hHlp); return(FALSE); } } // if winhelp.exe was launched from this process, normal sendmessage else // we need to thunk the data across WOWVDM processes and the format is // msg = WM_WINHELP, a private msg // wparam = 0 instead of hwndMain, (note 1) // lparam = LPHLP // // note 1: winhelp, calls GetWindowWord(wParam, GWW_HINSTANCE) when it receives HELP_QUIT // command. If this matches a value in its table and is the only registered instance // winhelp will close - this is quite ok undernormal circumstances (just one WOWVDM) // but under multiple WOWVDM, numeric value of hinstances could be same for different // hwnds. // // So we workaround this by passing a NULL hwnd in wParam and by not sending HELP_QUIT // message - which effectively implies that WinHelp will close only if there are no // references to it from the same WOWVDM (as itself). // // This is the best compromise I could comeup with for running "only one WinHelp for all // WOWVDMs". // // - nanduri if (HIWORD(dwHelpPid)) { SendMessage((HWND)LOWORD(dwHelpPid), msgWinHelp, (WPARAM)hwndMain, MAKELPARAM(hHlp, 0)); } else { if (usCommand != HELP_QUIT) { SendMessage((HWND)LOWORD(dwHelpPid), WM_WINHELP, (WPARAM)0, (LPARAM)GlobalLock(hHlp)); GlobalUnlock(hHlp); } } GlobalFree(hHlp); return(TRUE); }