/***************************************************************************** * * * 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" #define _WINGDIP_ // We need to define these to prevent #include "wowcmpat.h" // redefinition of the GACF flags #define WM_WINHELP 0x38 DWORD API NotifyWow(WORD, LPBYTE); BOOL API Win32WinHelp( HWND hwndMain, LPCSTR lpszHelp, UINT usCommand, DWORD ulData ); DWORD WINAPI GetWOWCompatFlagsEx( void ); /* This must match its counterpart in mvdm\inc\wowusr.h */ #define NW_WINHELP 6 // Internal 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; UINT usCommand; DWORD ulData; { register HANDLE hHlp; DWORD dwHelpPid; /* loword is hwndHelp */ /* hiword TRUE if hwndHelp is of this process */ DWORD dwWOWCompatFlagsEx; /* RAID BUG 394455 Some apps have problems loading their help files with 16 bit winhelp. Hard coded paths, 32 bit helper dlls, etc. These issues can be fixed by redirecting the call to winhelp32. Check to see if the compatibility bit has been set for this app. */ dwWOWCompatFlagsEx = GetWOWCompatFlagsEx(); if (dwWOWCompatFlagsEx & WOWCFEX_USEWINHELP32) { return Win32WinHelp(hwndMain, lpszHelp, usCommand, ulData); } 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(NW_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(NW_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); }