/***************************************************************************** * * HINIT.C * * Copyright (C) Microsoft Corporation 1990-1994. * All Rights reserved. * ****************************************************************************** * * Module Intent * * All the necessary initialization code for WinHelp belongs here. * This code should only be active (loaded in memory in real mode only * during program initialization and termination. That means that no * modules that will be needed at other times should be here. * Similarly, this module should not have code that is needed only * rarely; the size of this module impacts the disk-load time of every * WinHelp initialization, even for new instances. Code used only when * unhiding help should not be here. * *****************************************************************************/ #include "help.h" #pragma hdrstop #include "inc\hwproc.h" #include "inc\hinit.h" #include "inc\winclass.h" #include "inc\printset.h" #include #include "resource.h" #include // for mmInit #include #ifdef _DEBUG #undef THIS_FILE static const char THIS_FILE[] = __FILE__; #endif INLINE static void STDCALL FTerminate(void); // Currently history and back still initialized in JumpTlp() (navsup.c) #define chGID 'g' // Create .GID file #define chHLPONHLP 'h' // Display help on help #define chID 'i' // Jump to topic based on ctx string #define chKEYWORD 'k' // Jump to topic based on keyword #define chCONTEXTNO 'n' // Jump to topic based on ctx no #define chWindow 'w' // window to use #define chCompare '7' // running 2 WinHelp's side by side #define chSilentGID 's' // Silent setup #ifdef _DEBUG #define chDEBUG 'd' // turns on DebugBreak() #define chTESTERS 't' // make asserts app-modal #define chFAKE 'f' // fake this as an app-called help #endif // Defined in core\inc\help.h // #define HLP_POPUP 'p' // Execute WinHelp as a popup // #define HLP_TRAININGCARD 'c' // Execute WinHelp as a training card // #define HLP_APPLICATION 'x' // Execute WinHelp as application help enum { CMD_NOTHING, CMD_CTX_NUMBER, CMD_KEYWORD, CMD_HELP_ON_HELP, CMD_CTX_STRING, }; #define SPACE ' ' /***************************************************************************** * * Variables * *****************************************************************************/ /*------- Variables Used Globally in this Module -----------------------*/ WRECT rctHelpOrg; // Original setting for window pos BOOL fMaxOrg; // Original setting for max flag /*------- Variables Referenced in Other Modules ----------------------------*/ BOOL fButtonsBusy; // Used in hwproc.c, helper.c /*------------------------------------------------------------*\ | Used as a default palette when no EWs have helped us out. \*------------------------------------------------------------*/ /***************************************************************************** * * Table of window classes. We walk this table and register all the window * class definitions therein. Each entry in this table contains a subset of * the infomation in a WNDCLASS structure. Note that near pointers to strings * are kept, since staticly initailzed far pointers to data are a no-no in * Windows. * *****************************************************************************/ // 25-Mar-1993 [ralphw] -- menus are not loaded anymore, since part of // initialization reloads the menu. extern BOOL fAppModal; // used in assertf.c extern HFS hfsBM; #ifndef NO_PRAGMAS #pragma data_seg(".text", "CODE") #endif const char txtDocClass[] = "MS_WINDOC"; #ifndef NO_PRAGMAS #pragma data_seg() #endif CLSINFO rgWndClsInfo[] = { { // Main help Window 0, // style HelpWndProc, // lpfnWndProc WE_HELP, // cbWndExtra 0, // hIcon 0, // hIconSm NULL, // hbrBackground 0, // wMenuName MS_WINHELP // szClassName }, { // Main help Window, when not help 0, // style HelpWndProc, // lpfnWndProc WE_HELP, // cbWndExtra 0, // hIcon 0, // hIconSm NULL, // hbrBackground 0, // wMenuName txtDocClass // szClassName }, { // Training Card Main Window 0, // style HelpWndProc, // lpfnWndProc WE_HELP, // cbWndExtra 0, // hIcon 0, // hIconSm NULL, // hbrBackground 0, // wMenuName MS_TCARDHELP // szClassName }, { // Right Mouse Popup main window 0, // style HelpWndProc, // lpfnWndProc WE_HELP, // cbWndExtra 0, // hIcon 0, // hIconSm NULL, // hbrBackground 0, // wMenuName MS_POPUPHELP // szClassName }, { // Topic Window CS_VREDRAW | CS_HREDRAW, // style TopicWndProc, // lpfnWndProc WE_TOPIC, // cbWndExtra NULL, // hIcon 0, // hIconSm NULL, // hbrBackground 0, // wMenuName "MS_WINTOPIC" // szClassName }, { // Note (popup) Window CS_VREDRAW | CS_HREDRAW, // style NoteWndProc, // lpfnWndProc 0, // cbWndExtra NULL, // hIcon 0, // hIconSm (HBRUSH) (COLOR_WINDOW + 1), // hbrBackground 0, // wMenuName "MS_WINNOTE" // szClassName }, { // NSR Window CS_VREDRAW | CS_HREDRAW, // style NSRWndProc, // lpfnWndProc WE_NSR, // cbWndExtra NULL, // hIcon 0, // hIconSm NULL, // hbrBackground 0, // wMenuName "MS_WINNSR" // szClassName }, { // Icon (Button Bar) Window 0, // style ButtonBarProc, // lpfnWndProc WE_ICON, // cbWndExtra NULL, // hIcon 0, // hIconSm 0, // hbrBackground 0, // wMenuName "MS_WINICON" // szClassName }, { // Path Window (history) CS_HREDRAW|CS_VREDRAW, // style HistoryProc, // lpfnWndProc 0, // cbWndExtra 0, // hIcon 0, // hIconSm (HBRUSH) (COLOR_WINDOW + 1), // hbrBackground 0, // wMenuName "MS_WIN_PATH" // szClassName }, { // Secondary Window CS_VREDRAW | CS_HREDRAW, // style HelpWndProc, // lpfnWndProc WE_HELP, // cbWndExtra 0, // hIcon 0, // hIconSm 0, // hbrBackground 0, // wMenuName "MS_WINTOPIC_SECONDARY", // szClassName }, }; /***************************************************************************** * * Prototypes * *****************************************************************************/ static BOOL STDCALL AppInit( HINSTANCE, HINSTANCE ); static BOOL STDCALL CreateMainWindow(PSTR pszClass, BOOL fButtonBar); static BOOL STDCALL FGetHelpRect(HWND); static BOOL STDCALL FLoadResources(HINSTANCE, HINSTANCE); static BOOL STDCALL RegHelpWinClasses(HINSTANCE); static void STDCALL WriteProfile(void); static PSTR STDCALL GetNextDigit(LONG* pdigit, PSTR pszCur); INLINE static void STDCALL LoadOOMString(VOID); INLINE void STDCALL ReadProfile(void); #ifdef DEADCODE INLINE static VOID STDCALL GetProfileWinPos(PSTR, LONG*, LONG*, LONG*, LONG*, BOOL*); #endif #pragma warning(disable:4113) // function parameter lists differed /******************************************************************** - - Name: * FInitialize * * Purpose: * Contains all of the initialization routines needed at program * initialization. Returns FALSE if this cannot be done, and the * program should then fail to run. * * Arguments: * hinsThis This instance handle * hinsPrev The last instance handle or hinsNil * qchzCmdLine The execution command line * wCmdShow show window type * * Returns; * TRUE, if the program may go on * else FALSE * ********************************************************************/ extern HIMAGELIST (WINAPI *pImageList_LoadImage)(HINSTANCE, LPCSTR, int, int, COLORREF, UINT, UINT); BOOL STDCALL FInitialize( HINSTANCE hinsThis, HINSTANCE hinsPrev, LPSTR szCmdLine, int wCmdShow ) { OSVERSIONINFO osver; BOOL fMax; PSTR pszTmp, pszTmp2; /* Buffer used for keywords and */ char pchBuffer[MAX_HELPONHELP]; // for help on help file load BOOL fHasParam = FALSE; int cmd = CMD_NOTHING; CTX ctx; char rgchName[MAX_PATH]; FM fm, fmSave; PSTR pszCmdLine; CHAR rgchCmdLine[MAX_PATH]; // Local Copy of command line PSTR pszClass; char szWindowName[cchWindowMemberMax]; HWND hwndOtherWinHelp; BOOL fCompare = FALSE; szWindowName[0] = '\0'; hinstPrevious = hinsPrev; hInsNow = hinsThis; pImageList_LoadImage = 0; #ifdef STACK_CHECK StackPrep(); #endif // Make a local copy of the command line ASSERT(lstrlen(szCmdLine) + 1 <= sizeof(rgchCmdLine)); lstrcpy(rgchCmdLine, szCmdLine); pszCmdLine = FirstNonSpace(rgchCmdLine); /* * The fNoSwitches flag is used to determine whether to exit if its a * bad file. If we got a switch, or no filename at all, then we stay * put. But if all we got is a file, and its bad, we exit. */ fNoSwitches = (*pszCmdLine == '-' || !*pszCmdLine) ? FALSE : TRUE; /* * NOTE: Though we do not use the file name until the end of this * function, we need to do the parsing here so that fHelp is is set * correctly. */ hwndParent = FindWindow("hcw_class", NULL); while (*pszCmdLine == '-') { // parse command line arguments switch (tolower(pszCmdLine[1])) { #ifdef _DEBUG case chTESTERS: // 't' fAppModal = TRUE; break; #endif case chKEYWORD: // 'k' case chID: // 'i' cmd = (*(pszCmdLine + 1) == chKEYWORD) ? CMD_KEYWORD : CMD_CTX_STRING; pszTmp = pszCmdLine + 2; // Parse out the keyword or the id while (*pszTmp == SPACE) pszTmp++; pszTmp2 = pchBuffer; // and place it in pchBuffer while((*pszTmp && (*pszTmp != SPACE)) && (pszTmp2 < pchBuffer + MAX_HELPONHELP - 1)) { #ifdef DBCS if (IsDBCSLeadByte(*pszTmp2)) { *pszTmp2++ = *pszTmp++; *pszTmp2++ = *pszTmp++; } else *pszTmp2++ = *pszTmp++; #else *pszTmp2++ = *pszTmp++; #endif //DBCS } *pszTmp2 = '\0'; fHasParam = TRUE; break; case chCONTEXTNO: // 'n' fNoHide = FALSE; cmd = CMD_CTX_NUMBER; pszTmp = pszCmdLine + 2; while (*pszTmp == SPACE) pszTmp++; ctx = (CTX) atol(pszTmp); fHasParam = TRUE; break; case chWindow: pszTmp = pszCmdLine + 2; while (*pszTmp == SPACE) pszTmp++; pszTmp2 = szWindowName; while (*pszTmp != SPACE && *pszTmp && pszTmp2 < szWindowName + (cchWindowMemberMax - 1)) *pszTmp2++ = *pszTmp++; *pszTmp2 = '\0'; while (*pszTmp == SPACE) pszTmp++; pszCmdLine = pszTmp - 2; // end of loop does pszCmdLine += 2 break; case chCompare: fCompare = TRUE; break; case chHLPONHLP: // 'h' cmd = CMD_HELP_ON_HELP; break; #ifdef _DEBUG case 'f': fNoQuit = FALSE; wCmdShow = SW_HIDE; fHelp = STANDARD_HELP; break; #endif case HLP_POPUP: // 'p' Was executed using WinHelp() fHelp = POPUP_HELP; wCmdShow = SW_HIDE; break; case HLP_APPLICATION: // 'x' Was executed using WinHelp() fHelp = STANDARD_HELP; fNoQuit = FALSE; wCmdShow = SW_HIDE; break; case HLP_TRAININGCARD: // 'c' Was executed using WinHelp() fHelp = TCARD_HELP; wCmdShow = SW_HIDE; break; case '\0': /*------------------------------------------------------------*\ | A special case for a command line terminated with '-' \*------------------------------------------------------------*/ pszCmdLine--; break; case chSilentGID: // 's' create .GID file without animation window fHiddenSetup = TRUE; // deliberately fall through case chGID: // 'g' create .GID file { int tab = 0; pszTmp = pszCmdLine + 2; if (isdigit(*pszTmp)) tab = atoi(pszTmp++); while (*pszTmp == SPACE) pszTmp++; if (!*pszTmp) return FALSE; // no filename was specified fm = FmNew(pszTmp); if (fm) fmCreating = FmCopyFm(fm); FindGidFile(fm, TRUE, tab); DisposeFm(fm); } return FALSE; default: /* * 29-Dec-1992 [ralphw] If there is no space after the switch, * then we assume the switch took a paramter, and we want to throw * away the parameter as well as the switch. If there is a space * after the switch, then we really don't know if the switch had * a paramter or not, so we leave it alone. */ if (pszCmdLine[2] != SPACE && pszCmdLine[2] != '\0') fHasParam = TRUE; break; // ignore what we can't understand } // switch pszCmdLine += 2; // skip white space while (*pszCmdLine == SPACE) pszCmdLine++; if (fHasParam) { // If the argument has a parameter // then we want to eat that param while ((*pszCmdLine != SPACE) && *pszCmdLine) pszCmdLine = CharNext(pszCmdLine); while (*pszCmdLine == SPACE) pszCmdLine++; fHasParam = FALSE; } } // while *pszCmdLine pszCaption = lcStrDup(GetStringResource(sidCaption)); if (fHelp != POPUP_HELP) { if (GetHighContrastFlag() || GetSysColor(COLOR_WINDOW) != RGB(255, 255, 255) || GetSysColor(COLOR_WINDOWTEXT) != 0) fDisableAuthorColors = TRUE; GetAuthorFlag(); } switch (fHelp) { case STANDARD_HELP: pszClass = pchHelp; break; case POPUP_HELP: pszClass = pchPopup; break; case TCARD_HELP: pszClass = pchTCard; break; default: pszClass = pchDoc; break; } /* Fix for bug 81 (kevynct) * * fFatalExit is set to FALSE in FInitialize, and set to * TRUE in Error(), in the case that a DIE action is received. * Setting fFatalExit to FALSE should be the first thing we do. */ fFatalExit = FALSE; /* (kevynct) * fButtonsBusy was introduced so that we do a minimal number of * screen updates when changing files. The flag is used only in * FReplaceCloneHde, and checked only by the WM_SIZE processing code. * We use it to ignore resizes generated by the button code. */ fButtonsBusy = FALSE; /* * We have to initialize dll's even for popup help, since they might * contain an imbedded window. */ InitDLL(); if (!AppInit(hinsThis, hinsPrev)) { return(FALSE); } // See if there is another book instance of WinHelp hwndOtherWinHelp = FindWindow(txtDocClass, NULL); // create the windows used in help if (!CreateMainWindow(pszClass, FALSE)) { Error(wERRS_OOM, wERRA_RETURN); return FALSE; } // Initialize the menu bar if (fHelp != TCARD_HELP && fHelp != POPUP_HELP) SendMessage(ahwnd[MAIN_HWND].hwndParent, MSG_CHANGEMENU, MNU_RESET, 0L); hwndFocusCur = ahwnd[iCurWindow].hwndTitle; // REVIEW: 30-Nov-1993 [ralphw] This doesn't make sense -- we don't specify // scroll bars when the window is created. I changed this to ShowScrollBar. if (ahwnd[iCurWindow].hwndTopic) ShowScrollBar(ahwnd[iCurWindow].hwndTopic, SB_BOTH, FALSE); if (fHelp != POPUP_HELP) { fMax = FGetHelpRect(hwndOtherWinHelp); #if defined(BIDI_MULT) // jgross - determine if vert scroll bars go on // the left or right { LPARAM l; SystemParametersInfo(SPI_GETMULTILINGUAL, 0, &l, 0); RtoL = (HIWORD(l) == Arabic) || (HIWORD(l) == Hebrew); MakeScrollBarsRtoL(hwndTopicMain, RtoL, TRUE); } #endif } else fMax = FALSE; hmnuHelp = GetMenu(ahwnd[iCurWindow].hwndParent); osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osver); fIsThisChicago = (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); fIsThisNewShell4 = (osver.dwMajorVersion >= 4 ) ; if (fHelp != POPUP_HELP && !fIsThisNewShell4) LoadCtl3d(); if (cmd == CMD_HELP_ON_HELP) { // We do not care what the command JumpHOH(NULL); // line is if the user requested help on help // request. CloseHelp(); } else { if (*pszCmdLine == '\0') { if (cmd) PostErrorMessage(wERRS_NOHELP_FILE); /* * If help was started by running the executable, and no * filename was specified, then put up the open file dialog box. */ if (fHelp == BOOK_HELP) { ASSERT(iCurWindow == MAIN_HWND); MoveWindow(ahwnd[iCurWindow].hwndParent, rctHelp.left, rctHelp.top, rctHelp.cx, rctHelp.cy, TRUE); ShowWindow(ahwnd[iCurWindow].hwndParent, wCmdShow); fm = DlgOpenFile(ahwnd[iCurWindow].hwndParent, NULL, NULL); if (!fm) { EarlyTermination: FlushMessageQueue(WM_USER); if (pCtl3dUnregister) pCtl3dUnregister(hInsNow); return FALSE; // terminate } OpenBookHelp: fDelayShow = TRUE; fmSave = FmCopyFm(fm); if (FReplaceHde("", &fm, NULL)) { fDelayShow = FALSE; SetOnTopState(iCurWindow, ahwnd[iCurWindow].fsOnTop); if (!hfsGid || !cntFlags.cCntItems || fCompare) { if (!cntFlags.fMainMax) { MoveWindow(ahwnd[iCurWindow].hwndParent, rctHelp.left, rctHelp.top, rctHelp.cx, rctHelp.cy, TRUE); ShowWindow(ahwnd[iCurWindow].hwndParent, wCmdShow); } else ShowWindow(ahwnd[iCurWindow].hwndParent, SW_MAXIMIZE); if (fCompare) FWinHelp(fmSave, HELP_CONTENTS, 0); else FJumpIndex(fmSave); } else { ShowWindow(ahwnd[iCurWindow].hwndParent, SW_HIDE); fNoQuit = FALSE; Finder(); } } else { goto EarlyTermination; } RemoveFM(&fm); RemoveFM(&fmSave); } } else { if (!(fm = FmNewExistSzDir(pszCmdLine, DIR_CURRENT | DIR_INI | DIR_PATH | DIR_SILENT_REG))) { lstrcpy(rgchName, pszCmdLine); CharUpper(rgchName); if (!strstr(rgchName, txtHlpExtension)) { ChangeExtension(rgchName, txtHlpExtension); fm = FmNewExistSzDir(rgchName, DIR_CURRENT | DIR_INI | DIR_PATH | DIR_SILENT_REG); if (fm) lstrcpy(rgchName, fm); } } if (!fm && !(fm = FindThisFile(pszCmdLine, TRUE))) { goto EarlyTermination; } else { if (cmd == CMD_NOTHING) { ASSERT(fHelp == BOOK_HELP); MoveWindow(ahwnd[iCurWindow].hwndParent, rctHelp.left, rctHelp.top, rctHelp.cx, rctHelp.cy, FALSE); goto OpenBookHelp; } switch(cmd) { case CMD_KEYWORD: if (fHelp == POPUP_HELP) return FALSE; // can't use popups for keywords FShowKey(fm, (LPSTR) pchBuffer); break; case CMD_CTX_NUMBER: if (fHelp == POPUP_HELP) FPopupCtx(fm, ctx); else { strcpy(rgchName, fm); if (szWindowName[0]) { lstrcat(rgchName, ">"); lstrcat(rgchName, szWindowName); } FJumpContext((LPSTR) rgchName, ctx); } break; case CMD_CTX_STRING: if (fHelp == POPUP_HELP) FPopupId(fm, (LPSTR) pchBuffer); else { strcpy(rgchName, fm); if (szWindowName[0]) { lstrcat(rgchName, ">"); lstrcat(rgchName, szWindowName); } FJumpId((LPSTR) rgchName, (LPSTR) pchBuffer); } break; default: if (fHelp == POPUP_HELP) return FALSE; // can't use popups without an id FJumpIndex(fm); break; } DisposeFm(fm); } } } if (fHelp != TCARD_HELP) { if (!IsZoomed(ahwnd[iCurWindow].hwndParent) && !IsIconic(ahwnd[iCurWindow].hwndParent)) MoveWindow(ahwnd[iCurWindow].hwndParent, rctHelp.left, rctHelp.top, rctHelp.cx, rctHelp.cy, FALSE); } // Attempt to register as a pen-win aware application return TRUE; } /*************************************************************************** * - Name: FTerminate( void ) - * Purpose: * Contains all of the termination routines needed when the program * falls out of the main message loop. Returns FALSE if this cannot * be done, though nothing can be done about it. * * Arguments: * None. * * Returns: * TRUE, if terminating seccessfully, else FALSE. * * * ***************************************************************************/ typedef LPMMIOPROC (WINAPI *LPMMIOINSTALL)(FOURCC, LPMMIOPROC, DWORD); extern LPMMIOINSTALL lpfnInstall; INLINE static void STDCALL FTerminate(void) { if (hfsBM != NULL) CloseAndCleanUpBMFS(); if (hbitLine) DeleteObject(hbitLine); if (hfontDefault != hfontSmallSys && hfontDefault) { DeleteObject(hfontDefault); hfontDefault = NULL; } if (hfontSmallSys != NULL) { DeleteObject(hfontSmallSys); hfontSmallSys = NULL; } // REVIEW: 08-Apr-1994 [ralphw] Make certain this happens BEFORE we unload // any dll's. // CleanupDlgPrint(); // De-initialize MM IOProc if we did it before. if (lpfnInstall) mmInit(FALSE); } /*----------------------------------------------------------------------------- * AppInit(HINSTANCE, HINSTANCE) * * Description: * This function is called when the application is first loaded into * memory. It performs all initalization which is not to be done once per * instance. * * Arguments: * 1. hIns - current instance handle * 2. hPrev - previous instance handle * * Returns; * TRUE, if successful * else FALSE *-----------------------------------------------------------------------------*/ static BOOL STDCALL AppInit(HINSTANCE hIns, HINSTANCE hPrev) { if (!FLoadResources(hIns, hPrev)) return FALSE; // REVIEW: okay not to register classes for this instance? if (!hPrev) { if (!RegHelpWinClasses(hIns)) // Register window classes return FALSE; } // REVIEW: why set the focus? else SetFocus(ahwnd[iCurWindow].hwndParent); return TRUE; } /******************* ** ** Name: HfontGetSmallSysFont ** ** Purpose: Returns a handle to a suitable small helvetica font ** ** Arguments: none ** ** Returns: The handle to the font, if created. ** ** Notes: This uses a static variable to save time. Some provision ** for deleting this puppy at termination is needed. ** *******************/ HFONT STDCALL HfontGetSmallSysFont(VOID) { if (hfontSmallSys == NULL) { int dyHeight = 0; PSTR pszFontName = GetStringResource(sidSmallFont); if (defcharset == (WORD) -1) { HWND hwndDesktop = GetDesktopWindow(); HDC hdc = GetDC(hwndDesktop); if (hdc) { TEXTMETRIC tm; GetTextMetrics(hdc, &tm); defcharset = (WORD) tm.tmCharSet; YAspectMul = GetDeviceCaps(hdc, LOGPIXELSY); XAspectMul = GetDeviceCaps(hdc, LOGPIXELSX); ReleaseDC(hwndDesktop, hdc); } else OOM(); } { PSTR pszPoint = StrRChrDBCS(pszFontName, ','); if (pszPoint) { *pszPoint = '\0'; pszPoint = FirstNonSpace(pszPoint + 1); if (isdigit((BYTE) *pszPoint)) dyHeight = MulDiv(YAspectMul, atoi(pszPoint) * 2, 144); } } if (!dyHeight) dyHeight = YAspectMul / 6; hfontSmallSys = CreateFont(-dyHeight, 0, 0, 0, 0, 0, 0, 0, defcharset, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, VARIABLE_PITCH | FF_MODERN, pszFontName); ASSERT(hfontSmallSys); hfontDefault = hfontSmallSys; } return hfontSmallSys; } /******************************************************************** - - Name: RegHelpWinClasses(HINSTANCE) * * Purpose: * This function registers Help's main window and note window and * topic window classes. * * Arguments: * 1. hIns - current instance handle * * Returns; * TRUE, if successful * else FALSE * ************************************************************************/ static BOOL STDCALL RegHelpWinClasses (HINSTANCE hIns) { WNDCLASSEX wc; int iCls; int endClass; HICON hIconSmDefault; // Fill in fields determined at runtime which are unique to specific // window classes. wc.cbSize = sizeof(wc); wc.cbClsExtra = 0; if (fHelp != POPUP_HELP) { rgWndClsInfo[IWNDCLSMAIN].hIcon = LoadIcon(hIns, MAKEINTRESOURCE(IDICO_DOCICON)); rgWndClsInfo[IWNDCLSMAIN].hIconSm = LoadImage(hIns, MAKEINTRESOURCE(IDICO_DOCICON), IMAGE_ICON, 16, 16, 0); rgWndClsInfo[IWNDCLSDOC].hIcon = rgWndClsInfo[IWNDCLSMAIN].hIcon; rgWndClsInfo[IWNDCLSDOC].hIconSm = rgWndClsInfo[IWNDCLSMAIN].hIconSm; rgWndClsInfo[IWNDCLSTCARD].hIcon = rgWndClsInfo[IWNDCLSMAIN].hIcon; rgWndClsInfo[IWNDCLSTCARD].hIconSm = rgWndClsInfo[IWNDCLSMAIN].hIconSm; rgWndClsInfo[IWNDCLSPATH].hIcon = hIconDefault; rgWndClsInfo[IWNDCLS2ND].hIcon = LoadIcon(hIns, MAKEINTRESOURCE(IDICO_PAGEICON)); rgWndClsInfo[IWNDCLS2ND].hIconSm = LoadImage(hIns, MAKEINTRESOURCE(IDICO_PAGEICON), IMAGE_ICON, 16, 16, 0); rgWndClsInfo[IWNDCLSICON].hbrBackground = (HBRUSH) GetStockObject(GRAY_BRUSH); iCls = (fHelp == TCARD_HELP ? IWNDCLSTCARD : 0); // index into class table endClass = sizeof(rgWndClsInfo) / sizeof(rgWndClsInfo[0]); } else { iCls = IWNDCLSPOPUP; endClass = IWNDCLSNSR + 1; } hIconSmDefault = LoadImage(hIns, MAKEINTRESOURCE(IDICO_HELPICON), IMAGE_ICON, 16, 16, 0); // Walk the class table and register each class. for (; iCls < endClass; iCls++) { // Fill in fields determined at runtime which are common to all classes // we create. wc.style = rgWndClsInfo[iCls].style; wc.lpfnWndProc = (WNDPROC) rgWndClsInfo[iCls].lpfnWndProc; wc.cbWndExtra = rgWndClsInfo[iCls].cbWndExtra; wc.hIcon = rgWndClsInfo[iCls].hIcon; wc.hIconSm = (wc.hIcon == hIconDefault) ? hIconSmDefault : rgWndClsInfo[iCls].hIconSm; wc.hbrBackground = rgWndClsInfo[iCls].hbrBackground; wc.lpszMenuName = MAKEINTRESOURCE(rgWndClsInfo[iCls].wMenuName); wc.lpszClassName = (LPSTR) rgWndClsInfo[iCls].szClassName; wc.hInstance = hIns; wc.hCursor = hcurArrow; if (!RegisterClassEx(&wc)) { #ifdef _DEBUG GetLastError(); #endif return FALSE; } } return TRUE; } /******************************************************************** - - Name: - CreateMainWindow(HINSTANCE) * * Purpose: * This function creates all the windows required to bring up basic * help on a topic. * a. Help Window * b. Topic WIndow * c. Button Bar (Icon) Window * d. NSR/Title window * * Arguments: * 1. hIns - current instance handle * * Returns; * TRUE, if successful else FALSE * *********************************************************************/ #ifndef NO_PRAGMAS #pragma data_seg(".text", "CODE") #endif const char txtWINHELP[] = "WM_WINHELP"; const char txtWINDOC[] = "WM_WINDOC"; #ifndef NO_PRAGMAS #pragma data_seg() #endif static BOOL STDCALL CreateMainWindow(PSTR pszClass, BOOL fButtonBar) { // We have to maintain the registered message, even though we don't use // it in order to be compatible with the shareres.dll help dll. // REVIEW: will this registered message be available to 16-bit dlls? msgWinHelp = RegisterWindowMessage(((fHelp) ? txtWINHELP : txtWINDOC)); ahwnd[MAIN_HWND].hwndParent = CreateWindowEx(WS_EX_CLIENTEDGE, pszClass, pszCaption, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, rctHelp.left, rctHelp.top, rctHelp.cx, rctHelp.cy, NULL, // no parent NULL, // use class menu hInsNow, // handle to window instance NULL // no params to pass on ); if (ahwnd[MAIN_HWND].hwndParent == NULL) return FALSE; ahwnd[MAIN_HWND].pszMemberName = (PSTR) txtMain; /* * REVIEW: 31-Mar-1994 [ralphw] -- no dice, you GPF because other * code assumes the existance of hwndTitle. So we have to create all * these child windows we don't use. We should figure out why and how to * prevent it. We don't want this overhead for popup help either. */ // if (fHelp != TCARD_HELP) { if (!CreateChildWindows(MAIN_HWND, NULL, fButtonBar)) return FALSE; // } return TRUE; } /*************************************************************************** FUNCTION: CreateChildWindows PURPOSE: Create child windows of ahwnd[MAIN_HWND].hwndParent PARAMETERS: hwndParent hinst fButtonBar -- FALSE to suppress creation of buttons RETURNS: COMMENTS: Breaking this out into a separate function makes it theoretically possible to create these windows only when they would actually be used. In the case of invoking only a popup or Training Card, these windows aren't needed. MODIFICATION DATES: 12-Mar-1993 [ralphw] ***************************************************************************/ BOOL STDCALL CreateChildWindows(int index, const WSMAG* pwsmag, BOOL fButtonBar) { // Create topic window ASSERT(IsValidWindow(ahwnd[index].hwndParent)); if (!(ahwnd[index].hwndTopic = CreateWindow(pchTopic, NULL, WS_CHILD | WS_VSCROLL | WS_HSCROLL, 0, 0, 0, 0, ahwnd[index].hwndParent, NULL, hInsNow, NULL))) return FALSE ; // Create a non-scrolling region window if (!(ahwnd[index].hwndTitle = CreateWindow(pchNSR, NULL, WS_CHILD, 0, 0, 0, 0, ahwnd[index].hwndParent, NULL, hInsNow, NULL))) return FALSE; if (fHelp == POPUP_HELP) return TRUE; // 4.0: we allow a button bar in a secondary window if (!pwsmag || pwsmag->wMax >= FWSMAG_FIRST_BUTTON) { if (!(ahwnd[index].hwndButtonBar = CreateWindow(pchIcon, NULL, WS_CHILD, 0, 0, 0, 0, ahwnd[index].hwndParent, NULL, hInsNow, NULL))) return FALSE; if (fButtonBar) { fButtonsBusy = TRUE; CreateCoreButtons(ahwnd[index].hwndButtonBar, pwsmag); fButtonsBusy = FALSE; } } return TRUE; } /******************************************************************** - - Name: - FLoadResources(HINSTANCE, HINSTANCE) * * Purpose: * This function creates all the windows used in help. * a. Loads the accelarator table. * b. Loads the arrow cursor * c. Loads the hour glass cursor * d. Loads the hand cursor used to idntify jump or glossary buttons * within the topic. * e. Load Bitmap line resource * f. Load icon accelerator string * * Arguments: * 1. hIns - current instance handle * 2. hPrev - previous instance handle * * Returns; * TRUE if successful *********************************************************************/ static BOOL STDCALL FLoadResources(HINSTANCE hIns, HINSTANCE hPrev) { // REVIEW: hndAccel and hIconDefault aren't necessary for popup windows hndAccel = LoadAccelerators(hIns, MAKEINTRESOURCE(HELPACCEL)); hIconDefault = LoadIcon(hIns, MAKEINTRESOURCE(IDICO_HELPICON)); hcurArrow = LoadCursor(NULL, IDC_ARROW); hcurIBeam = LoadCursor(NULL, IDC_IBEAM); hbitLine = LoadBitmap(hIns, MAKEINTRESOURCE(IDBMP_HELPLINE)); LoadOOMString(); // Load resident error strings if (!hndAccel || !hcurArrow || !hIconDefault || !hbitLine) { Error(wERRS_OOM_FLOADRESOURCES, wERRA_RETURN); return FALSE; } return TRUE; } /*************************************************************************** FUNCTION: LoadOOMString PURPOSE: Load Out of Memory string from the resource file. PARAMETERS: VOID RETURNS: COMMENTS: MODIFICATION DATES: 12-Mar-1993 [ralphw] ***************************************************************************/ #define MAX_OOM_ERROR_STRING 250 // Max size of resident errors INLINE static void STDCALL LoadOOMString(VOID) { pszOutOfMemory = LocalStrDup(GetStringResource(wERRS_OOM)); } /******************************************************************** - - Name: FGetHelpRect( ) * * Purpose: This function sets the values of rctHelp, either * offset from the previous instance, or from the win.ini * file. * * Arguments: hIns - current instance handle * hInsPrev - previous instance handle * * Returns: TRUE if previous instance of help was maximized * *********************************************************************/ // minimum width and height values #define HELP_WIDTH_MINIMUM 200 #define HELP_HEIGHT_MINIMUM 200 static BOOL STDCALL FGetHelpRect(HWND hwndOtherWinHelp) { BOOL fMaximized; if (!cxScreen) GetScreenResolution(); if (hwndOtherWinHelp && !IsIconic(hwndOtherWinHelp)) { GetWindowWRect(hwndOtherWinHelp, &rctHelp); rctHelp.top += GetSystemMetrics(SM_CYCAPTION); rctHelp.left += GetSystemMetrics(SM_CYFRAME); CheckWindowPosition(&rctHelp, TRUE); return IsZoomed(hwndOtherWinHelp); } ReadWinRect(&rctHelp, WCH_MAIN, &fMaximized); rctHelpOrg = rctHelp; fMaxOrg = fMaximized; return fMaximized; } /******************************************************************** - Name: - QuitHelp() - * Description: * This function should be called to terminate the help session. * * Arguments: * None. * * Returns; * NULL * * Notes: * If help is currently printing, help's termination will be * delayed until the print job is over. * *********************************************************************/ void STDCALL QuitHelp(void) { KillOurTimers(); if (hdlgPrint == NULL) { CloseHelp(); } else fQuitHelp = TRUE; } /******************************************************************** - - Name: - DestroyHelp() * * Purpose: * This function cleans up help. * * Arguments: * None. * * Returns; * NULL * *********************************************************************/ void STDCALL DestroyHelp(void) { HDE hde; // reset the icon to default and release the icon if required. // ResetIcon(); // REVIEW: we should only call this if we invoked help // if (!fHelp) // WinHelp(ahwnd[MAIN_HWND].hwndParent, NULL, HELP_QUIT, 0L); // We only write if the winpos has changed // (fMaxOrg != IsZoomed(ahwnd[iCurWindow].hwndParent))) { // (kevynct) Destroy all enlisted DEs (in random order) while ((hde = HdeRemoveEnv()) != NULL) DestroyHde(hde); if (ppd) { GlobalFree(ppd->hDevNames); GlobalFree(ppd->hDevMode); } FTerminate(); if (hfsGid) { SaveGidPositions(); CloseGid(); } if (pCtl3dUnregister) pCtl3dUnregister(hInsNow); // Send Quit message to terminate message polling if (hfShare) CloseHandle(hfShare); PostQuitMessage(0); } /*************************************************************************** FUNCTION: GetAuthorFlag PURPOSE: Determine is Help Author mode is on or not PARAMETERS: void RETURNS: COMMENTS: Avoid the temptation to put this in the registry. By leaving it in win.ini, product support technicians can easily have a user turn it on in order to more easily track down a help problem. MODIFICATION DATES: 05-Apr-1995 [ralphw] ***************************************************************************/ #ifndef NO_PRAGMAS #pragma data_seg(".text", "CODE") #endif static char txtHlpAuthor[] = "Help Author"; #ifndef NO_PRAGMAS #pragma data_seg() #endif void STDCALL GetAuthorFlag(void) { fHelpAuthor = GetProfileInt(txtIniHelpSection, txtHlpAuthor, 0); } /*************************************************************************** FUNCTION: WriteProfile PURPOSE: PARAMETERS: void RETURNS: COMMENTS: MODIFICATION DATES: 28-Jan-1993 [ralphw] ***************************************************************************/ #if 0 static void STDCALL WriteProfile(void) { char szKeyBuf[80]; ASSERT (fHelp != TCARD_HELP && fHelp != POPUP_HELP && !hfsGid); /* * Note that we only save the on-top state if it was forced, not if it * was set by the help author. */ wsprintf(szKeyBuf, "%u %u %u %d 1", INI_VERSION, cntFlags.fsOnTop, cntFlags.iFontAdjustment, cntFlags.fOverColor); WriteProfileString(txtIniHelpSection, txtSettings, szKeyBuf); } #endif /*************************************************************************** FUNCTION: FirstNonSpace PURPOSE: Return a pointer to the first non-space character RETURNS: COMMENTS: MODIFICATION DATES: 30-May-1989 [ralphw] ***************************************************************************/ PSTR STDCALL FirstNonSpace(PCSTR pszOrg) { // Assign to local because we're changing the pointer, not the contents. PSTR psz = (PSTR) pszOrg; if (psz != NULL) { while (*psz == SPACE || *psz == '\t') psz++; } return psz; } #if 0 /*************************************************************************** * - Name ResetIcon() - * Purpose Used for resetting the default icon inside window class. * * Returns * Nothing * * +++ * * Notes * ***************************************************************************/ void STDCALL ResetIcon() { HICON hIconOverLoad; // Ensure that the window class actually refers to the correct icon if (hIconDefault) SetClassLong(ahwnd[iCurWindow].hwndParent, GCL_HICON, (LONG) hIconDefault); // Now remove the icon which is help in the current window hIconOverLoad = (HICON) GetWindowLong(ahwnd[iCurWindow].hwndParent, GHWL_HICON); if (hIconOverLoad) { GlobalFree(hIconOverLoad); SetWindowLong(ahwnd[iCurWindow].hwndParent, GHWL_HICON, 0); } } #endif /*************************************************************************** FUNCTION: ReadWinRect PURPOSE: Read a window position from .GID or WIN.INI. Cannot be used for secondary windows. PARAMETERS: prc ch pfMax RETURNS: COMMENTS: MODIFICATION DATES: 28-Dec-1993 [ralphw] ***************************************************************************/ void STDCALL ReadWinRect(WRECT* prc, char ch, BOOL* pfMax) { BOOL fGotRect = FALSE; ASSERT(fHelp != POPUP_HELP) if (hfsGid) { switch (ch) { case WCH_MAIN: if (pPositions[POS_MAIN].rc.cx) { *prc = pPositions[POS_MAIN].rc; *pfMax = cntFlags.fMainMax; fGotRect = TRUE; } break; case WCH_HISTORY: // history window if (pPositions[POS_HISTORY].rc.cx) { *prc = pPositions[POS_HISTORY].rc; fGotRect = TRUE; } break; case WCH_TOPICS: // Finder dialog box if (pPositions[POS_TOPICS].rc.cx) { *prc = pPositions[POS_TOPICS].rc; fGotRect = TRUE; } break; } } if (!fGotRect) { SetRectEmpty((PRECT) prc); if (prc->left == 0 && prc->cx == 0) { switch(ch) { case WCH_HISTORY: SetRect((PRECT) prc, 0, 0, 200, 200); break; case WCH_TOPICS: SetRect((PRECT) prc, cxScreen / 4, 50, 200, 200); break; default: case WCH_MAIN: SetRect((PRECT) prc, rcWorkArea.left + RECT_WIDTH(rcWorkArea) / 8, rcWorkArea.top + 4, (RECT_WIDTH(rcWorkArea) / 8) * 6 + rcWorkArea.left, RECT_HEIGHT(rcWorkArea) - 4); break; } } } CheckWindowPosition(prc, TRUE); } /*************************************************************************** FUNCTION: CheckWindowPosition PURPOSE: Ensure that the window is within the work area (that portion of the desktop that is outside of the tray). PARAMETERS: prc RETURNS: COMMENTS: MODIFICATION DATES: 28-Dec-1993 [ralphw] ***************************************************************************/ void STDCALL CheckWindowPosition(WRECT* prc, BOOL fAllowShrinkage) { int diff; ASSERT(cxScreen); // Make certain we don't go off the edge of the screen if (prc->left < rcWorkArea.left) prc->left = rcWorkArea.left; if (prc->top < rcWorkArea.top) prc->top = rcWorkArea.top; /* * If the right side of the window is off the work area, move the * window to the left. If we don't have enough room for the window when * moved all the way to the left, then shrink the window (won't work for * dialogs). */ if (prc->cx > RECT_WIDTH(rcWorkArea)) { diff = (prc->left + prc->cx) - RECT_WIDTH(rcWorkArea); if (diff < prc->left) prc->left -= diff; else if (fAllowShrinkage) { diff -= prc->left; prc->left = rcWorkArea.left; prc->cx -= diff; } else // Can't shrink, so shove to the left side prc->left = rcWorkArea.left; } // Same question about the bottom of the window being off the work area if (prc->cy > RECT_HEIGHT(rcWorkArea)) { diff = (prc->top + prc->cy) - RECT_HEIGHT(rcWorkArea); if (diff < prc->top) prc->top -= diff; else if (fAllowShrinkage) { diff -= prc->top; prc->top = rcWorkArea.top; prc->cy -= diff; } else // Can't shrink, so shove to the top prc->top = rcWorkArea.top; } // Force minimum window size if (prc->cx < HELP_WIDTH_MINIMUM) { prc->cx = HELP_WIDTH_MINIMUM; // Width is now correct, but we could be off the work area. Start over CheckWindowPosition(prc, fAllowShrinkage); } if (prc->cy < HELP_HEIGHT_MINIMUM) { prc->cy = HELP_HEIGHT_MINIMUM; // Height is now correct, but we could be off the work area. Start over CheckWindowPosition(prc, fAllowShrinkage); } } #if DEADCODE /******************* - - Name: GetProfileWinPos * * Purpose: Gets a window position from the WIN.INI file * * Arguments: pch - name of variable to get * px, py, pdx, pdy - pointer to places to load position into * pfMax - pointer to max flag. May be NULL. * * Returns: nothing. * ******************/ INLINE static VOID STDCALL GetProfileWinPos(PSTR pch, LONG* px, LONG* py, LONG* pdx, LONG* pdy, BOOL* pfMax) { PSTR psz; char szBuf[40]; if (!GetProfileString(txtIniHelpSection, pch, txtZeroLength, szBuf, sizeof(szBuf))) { *px = *py = *pdx = *pdy = 0; // Initialize all positions to 0 if (pfMax != NULL) *pfMax = 0; return; } psz = GetNextDigit(px, szBuf); psz = GetNextDigit(py, psz); psz = GetNextDigit(pdx, psz); psz = GetNextDigit(pdy, psz); ASSERT(sizeof(BOOL) == sizeof(LONG)); if (pfMax != NULL) GetNextDigit((LONG*) pfMax, psz); } #endif static PSTR STDCALL GetNextDigit(LONG* pdigit, PSTR pszCur) { while (!isdigit((BYTE) *pszCur) && *pszCur) pszCur++; *pdigit = atoi(pszCur); while (isdigit((BYTE) *pszCur)) pszCur++; return pszCur; } /*************************************************************************** FUNCTION: GetScreenResolution PURPOSE: Get the screen resolution PARAMETERS: void RETURNS: COMMENTS: MODIFICATION DATES: 22-Mar-1993 [ralphw] ***************************************************************************/ #ifndef SPI_GETWORKAREA #define SPI_GETWORKAREA 48 #endif void STDCALL GetScreenResolution(void) { cxScreen = GetSystemMetrics(SM_CXSCREEN); cyScreen = GetSystemMetrics(SM_CYSCREEN); if (!SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, 0)) { SetRectEmpty(&rcWorkArea); } if (IsRectEmpty(&rcWorkArea)) { rcWorkArea.right = cxScreen; rcWorkArea.bottom = cyScreen; } } LPVOID (WINAPI* pWOWGetVDMPointerFix)(DWORD vp, DWORD dwBytes, BOOL fProtectMode); VOID (WINAPI* pWOWGetVDMPointerUnfix)(DWORD vp); LPVOID (WINAPI* pGlobalLock16)(HGLOBAL hMem); BOOL (WINAPI* pGlobalUnlock16)(HGLOBAL hMem); BOOL STDCALL LoadLockFunctions(void) { HLIBMOD hmodule; if (fIsThisChicago) { if ((hmodule = HFindDLL("wow32.dll", FALSE))) { pWOWGetVDMPointerFix = (WOWGETVDMPOINTERFIX) GetProcAddress(hmodule, "WOWGetVDMPointerFix"); pWOWGetVDMPointerUnfix = (WOWGETVDMPOINTERUNFIX) GetProcAddress(hmodule, "WOWGetVDMPointerUnfix"); } ASSERT(pWOWGetVDMPointerFix); ASSERT(pWOWGetVDMPointerUnfix); return (BOOL) pWOWGetVDMPointerFix; } else { if ((hmodule = HFindDLL("wow32.dll", FALSE))) { pGlobalLock16 = (GLOBALLOCK16) GetProcAddress(hmodule, "WOWGlobalLock16"); pGlobalUnlock16 = (GLOBALUNLOCK16) GetProcAddress(hmodule, "WOWGlobalUnlock6"); } ASSERT(pGlobalLock16); return (BOOL) pGlobalLock16; } } void STDCALL SaveGidPositions(void) { if (fHelp == POPUP_HELP || fHelp == TCARD_HELP) return; ASSERT(IsValidWindow(ahwnd[MAIN_HWND].hwndParent)); cntFlags.fMainMax = IsZoomed(ahwnd[MAIN_HWND].hwndParent); if (!cntFlags.fMainMax) { if (!IsIconic(ahwnd[MAIN_HWND].hwndParent) && !EqualRect((PRECT) &rctHelp, (PRECT) &rctHelpOrg)) { WriteWinPosHwnd(ahwnd[MAIN_HWND].hwndParent, cntFlags.fMainMax, WCH_MAIN); } } } BOOL STDCALL GetHighContrastFlag(void) { HIGHCONTRAST highcontrast; highcontrast.cbSize = sizeof(highcontrast); if (fIsThisNewShell4 && SystemParametersInfo(SPI_GETHIGHCONTRAST, sizeof(highcontrast), &highcontrast, FALSE)) { return (highcontrast.dwFlags & HCF_HIGHCONTRASTON); } else return FALSE; }