Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

help.c

Go to the documentation of this file.
00001 /**************************************************************************\ 00002 * Module Name: help.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * History: 00007 * 23-May-95 BradG Created to consolicate client-side help routines. 00008 * 00009 \**************************************************************************/ 00010 00011 #include "precomp.h" 00012 #pragma hdrstop 00013 00014 00015 #define MAX_ATTEMPTS 5 // maximum -1 id controls to search through 00016 char szDefaultHelpFileA[] = "windows.hlp"; 00017 00018 PWCHAR szEXECHELP = TEXT("\\winhlp32 - "); 00019 PWCHAR szMS_WINHELP = L"MS_WINHELP"; // Application class 00020 PWCHAR szMS_POPUPHELP = L"MS_POPUPHELP"; // Popup class 00021 PWCHAR szMS_TCARDHELP = L"MS_TCARDHELP"; // Training card class 00022 00023 // These are in winhelp.h in Chicago 00024 #define HLP_POPUP 'p' // Execute WinHelp as a popup 00025 #define HLP_TRAININGCARD 'c' // Execute WinHelp as a training card 00026 #define HLP_APPLICATION 'x' // Execute WinHelp as application help 00027 00028 00029 /***************************************************************************\ 00030 * SendWinHelpMessage 00031 * 00032 * Attempts to give the winhelp process the right to take the 00033 * foreground (it will fail if the calling processs doesn't have 00034 * the right itself). Then it sends the WM_WINHELP message 00035 * 00036 * History: 00037 * 02-10-98 GerardoB Created 00038 \***************************************************************************/ 00039 LRESULT SendWinHelpMessage (HWND hwnd, WPARAM wParam, LPARAM lParam) 00040 { 00041 DWORD dwProcessId = 0; 00042 GetWindowThreadProcessId(hwnd, &dwProcessId); 00043 AllowSetForegroundWindow(dwProcessId); 00044 return SendMessage(hwnd, WM_WINHELP, wParam, lParam); 00045 } 00046 /***************************************************************************\ 00047 * HFill 00048 * 00049 * Builds a data block for communicating with help 00050 * 00051 * LATER 13 Feb 92 GregoryW 00052 * This needs to stay ANSI until we have a Unicode help engine 00053 * 00054 * History: 00055 * 04-15-91 JimA Ported. 00056 * 03-24-95 BradG - YAP of Win95 code. Added code to prevent memory 00057 * overwrite on bad ulData == 0 parameter. 00058 \***************************************************************************/ 00059 00060 LPHLP HFill( 00061 LPCSTR lpszHelp, 00062 DWORD ulCommand, // HELP_ constant 00063 ULONG_PTR ulData) 00064 { 00065 DWORD cb; // Size of the data block 00066 DWORD cbStr; // Length of the help file name 00067 DWORD cbData; // Size of the dwData parameter in bytes (0 if not used) 00068 LPHLP phlp; // Pointer to data block 00069 BYTE bType; // dwData parameter type 00070 00071 /* 00072 * Get the length of the help file name 00073 */ 00074 cbStr = (lpszHelp) ? strlen(lpszHelp) + 1 : 0; 00075 00076 /* 00077 * Get the length of any dwData parameters 00078 */ 00079 bType = HIBYTE(LOWORD(ulCommand)); 00080 if (ulData) { 00081 switch (bType) { 00082 case HIBYTE(HELP_HB_STRING): 00083 /* 00084 * ulData is an ANSI string, so compute its length 00085 */ 00086 cbData = strlen((LPSTR)ulData) + 1; 00087 break; 00088 00089 case HIBYTE(HELP_HB_STRUCT): 00090 /* 00091 * ulData points to a structure who's first member is 00092 * an int that contains the size of the structure in bytes. 00093 */ 00094 cbData = *((int *)ulData); 00095 break; 00096 00097 default: 00098 /* 00099 * dwData has no parameter 00100 */ 00101 cbData = 0; 00102 } 00103 } else { 00104 /* 00105 * No parameter is present 00106 */ 00107 cbData = 0; 00108 } 00109 00110 /* 00111 * Calculate size (NOTE: HLP is called WINHLP in Win95) 00112 */ 00113 cb = sizeof(HLP) + cbStr + cbData; 00114 00115 /* 00116 * Get data block 00117 */ 00118 if ((phlp = (LPHLP)LocalAlloc(LPTR, cb)) == NULL) 00119 return NULL; 00120 00121 /* 00122 * Fill in info 00123 */ 00124 phlp->cbData = (WORD)cb; 00125 phlp->usCommand = (WORD)ulCommand; 00126 phlp->ulReserved = 0; 00127 // phlp->ulTopic = 0; 00128 00129 /* 00130 * Fill in file name 00131 */ 00132 if (lpszHelp) { 00133 phlp->offszHelpFile = sizeof(HLP); // NOTE: HLP is called WINHLP in Win95 00134 strcpy((LPSTR)(phlp + 1), lpszHelp); 00135 } else { 00136 phlp->offszHelpFile = 0; 00137 } 00138 00139 /* 00140 * Fill in data 00141 */ 00142 switch (bType) { 00143 case HIBYTE(HELP_HB_STRING): 00144 if (cbData) { 00145 phlp->offabData = (WORD)(sizeof(HLP) + cbStr); // NOTE: HLP is called WINHLP in Win95 00146 strcpy((LPSTR)phlp + phlp->offabData, (LPSTR)ulData); 00147 } else { 00148 phlp->offabData = 0; 00149 } 00150 break; 00151 00152 case HIBYTE(HELP_HB_STRUCT): 00153 if (cbData) { 00154 phlp->offabData = (WORD)(sizeof(HLP) + cbStr); // NOTE: HLP is called WINHLP in Win95 00155 RtlCopyMemory((LPBYTE)phlp + phlp->offabData, (PVOID)ulData, 00156 *((int far *)ulData)); 00157 } else { 00158 phlp->offabData = 0; 00159 } 00160 break; 00161 00162 default: 00163 phlp->offabData = 0; 00164 // BradG - This item is named differently in the Win95 WINHLP structure 00165 // phlp->ctx = ulData; 00166 phlp->ulTopic = ulData; 00167 break; 00168 } 00169 00170 return(phlp); 00171 } 00172 00173 00174 /***************************************************************************\ 00175 * LaunchHelper 00176 * 00177 * This function launches the WinHlp32 executable with the correct command 00178 * line arguments. 00179 * 00180 * History: 00181 * 3/23/95 BradG YAP (yet another port) of changes from Win95. 00182 \***************************************************************************/ 00183 BOOL LaunchHelper(LPWSTR lpfile, DWORD dwType) 00184 { 00185 int cchLen; 00186 int cchShift; 00187 DWORD idProcess; 00188 STARTUPINFO StartupInfo; 00189 PROCESS_INFORMATION ProcessInformation; 00190 PWCHAR pwcExecHelp; 00191 00192 pwcExecHelp = szEXECHELP; 00193 00194 /* 00195 * Are we at the root?? If so, skip over leading backslash in text string 00196 */ 00197 if (*lpfile) { 00198 cchLen = wcslen(lpfile); 00199 cchShift = (lpfile[cchLen - 1] == TEXT('\\')) ? 1 : 0; 00200 wcscat(lpfile, pwcExecHelp + cchShift); 00201 } else { 00202 wcscat(lpfile, pwcExecHelp + 1); 00203 } 00204 00205 00206 /* 00207 * Defaultly send "winhlp32 -x" or adjust the last flag character 00208 */ 00209 switch (dwType) { 00210 case TYPE_POPUP: 00211 lpfile[wcslen(lpfile)-1] = TEXT(HLP_POPUP); 00212 break; 00213 00214 case TYPE_TCARD: 00215 lpfile[wcslen(lpfile)-1] = TEXT(HLP_TRAININGCARD); 00216 break; 00217 00218 default: 00219 lpfile[wcslen(lpfile)-1] = TEXT(HLP_APPLICATION); 00220 break; 00221 } 00222 00223 /* 00224 * Launch winhelp 00225 */ 00226 memset(&StartupInfo,0,sizeof(StartupInfo)); 00227 StartupInfo.cb = sizeof(StartupInfo); 00228 StartupInfo.wShowWindow = SW_SHOW; 00229 StartupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_FORCEONFEEDBACK; 00230 00231 idProcess = (DWORD)CreateProcessW(NULL, lpfile, 00232 NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &StartupInfo, 00233 &ProcessInformation); 00234 00235 if (idProcess) { 00236 WaitForInputIdle(ProcessInformation.hProcess, 10000); 00237 NtClose(ProcessInformation.hProcess); 00238 NtClose(ProcessInformation.hThread); 00239 return TRUE; 00240 } 00241 00242 return FALSE; 00243 } 00244 00245 00246 /***************************************************************************\ 00247 * LaunchHelp 00248 * 00249 * Traverse the Windows, System and %PATH% directories attempting to launch 00250 * the WinHelp32 application. 00251 * 00252 * History: 00253 * 3/23/95 BradG YAP of new changes from Win95 00254 \***************************************************************************/ 00255 00256 BOOL LaunchHelp(DWORD dwType) 00257 { 00258 WCHAR wszPath[MAX_PATH]; 00259 00260 GetSystemWindowsDirectoryW(wszPath, MAX_PATH); 00261 00262 if (LaunchHelper(wszPath, dwType)) 00263 return TRUE; 00264 00265 /* 00266 * Search the system directory (Not in Win95) 00267 */ 00268 GetSystemDirectoryW(wszPath, MAX_PATH); 00269 if (LaunchHelper(wszPath, dwType)) 00270 return TRUE; 00271 00272 /* 00273 * Try the search path 00274 */ 00275 wszPath[0] = L'\0'; 00276 return LaunchHelper(wszPath, dwType); 00277 00278 } 00279 00280 00281 /***************************************************************************\ 00282 * GetNextDlgHelpItem 00283 * 00284 * This is a reduced version of the GetNextDlgTabItem function that does not 00285 * skip disabled controls. 00286 * 00287 * History: 00288 * 3/25/95 BradG Ported from Win95 00289 \***************************************************************************/ 00290 PWND GetNextDlgHelpItem(PWND pwndDlg, PWND pwnd) 00291 { 00292 PWND pwndSave; 00293 00294 if (pwnd == pwndDlg) 00295 pwnd = NULL; 00296 else 00297 { 00298 pwnd = _GetChildControl(pwndDlg, pwnd); 00299 if (pwnd) 00300 { 00301 if (!_IsDescendant(pwndDlg, pwnd)) 00302 return(NULL); 00303 } 00304 } 00305 00306 /* 00307 * BACKWARD COMPATIBILITY 00308 * 00309 * Note that the result when there are no tabstops of 00310 * IGetNextDlgTabItem(hwndDlg, NULL, FALSE) was the last item, now 00311 * will be the first item. We could put a check for fRecurse here 00312 * and do the old thing if not set. 00313 */ 00314 00315 /* 00316 * We are going to bug out if we hit the first child a second time. 00317 */ 00318 pwndSave = pwnd; 00319 pwnd = _NextControl(pwndDlg, pwnd, CWP_SKIPINVISIBLE); 00320 00321 while ((pwnd != pwndSave) && (pwnd != pwndDlg)) 00322 { 00323 UserAssert(pwnd); 00324 00325 if (!pwndSave) 00326 pwndSave = pwnd; 00327 00328 if ((pwnd->style & (WS_TABSTOP | WS_VISIBLE)) == (WS_TABSTOP | WS_VISIBLE)) 00329 /* 00330 * Found it. 00331 */ 00332 break; 00333 00334 pwnd = _NextControl(pwndDlg, pwnd, CWP_SKIPINVISIBLE); 00335 } 00336 00337 return(pwnd); 00338 } 00339 00340 00341 /***************************************************************************\ 00342 * HelpMenu 00343 * 00344 * History: 00345 * 01-Feb-1994 mikeke Ported. 00346 \***************************************************************************/ 00347 00348 UINT HelpMenu( 00349 HWND hwnd, 00350 PPOINT ppt) 00351 { 00352 INT cmd; 00353 HMENU hmenu = LoadMenu( hmodUser, MAKEINTRESOURCE(ID_HELPMENU)); 00354 00355 if (hmenu != NULL) { 00356 cmd = TrackPopupMenu( GetSubMenu(hmenu, 0), 00357 TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON, 00358 ppt->x, ppt->y, 0, hwnd, NULL); 00359 NtUserDestroyMenu(hmenu); 00360 return cmd; 00361 } 00362 00363 return (UINT)-1; 00364 } 00365 00366 /***************************************************************************\ 00367 * FindWinHelpWindow 00368 * 00369 * This function attempts to locate the help window. If it fails, it attempts 00370 * to launch WinHlp32.exe and then look for its window. 00371 * 00372 * History: 00373 * 03/24/95 BradG Created by extracting code from xxxWinHelpA 00374 \***************************************************************************/ 00375 HWND FindWinHelpWindow( 00376 LPCWSTR lpwstrHelpWindowClass, 00377 DWORD dwType, 00378 BOOL bLaunchIt 00379 ) 00380 { 00381 HWND hwndHelp; 00382 00383 /* 00384 * Find the current help window. If not found, try and launch 00385 * the WinHlp32 application. We are interested only in 32 bit help. 00386 * Note that 16 bit apps don't walk this path, ntvdm taking care of 00387 * starting the 16 bit help for them. 00388 */ 00389 hwndHelp = InternalFindWindowExW(NULL, NULL, lpwstrHelpWindowClass, NULL, FW_32BIT); 00390 00391 if (hwndHelp == NULL) { 00392 if (bLaunchIt) { 00393 /* 00394 * Can't find it --> see if we want to launch it 00395 */ 00396 if ((LaunchHelp(dwType) == FALSE) || 00397 (hwndHelp = FindWindowEx(NULL, NULL, (LPWSTR)lpwstrHelpWindowClass, NULL)) == NULL) 00398 { 00399 00400 /* 00401 * Can't find help, or not enough memory to load help. 00402 * pwndHelp will be NULL at this point. 00403 */ 00404 #if DBG 00405 RIPMSG0( RIP_WARNING, "xxxWinHelpA: xxxLaunchHelp and xxxFindWinow failed." ); 00406 #endif 00407 } 00408 } 00409 } 00410 00411 return hwndHelp; 00412 } 00413 00414 00415 /* 00416 * HWND version of Enumeration function to fins controls while 00417 * ignoring group boxes but not disabled controls. 00418 */ 00419 BOOL CALLBACK EnumHwndDlgChildProc(HWND hwnd, LPARAM lParam ) 00420 { 00421 PWND pwnd; 00422 BOOL bResult; 00423 00424 if (pwnd = ValidateHwnd(hwnd)) 00425 bResult = EnumPwndDlgChildProc( pwnd, lParam ); 00426 else 00427 bResult = TRUE; 00428 00429 return bResult; 00430 } 00431 00432 00433 /***************************************************************************\ 00434 * WinHelp 00435 * 00436 * Displays help 00437 * 00438 * History: 00439 * 04-15-91 JimA Ported. 00440 * 01-29-92 GregoryW Neutral version. 00441 * 05-22-92 SanfordS Added support for help structures 00442 * 03-24-95 BradG Moved from Client side WinHelpA to server side 00443 * xxxWinHelpA because of changes in Win95. The 00444 * function xxxServerWinHelp was merged. 00445 \***************************************************************************/ 00446 00447 BOOL WinHelpA( 00448 HWND hwnd, // hwndMain may be NULL. 00449 LPCSTR lpszHelp, 00450 UINT uCommand, 00451 ULONG_PTR dwData) 00452 { 00453 LPWSTR lpwstrHelpWindowClass; 00454 LPHLP lpHlp = NULL; 00455 DWORD dwType; 00456 PWND pwnd; 00457 HWND hwndHelp = NULL; /* Handle of help's main window */ 00458 PWND pwndTop = NULL; /* Top level window that WinHelp uses. */ 00459 PWND pwndMain; /* pointer to main help control */ 00460 LRESULT lResult; 00461 POINT ptCur; 00462 BOOL bResult = TRUE; 00463 00464 pwnd = ValidateHwnd(hwnd); 00465 00466 if (uCommand & HELP_TCARD) { 00467 /* 00468 * For Training Cards, the HELP_TCARD bit is set. We need to 00469 * set our help window class to szMS_TCARDHELP and then remove 00470 * the HELP_TCARD bit. 00471 */ 00472 lpwstrHelpWindowClass = szMS_TCARDHELP; 00473 uCommand &= ~HELP_TCARD; // mask out the tcard flag 00474 dwType = TYPE_TCARD; 00475 } else { 00476 if( (uCommand == HELP_CONTEXTMENU) || (uCommand == HELP_CONTEXTPOPUP) || 00477 (uCommand == HELP_SETPOPUP_POS) || (uCommand == HELP_WM_HELP)) { 00478 /* 00479 * Popups should be connected to a valid window. pwndMain has already 00480 * been validated as a real window handle or NULL, so we just need to 00481 * check the NULL case here. 00482 */ 00483 if (pwnd == NULL) { 00484 RIPERR1(ERROR_INVALID_PARAMETER, 00485 RIP_WARNING, 00486 "WinHelpA: NULL hWnd invalid for this type of help command (0x%X)", 00487 uCommand); 00488 00489 bResult = FALSE; 00490 goto Exit_WinHelp; 00491 } 00492 dwType = TYPE_POPUP; 00493 lpwstrHelpWindowClass = szMS_POPUPHELP; 00494 } else { 00495 dwType = TYPE_NORMAL; 00496 lpwstrHelpWindowClass = szMS_WINHELP; 00497 } 00498 } 00499 00500 /* 00501 * Get the cursor's current location This is where we assume the user 00502 * clicked. We will use this position to search for a child window and 00503 * to set the context sensitive help popup window's location. 00504 * 00505 * If the last input was a keyboard one, use the point in the center 00506 * of the focus window rectangle. MCostea #249270 00507 */ 00508 if (gpsi->bLastRITWasKeyboard) { 00509 HWND hWndFocus = GetFocus(); 00510 RECT rcWindow; 00511 00512 if (GetWindowRect(hWndFocus, &rcWindow)) { 00513 ptCur.x = (rcWindow.left + rcWindow.right)/2; 00514 ptCur.y = (rcWindow.top + rcWindow.bottom)/2; 00515 } else { 00516 goto getCursorPos; 00517 } 00518 } else { 00519 getCursorPos: 00520 GetCursorPos(&ptCur); 00521 } 00522 00523 /* 00524 * If we are handling the HELP_CONTEXTMENU command, see if we 00525 * can determine the correct child window. 00526 */ 00527 if (uCommand == HELP_CONTEXTMENU && FIsParentDude(pwnd)) { 00528 LONG lPt; 00529 int nHit; 00530 DLGENUMDATA DlgEnumData; 00531 00532 /* 00533 * If the user really clicked on the caption or the system menu, 00534 * then we want the context menu for the window, not help for a 00535 * control. This makes it consistent across all 3.x and 4.0 00536 * windows. 00537 */ 00538 lPt = MAKELONG(ptCur.x,ptCur.y); 00539 nHit = FindNCHit(pwnd, lPt); 00540 if ((nHit == HTCAPTION) || (nHit == HTSYSMENU)) 00541 DefWindowProc(hwnd, WM_CONTEXTMENU, (WPARAM)hwnd, lPt); 00542 00543 /* 00544 * If this is a dialog class, then one of three things has 00545 * happened: 00546 * 00547 * o This is a disabled control 00548 * o This is a static text control 00549 * o This is the background of the dialog box. 00550 * 00551 * What we do is enumerate the child windows and see if 00552 * any of them contain the current cursor point. If they do, 00553 * change our window handle and continue on. Otherwise, 00554 * return doing nothing -- we don't want context-sensitive 00555 * help for a dialog background. 00556 * 00557 * If this is a group box, then we might have clicked on a 00558 * disabled control, so we enumerate child windows to see 00559 * if we get another control. 00560 */ 00561 DlgEnumData.pwndDialog = pwnd; 00562 DlgEnumData.pwndControl = NULL; 00563 DlgEnumData.ptCurHelp = ptCur; 00564 EnumChildWindows(hwnd, (WNDENUMPROC)EnumHwndDlgChildProc, (LPARAM)&DlgEnumData); 00565 if (DlgEnumData.pwndControl == NULL) { 00566 /* 00567 * Can't find a control, so nothing to do. 00568 */ 00569 goto Exit_WinHelp; 00570 } else { 00571 /* 00572 * Remember this control because it will be used as the 00573 * control for context sensitive help. 00574 */ 00575 pwndMain = DlgEnumData.pwndControl; 00576 } 00577 } else { 00578 /* 00579 * We will use pwnd as our main control. No need to lock it 00580 * because it is already locked. 00581 */ 00582 pwndMain = pwnd; 00583 } 00584 00585 /* 00586 * For HELP_CONTEXTPOPUP and HELP_WM_HELP, see if we can derive the 00587 * context id by looking at the array of double word ID pairs that 00588 * have been passed in in dwData. 00589 */ 00590 if (uCommand == HELP_CONTEXTMENU || uCommand == HELP_WM_HELP) { 00591 int id; 00592 int i; 00593 LPDWORD pid; 00594 00595 // MapIdToHelp: 00596 /* 00597 * Be careful about the cast below. We need the ID, which is stored 00598 * in the LOWORD of spmenu to be sign extended to an int. 00599 * Don't sign extend so IDs like 8008 work 00600 */ 00601 id = (DWORD)(PTR_TO_ID(pwndMain->spmenu)); // get control id 00602 pid = (LPDWORD) dwData; 00603 00604 /* 00605 * Is the control's ID -1? 00606 */ 00607 if ((SHORT)id == -1) 00608 { 00609 /* 00610 * This is a static (i.e., ID'less) control 00611 */ 00612 PWND pwndCtrl; 00613 int cAttempts = 0; 00614 00615 /* 00616 * If the control is a group box, with an ID of -1, bail out 00617 * as the UI specs decided to have no context help 00618 * for these cases. MCostea 00619 */ 00620 if ((TestWF(pwndMain, BFTYPEMASK) == BS_GROUPBOX) && 00621 (GETFNID(pwndMain) == FNID_BUTTON)) { 00622 goto Exit_WinHelp; 00623 } 00624 00625 /* 00626 * For non-id controls (typically static controls), step 00627 * through to the next tab item. Keep finding the next tab 00628 * item until we find a valid id, or we have tried 00629 * MAX_ATTEMPTS times. 00630 */ 00631 do { 00632 pwndCtrl = GetNextDlgHelpItem( REBASEPWND(pwndMain,spwndParent), pwndMain ); 00633 00634 /* 00635 * pwndCtrl will be NULL if hwndMain doesn't have a parent, 00636 * or if there are no tab stops. 00637 */ 00638 if (!pwndCtrl) { 00639 /* 00640 * Remember to unlock the control 00641 */ 00642 bResult = FALSE; 00643 goto Exit_WinHelp; 00644 } 00645 00646 /* 00647 * Be careful about the cast below. We need the ID, which is stored 00648 * in the LOWORD of spmenu to be sign extended to an int. 00649 * Don't sign extend so IDs like 8008 work 00650 */ 00651 id = (DWORD)(PTR_TO_ID(pwndCtrl->spmenu)); 00652 00653 } while (((SHORT)id == -1) && (++cAttempts < MAX_ATTEMPTS)); 00654 } 00655 00656 if ((SHORT)id == -1) { 00657 id = -1; 00658 } 00659 00660 /* 00661 * Find the id value in array of id/help context values 00662 */ 00663 for (i = 0; pid[i]; i += 2) { 00664 if ((int) pid[i] == id) 00665 break; 00666 } 00667 00668 /* 00669 * Since no help was specified for the found control, see if 00670 * the control is one of the known ID (i.e., OK, Cancel...) 00671 */ 00672 if (!pid[i]) { 00673 /* 00674 * Help for the standard controls is in the default 00675 * help file windows.hlp. Switch to this file. 00676 */ 00677 lpszHelp = szDefaultHelpFileA; 00678 00679 switch (id) { 00680 case IDOK: 00681 dwData = IDH_OK; 00682 break; 00683 00684 case IDCANCEL: 00685 dwData = IDH_CANCEL; 00686 break; 00687 00688 case IDHELP: 00689 dwData = IDH_HELP; 00690 break; 00691 00692 default: 00693 /* 00694 * Unknown control, give a generic missing context info 00695 * popup message in windows.hlp. 00696 */ 00697 dwData = IDH_MISSING_CONTEXT; 00698 } 00699 } else { 00700 dwData = pid[i + 1]; 00701 if (dwData == (DWORD)-1) { 00702 /* 00703 * Remember, to unlock the control 00704 */ 00705 goto Exit_WinHelp; // caller doesn't want help after all 00706 } 00707 } 00708 00709 /* 00710 * Now that we know the caller wants help for this control, display the 00711 * help menu. 00712 */ 00713 if (uCommand == HELP_CONTEXTMENU) 00714 { 00715 int cmd; 00716 00717 /* 00718 * Must lock pwndMain because it may have been reassigned above. 00719 */ 00720 cmd = HelpMenu(HW(pwndMain), &ptCur); 00721 if (cmd <= 0) // probably means user cancelled the menu 00722 goto Exit_WinHelp; 00723 } 00724 00725 /* 00726 * Create WM_WINHELP's HLP data structure for HELP_SETPOPUP_POS 00727 */ 00728 if (!(lpHlp = HFill(lpszHelp, HELP_SETPOPUP_POS, 00729 MAKELONG(pwndMain->rcWindow.left, pwndMain->rcWindow.top)))) { 00730 /* 00731 * Remember to unlock pwndMain if needed 00732 */ 00733 bResult = FALSE; 00734 goto Exit_WinHelp; 00735 } 00736 00737 /* 00738 * Tell WinHelp where to put the popup. This is different than Win95 00739 * because we try and avoid a recursive call here. So, we find the 00740 * WinHlp32 window and send the HELP_SETPOPUP_POS. No recursion. 00741 */ 00742 hwndHelp = FindWinHelpWindow( lpwstrHelpWindowClass, dwType, TRUE); 00743 if (hwndHelp == NULL ) { 00744 /* 00745 * Uable to communicate with WinHlp32.exe. 00746 * Remember to unlock the control 00747 */ 00748 bResult = FALSE; 00749 goto Exit_WinHelp; 00750 } 00751 00752 /* 00753 * Send the WM_WINHELP message to WinHlp32's window. 00754 */ 00755 lResult = SendWinHelpMessage(hwndHelp, (WPARAM)HW(pwndMain), (LPARAM)lpHlp); 00756 LocalFree(lpHlp); 00757 lpHlp = NULL; 00758 00759 /* BradG - revalidate pwndMain? */ 00760 00761 if (!lResult) 00762 { 00763 /* 00764 * WinHlp32 couldn't process the command. Bail out! 00765 */ 00766 bResult = FALSE; 00767 goto Exit_WinHelp; 00768 } 00769 00770 /* 00771 * Make HELP_WM_HELP and HELP_CONTEXTMENU act like HELP_CONTEXTPOPUP 00772 */ 00773 uCommand = HELP_CONTEXTPOPUP; 00774 } 00775 00776 00777 if (uCommand == HELP_CONTEXTPOPUP ) { 00778 // MapNullHlpToWindowsHlp: 00779 /* 00780 * If no help file was specified, use windows.hlp 00781 */ 00782 if (lpszHelp == NULL || *lpszHelp == '\0') 00783 lpszHelp = szDefaultHelpFileA; // default: use windows.hlp 00784 00785 /* 00786 * WINHELP.EXE will call SetForegroundWindow on the hwnd that we pass 00787 * to it below. We really want to pass the parent dialog hwnd of the 00788 * control so that focus will properly be restored to the dialog and 00789 * not the control that wants help. 00790 */ 00791 pwndTop = GetTopLevelWindow(pwndMain); 00792 } else { 00793 pwndTop = pwndMain; 00794 } 00795 00796 00797 /* 00798 * Move Help file name to a handle 00799 */ 00800 if (!(lpHlp = HFill(lpszHelp, uCommand, dwData))) { 00801 /* 00802 * Can't allocate memory 00803 */ 00804 bResult = FALSE; 00805 goto Exit_WinHelp; 00806 } 00807 00808 /* 00809 * Get a pointer to the help window. 00810 */ 00811 hwndHelp = FindWinHelpWindow( lpwstrHelpWindowClass, dwType, (uCommand != HELP_QUIT)); 00812 if (hwndHelp == NULL) { 00813 if (uCommand != HELP_QUIT) 00814 /* 00815 * Can't find Winhlp 00816 */ 00817 bResult = FALSE; 00818 goto Exit_WinHelp; 00819 } 00820 00821 /* 00822 * Send the WM_WINHELP message to WinHlp32's window 00823 * Must ThreadLock pwndHelp AND pwndMain (because pwndMain may have been 00824 * reassigned above). 00825 */ 00826 SendWinHelpMessage(hwndHelp, (WPARAM)HW(pwndTop), (LPARAM)lpHlp); 00827 00828 /* 00829 * Free the help info data structure (if not already free). 00830 */ 00831 Exit_WinHelp: 00832 if (lpHlp != NULL) { 00833 LocalFree(lpHlp); 00834 } 00835 00836 return bResult; 00837 } 00838 00839 00840 00841 00842 00843 00844 00845 00846 00847 00848 00849 00850 #if 0 00851 /* 00852 * 00853 * Communicating with WinHelp involves using Windows SendMessage function 00854 * to pass blocks of information to WinHelp. The call looks like. 00855 * 00856 * SendMessage(hwndHelp, WM_WINHELP, pidSource, pwinhlp); 00857 * 00858 * Where: 00859 * 00860 * hwndHelp - the window handle of the help application. This 00861 * is obtained by enumerating all the windows in the 00862 * system and sending them HELP_FIND commands. The 00863 * application may have to load WinHelp. 00864 * pidSource - the process id of the sending process 00865 * pwinhlp - a pointer to a WINHLP structure 00866 * 00867 * The data in the handle will look like: 00868 * 00869 * +-------------------+ 00870 * | cbData | 00871 * | ulCommand | 00872 * | hwndHost | 00873 * | ulTopic | 00874 * | ulReserved | 00875 * | offszHelpFile |\ - offsets measured from beginning 00876 * | offaData | \ of header. 00877 * +-------------------+ / 00878 * | Help file name |/ 00879 * | and path | 00880 * +-------------------+ 00881 * | Other data | 00882 * | (keyword) | 00883 * +-------------------+ 00884 * 00885 * hwndMain - the handle to the main window of the application 00886 * calling help 00887 * 00888 * The defined commands are: 00889 * 00890 * HELP_CONTEXT 0x0001 Display topic in ulTopic 00891 * HELP_KEY 0x0101 Display topic for keyword in offabData 00892 * HELP_QUIT 0x0002 Terminate help 00893 * 00894 */ 00895 00896 BOOL WinHelpA( 00897 HWND hwndMain, 00898 LPCSTR lpszHelp, 00899 UINT uCommand, 00900 ULONG_PTR dwData) 00901 { 00902 LPHLP lpHlp; 00903 BOOL fSuccess; 00904 DWORD dwType; 00905 HWND hwndHelp; /* Handle of help's main window */ 00906 LPWSTR lpwstr; 00907 PWND pwndMain; 00908 00909 pwndMain = ValidateHwnd(hwndMain); 00910 00911 if ((uCommand == HELP_CONTEXTMENU) || (uCommand == HELP_CONTEXTPOPUP) || 00912 (uCommand == HELP_SETPOPUP_POS) || (uCommand == HELP_WM_HELP)) { 00913 dwType = TYPE_POPUP; 00914 } else { 00915 dwType = TYPE_NORMAL; 00916 } 00917 00918 switch (uCommand) { 00919 00920 case HELP_WM_HELP: 00921 { 00922 #if 0 00923 // Tell WinHelp where to put the popup 00924 00925 if (!WinHelpA(hwndMain, lpszHelp, HELP_SETPOPUP_POS, 00926 MAKELONG(pwndMain->rcWindow.left, pwndMain->rcWindow.top))) 00927 return FALSE; 00928 00929 /* 00930 * Unlike HELP_CONTEXTMENU, with this command we pop up the help 00931 * topic immediately instead of making the user go through a menu. 00932 */ 00933 #endif 00934 00935 goto MapIdToHelp; 00936 00937 } 00938 break; 00939 00940 case HELP_CONTEXTMENU: 00941 { 00942 int cmd; 00943 int id; 00944 int i; 00945 POINT ptCur; 00946 LPDWORD pid; 00947 00948 GetCursorPos(&ptCur); 00949 00950 if (pwndMain != NULL && pwndMain->fnid == FNID_DIALOG) { 00951 /* 00952 * If this is a dialog class, then one of three things has 00953 * happened: 00954 * 00955 * o This is a disabled control 00956 * o This is a static text control 00957 * o This is the background of the dialog box. 00958 * 00959 * What we do is enumerate the child windows and see if 00960 * any of them contain the current cursor point. If they do, 00961 * change our window handle and continue on. Otherwise, 00962 * return doing nothing -- we don't want context-sensitive 00963 * help for a dialog background. 00964 */ 00965 00966 pwndMain = REBASEPWND(pwndMain, spwndChild); 00967 00968 while (pwndMain != NULL 00969 && PtInRect(&(pwndMain->rcWindow), ptCur)) { 00970 pwndMain = REBASEPWND(pwndMain, spwndNext); 00971 } 00972 00973 if (pwndMain == NULL) 00974 return FALSE; 00975 } 00976 00977 cmd = HelpMenu(hwndMain, &ptCur); 00978 00979 if (cmd <= 0) { // probably means user cancelled the menu 00980 return(FALSE); // !!! mem leak? 00981 00982 } else if (cmd == HELP_INDEX) { 00983 // Search 00984 uCommand = HELP_FINDER; 00985 } else { 00986 MapIdToHelp: 00987 UserAssert(pwndMain); 00988 00989 // Tell WinHelp where to put the popup 00990 00991 if (!WinHelpA(hwndMain, lpszHelp, HELP_SETPOPUP_POS, 00992 MAKELONG(pwndMain->rcWindow.left, pwndMain->rcWindow.top))) 00993 return FALSE; 00994 id = LOWORD(pwndMain->spmenu); // get control id 00995 00996 pid = (LPDWORD) dwData; 00997 00998 if (id == -1) { 00999 // static control? 01000 PWND pwndCtrl; 01001 int cAttempts = 0; 01002 01003 // For non-id controls (typically static controls), step 01004 // through to the next tab item. Keep finding the next tab 01005 // item until we find a valid id, or we have tried 01006 // MAX_ATTEMPTS times. 01007 do { 01008 pwndCtrl = _GetNextDlgTabItem(REBASEPWND(pwndMain, spwndParent), 01009 pwndMain, FALSE); 01010 01011 // hwndCtrl will be NULL if hwndMain doesn't have a parent, 01012 // or if there are no tab stops. 01013 01014 if (!pwndCtrl) { 01015 return(FALSE); 01016 } 01017 01018 01019 01020 id = LOWORD(pwndCtrl->spmenu); 01021 } 01022 while ((id == -1) && (++cAttempts < MAX_ATTEMPTS)); 01023 } 01024 01025 // Find the id value in array of id/help context values 01026 01027 for (i = 0; pid[i]; i += 2) { 01028 if ((int) pid[i] == id) 01029 break; 01030 } 01031 01032 if (!pid[i]) { 01033 01034 01035 lpszHelp = szDefaultHelpFileA; // switch to windows.hlp 01036 01037 switch (id) { 01038 case IDOK: 01039 dwData = IDH_OK; 01040 break; 01041 01042 case IDCANCEL: 01043 dwData = IDH_CANCEL; 01044 break; 01045 01046 case IDHELP: 01047 dwData = IDH_HELP; 01048 break; 01049 01050 default: 01051 dwData = IDH_MISSING_CONTEXT; 01052 } 01053 } else { 01054 dwData = pid[i + 1]; 01055 if (dwData == (DWORD) -1) { 01056 return TRUE; // caller doesn't want help after all 01057 } 01058 } 01059 01060 uCommand = HELP_CONTEXTPOPUP; 01061 } 01062 01063 // If no help file was specified, use windows.hlp 01064 01065 if (lpszHelp == NULL || *lpszHelp == '\0') 01066 lpszHelp = szDefaultHelpFileA; // default: use windows.hlp 01067 } 01068 } 01069 01070 /* 01071 * Move Help file name to a handle 01072 */ 01073 if (!(lpHlp = HFill(lpszHelp, uCommand, dwData))) 01074 return FALSE; 01075 01076 /* 01077 * Pass it on to WinHelp32 01078 */ 01079 fSuccess = TRUE; 01080 if (dwType == TYPE_POPUP) 01081 lpwstr = szMS_POPUPHELP; 01082 else 01083 lpwstr = szMS_WINHELP; 01084 01085 if ((hwndHelp = FindWindowEx(NULL, NULL, lpwstr, NULL)) == NULL) { 01086 if (uCommand == HELP_QUIT) 01087 fSuccess = TRUE; 01088 01089 /* 01090 * Can't find it --> launch it 01091 */ 01092 if (!LaunchHelp(dwType) || 01093 (hwndHelp = FindWindowEx(NULL, NULL, lpwstr, NULL)) == NULL) 01094 fSuccess = FALSE; 01095 } 01096 01097 if (hwndHelp != NULL) 01098 SendMessage(hwndHelp, WM_WINHELP, (DWORD)hwndMain, (LONG)lpHlp); 01099 01100 LocalFree(lpHlp); 01101 01102 return fSuccess; 01103 } 01104 #endif 01105 01106 01107 01108 /***************************************************************************\ 01109 * WinHelpW 01110 * 01111 * Calls WinHelpA after doing any necessary translation. 01112 * Our help engine is ASCII only. 01113 * 01114 \***************************************************************************/ 01115 01116 BOOL WinHelpW( 01117 HWND hwndMain, 01118 LPCWSTR lpwszHelp, 01119 UINT uCommand, 01120 ULONG_PTR dwData) 01121 { 01122 BOOL fSuccess = FALSE; 01123 LPSTR lpAnsiHelp = NULL; 01124 LPSTR lpAnsiKey = NULL; 01125 PMULTIKEYHELPA pmkh = NULL; 01126 PHELPWININFOA phwi = NULL; 01127 NTSTATUS Status; 01128 01129 01130 /* 01131 * First convert the string. 01132 */ 01133 if (lpwszHelp != NULL && 01134 !WCSToMB(lpwszHelp, -1, &lpAnsiHelp, -1, TRUE)) { 01135 return FALSE; 01136 } 01137 01138 /* 01139 * Then convert dwData if needed 01140 */ 01141 switch (uCommand) { 01142 case HELP_MULTIKEY: 01143 if (!WCSToMB(((PMULTIKEYHELPW)dwData)->szKeyphrase, -1, &lpAnsiKey, 01144 -1, TRUE)) { 01145 goto FreeAnsiHelp; 01146 } 01147 01148 pmkh = (PMULTIKEYHELPA)LocalAlloc(LPTR, 01149 sizeof(MULTIKEYHELPA) + strlen(lpAnsiKey)); 01150 if (pmkh == NULL) { 01151 goto FreeAnsiKeyAndHelp; 01152 } 01153 01154 pmkh->mkSize = sizeof(MULTIKEYHELPA) + strlen(lpAnsiKey); 01155 Status = RtlUnicodeToMultiByteN((LPSTR)&pmkh->mkKeylist, sizeof(CHAR), 01156 NULL, (LPWSTR)&((PMULTIKEYHELPW)dwData)->mkKeylist, 01157 sizeof(WCHAR)); 01158 strcpy(pmkh->szKeyphrase, lpAnsiKey); 01159 if (!NT_SUCCESS(Status)) { 01160 goto FreeAnsiKeyAndHelp; 01161 } 01162 01163 dwData = (ULONG_PTR)pmkh; 01164 break; 01165 01166 case HELP_SETWINPOS: 01167 if (!WCSToMB(((PHELPWININFOW)dwData)->rgchMember, -1, &lpAnsiKey, 01168 -1, TRUE)) { 01169 goto FreeAnsiKeyAndHelp; 01170 } 01171 01172 phwi = (PHELPWININFOA)LocalAlloc(LPTR, ((PHELPWININFOW)dwData)->wStructSize); 01173 if (phwi == NULL) { 01174 goto FreeAnsiKeyAndHelp; 01175 } 01176 01177 *phwi = *((PHELPWININFOA)dwData); // copies identical parts 01178 strcpy(phwi->rgchMember, lpAnsiKey); 01179 dwData = (ULONG_PTR)phwi; 01180 break; 01181 01182 case HELP_KEY: 01183 case HELP_PARTIALKEY: 01184 case HELP_COMMAND: 01185 if (!WCSToMB((LPCTSTR)dwData, -1, &lpAnsiKey, -1, TRUE)) { 01186 goto FreeAnsiKeyAndHelp; 01187 } 01188 01189 dwData = (ULONG_PTR)lpAnsiKey; 01190 break; 01191 } 01192 01193 /* 01194 * Call the Ansi version 01195 */ 01196 fSuccess = WinHelpA(hwndMain, lpAnsiHelp, uCommand, dwData); 01197 01198 if (pmkh) { 01199 LocalFree(pmkh); 01200 } 01201 01202 if (phwi) { 01203 LocalFree(phwi); 01204 } 01205 01206 FreeAnsiKeyAndHelp: 01207 if (lpAnsiKey) { 01208 LocalFree(lpAnsiKey); 01209 } 01210 01211 01212 FreeAnsiHelp: 01213 if (lpAnsiHelp) 01214 LocalFree(lpAnsiHelp); 01215 01216 return fSuccess; 01217 }

Generated on Sat May 15 19:40:17 2004 for test by doxygen 1.3.7