4494 lines
112 KiB
C++
4494 lines
112 KiB
C++
/************************************************************************
|
|
* *
|
|
* HDLGSRCH.CPP *
|
|
* *
|
|
* Copyright (C) Microsoft Corporation 1993-1994 *
|
|
* All Rights reserved. *
|
|
* *
|
|
************************************************************************/
|
|
|
|
extern "C" { // Assume C declarations for C++
|
|
#include "help.h"
|
|
}
|
|
#include "inc\whclass.h"
|
|
#pragma hdrstop
|
|
|
|
#include "inc\idxchoos.h"
|
|
#include "resource.h"
|
|
|
|
#include <prsht.h> // Include property sheet stuff for wizards
|
|
|
|
#ifndef MAX_PAGES // This should have been defined in prsht.h but was not (yet)
|
|
#define MAX_PAGES 24
|
|
#endif // MAX_PAGES
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#define NOTOOLBAR
|
|
#define NOSTATUSBAR
|
|
#define NOTRACKBAR
|
|
#define NOPROGRESS
|
|
|
|
extern "C" { // Assume C declarations for C++
|
|
#include <commctrl.h>
|
|
|
|
#include <ctype.h>
|
|
#include <io.h>
|
|
#include <direct.h>
|
|
#include <stdio.h>
|
|
|
|
#include "inc\helpids.h"
|
|
}
|
|
|
|
#include "inc\table.h"
|
|
#include "inc\hwproc.h"
|
|
#include "inc\hdlgsrch.h"
|
|
#include "inc\idxchoos.h"
|
|
|
|
#define GETIMAGE_TYPE(c) (c & 0x0f)
|
|
#define GETLEVEL(c) ((UINT) (c >> 4))
|
|
const int LEVEL_MASK = 0x00f0;
|
|
const int IMAGE_MASK = 0x000f;
|
|
|
|
#ifndef STM_SETIMAGE
|
|
#define STM_SETIMAGE 0x0172
|
|
#define IMAGE_BITMAP 0
|
|
#endif
|
|
|
|
// This is for context-sensitive help
|
|
|
|
#ifndef NO_PRAGMAS
|
|
#pragma data_seg(".text", "CODE")
|
|
#endif
|
|
static DWORD aKeywordIds[] = {
|
|
IDC_TEXT, IDH_HELPFINDER_INDEX,
|
|
DLGEDIT, IDH_HELPFINDER_INDEX,
|
|
DLGVLISTBOX, IDH_HELPFINDER_INDEX,
|
|
ID_TREEVIEW, IDH_HELPFINDER_CONTENTS,
|
|
IDC_CNT_INSTRUCTIONS, IDH_HELPFINDER_CONTENTS,
|
|
IDC_PRINT, IDH_HELPFINDER_PRINT,
|
|
IDOK, IDH_HELPFINDER_DISPLAY,
|
|
|
|
0, 0
|
|
};
|
|
#ifndef NO_PRAGMAS
|
|
#pragma data_seg()
|
|
#endif
|
|
|
|
const int CWIDTH_IMAGE_LIST = 20;
|
|
typedef HANDLE HSEARCHER;
|
|
|
|
typedef void (__stdcall *ANIMATOR)(void);
|
|
|
|
#ifndef _HILIGHT // these are also in hilite.h
|
|
typedef INT ERRORCODE;
|
|
typedef HANDLE HHILITER;
|
|
#endif
|
|
|
|
typedef HSEARCHER (WINAPI* NEWSEARCHER)(void);
|
|
typedef ERRORCODE (WINAPI* DELETESEARCHER)(HSEARCHER);
|
|
typedef ERRORCODE (WINAPI* OPENINDEX)(HSEARCHER, PCSTR, PSTR, PDWORD, PDWORD, PDWORD);
|
|
typedef ERRORCODE (WINAPI* SAVEGROUP)(HSEARCHER, PSTR);
|
|
typedef ERRORCODE (WINAPI* LOADGROUP)(HSEARCHER, PSTR);
|
|
typedef ERRORCODE (WINAPI* ISVALIDINDEX)(PCSTR, UINT);
|
|
typedef ERRORCODE (WINAPI* DISCARDINDEX)(HSEARCHER, int);
|
|
typedef void (WINAPI* SETDIRECTORYLOCATOR)(HWND hwndLocator);
|
|
typedef ERRORCODE (WINAPI* REGISTERANIMATOR)(ANIMATOR pAnimator, HWND hwnd);
|
|
|
|
typedef HHILITER (WINAPI* NEWHILITER)(HSEARCHER); // Hiliter interfaces
|
|
typedef ERRORCODE (WINAPI* DELETEHILITER)(HHILITER);
|
|
|
|
HSEARCHER (WINAPI *pNewSearcher)(void);
|
|
ERRORCODE (WINAPI *pDeleteSearcher)(HSEARCHER);
|
|
ERRORCODE (WINAPI *pOpenIndex)(HSEARCHER, PCSTR, PSTR, PDWORD, PDWORD, PDWORD);
|
|
HWND (WINAPI *pOpenTabDialog)(HWND, DWORD, DWORD);
|
|
ERRORCODE (WINAPI *pSaveGroup)(HSEARCHER, PSTR);
|
|
ERRORCODE (WINAPI *pLoadGroup)(HSEARCHER, PSTR);
|
|
ERRORCODE (WINAPI *pIsValidIndex)(PCSTR, UINT);
|
|
ERRORCODE (WINAPI *pDiscardIndex)(HSEARCHER, int);
|
|
void (WINAPI *pSetDirectoryLocator)(HWND hwndLocator);
|
|
extern "C" {
|
|
ERRORCODE (APIENTRY *pRegAnimate)(ANIMATOR pAnimator, HWND hwnd);
|
|
}
|
|
|
|
#ifdef _HILIGHT
|
|
static void STDCALL RemoveHiliter(HHILITER* phhiliter);
|
|
|
|
NEWHILITER pNewHiliter;
|
|
DELETEHILITER pDeleteHiliter;
|
|
SCANDISPLAYTEXT pScanDisplayText;
|
|
CLEARDISPLAYTEXT pClearDisplayText;
|
|
COUNTHILITES pCountHilites;
|
|
QUERYHILITES pQueryHilites;
|
|
|
|
static HHILITER hhiliter;
|
|
|
|
#else
|
|
#define RemoveHiliter(hhiliter)
|
|
#endif
|
|
|
|
static BOOL STDCALL AskAboutIndexes(HWND);
|
|
static RC STDCALL FindKeywordMacro(PCSTR pszKeyword, HDE hde);
|
|
static void STDCALL OnFtsMove(HWND hwndDlg, BOOL fAdd);
|
|
static void STDCALL PageChange(HWND hwndTab);
|
|
static void STDCALL SetCntTabText(HWND hwndDlg, BOOL fOpen);
|
|
static void STDCALL AddTab(TC_ITEM* pti, TAB_ID tab, PSTR pszName, HWND hwndTabs);
|
|
|
|
static HSEARCHER hsrch;
|
|
static HWND hwndFindTab;
|
|
static TAB_ID aTabIds[MAX_IDTABS];
|
|
|
|
// BUGBUG fFTSJump should be in global.c
|
|
|
|
BOOL fFTSJump;
|
|
|
|
// Extensible Tab support
|
|
|
|
const int MAX_TABS = 7; // maximum help-authored tabs including FTS
|
|
|
|
// All extensable tabs must support this function
|
|
|
|
typedef HWND (WINAPI* OPENTABDIALOG)(HWND, DWORD, DWORD);
|
|
#ifndef NO_PRAGMAS
|
|
#pragma data_seg(".text", "CODE")
|
|
#endif
|
|
static const char txtOpenTabDialog[] = "OpenTabDialog";
|
|
#ifndef NO_PRAGMAS
|
|
#pragma data_seg()
|
|
#endif
|
|
|
|
typedef struct {
|
|
PSTR pszName;
|
|
OPENTABDIALOG pOpenTabDialog;
|
|
} TAB_EXTENSION;
|
|
|
|
TAB_EXTENSION aTabs[MAX_TABS + 1];
|
|
|
|
typedef struct {
|
|
DWORD dwPagesHit;
|
|
HBITMAP hWizBMP;
|
|
FTS_FLAGS flgs;
|
|
BOOL bExpress;
|
|
} WIZDATA,FAR *LPWIZDATA;
|
|
|
|
typedef struct {
|
|
LPWIZDATA wd;
|
|
int nID;
|
|
} WIZSHEET, FAR *LPWIZSHEET;
|
|
|
|
/*****************************************************************************
|
|
* *
|
|
* Static Variables *
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
char szSavedKeyword[MAXKEYLEN];
|
|
char szSavedContext[MAXKEYLEN];
|
|
|
|
// in honor of Pete, who will reverse-engineer the .GID file format
|
|
#ifndef NO_PRAGMAS
|
|
#pragma data_seg(".text", "CODE")
|
|
#endif
|
|
const char txtFileInfo[] = "|Pete";
|
|
#ifndef NO_PRAGMAS
|
|
#pragma data_seg()
|
|
#endif
|
|
|
|
static BOOL fDirtyInfo; // TRUE to write pFileInfo
|
|
static BOOL fReadOnlyGid; // TRUE if we can't write to the .GID file
|
|
|
|
CSearch* pSrchClass;
|
|
|
|
extern "C" {
|
|
|
|
HIMAGELIST (WINAPI *pImageList_LoadImage)(HINSTANCE, PCSTR, int, int, COLORREF, UINT, UINT);
|
|
HIMAGELIST (WINAPI *pImgLst_Destroy)(HIMAGELIST);
|
|
void (WINAPI *pInitCommonControls)(void);
|
|
HPROPSHEETPAGE (WINAPI *pCreatePropertySheetPage)(LPCPROPSHEETPAGE);
|
|
int (WINAPI *pPropertySheet)(LPCPROPSHEETHEADER);
|
|
|
|
DLGRET FtsWizardProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
|
|
extern BOOL fMacroFlag;
|
|
|
|
}
|
|
|
|
static HIMAGELIST hil;
|
|
static const int NOMATCH = -1;
|
|
static BOOL fCommControlInitialized;
|
|
int cntFirstVisible;
|
|
int cntCurHighlight;
|
|
HTREEITEM hitemCurHighlight;
|
|
HBT hbtTabDialogs;
|
|
|
|
#ifdef SPECIFICATION
|
|
|
|
*****************************************************************************
|
|
|
|
When we are first started, and we're handed a help file, we see if we can
|
|
find a contents file. If so, we fill in the following:
|
|
|
|
pTblFiles -- if index files are specified in the contents file, then
|
|
this table will contain double entries. The first entry is the name
|
|
to display on the tab control, and the second entry is the fully
|
|
qualified file to use. The filename portion contains a leading 7
|
|
characters -- the first character is the file type consisting of:
|
|
a binary flag (bit 1 is always set to get a non-zero value)
|
|
|
|
CHFLAG_MISSING file specified, but not found
|
|
CHFLAG_LINK file for alink/klink, but not combined index or FTS
|
|
CHFLAG_FTS_AVAIL FTS index available
|
|
CHFLAG_FTS_ASKED FTS index NOT available and user doesn't want it
|
|
|
|
The next 6 characters are a hex representation of the time-date stamp
|
|
|
|
pbTree -- contains a far pointer to an array of bytes specifying
|
|
whether an image is a container or a topic, what its level is,
|
|
and if it is a container, whether it is opened or not.
|
|
|
|
cntFlags -- Contains information about the number of Contents Tab entries,
|
|
first visible item in the Contents Tab, position of all windows,
|
|
flag indicating if Contents or Index tab had the focus, etc.
|
|
|
|
We fill in the pszGidFile with the path of the current .GID file (if any).
|
|
|
|
We fill in pszHelpTitle if specified in the .GID file -- this is used
|
|
for the help title for any file using that Contents file.
|
|
|
|
We fill in pszHelpBase if specified in the .GID file -- this will be
|
|
used to force an interfile jump for any topic that does not explicitly
|
|
specify one.
|
|
|
|
*****************************************************************************
|
|
|
|
#endif // SPECIFICATION
|
|
|
|
PSTR pszGidFile;
|
|
PSTR pszHelpTitle;
|
|
|
|
PSTR pszHelpBase;
|
|
PBYTE pbTree;
|
|
GID_FILE_INFO* pFileInfo;
|
|
|
|
#define GetFileIndex(x) (pFileInfo[(x)].index)
|
|
#define SetFileIndex(pos, x) (pFileInfo[(pos)].index = (x))
|
|
|
|
CTable* pTblFiles; // files considered part of contents file
|
|
|
|
/*****************************************************************************
|
|
* *
|
|
* Prototypes *
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
INLINE static BOOL STDCALL InitContents(HWND hwndDlg);
|
|
|
|
LRESULT EXPORT MessageWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
INLINE static HTREEITEM STDCALL Tree_AddItem(HWND hwndTree, HTREEITEM htiParent, int iImage, UINT cChildren, LPARAM lParam, TV_INSERTSTRUCT* ptcInsert);
|
|
static LRESULT STDCALL Tree_SetImage(HWND hwndTree, int iImage, HTREEITEM hItem);
|
|
HWND STDCALL CreateTabChild(TAB_ID idCurTab, HWND hwndDlg);
|
|
static void STDCALL ContentsCmdLine(PSTR pszLine);
|
|
INLINE void STDCALL ParseContentsString(PSTR pszString);
|
|
INLINE void STDCALL CollapseChildren(HWND hwndTree, int pos);
|
|
static void STDCALL FreeLocalStrings(void);
|
|
static int STDCALL OpenGidFile(PSTR pszGidFile, FM fmHelpFile);
|
|
static void STDCALL PrintContents(HWND hwndDlg);
|
|
static void STDCALL CheckDialogSize(HWND hwndParentDlg, HWND hwndTabDlg);
|
|
static void STDCALL ClosePropertySheet(HWND hwndPropDlg, int result);
|
|
static PCSTR FASTCALL FtsIndexToFile(int index);
|
|
static PCSTR FASTCALL FtsIndexToTitle(int index);
|
|
|
|
DLGRET ContentsDlg(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
DLGRET TabDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: ContentsDlg
|
|
|
|
PURPOSE: Dialog box procedure for Contents Tab control
|
|
|
|
PARAMETERS:
|
|
hwndDlg
|
|
msg
|
|
wParam
|
|
lParam
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
17-Aug-1993 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
BOOL fHack;
|
|
|
|
DLGRET ContentsDlg(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HWND hwndTree;
|
|
|
|
switch(msg) {
|
|
case WM_INITDIALOG:
|
|
{
|
|
CWaitCursor cursor;
|
|
ChangeDlgFont(hwndDlg);
|
|
ASSERT(hfontDefault);
|
|
SendMessage(GetDlgItem(hwndDlg, ID_TREEVIEW), WM_SETFONT,
|
|
(WPARAM) hfontDefault, FALSE);
|
|
|
|
if (!InitContents(hwndDlg))
|
|
return FALSE;
|
|
EnableWindow(GetDlgItem(GetParent(hwndDlg), IDC_PRINT), TRUE);
|
|
EnableWindow(GetDlgItem(GetParent(hwndDlg), IDOK), TRUE);
|
|
SetCntTabText(hwndDlg, TRUE);
|
|
}
|
|
return TRUE;
|
|
|
|
|
|
case WM_COMMAND:
|
|
switch(wParam) {
|
|
case IDOK:
|
|
{
|
|
|
|
hwndTree = GetDlgItem(hwndDlg, ID_TREEVIEW);
|
|
TV_ITEM tvi;
|
|
|
|
tvi.hItem = TreeView_GetSelection(hwndTree);
|
|
if (!tvi.hItem)
|
|
break; // probably ENTER with no selection
|
|
tvi.mask = TVIF_PARAM;
|
|
TreeView_GetItem(hwndTree, &tvi);
|
|
|
|
/*
|
|
* We might have gotten here from ENTER or
|
|
* DBL_CLICK, so we must be sure we actually have a
|
|
* topic selected.
|
|
*/
|
|
|
|
/*
|
|
* 21-Jan-1994 [ralphw] Hack time. This code
|
|
* should work the same whether the user
|
|
* double-clicked, or whether they single clicked
|
|
* and pressed the Display button. Both cases should
|
|
* just send a WM_COMMAND message with IDOK. But
|
|
* they don't, hence the fHack flag to do the right
|
|
* (but weird) thing to get the current book to
|
|
* expand or contract.
|
|
*/
|
|
|
|
if (GETIMAGE_TYPE(pbTree[(UINT) tvi.lParam]) !=
|
|
IMAGE_TOPIC) {
|
|
IMAGE_TYPE curType = (IMAGE_TYPE) GETIMAGE_TYPE(pbTree[tvi.lParam]);
|
|
#ifdef _DEBUG
|
|
UINT curLevel = GETLEVEL(pbTree[tvi.lParam]);
|
|
#endif
|
|
|
|
if (curType ==
|
|
(fHack ? IMAGE_CLOSED_FOLDER : IMAGE_CLOSED_FOLDER)) {
|
|
pbTree[(UINT) tvi.lParam] =
|
|
IMAGE_OPEN_FOLDER |
|
|
(pbTree[(UINT) tvi.lParam] & LEVEL_MASK);
|
|
TreeView_Expand(hwndTree, tvi.hItem,
|
|
(fHack ? TVE_COLLAPSE : TVE_EXPAND));
|
|
if (!fHack && curType != IMAGE_CLOSED_FOLDER)
|
|
CollapseChildren(hwndTree, tvi.lParam);
|
|
}
|
|
else {
|
|
pbTree[(UINT) tvi.lParam] =
|
|
IMAGE_CLOSED_FOLDER |
|
|
(pbTree[(UINT) tvi.lParam] & LEVEL_MASK);
|
|
TreeView_Expand(hwndTree, tvi.hItem,
|
|
(fHack ? TVE_EXPAND : TVE_COLLAPSE));
|
|
if (!fHack || curType == IMAGE_OPEN_FOLDER)
|
|
CollapseChildren(hwndTree, tvi.lParam);
|
|
}
|
|
|
|
Tree_SetImage(GetDlgItem(hwndDlg, ID_TREEVIEW),
|
|
GETIMAGE_TYPE(pbTree[(UINT) tvi.lParam]),
|
|
tvi.hItem);
|
|
|
|
SetWindowText(GetDlgItem(GetParent(hwndDlg), IDOK),
|
|
GetStringResource(
|
|
GETIMAGE_TYPE(pbTree[(UINT) tvi.lParam]) ==
|
|
IMAGE_CLOSED_FOLDER ?
|
|
sidOpenButton : sidCloseButton));
|
|
SetCntTabText(hwndDlg,
|
|
(GETIMAGE_TYPE(pbTree[(UINT) tvi.lParam]) ==
|
|
IMAGE_CLOSED_FOLDER));
|
|
SetFocus(hwndTree);
|
|
break;
|
|
}
|
|
HBT hbtCntJump = HbtOpenBtreeSz(txtCntJump,
|
|
hfsGid, fFSOpenReadOnly);
|
|
if (!hbtCntJump)
|
|
|
|
// REVIEW: what should we really do?
|
|
|
|
return FALSE;
|
|
|
|
/*
|
|
* REVIEW: It's theoretically possible for
|
|
* RcLookupByKey to fail, so we'll need to add some
|
|
* useful error handling here. This could happen
|
|
* with the .GID file on the net and the network
|
|
* goes down, or the .GID file could be corrupted.
|
|
*/
|
|
|
|
RcLookupByKey(hbtCntJump,
|
|
(KEY) (LPVOID) &tvi.lParam,
|
|
NULL, szSavedContext);
|
|
|
|
RcCloseBtreeHbt(hbtCntJump);
|
|
|
|
/*
|
|
* Call ParseContentsString to add base help
|
|
* filename and window, as necessary.
|
|
*/
|
|
|
|
ParseContentsString(szSavedContext);
|
|
PostMessage(GetParent(hwndDlg), WM_COMMAND,
|
|
ID_JMP_CONTEXT, 0);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_HELP:
|
|
OnF1Help(lParam, aKeywordIds);
|
|
return TRUE;
|
|
|
|
case WM_CONTEXTMENU:
|
|
OnContextMenu(wParam, aKeywordIds);
|
|
return TRUE;
|
|
|
|
case WM_NOTIFY:
|
|
{
|
|
#ifdef _DEBUG
|
|
NM_TREEVIEW* pnmhdr = (NM_TREEVIEW*)lParam;
|
|
#else
|
|
#define pnmhdr ((NM_TREEVIEW*)lParam)
|
|
#endif
|
|
|
|
switch(pnmhdr->hdr.code) {
|
|
case TVN_GETDISPINFO:
|
|
|
|
#define pdi ((TV_DISPINFO FAR *)lParam)
|
|
|
|
if (pdi->item.mask & TVIF_TEXT) {
|
|
char szBuf[260];
|
|
|
|
/*
|
|
* REVIEW: Should we do something about a failure
|
|
* here? I.e., what happens if the .GID file gets
|
|
* corrupted, and RcLookupByKey fails?
|
|
*/
|
|
|
|
// NTBUG 51883, tooltips are 80 chars, must truncate
|
|
RcLookupByKey(pSrchClass->hbtCntText,
|
|
(KEY) (LPVOID) &pdi->item.lParam,
|
|
NULL, szBuf);
|
|
lstrcpyn(pdi->item.pszText,szBuf,pdi->item.cchTextMax);
|
|
}
|
|
break;
|
|
|
|
case NM_RETURN:
|
|
case NM_DBLCLK:
|
|
fHack = TRUE;
|
|
SendMessage(hwndDlg, WM_COMMAND, IDOK, 0);
|
|
break;
|
|
|
|
case TVN_SELCHANGING:
|
|
if (GETIMAGE_TYPE(
|
|
pbTree[(UINT) pnmhdr->itemNew.lParam]) ==
|
|
IMAGE_TOPIC) {
|
|
SetWindowText(GetDlgItem(GetParent(hwndDlg), IDOK),
|
|
GetStringResource(sidDisplay));
|
|
SetCntTabText(hwndDlg, FALSE);
|
|
}
|
|
else {
|
|
SetCntTabText(hwndDlg, TRUE);
|
|
if (GETIMAGE_TYPE(
|
|
pbTree[(UINT) pnmhdr->itemNew.lParam]) ==
|
|
IMAGE_CLOSED_FOLDER)
|
|
SetWindowText(GetDlgItem(GetParent(hwndDlg), IDOK),
|
|
GetStringResource(sidOpenButton));
|
|
else
|
|
SetWindowText(GetDlgItem(GetParent(hwndDlg), IDOK),
|
|
GetStringResource(sidCloseButton));
|
|
}
|
|
hitemCurHighlight = pnmhdr->itemNew.hItem;
|
|
break;
|
|
|
|
case TVN_ITEMEXPANDING:
|
|
if (fHack) {
|
|
fHack = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (pnmhdr->action & TVE_EXPAND) {
|
|
pbTree[pnmhdr->itemNew.lParam] =
|
|
IMAGE_OPEN_FOLDER |
|
|
(pbTree[pnmhdr->itemNew.lParam] & LEVEL_MASK);
|
|
}
|
|
else {
|
|
ASSERT(pnmhdr->action & TVE_COLLAPSE);
|
|
|
|
pbTree[pnmhdr->itemNew.lParam] =
|
|
IMAGE_CLOSED_FOLDER |
|
|
(pbTree[pnmhdr->itemNew.lParam] & LEVEL_MASK);
|
|
}
|
|
|
|
// Set the correct image
|
|
|
|
Tree_SetImage(GetDlgItem(hwndDlg, ID_TREEVIEW),
|
|
GETIMAGE_TYPE(pbTree[pnmhdr->itemNew.lParam]),
|
|
pnmhdr->itemNew.hItem);
|
|
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
/*
|
|
* Save our current position. This is a really ugly hack
|
|
* because the treeview control only understands handles,
|
|
* not position, and since we are destroying the treeview
|
|
* control, the handle will change the next time we come
|
|
* back up. So we have to save an array of handles when we
|
|
* create the treeview control, and here walk through the
|
|
* array to find the position of the treeview item. The next
|
|
* time we come back up, we again create an array of
|
|
* handles, and then use this saved position to index into
|
|
* that array of handles to find the handle to set as the
|
|
* first visible item.
|
|
*/
|
|
|
|
hwndTree = GetDlgItem(hwndDlg, ID_TREEVIEW);
|
|
HTREEITEM hItemFirstVisible =
|
|
TreeView_GetFirstVisible(hwndTree);
|
|
HTREEITEM* phTreeItem =
|
|
(HTREEITEM*) PtrFromGh(pSrchClass->hTreeItem);
|
|
int oldSaved = cntFirstVisible;
|
|
for (cntFirstVisible = 1;
|
|
cntFirstVisible < cntFlags.cCntItems;
|
|
cntFirstVisible++) {
|
|
if (hItemFirstVisible == phTreeItem[cntFirstVisible])
|
|
break;
|
|
}
|
|
if (cntFirstVisible >= cntFlags.cCntItems)
|
|
cntFirstVisible = 0;
|
|
if (hitemCurHighlight) {
|
|
for (cntCurHighlight = 1;
|
|
cntCurHighlight < cntFlags.cCntItems;
|
|
cntCurHighlight++) {
|
|
if (hitemCurHighlight == phTreeItem[cntCurHighlight])
|
|
break;
|
|
}
|
|
if (cntCurHighlight >= cntFlags.cCntItems)
|
|
cntCurHighlight = 0;
|
|
}
|
|
else
|
|
cntCurHighlight = 0;
|
|
}
|
|
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: InitContents
|
|
|
|
PURPOSE: Initialize the Contents Tab control
|
|
|
|
PARAMETERS:
|
|
hwndDlg
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
14-Jul-1993 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
INLINE static BOOL STDCALL InitContents(HWND hwndDlg)
|
|
{
|
|
ASSERT(hfsGid);
|
|
if (!hfsGid)
|
|
return FALSE;
|
|
|
|
if (pSrchClass->hTreeItem)
|
|
FreeGh(pSrchClass->hTreeItem);
|
|
|
|
// BUGBUG: Need to complain if we can't find the comctl32.dll and then
|
|
// do something intelligent. The only thing we could display is the
|
|
// search dialog.
|
|
|
|
if (!LoadShellApi())
|
|
return FALSE;
|
|
|
|
pSrchClass->hbtCntText = HbtOpenBtreeSz(txtCntText, hfsGid,
|
|
fFSOpenReadOnly);
|
|
if (!pSrchClass->hbtCntText)
|
|
return FALSE; // REVIEW: what should we really do?
|
|
|
|
HTREEITEM ahtiParents[MAX_LEVELS + 1];
|
|
|
|
HWND hwndTreeView = GetDlgItem(hwndDlg, ID_TREEVIEW);
|
|
HTREEITEM hti = NULL;
|
|
HTREEITEM htiParent = TVI_ROOT;
|
|
int curLevel = 1;
|
|
ahtiParents[0] = TVI_ROOT;
|
|
|
|
// REVIEW: This may be unnecessary once TreeView is supported by AppStudio
|
|
|
|
SetWindowLong(hwndTreeView, GWL_EXSTYLE,
|
|
GetWindowLong(hwndTreeView, GWL_EXSTYLE) | WS_EX_CLIENTEDGE);
|
|
|
|
SetWindowPos(hwndTreeView, NULL, 0, 0, 1, 1,
|
|
SWP_DRAWFRAME | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE);
|
|
|
|
// Load our image bitmap
|
|
|
|
if (!hil)
|
|
hil = pImageList_LoadImage(hInsNow,
|
|
MAKEINTRESOURCE(ID_VIEW_BITMAPS),
|
|
CWIDTH_IMAGE_LIST, 0, 0x00FFFFFF, IMAGE_BITMAP, 0);
|
|
|
|
TreeView_SetImageList(hwndTreeView, hil, TVSIL_NORMAL);
|
|
|
|
// REVIEW: enabable once tree-view works
|
|
|
|
SendMessage(hwndTreeView, WM_SETREDRAW, FALSE, 0);
|
|
|
|
pSrchClass->hTreeItem =
|
|
GhAlloc(GMEM_FIXED, cntFlags.cCntItems * sizeof(HTREEITEM));
|
|
HTREEITEM* phTreeItem = (HTREEITEM*) PtrFromGh(pSrchClass->hTreeItem);
|
|
|
|
TV_INSERTSTRUCT tcAdd;
|
|
tcAdd.hInsertAfter = TVI_LAST;
|
|
tcAdd.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT | TVIF_CHILDREN | TVIF_PARAM;
|
|
tcAdd.item.hItem = NULL;
|
|
tcAdd.item.pszText = LPSTR_TEXTCALLBACK;
|
|
|
|
int pos;
|
|
for (pos = 1; pos < cntFlags.cCntItems; pos++) {
|
|
if (GETIMAGE_TYPE(pbTree[pos]) == IMAGE_TOPIC) {
|
|
if (GETLEVEL(pbTree[pos]) > 0 && GETLEVEL(pbTree[pos]) < (UINT) curLevel)
|
|
htiParent = ahtiParents[curLevel = GETLEVEL(pbTree[pos])];
|
|
|
|
// Add the topic to the treeview control
|
|
|
|
HTREEITEM hItem = Tree_AddItem(hwndTreeView,
|
|
htiParent, // parent
|
|
IMAGE_TOPIC, // image index
|
|
0, // has kids
|
|
(LPARAM) pos, // extra data
|
|
&tcAdd);
|
|
phTreeItem[pos] = hItem;
|
|
}
|
|
else {
|
|
|
|
// *** FOLDER LINE ***
|
|
|
|
int this_level = GETLEVEL(pbTree[pos]);
|
|
|
|
htiParent = Tree_AddItem(hwndTreeView,
|
|
ahtiParents[this_level - 1],
|
|
GETIMAGE_TYPE(pbTree[pos]),
|
|
TRUE, (DWORD) pos, &tcAdd);
|
|
phTreeItem[pos] = htiParent;
|
|
ahtiParents[curLevel = this_level] = htiParent;
|
|
}
|
|
}
|
|
|
|
FlushMessageQueue(WM_USER);
|
|
|
|
for (pos = 1; pos < cntFlags.cCntItems; pos++) {
|
|
|
|
// Restore our position
|
|
|
|
if (GETIMAGE_TYPE(pbTree[pos]) == IMAGE_OPEN_FOLDER) {
|
|
TreeView_Expand(hwndTreeView, phTreeItem[pos],
|
|
TVE_EXPAND);
|
|
FlushMessageQueue(WM_USER);
|
|
}
|
|
}
|
|
SendMessage(hwndTreeView, WM_SETREDRAW, TRUE, 0);
|
|
ASSERT(cntFirstVisible < cntFlags.cCntItems);
|
|
if (cntFirstVisible)
|
|
TreeView_Select(hwndTreeView, phTreeItem[cntFirstVisible],
|
|
TVGN_FIRSTVISIBLE);
|
|
|
|
#ifdef _DEBUG
|
|
HTREEITEM hItemFirstVisible =
|
|
TreeView_GetFirstVisible(hwndTreeView);
|
|
#endif
|
|
if (cntCurHighlight)
|
|
TreeView_SelectItem(hwndTreeView, phTreeItem[cntCurHighlight]);
|
|
|
|
hitemCurHighlight = TreeView_GetSelection(hwndTreeView);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
INLINE static HTREEITEM STDCALL Tree_AddItem(HWND hwndTree,
|
|
HTREEITEM htiParent, int iImage, UINT cChildren, LPARAM lParam,
|
|
TV_INSERTSTRUCT* ptcInsert)
|
|
{
|
|
ptcInsert->hParent = htiParent;
|
|
ptcInsert->item.iImage = iImage;
|
|
ptcInsert->item.iSelectedImage = iImage;
|
|
ptcInsert->item.cChildren = cChildren;
|
|
ptcInsert->item.lParam = lParam;
|
|
|
|
return TreeView_InsertItem(hwndTree, ptcInsert);
|
|
}
|
|
|
|
static LRESULT STDCALL Tree_SetImage(HWND hwndTree, int iImage,
|
|
HTREEITEM hItem)
|
|
{
|
|
TV_ITEM tvinfo;
|
|
ZeroMemory(&tvinfo, sizeof(tvinfo));
|
|
|
|
tvinfo.hItem = hItem;
|
|
tvinfo.iImage = iImage;
|
|
tvinfo.iSelectedImage = iImage;
|
|
tvinfo.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
|
|
return TreeView_SetItem(hwndTree, &tvinfo);
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: PrintContents
|
|
|
|
PURPOSE: Print whatever is selected in the Contents Tab.
|
|
If its a book, print every contained in the book,
|
|
including any topics within books contained in the
|
|
selected books.
|
|
|
|
PARAMETERS:
|
|
hwndDlg
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
If treeview control ever has multiple selection, we'll need to add
|
|
support for that.
|
|
|
|
MODIFICATION DATES:
|
|
20-Feb-1994 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
static void STDCALL PrintContents(HWND hwndDlg)
|
|
{
|
|
RC rc;
|
|
PSTR psz;
|
|
BOOL fMPrintIdSuccess = FALSE;
|
|
|
|
HWND hwndTree = GetDlgItem(hwndDlg, ID_TREEVIEW);
|
|
TV_ITEM tvi;
|
|
|
|
tvi.hItem = TreeView_GetSelection(hwndTree);
|
|
if (!tvi.hItem)
|
|
return; // REVIEW: should we tell user nothing is selected?
|
|
|
|
tvi.mask = TVIF_PARAM;
|
|
TreeView_GetItem(hwndTree, &tvi);
|
|
|
|
if (!InitMPrint())
|
|
return;
|
|
fMacroFlag = FALSE;
|
|
|
|
HBT hbtCntJump = HbtOpenBtreeSz(txtCntJump, hfsGid, fFSOpenReadOnly);
|
|
if (!hbtCntJump)
|
|
// REVIEW: what should we really do?
|
|
return;
|
|
|
|
if (GETIMAGE_TYPE(pbTree[(UINT) tvi.lParam]) == IMAGE_TOPIC) {
|
|
|
|
/*
|
|
* REVIEW: It's theoretically possible for
|
|
* RcLookupByKey to fail, so we'll need to add some
|
|
* useful error handling here. This could happen
|
|
* with the .GID file on the net and the network
|
|
* goes down, or the .GID file could be corrupted.
|
|
*/
|
|
|
|
rc = RcLookupByKey(hbtCntJump, (KEY) (LPVOID) &tvi.lParam,
|
|
NULL, szSavedContext);
|
|
|
|
if (rc != rcSuccess)
|
|
goto error_exit; // REVIEW: we should tell the user something
|
|
if (szSavedContext[0] == chMACRO)
|
|
goto error_exit; // REVIEW: tell the user this topic can't be printed
|
|
|
|
ParseContentsString(szSavedContext);
|
|
psz = StrChrDBCS(szSavedContext, FILESEPARATOR);
|
|
if (psz)
|
|
*psz++ = '\0';
|
|
EnableWindows();
|
|
fMPrintIdSuccess = MPrintId((psz ? psz : ""), szSavedContext);
|
|
}
|
|
else {
|
|
|
|
int curpos;
|
|
UINT level = GETLEVEL(pbTree[tvi.lParam]);
|
|
|
|
for (curpos = tvi.lParam + 1; curpos < cntFlags.cCntItems &&
|
|
!fAbortPrint && fMultiPrinting;
|
|
curpos++) {
|
|
|
|
#ifdef _DEBUG
|
|
int curlevel = GETLEVEL(pbTree[curpos]);
|
|
#endif
|
|
if (GETIMAGE_TYPE(pbTree[curpos]) != IMAGE_TOPIC) {
|
|
if (GETLEVEL(pbTree[curpos]) <= level)
|
|
break; // stop if not a child book
|
|
else
|
|
continue; // don't print books
|
|
}
|
|
rc = RcLookupByKey(hbtCntJump, (KEY) (LPVOID) &curpos,
|
|
NULL, szSavedContext);
|
|
if (rc != rcSuccess)
|
|
continue;
|
|
if (szSavedContext[0] == chMACRO)
|
|
continue; // don't print macros
|
|
ParseContentsString(szSavedContext);
|
|
psz = StrChrDBCS(szSavedContext, FILESEPARATOR);
|
|
if (psz)
|
|
*psz++ = '\0';
|
|
EnableWindows();
|
|
fMPrintIdSuccess = MPrintId((psz ? psz : ""), szSavedContext);
|
|
if (!fMPrintIdSuccess)
|
|
break;
|
|
}
|
|
}
|
|
|
|
error_exit:
|
|
EndMPrint();
|
|
DisableWindows();
|
|
RcCloseBtreeHbt(hbtCntJump);
|
|
|
|
/*
|
|
* We check for fAbortPrint in case the user tried to close down the
|
|
* help window directly (which will terminate help).
|
|
*/
|
|
|
|
if (fMPrintIdSuccess && !fQuitHelp && !fAbortPrint)
|
|
Finder();
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: FindGidFile
|
|
|
|
PURPOSE: Finds a matching .GID file, if any.
|
|
|
|
PARAMETERS:
|
|
void
|
|
|
|
RETURNS:
|
|
NO_GID No .GID file was found, and a new one could not be created.
|
|
SAME_GID Current help file is contained in our current .GID file.
|
|
NEW_GID We have opened a new .GID file.
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
30-Nov-1993 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
extern "C" int STDCALL FindGidFile(FM fm, BOOL fForceCreate, int tab)
|
|
{
|
|
char szNewGid[MAX_PATH];
|
|
BOOL fTriedOnce = FALSE;
|
|
|
|
if (fHelp == POPUP_HELP)
|
|
return NO_GID;
|
|
|
|
// Once we have a .GID file, we don't let go of it unless the user
|
|
// opens a help file via File Open.
|
|
|
|
if (hfsGid)
|
|
return SAME_GID;
|
|
|
|
if (pszCntFile) // Was the .CNT file specified in the .HLP file?
|
|
lstrcpy(szNewGid, pszCntFile);
|
|
else { // no, use the .HLP basename
|
|
if (fm)
|
|
lstrcpy(szNewGid, PszFromGh(fm));
|
|
else
|
|
lstrcpy(szNewGid, GetCurFilename());
|
|
}
|
|
|
|
ChangeExtension(szNewGid, txtGidExtension);
|
|
|
|
FM fmGid = FmNewExistSzDir(szNewGid,
|
|
DIR_CUR_HELP | DIR_SILENT_INI | DIR_CURRENT | DIR_PATH | DIR_SILENT_REG);
|
|
if (fForceCreate && fmGid) {
|
|
lstrcpy(szNewGid, fmGid);
|
|
RemoveFM(&fmGid);
|
|
}
|
|
|
|
if (!fmGid) { // couldn't find a .GID file for this help file
|
|
char szCopy[MAX_PATH];
|
|
|
|
BuildGid:
|
|
CloseGid(); // Close our current .GID file, if any.
|
|
|
|
ChangeExtension(szNewGid, txtCntExtension);
|
|
CFM fmCnt(szNewGid,
|
|
DIR_CUR_HELP | DIR_SILENT_INI | DIR_CURRENT | DIR_PATH | DIR_SILENT_REG);
|
|
cntFlags.idOldTab = tab;
|
|
|
|
/*
|
|
* If we find a help file in the same location as the .CNT file,
|
|
* and that help file is NOT the same as the current help file, then
|
|
* the .CNT file is invalid.
|
|
*/
|
|
|
|
if (fmCnt.fm) {
|
|
strcpy(szCopy, fmCnt.fm);
|
|
ChangeExtension(szCopy, txtHlpExtension);
|
|
if (FExistFm(szCopy)) {
|
|
char szBaseCurrent[MAX_PATH], szBaseCnt[MAX_PATH];
|
|
GetFmParts(szCopy, szBaseCnt, PARTBASE);
|
|
GetFmParts(fm, szBaseCurrent, PARTBASE);
|
|
|
|
if (lstrcmpi(szBaseCnt, szBaseCurrent) == 0 &&
|
|
!FSameFmFm(szCopy, fm)) {
|
|
ASSERT(fmCnt.fm);
|
|
RemoveFM(&fmCnt.fm);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!fmCnt.fm || !(pszGidFile = CreateGidFile(fmCnt.fm, FALSE))) {
|
|
|
|
// Create a .GID file even if there isn't a .CNT file
|
|
|
|
if (fm) {
|
|
strcpy(szNewGid, fm); // because CreateGidFile changes this
|
|
if (!fmCreating)
|
|
fmCreating = fm;
|
|
}
|
|
if (!(pszGidFile = CreateGidFile(szNewGid, TRUE)))
|
|
return NO_GID;
|
|
}
|
|
lstrcpy(szNewGid, pszGidFile);
|
|
}
|
|
else {
|
|
lstrcpy(szNewGid, fmGid);
|
|
DisposeFm(fmGid);
|
|
}
|
|
|
|
/*
|
|
* If we got here then we are going to open a new GID file. We need to
|
|
* blow away any tables we created for the last GID file.
|
|
*/
|
|
|
|
CloseGid(); // Close our current .GID file, if any.
|
|
|
|
int result;
|
|
if (fTriedOnce)
|
|
return OpenGidFile(szNewGid, NULL);
|
|
while ((result = OpenGidFile(szNewGid, fm)) == WRONG_GID) {
|
|
fTriedOnce = TRUE;
|
|
CStr cszNewGid(szNewGid);
|
|
GetFmParts(cszNewGid.psz, szNewGid, PARTBASE | PARTEXT);
|
|
FM fmGid = FmNewExistSzDir(szNewGid,
|
|
DIR_CUR_HELP | DIR_SILENT_INI | DIR_CURRENT | DIR_PATH | DIR_SILENT_REG);
|
|
do {
|
|
DisposeFm(fmGid);
|
|
fmGid = FmNewExistSzDir(szNewGid, DIR_ENUMERATE);
|
|
if (!fmGid)
|
|
goto BuildGid;
|
|
} while (!IsSameFile(cszNewGid.psz, szNewGid));
|
|
|
|
DisposeFm(fmGid);
|
|
|
|
fmGid = FmNewExistSzDir(szNewGid, DIR_ENUMERATE);
|
|
if (!fmGid)
|
|
goto BuildGid;
|
|
|
|
strcpy(szNewGid, fmGid); // let's try this new file
|
|
DisposeFm(fmGid);
|
|
}
|
|
if (result == INVALID_GID && !fTriedOnce) {
|
|
fTriedOnce = TRUE;
|
|
goto BuildGid;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: ChangeExtension
|
|
|
|
PURPOSE: Change the extension of a file
|
|
|
|
PARAMETERS:
|
|
pszFile -- pointer to the file
|
|
idExt -- resource id of the extension
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
20-Aug-1993 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
extern "C" void STDCALL ChangeExtension(PSTR pszFile, PCSTR pszExt)
|
|
{
|
|
PSTR psz = StrRChrDBCS(pszFile, '.');
|
|
if (psz == NULL)
|
|
psz = pszFile + lstrlen(pszFile);
|
|
|
|
// Remove trailing spaces
|
|
|
|
while (psz[-1] == ' ' && psz > pszFile + 1)
|
|
psz--;
|
|
|
|
lstrcpy(psz, pszExt);
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: ParseContentsString
|
|
|
|
PURPOSE: Parse a contents string, making certain that it specifies
|
|
a filename.
|
|
|
|
PARAMETERS:
|
|
pszString
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
We have to do this here rather then in mastkey, because we don't
|
|
know where the :Base command will be specified. It should appear
|
|
before any topics, but we can't be certain of that.
|
|
|
|
MODIFICATION DATES:
|
|
02-Sep-1993 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
INLINE void STDCALL ParseContentsString(PSTR pszString)
|
|
{
|
|
PSTR psz;
|
|
|
|
ASSERT(pszHelpBase);
|
|
|
|
// If no filename was specified, then add one
|
|
|
|
if (*pszString != chMACRO && !StrChrDBCS(pszString, FILESEPARATOR)) {
|
|
if ((psz = StrChrDBCS(pszString, WINDOWSEPARATOR))) {
|
|
CLMem mem(strlen(psz) + 1);
|
|
lstrcpy(mem.pBuf, psz);
|
|
*psz++ = FILESEPARATOR;
|
|
if (!*pszHelpBase)
|
|
AuthorMsg(GetStringResource(wERRS_NO_BASE), ahwnd[iCurWindow].hwndParent);
|
|
lstrcpy(psz, pszHelpBase);
|
|
if ((psz = StrChrDBCS(psz, WINDOWSEPARATOR)))
|
|
*psz = '\0';
|
|
lstrcat(pszString, mem.pBuf);
|
|
}
|
|
else {
|
|
int cb = lstrlen(pszString);
|
|
pszString[cb] = FILESEPARATOR;
|
|
if (!*pszHelpBase)
|
|
AuthorMsg(GetStringResource(wERRS_NO_BASE), ahwnd[iCurWindow].hwndParent);
|
|
lstrcpy(pszString + cb + 1, pszHelpBase);
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: CollapseChildren
|
|
|
|
PURPOSE: Change collapsed folder images
|
|
|
|
PARAMETERS:
|
|
hwndTree
|
|
hItem
|
|
pszParent
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
When a parent folder is closed, we want to close all the children
|
|
as well. The TreeView control handles that closing, but fails to
|
|
tell us to change our image. This routine parses through all the
|
|
children of the item being closed, and changes the image of all
|
|
child folders to a closed image.
|
|
|
|
MODIFICATION DATES:
|
|
17-Sep-1993 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
INLINE void STDCALL CollapseChildren(HWND hwndTree, int pos)
|
|
{
|
|
UINT level = GETLEVEL(pbTree[pos]);
|
|
|
|
HTREEITEM hItemFirstVisible = TreeView_GetFirstVisible(hwndTree);
|
|
|
|
HTREEITEM* phTreeItem = (HTREEITEM*) PtrFromGh(pSrchClass->hTreeItem);
|
|
|
|
for (pos++; pos < cntFlags.cCntItems; pos++) {
|
|
#ifdef _DEBUG
|
|
IMAGE_TYPE curType = (IMAGE_TYPE) GETIMAGE_TYPE(pbTree[pos]);
|
|
UINT curLevel = GETLEVEL(pbTree[pos]);
|
|
#endif
|
|
|
|
if (GETIMAGE_TYPE(pbTree[pos]) < IMAGE_TOPIC &&
|
|
GETLEVEL(pbTree[pos]) <= level)
|
|
break;
|
|
if (GETIMAGE_TYPE(pbTree[pos]) == IMAGE_OPEN_FOLDER) {
|
|
pbTree[pos] = IMAGE_CLOSED_FOLDER | (pbTree[pos] & LEVEL_MASK);
|
|
TreeView_Expand(hwndTree, phTreeItem[pos], TVE_COLLAPSE);
|
|
Tree_SetImage(hwndTree, IMAGE_CLOSED_FOLDER, phTreeItem[pos]);
|
|
}
|
|
}
|
|
|
|
// Restore our position
|
|
|
|
// if (hItemFirstVisible)
|
|
// TreeView_Select(hwndTree, hItemFirstVisible, TVGN_FIRSTVISIBLE);
|
|
}
|
|
|
|
extern "C" void STDCALL FlushMessageQueue(UINT msgEnd)
|
|
{
|
|
MSG msg;
|
|
|
|
while (PeekMessage(&msg, NULL, 0, msgEnd, PM_REMOVE)) {
|
|
if (pSrchClass && pSrchClass->hwndTabParent &&
|
|
IsDialogMessage(pSrchClass->hwndTabParent, &msg))
|
|
continue;
|
|
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
|
|
extern "C" BOOL STDCALL IsTopicsDlgCreated(void)
|
|
{
|
|
return (BOOL) pSrchClass;
|
|
}
|
|
|
|
extern "C" HWND STDCALL GetTopicsDlgHwnd(void)
|
|
{
|
|
return (pSrchClass && pSrchClass->hwndTabParent) ?
|
|
pSrchClass->hwndTabParent : NULL;
|
|
}
|
|
|
|
int curIndex = 1;
|
|
int oldIndex;
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: CSearch::CSearch
|
|
|
|
PURPOSE: creates CSearch class
|
|
|
|
PARAMETERS:
|
|
void
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
13-Aug-1993 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
CSearch::CSearch(void)
|
|
{
|
|
if (!pszIndexSeparators)
|
|
GetMacroHde();
|
|
ASSERT(pszIndexSeparators);
|
|
lstrcpy(szKeyword, szSavedKeyword);
|
|
dwTop = (DWORD) -1;
|
|
oldIndex = 0;
|
|
cTabs = 0;
|
|
dwTemp = 0;
|
|
hmapbtGid = hbtGid = hbtCntText = NULL;
|
|
hss = hfsMaster = hmapbt = NULL;
|
|
hbt = NULL;
|
|
fm = NULL;
|
|
fSelectionChange = FALSE;
|
|
hTreeItem = NULL;
|
|
pInclude = NULL;
|
|
pIgnore = NULL;
|
|
lcidSave = lcid;
|
|
if (idTabSetting) {
|
|
cntFlags.idOldTab = idTabSetting;
|
|
idTabSetting = 0;
|
|
}
|
|
}
|
|
|
|
CSearch::~CSearch(void)
|
|
{
|
|
FreeKeywordList();
|
|
if (hTreeItem)
|
|
FreeGh(hTreeItem);
|
|
if (hbtCntText)
|
|
RcCloseBtreeHbt(hbtCntText);
|
|
if (hmapbtGid)
|
|
FreeGh(hmapbtGid);
|
|
if (hbtGid)
|
|
RcCloseBtreeHbt(hbtGid);
|
|
lcid = lcidSave;
|
|
}
|
|
|
|
HWND CSearch::doModeless(HWND hwndParent, int idDlg, FARPROC proc)
|
|
{
|
|
HWND hwndDlg = CreateDialog(hInsNow, MAKEINTRESOURCE(idDlg), hwndParent,
|
|
(DLGPROC) proc);
|
|
if (hwndDlg) {
|
|
|
|
// REVIEW: if we use this to create extensible tabs, then we
|
|
// should force the style to child, and also readjust the parent
|
|
// dialog (and its granparent) if we don't fit.
|
|
|
|
#ifdef _DEBUG
|
|
LONG style = GetWindowLong(hwndDlg, GWL_STYLE);
|
|
#endif
|
|
|
|
SetWindowLong(hwndDlg, GWL_STYLE,
|
|
GetWindowLong(hwndDlg, GWL_STYLE) | DS_3DLOOK | WS_TABSTOP | DS_CONTROL);
|
|
|
|
SetWindowPos(hwndDlg, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW |
|
|
SWP_NOMOVE | SWP_NOSIZE);
|
|
}
|
|
return hwndDlg;
|
|
}
|
|
|
|
extern "C" PSTR STDCALL LocalStrDup(PCSTR psz)
|
|
{
|
|
PSTR pszDup = (PSTR) LhAlloc(LMEM_FIXED, lstrlen(psz) + 1);
|
|
if (pszDup)
|
|
lstrcpy(pszDup, psz);
|
|
return pszDup;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: CloseGid
|
|
|
|
PURPOSE: Close the current .GID file, if any. Saves state information
|
|
before closing.
|
|
|
|
PARAMETERS:
|
|
void
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
30-Nov-1993 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
extern "C" void STDCALL CloseGid(void)
|
|
{
|
|
RC rc;
|
|
HF hf;
|
|
|
|
cntFirstVisible = 0;
|
|
cntCurHighlight = 0;
|
|
|
|
if (pbTree) {
|
|
FreeGh(pbTree);
|
|
pbTree = NULL;
|
|
}
|
|
|
|
if (pTblFiles) {
|
|
delete pTblFiles;
|
|
pTblFiles = NULL;
|
|
}
|
|
ZeroMemory(aTabs, sizeof(aTabs));
|
|
|
|
if (!hfsGid)
|
|
return;
|
|
|
|
RemoveHiliter(&hhiliter);
|
|
|
|
if (hsrch && pDeleteSearcher) {
|
|
pDeleteSearcher(hsrch);
|
|
hsrch = 0;
|
|
}
|
|
|
|
if (fReadOnlyGid) {
|
|
hf = 0;
|
|
fReadOnlyGid = FALSE;
|
|
goto JustClose;
|
|
}
|
|
|
|
/*
|
|
* This isn't really a for loop. We use it simply so that we can
|
|
* break out in case of an error condition.
|
|
*/
|
|
|
|
for(;;) {
|
|
|
|
// REVIEW: Yank this stuff if we end up not saving state information
|
|
|
|
hf = HfOpenHfs(hfsGid, txtFlags, fFSOpenReadWrite);
|
|
if (!hf) {
|
|
HfFailure:
|
|
if (RcGetFSError() == rcOutOfMemory)
|
|
rc = rcOutOfMemory;
|
|
else
|
|
rc = rcNoPermission;
|
|
break; // drop out into the error handler
|
|
}
|
|
if (LcbWriteHf(hf, &cntFlags, sizeof(cntFlags)) != sizeof(cntFlags)) {
|
|
rc = rcNoPermission;
|
|
break;
|
|
}
|
|
if (LcbWriteHf(hf, pPositions, sizeof(POS_RECT) * MAX_POSITIONS) !=
|
|
sizeof(POS_RECT) * MAX_POSITIONS) {
|
|
rc = rcNoPermission;
|
|
break;
|
|
}
|
|
|
|
if (RcCloseHf(hf) != rcSuccess) {
|
|
hf = 0; // Don't try to close it again
|
|
rc = rcNoPermission;
|
|
break;
|
|
}
|
|
hf = 0;
|
|
if (fDirtyInfo) {
|
|
hf = HfOpenHfs(hfsGid, (LPCSTR)txtFileInfo, fFSOpenReadWrite);
|
|
if (!hf)
|
|
goto HfFailure;
|
|
if (LcbWriteHf(hf, pFileInfo,
|
|
sizeof(GID_FILE_INFO) * MAX_FILES) !=
|
|
sizeof(GID_FILE_INFO) * MAX_FILES) {
|
|
rc = rcNoPermission;
|
|
break;
|
|
}
|
|
if (RcCloseHf(hf) != rcSuccess) {
|
|
hf = 0; // Don't try to close it again
|
|
rc = rcNoPermission;
|
|
break;
|
|
}
|
|
}
|
|
|
|
JustClose:
|
|
if (pFileInfo) {
|
|
FreePtr(pFileInfo);
|
|
pFileInfo = NULL;
|
|
}
|
|
|
|
if (RcCloseHfs(hfsGid) != rcSuccess) {
|
|
hfsGid = 0; // Don't try to close it again
|
|
rc = rcNoPermission;
|
|
break;
|
|
}
|
|
|
|
goto FinishUp;
|
|
}
|
|
|
|
if (pFileInfo) {
|
|
FreePtr(pFileInfo);
|
|
pFileInfo = NULL;
|
|
}
|
|
|
|
// We only get here if there are error conditions
|
|
|
|
if (hf)
|
|
RcCloseHf(hf);
|
|
if (hfsGid)
|
|
RcCloseHfs(hfsGid);
|
|
|
|
if (rc == rcNoPermission) {
|
|
#ifdef _DEBUG
|
|
char szBuf[300];
|
|
wsprintf(szBuf, "Unable to write to %s.", pszGidFile);
|
|
DBWIN(szBuf);
|
|
#endif
|
|
// Silently ignore in retail version
|
|
|
|
}
|
|
else if (rc == rcOutOfMemory)
|
|
OOM();
|
|
|
|
FinishUp:
|
|
|
|
FreeLocalStrings();
|
|
|
|
hfsGid = NULL;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: OpenGidFile
|
|
|
|
PURPOSE: Open the specified .GID file, and read in all initialization
|
|
information.
|
|
|
|
PARAMETERS:
|
|
pszGidFile
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
30-Nov-1993 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
static int STDCALL OpenGidFile(PSTR pszNewGid, FM fmHelpFile)
|
|
{
|
|
BOOL fTriedOnce = FALSE;
|
|
HELPFILE_DIRECTORY_ENTRY hfde;
|
|
KEY iFile;
|
|
char szBuf[MAX_PATH];
|
|
HBT hbt = NULL;
|
|
KEY key;
|
|
RC rc;
|
|
|
|
if (fmHelpFile)
|
|
GetFmParts(fmHelpFile, szBuf, PARTBASE | PARTEXT);
|
|
else
|
|
szBuf[0] = '\0';
|
|
CStr cszHelpFile(szBuf);
|
|
|
|
{
|
|
char szBuf[MAX_PATH + 100];
|
|
wsprintf(szBuf, GetStringResource(sidIndexing), pszNewGid);
|
|
SendStringToParent(szBuf);
|
|
}
|
|
|
|
if (!pFileInfo) {
|
|
pFileInfo = (GID_FILE_INFO*) GhAlloc(GMEM_FIXED | GMEM_ZEROINIT,
|
|
sizeof(GID_FILE_INFO) * MAX_FILES);
|
|
if (!pFileInfo) {
|
|
OOM();
|
|
return NO_GID; // shouldn't be able to get here
|
|
}
|
|
}
|
|
|
|
TryAgain:
|
|
FM fm = FmNew(pszNewGid);
|
|
|
|
hfsGid = HfsOpenFm(fm, fFSOpenReadWrite);
|
|
if (!hfsGid) {
|
|
|
|
if (RcGetFSError() == rcInvalid) { // invalid .gid file
|
|
DisposeFm(fm);
|
|
|
|
return INVALID_GID;
|
|
}
|
|
|
|
// If we can't open it here, try the local machine or windows\help
|
|
// directory. This takes care of us when we weren't able to write
|
|
// to the original .GID file.
|
|
|
|
char szHelpDir[MAX_PATH];
|
|
ConvertToWindowsHelp(fm, szHelpDir);
|
|
hfsGid = HfsOpenFm(szHelpDir, fFSOpenReadWrite);
|
|
|
|
if (!hfsGid) {
|
|
hfsGid = HfsOpenFm(fm, fFSOpenReadOnly);
|
|
if (hfsGid)
|
|
fReadOnlyGid = TRUE;
|
|
else if (RcGetFSError() == rcInvalid) {
|
|
DisposeFm(fm);
|
|
|
|
return INVALID_GID;
|
|
}
|
|
}
|
|
else {
|
|
// Make certain fm points to the .gid file we just opened
|
|
|
|
RemoveFM(&fm);
|
|
fm = FmCopyFm(szHelpDir);
|
|
}
|
|
}
|
|
|
|
if (!hfsGid) {
|
|
DisposeFm(fm);
|
|
|
|
// REVIEW: Here we should strip the path and look elsewhere for
|
|
// the .GID file.
|
|
|
|
return NO_GID; // extremely unlikely that we can't open it
|
|
}
|
|
|
|
// Get the flags and Contents Tab information
|
|
|
|
HF hf = HfOpenHfs(hfsGid, txtFlags, fFSOpenReadOnly);
|
|
|
|
// REVIEW: What should we do if we can't open this?
|
|
|
|
ZeroMemory(&hfde, sizeof(hfde));
|
|
if (hf) {
|
|
if (LcbReadHf(hf, &cntFlags, sizeof(cntFlags)) != sizeof(cntFlags))
|
|
goto ReInitialize;
|
|
if (cntFlags.version != GID_VERSION) {
|
|
RcCloseHf(hf);
|
|
RcCloseHfs(hfsGid);
|
|
hfsGid=NULL;
|
|
DeleteFile(fm);
|
|
RemoveFM(&fm);
|
|
return INVALID_GID;
|
|
}
|
|
if (!pPositions) {
|
|
pPositions = (POS_RECT*) GhAlloc(GMEM_FIXED,
|
|
sizeof(POS_RECT) * MAX_POSITIONS);
|
|
if (!pPositions) {
|
|
DisposeFm(fm);
|
|
OOM(); // doesn't return
|
|
}
|
|
}
|
|
if (LcbReadHf(hf, pPositions, sizeof(POS_RECT) * MAX_POSITIONS) !=
|
|
sizeof(POS_RECT) * MAX_POSITIONS)
|
|
goto ReInitialize;
|
|
|
|
if (cntFlags.cCntItems > 1) {
|
|
pbTree = (PBYTE) GhAlloc(GMEM_FIXED, cntFlags.cCntItems);
|
|
if (!pbTree) {
|
|
DisposeFm(fm);
|
|
OOM(); // doesn't return
|
|
}
|
|
|
|
if (LcbReadHf(hf, pbTree, cntFlags.cCntItems) !=
|
|
cntFlags.cCntItems) {
|
|
goto ReInitialize;
|
|
}
|
|
}
|
|
|
|
RcCloseHf(hf);
|
|
hf = 0;
|
|
}
|
|
else {
|
|
goto ReInitialize;
|
|
}
|
|
|
|
// Read file type and time stamp information
|
|
|
|
hf = HfOpenHfs(hfsGid, (LPCSTR) txtFileInfo, fFSOpenReadOnly);
|
|
|
|
if (hf) {
|
|
if (LcbReadHf(hf, pFileInfo, sizeof(GID_FILE_INFO) * MAX_FILES) !=
|
|
sizeof(GID_FILE_INFO) * MAX_FILES) {
|
|
goto ReInitialize;
|
|
}
|
|
RcCloseHf(hf);
|
|
hf = 0;
|
|
}
|
|
|
|
// Get the base filename and the title for the group of help files
|
|
|
|
hbt = HbtOpenBtreeSz(txtCntText, hfsGid, fFSOpenReadOnly);
|
|
|
|
// REVIEW: What should we do if we can't open this?
|
|
|
|
if (hbt) {
|
|
key = CNT_TITLE;
|
|
|
|
if (RcLookupByKey(hbt, (KEY) (LPVOID) &key, NULL, szBuf) == rcSuccess)
|
|
pszHelpTitle = LocalStrDup(szBuf);
|
|
key = CNT_BASE;
|
|
if (RcLookupByKey(hbt, (KEY) (LPVOID) &key, NULL, szBuf) == rcSuccess)
|
|
pszHelpBase = LocalStrDup(szBuf);
|
|
RcCloseBtreeHbt(hbt);
|
|
}
|
|
if (!pszHelpBase)
|
|
pszHelpBase = LocalStrDup(txtZeroLength);
|
|
|
|
// Get the names and titles of each individual help file
|
|
|
|
hbt = HbtOpenBtreeSz(txtFNAMES, hfsGid, fFSOpenReadOnly);
|
|
|
|
// REVIEW: What should we do if we can't open this?
|
|
|
|
RemoveFM(&fm);
|
|
if (hbt) {
|
|
|
|
// Find out if the .CNT file has a newer time/date stamp, and if so,
|
|
// regenerate the .GID file.
|
|
|
|
iFile = CNT_FILE;
|
|
|
|
if ((rc = RcLookupByKey(hbt, (KEY) (LPVOID) &iFile, NULL, &hfde)) !=
|
|
rcSuccess || !MatchTimestamp(hfde.szFileName, hfde.TimeStamp, &fm)) {
|
|
|
|
// It's okay if the .CNT file is simply gone.
|
|
|
|
if (rc == rcSuccess) {
|
|
if (GetFileAttributes(hfde.szFileName) == (DWORD) -1)
|
|
goto OkayAferAll;
|
|
else
|
|
cntFlags.flags &= ~GID_NO_CNT; // we now have a .CNT file
|
|
}
|
|
ReInitialize:
|
|
|
|
// We can get here while trying to read the cntFlags data,
|
|
// or while reading the various filenames.
|
|
|
|
if (hf)
|
|
RcCloseHf(hf);
|
|
if (!hbt) {
|
|
|
|
iFile = CNT_FILE;
|
|
|
|
// Try to read the .CNT file name
|
|
|
|
hbt = HbtOpenBtreeSz(txtCntText, hfsGid, fFSOpenReadOnly);
|
|
if (hbt) {
|
|
iFile = CNT_FILE;
|
|
if (RcLookupByKey(hbt, (KEY) (LPVOID) &iFile, NULL,
|
|
&hfde) != rcSuccess)
|
|
lstrcpy(hfde.szFileName, pszNewGid);
|
|
}
|
|
}
|
|
|
|
if (hbt)
|
|
RcCloseBtreeHbt(hbt);
|
|
|
|
if (pbTree) {
|
|
FreeGh(pbTree);
|
|
pbTree = NULL;
|
|
}
|
|
RcCloseHfs(hfsGid);
|
|
hfsGid = NULL;
|
|
FreeLocalStrings();
|
|
if (fTriedOnce || !(pszGidFile = CreateGidFile(hfde.szFileName,
|
|
(cntFlags.flags & GID_NO_CNT)))) {
|
|
if (!fTriedOnce && fReadOnlyGid) {
|
|
char szNewCnt[MAX_PATH];
|
|
strcpy(szNewCnt, pszNewGid);
|
|
ChangeExtension(szNewCnt, txtCntExtension);
|
|
if (WCmpiSz(szNewCnt, hfde.szFileName) != 0) {
|
|
if ((pszGidFile = CreateGidFile(szNewCnt,
|
|
(cntFlags.flags & GID_NO_CNT))))
|
|
goto KeepTrying;
|
|
}
|
|
}
|
|
return NO_GID;
|
|
}
|
|
KeepTrying:
|
|
lstrcpy(pszNewGid, pszGidFile);
|
|
fTriedOnce = TRUE;
|
|
if (pTblFiles) {
|
|
delete pTblFiles;
|
|
pTblFiles = NULL;
|
|
}
|
|
goto TryAgain;
|
|
}
|
|
else if (fm) // can be set by MatchTimestamp()
|
|
RemoveFM(&fm);
|
|
OkayAferAll:
|
|
iFile = 1;
|
|
|
|
while (RcLookupByKey(hbt, (KEY) (LPVOID) &iFile, NULL, &hfde) ==
|
|
rcSuccess) {
|
|
PSTR psz = StrChrDBCS(hfde.szFileName, '=');
|
|
if (psz) {
|
|
if (!pTblFiles)
|
|
pTblFiles = new CTable();
|
|
*psz++ = '\0';
|
|
GetFmParts(psz, szBuf, PARTBASE | PARTEXT);
|
|
|
|
// Same filename, but different directory?
|
|
|
|
if (!(pFileInfo[iFile - 1].filetype & CHFLAG_LINK) &&
|
|
fmHelpFile && lstrcmpi(szBuf, cszHelpFile.psz) == 0 &&
|
|
lstrcmpi(psz, fmHelpFile) != 0) {
|
|
|
|
// Wrong .GID file. Bail out.
|
|
|
|
if (hf)
|
|
RcCloseHf(hf);
|
|
if (hbt)
|
|
RcCloseBtreeHbt(hbt);
|
|
|
|
if (pbTree) {
|
|
FreeGh(pbTree);
|
|
pbTree = NULL;
|
|
}
|
|
RcCloseHfs(hfsGid);
|
|
hfsGid = NULL;
|
|
FreeLocalStrings();
|
|
delete pTblFiles;
|
|
pTblFiles = NULL;
|
|
return WRONG_GID;
|
|
}
|
|
|
|
/*
|
|
* We now check to see if the file either now exists
|
|
* where it didn't before, or it no longer exists, or it has
|
|
* changed. If any change occurs, then we must reinitialize
|
|
* the entire .GID file.
|
|
*/
|
|
|
|
if (pFileInfo[iFile - 1].filetype & CHFLAG_INDEX) {
|
|
if (pFileInfo[iFile - 1].filetype & CHFLAG_MISSING) {
|
|
HANDLE hfind;
|
|
|
|
// BUGBUG: won't find files in help directory or current directory!
|
|
|
|
WIN32_FIND_DATA fd;
|
|
if ((hfind = FindFirstFile(psz, &fd)) != INVALID_HANDLE_VALUE) {
|
|
FindClose(hfind);
|
|
ResetCnt:
|
|
iFile = CNT_FILE;
|
|
if (RcLookupByKey(hbt, (KEY) (LPVOID) &iFile,
|
|
NULL, &hfde) != rcSuccess)
|
|
lstrcpy(hfde.szFileName, pszNewGid);
|
|
goto ReInitialize; // this file exists now
|
|
}
|
|
#ifdef _DEBUG
|
|
else if (hwndParent) {
|
|
char szBuf[MAX_PATH + 100];
|
|
wsprintf(szBuf, "Missing: %s\r\n", psz);
|
|
SendStringToParent(szBuf);
|
|
}
|
|
#endif
|
|
}
|
|
else if (!MatchTimestamp(psz, pFileInfo[iFile - 1].timestamp,
|
|
&fm)) {
|
|
goto ResetCnt; // file has changed or is now missing
|
|
}
|
|
}
|
|
pTblFiles->AddString(hfde.szFileName); // Add the title
|
|
if (fm) { // is file in a new location?
|
|
pTblFiles->AddString(fm); // Add the filename
|
|
RemoveFM(&fm);
|
|
}
|
|
else
|
|
pTblFiles->AddString(psz); // Add the filename
|
|
}
|
|
iFile++;
|
|
}
|
|
RcCloseBtreeHbt(hbt);
|
|
hbt = NULL;
|
|
}
|
|
|
|
if (!pTblFiles) {
|
|
ASSERT(fmCreating);
|
|
pTblFiles = new CTable();
|
|
pTblFiles->AddString(txtZeroLength, PszFromGh(fmCreating));
|
|
}
|
|
|
|
if (cntFlags.cTabs) {
|
|
hbt = HbtOpenBtreeSz(txtTabDlgs, hfsGid, fFSOpenReadOnly);
|
|
ASSERT(hbt);
|
|
if (hbt) {
|
|
for (key = 1; key <= cntFlags.cTabs; key++) {
|
|
if (RcLookupByKey(hbt, (KEY) (LPVOID) &key, NULL, szBuf) == rcSuccess) {
|
|
HMODULE hmod;
|
|
PSTR psz = StrChrDBCS(szBuf, '=');
|
|
ASSERT(psz);
|
|
if (!psz)
|
|
continue; // paranoia -- mastkey.cpp should prevent this
|
|
*psz++ = '\0';
|
|
if ((hmod = (HMODULE)HFindDLL(psz, TRUE))) {
|
|
aTabs[key].pOpenTabDialog =
|
|
(OPENTABDIALOG) GetProcAddress(hmod, (LPCSTR)txtOpenTabDialog);
|
|
ASSERT(aTabs[key].pOpenTabDialog);
|
|
if (!aTabs[key].pOpenTabDialog) {
|
|
if (fHelpAuthor) {
|
|
wsprintf(szBuf, GetStringResource(wERRS_BAD_TAB),
|
|
psz);
|
|
ErrorQch(szBuf);
|
|
}
|
|
continue;
|
|
}
|
|
aTabs[key].pszName = (PSTR) LocalStrDup(szBuf);
|
|
}
|
|
#ifdef _DEBUG
|
|
if (!hmod) {
|
|
char szMsg[512];
|
|
char szPath[MAX_PATH];
|
|
_getcwd(szPath, sizeof(szPath));
|
|
wsprintf(szMsg, "Could not find the dll %s needed for an extensible tab.\r\nCurrent directory is %s",
|
|
psz, szPath);
|
|
OkMsgBox(szMsg);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
#ifdef _DEBUG
|
|
else
|
|
ASSERT(!"Bad entry");
|
|
#endif
|
|
}
|
|
RcCloseBtreeHbt(hbt);
|
|
hbt = NULL;
|
|
}
|
|
}
|
|
|
|
if (pPositions[POS_MAIN].rc.cx) {
|
|
rctHelp = pPositions[POS_MAIN].rc;
|
|
CheckWindowPosition(&rctHelp, TRUE);
|
|
if (ahwnd[MAIN_HWND].hwndParent) {
|
|
if (!cntFlags.fMainMax && IsWindowVisible(ahwnd[MAIN_HWND].hwndParent)
|
|
&& IsZoomed(ahwnd[MAIN_HWND].hwndParent))
|
|
ShowWindow(ahwnd[MAIN_HWND].hwndParent, SW_RESTORE);
|
|
|
|
MoveWindow(ahwnd[MAIN_HWND].hwndParent, rctHelp.left,
|
|
rctHelp.top, rctHelp.cx, rctHelp.cy,
|
|
IsWindowVisible(ahwnd[MAIN_HWND].hwndParent));
|
|
}
|
|
}
|
|
|
|
if (!pszGidFile)
|
|
pszGidFile = LocalStrDup(pszNewGid);
|
|
|
|
return NEW_GID;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: doTabSearch
|
|
|
|
PURPOSE: Chicago entry point into TabThing dialog box
|
|
|
|
PARAMETERS:
|
|
void
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
13-Aug-1993 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
extern "C" int STDCALL doTabSearch(void)
|
|
{
|
|
// Prevent reentrancy by verifying that we haven't already inited a tabbed
|
|
// search.
|
|
if (pSrchClass) {
|
|
if (!IsValidWindow(pSrchClass->hwndTabParent)) {
|
|
RemoveWaitCursor();
|
|
Finder();
|
|
}
|
|
fNoQuit = TRUE;
|
|
return TAB_ALREADY_UP;
|
|
}
|
|
|
|
if (fAutoClose) {
|
|
KillOurTimers();
|
|
fAutoClose = FALSE;
|
|
}
|
|
|
|
if (!fCommControlInitialized) {
|
|
if (!LoadShellApi())
|
|
return -1;
|
|
fCommControlInitialized = TRUE;
|
|
}
|
|
|
|
/*
|
|
* We don't want to have our parent window be on-top, or they will
|
|
* end up on top of our dialog box. So we temporarily shut off the
|
|
* on-top style until we finish this dialog.
|
|
*/
|
|
|
|
CWaitCursor* pcursor = new CWaitCursor; // put up an hourglass
|
|
|
|
RemoveOnTop(); // remove on-top state from all windows
|
|
DisableWindows(); // disable all windows
|
|
|
|
pSrchClass = new CSearch;
|
|
|
|
pSrchClass->hwndTabParent = CreateDialog(hInsNow,
|
|
MAKEINTRESOURCE(IDDLG_TAB), ahwnd[iCurWindow].hwndParent,
|
|
(DLGPROC) TabDlgProc);
|
|
|
|
if (!pSrchClass->hwndTabParent) {
|
|
if (pSrchClass->result != NO_TABS) {
|
|
PostErrorMessage(wERRS_OOM);
|
|
pSrchClass->result = -1;
|
|
}
|
|
goto Error;
|
|
}
|
|
|
|
ShowWindow(pSrchClass->hwndTabParent, SW_SHOW);
|
|
|
|
delete pcursor; // remove the hourglass
|
|
|
|
// We do our own message loop since we are modeless
|
|
|
|
MSG msg;
|
|
|
|
for (pSrchClass->fMsgLoop = TRUE; pSrchClass->fMsgLoop;) {
|
|
GetMessage(&msg, NULL, 0, 0);
|
|
|
|
if (msg.message == WM_KEYDOWN && msg.wParam == VK_TAB &&
|
|
GetAsyncKeyState(VK_CONTROL) < 0) {
|
|
HWND hwndTabDlg = GetDlgItem(pSrchClass->hwndTabParent, ID_TABCONTROL);
|
|
int idCurTab = TabCtrl_GetCurSel(hwndTabDlg);
|
|
int idSaveTab = idCurTab;
|
|
|
|
// tab in reverse if shift is down
|
|
|
|
if (GetAsyncKeyState(VK_SHIFT) < 0)
|
|
idCurTab--;
|
|
else
|
|
idCurTab++;
|
|
|
|
if (idCurTab > pSrchClass->cTabs)
|
|
idCurTab = 0;
|
|
else if (idCurTab < 0)
|
|
idCurTab = pSrchClass->cTabs;
|
|
|
|
if (SendMessage(hwndTabDlg, TCM_SETCURSEL, idCurTab, 0L) == -1)
|
|
// if we couldn't select (find) the new one, fail out
|
|
// and restore the old one
|
|
SendMessage(hwndTabDlg, TCM_SETCURSEL, idSaveTab, 0L);
|
|
PageChange(hwndTabDlg);
|
|
continue;
|
|
}
|
|
|
|
if (IsDialogMessage(pSrchClass->hwndTabParent, &msg))
|
|
continue;
|
|
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
Error:
|
|
|
|
// REVIEW: Is this necessary?
|
|
// Make certain the window gets destroyed.
|
|
|
|
if (IsValidWindow(pSrchClass->hwndTabParent))
|
|
DestroyWindow(pSrchClass->hwndTabParent);
|
|
|
|
RestoreOnTop(); // restore on-top state of all windows
|
|
EnableWindows(); // re-enable all windows
|
|
|
|
int result = pSrchClass->result;
|
|
delete pSrchClass;
|
|
pSrchClass = NULL;
|
|
return result;
|
|
}
|
|
|
|
#ifndef DM_REPOSITION
|
|
#define DM_REPOSITION (WM_USER+2)
|
|
#endif
|
|
|
|
DLGRET TabDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch(msg) {
|
|
|
|
case WM_INITDIALOG:
|
|
ChangeDlgFont(hwndDlg);
|
|
if (!InitTabControl(hwndDlg))
|
|
ClosePropertySheet(hwndDlg, NO_TABS);
|
|
else {
|
|
WRECT rc;
|
|
GetWindowWRect(hwndDlg, &rc);
|
|
int width = rc.cx;
|
|
int height = rc.cy;
|
|
ReadWinRect(&rc, WCH_TOPICS, NULL);
|
|
MoveWindow(hwndDlg, rc.left, rc.top, width,
|
|
height, FALSE);
|
|
SendMessage(hwndDlg, DM_REPOSITION, 0, 0L);
|
|
}
|
|
return TRUE;
|
|
|
|
case WM_NOTIFY:
|
|
#define lpnm ((LPNMHDR)lParam)
|
|
switch (lpnm->code) {
|
|
|
|
case TCN_SELCHANGE:
|
|
PageChange(lpnm->hwndFrom);
|
|
break;
|
|
}
|
|
#undef lpnm
|
|
break;
|
|
|
|
case WM_HELP:
|
|
OnF1Help(lParam, aKeywordIds);
|
|
return TRUE;
|
|
|
|
case WM_CONTEXTMENU:
|
|
OnContextMenu(wParam, aKeywordIds);
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
switch (wParam) {
|
|
case ID_NO_INDEX:
|
|
cntFlags.flags |= GID_NO_INDEX;
|
|
ClosePropertySheet(hwndDlg, RETRY);
|
|
break;
|
|
|
|
case IDCANCEL:
|
|
ClosePropertySheet(hwndDlg, 0);
|
|
|
|
// REVIEW: 02-Aug-1993 [ralphw] We should destroy help if it wasn't visible
|
|
|
|
break;
|
|
|
|
case IDOK:
|
|
SendMessage(hwndTabSub, WM_COMMAND, wParam, lParam);
|
|
break;
|
|
|
|
case IDDOSEARCH:
|
|
ClosePropertySheet(hwndDlg, lParam);
|
|
break;
|
|
|
|
case ID_JMP_CONTEXT:
|
|
ClosePropertySheet(hwndDlg, CONTEXT_SEARCH);
|
|
break;
|
|
|
|
case IDBTN_GEN_INDEX: // pass it on
|
|
SendMessage(hwndTabSub, msg, wParam, lParam);
|
|
break;
|
|
|
|
case IDC_PRINT:
|
|
|
|
// REVIEW: this had better be the Contents tab!!!
|
|
|
|
PrintContents(hwndTabSub);
|
|
break;
|
|
|
|
}
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
if (IsValidWindow(hwndTabSub)) {
|
|
if (hwndTabSub == hwndFindTab)
|
|
SendMessage(hwndTabSub, WM_CLOSE, 0, 0);
|
|
else {
|
|
ASSERT(IsValidWindow(hwndTabSub));
|
|
DestroyWindow(hwndTabSub);
|
|
}
|
|
hwndTabSub = NULL;
|
|
}
|
|
if (pImgLst_Destroy && hil) {
|
|
pImgLst_Destroy(hil);
|
|
hil = NULL;
|
|
}
|
|
|
|
// Save the window position
|
|
|
|
WriteWinPosHwnd(hwndDlg, 0, WCH_TOPICS);
|
|
break;
|
|
|
|
case MSG_FTS_JUMP_HASH:
|
|
fFTSJump= TRUE;
|
|
tabLparam = lParam;
|
|
lstrcpy(szSavedContext, FtsIndexToFile(wParam));
|
|
ClosePropertySheet(hwndDlg, FTS_HASH_SEARCH);
|
|
break;
|
|
|
|
case MSG_FTS_JUMP_VA:
|
|
fFTSJump= TRUE;
|
|
tabLparam = lParam;
|
|
lstrcpy(szSavedContext, FtsIndexToFile(wParam));
|
|
ClosePropertySheet(hwndDlg, FTS_VA_SEARCH);
|
|
break;
|
|
|
|
case MSG_TAB_CONTEXT:
|
|
tabLparam = lParam;
|
|
tabWparam = wParam;
|
|
ClosePropertySheet(hwndDlg, EXT_TAB_CONTEXT);
|
|
break;
|
|
|
|
case MSG_TAB_MACRO:
|
|
tabLparam = lParam;
|
|
ClosePropertySheet(hwndDlg, EXT_TAB_MACRO);
|
|
break;
|
|
|
|
case MSG_FTS_GET_TITLE:
|
|
ASSERT(lParam != NULL); // Don't call me without a pointer
|
|
if (lParam != NULL)
|
|
{
|
|
// Ralph FYI : The code which returned the pointer was fine on your side
|
|
// but somewhere before it got to the find dll the value was
|
|
// getting zapped to 00000000(at least in NT). So I changed
|
|
// call to return the pointer in the pointer sent in the lParam
|
|
|
|
PCSTR *ptr = (PCSTR *)lParam; // Pointer to a PCSTR in lParam
|
|
*ptr = FtsIndexToTitle((int) wParam); // Map and return result
|
|
}
|
|
break;
|
|
|
|
case MSG_REINDEX_REQUEST:
|
|
{
|
|
// We're in big trouble if we get this message when Find
|
|
// isn't the current tab
|
|
|
|
ASSERT(hwndTabSub == hwndFindTab);
|
|
|
|
HWND hwnd = CreateFindTab(hwndDlg, FTS_RE_INDEX);
|
|
if (pRegAnimate) {
|
|
pRegAnimate(NULL, NULL);
|
|
StopAnimation();
|
|
}
|
|
if (!hwnd) {
|
|
hwnd = CreateFindTab(hwndDlg, FTS_NORMAL_INDEX);
|
|
if (!hwnd) {
|
|
Error(wERRS_BAD_FIND_TAB, wERRA_RETURN);
|
|
ClosePropertySheet(hwndDlg, 0);
|
|
}
|
|
}
|
|
hwndTabSub = hwndFindTab;
|
|
}
|
|
break;
|
|
|
|
case MSG_FTS_WHERE_IS_IT:
|
|
ASSERT(lParam != NULL); // Don't call me without a pointer
|
|
{
|
|
char szOldName[MAX_PATH];
|
|
FM fmWhereTheHeckIsIt;
|
|
GetFmParts((PSTR) lParam, szOldName, PARTBASE | PARTEXT);
|
|
fmWhereTheHeckIsIt = FmNewExistSzDir(szOldName,
|
|
(wParam? 0 : DIR_ENUMERATE)
|
|
| DIR_CUR_HELP | DIR_SILENT_INI | DIR_CURRENT | DIR_PATH | DIR_SILENT_REG);
|
|
if (fmWhereTheHeckIsIt) {
|
|
strcpy((PSTR) lParam, fmWhereTheHeckIsIt);
|
|
DisposeFm(fmWhereTheHeckIsIt);
|
|
}
|
|
else
|
|
strcpy((PSTR) lParam, txtZeroLength);
|
|
}
|
|
break;
|
|
|
|
case MSG_GET_DEFFONT:
|
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, (LONG) hfontDefault);
|
|
return TRUE;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: CreateTabChild
|
|
|
|
PURPOSE: Used to create a tab child dialog box
|
|
|
|
PARAMETERS:
|
|
idCurTab
|
|
hwndDlg
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
09-Aug-1993 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
HWND STDCALL CreateTabChild(TAB_ID idCurTab, HWND hwndDlg)
|
|
{
|
|
HWND hwnd;
|
|
EnableWindow(GetDlgItem(hwndDlg, IDC_PRINT), FALSE);
|
|
|
|
if (idCurTab == TAB_CONTENTS)
|
|
hwnd = pSrchClass->doModeless(hwndDlg,
|
|
IDD_TAB_CONTENTS, (FARPROC) ContentsDlg);
|
|
else if (idCurTab == TAB_INDEX)
|
|
hwnd = pSrchClass->doModeless(hwndDlg,
|
|
IDD_TAB_INDEX, (FARPROC) IndexDlg);
|
|
else if (idCurTab == TAB_FIND) {
|
|
hwnd = CreateFindTab(hwndDlg, FTS_NORMAL_INDEX);
|
|
if (pRegAnimate) {
|
|
pRegAnimate(NULL, NULL);
|
|
StopAnimation();
|
|
}
|
|
if (!hwnd)
|
|
Error(wERRS_BAD_FIND_TAB, wERRA_RETURN);
|
|
else if (hwnd == (HWND) -1) // means the user cancelled the Find wizard
|
|
hwnd = NULL;
|
|
}
|
|
else {
|
|
if (!aTabs[idCurTab - TAB_FIND].pOpenTabDialog)
|
|
return NULL;
|
|
hwnd = aTabs[idCurTab - TAB_FIND].pOpenTabDialog(
|
|
hwndDlg, 0, 0);
|
|
|
|
if (hwnd) {
|
|
DWORD style = GetWindowLong(hwnd, GWL_STYLE);
|
|
style &= ~(DS_MODALFRAME | WS_BORDER | WS_THICKFRAME | WS_DLGFRAME);
|
|
style |= DS_3DLOOK;
|
|
|
|
SetWindowLong(hwnd, GWL_STYLE, style);
|
|
|
|
CheckDialogSize(hwndDlg, hwnd);
|
|
|
|
// Force the dialog box on top and display it
|
|
|
|
SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
|
|
SWP_NOMOVE | SWP_NOSIZE);
|
|
}
|
|
}
|
|
|
|
// REVIEW: we need to position the dialog box
|
|
|
|
return hwnd;
|
|
}
|
|
|
|
BOOL STDCALL InitTabControl(HWND hwndDlg)
|
|
{
|
|
HWND hwndTabs = GetDlgItem(hwndDlg, ID_TABCONTROL);
|
|
ASSERT(hwndTabs);
|
|
int i;
|
|
|
|
TC_ITEM ti;
|
|
ZeroMemory(&ti, sizeof(TC_ITEM));
|
|
ZeroMemory(aTabIds, sizeof(aTabIds));
|
|
|
|
ti.mask = TCIF_TEXT;
|
|
|
|
#ifdef _DEBUG
|
|
ShowCntFlags();
|
|
#endif
|
|
|
|
if (cntFlags.flags & GID_CONTENTS)
|
|
AddTab(&ti, TAB_CONTENTS, GetStringResource(sidCONTENTS), hwndTabs);
|
|
else if (cntFlags.idOldTab == TAB_CONTENTS)
|
|
cntFlags.idOldTab++;
|
|
|
|
// Add the index tab
|
|
|
|
if (!(cntFlags.flags & GID_NO_INDEX))
|
|
AddTab(&ti, TAB_INDEX, GetStringResource(sidINDEX), hwndTabs);
|
|
else if (cntFlags.idOldTab == TAB_INDEX)
|
|
cntFlags.idOldTab++;
|
|
|
|
if (cntFlags.flags & GID_FTS) {
|
|
|
|
/*
|
|
* Find out if the ftsrch dll exists. If it exists, we'll assume
|
|
* (perhaps mistakenly) that we can load it. We won't really try
|
|
* to load it until the user clicks the Find tab.
|
|
*/
|
|
|
|
if (IsSearchAvailable()) {
|
|
|
|
/*
|
|
* If our first tab is the Find tab, then we MUST be certain
|
|
* that we can actually load the ftsrch.dll. We default to the
|
|
* first tab whenever we fail to create a tab, so the first
|
|
* tab MUST be usable.
|
|
*/
|
|
|
|
if (!pSrchClass->cTabs) {
|
|
if (!LoadSearchDll())
|
|
goto NoFindTab;
|
|
}
|
|
AddTab(&ti, TAB_FIND, GetStringResource(sidFIND), hwndTabs);
|
|
}
|
|
}
|
|
else if (cntFlags.idOldTab == TAB_FIND)
|
|
cntFlags.idOldTab++;
|
|
|
|
NoFindTab:
|
|
for (i = 1; i <= MAX_TABS; i++) {
|
|
if (aTabs[i].pszName) {
|
|
AddTab(&ti, (TAB_ID) (TAB_1 + (i - 1)), aTabs[i].pszName, hwndTabs);
|
|
}
|
|
}
|
|
|
|
if (!pSrchClass->cTabs)
|
|
return FALSE;
|
|
|
|
char szBuf[256];
|
|
LoadString(hInsNow, sidFinderTitle, szBuf, sizeof(szBuf));
|
|
|
|
QDE qde = (QDE) QdeFromGh(HdeGetEnv());
|
|
if (pszHelpTitle)
|
|
lstrcat(szBuf, pszHelpTitle);
|
|
else if ((QDE_RGCHTITLE(qde)[0] != '\0'))
|
|
lstrcat(szBuf, (LPSTR) QDE_RGCHTITLE(qde));
|
|
else
|
|
GetFmParts(QDE_FM(qde), szBuf + lstrlen(szBuf), PARTBASE | PARTEXT);
|
|
|
|
SetWindowText(hwndDlg, szBuf);
|
|
if (cntFlags.idOldTab > cntFlags.cTabs + 2) {
|
|
cntFlags.idOldTab = (cntFlags.flags & GID_CONTENTS) ? TAB_CONTENTS :
|
|
(!(cntFlags.flags & GID_NO_INDEX)) ? TAB_INDEX : TAB_FIND;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
TAB_ID idOld = (TAB_ID) cntFlags.idOldTab;
|
|
#endif
|
|
|
|
TabCtrl_SetCurSel(GetDlgItem(hwndDlg, ID_TABCONTROL),
|
|
GetTabPosition(cntFlags.idOldTab));
|
|
hwndTabSub = CreateTabChild((TAB_ID) cntFlags.idOldTab, hwndDlg);
|
|
if (!hwndTabSub && aTabIds[0] != cntFlags.idOldTab) {
|
|
hwndTabSub = CreateTabChild(aTabIds[0], hwndDlg);
|
|
TabCtrl_SetCurSel(GetDlgItem(hwndDlg, ID_TABCONTROL), 0);
|
|
cntFlags.idOldTab = aTabIds[0];
|
|
}
|
|
|
|
// REVIEW: Contents dialog could fail if the contents file
|
|
// could not be read (sharing violation?). We should do
|
|
// something intelligent in that case.
|
|
|
|
return (BOOL) hwndTabSub;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: FreeLocalStrings
|
|
|
|
PURPOSE: Free up some localally allocated strings
|
|
|
|
PARAMETERS:
|
|
void
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
26-Dec-1993 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
static void STDCALL FreeLocalStrings(void)
|
|
{
|
|
if (pszHelpTitle)
|
|
lcClearFree(&pszHelpTitle);
|
|
|
|
if (pszHelpBase)
|
|
lcClearFree(&pszHelpBase);
|
|
|
|
if (pszGidFile)
|
|
lcClearFree(&pszGidFile);
|
|
|
|
if (pszCntFile)
|
|
lcClearFree(&pszCntFile);
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: CreateFindTab
|
|
|
|
PURPOSE:
|
|
|
|
PARAMETERS:
|
|
hwndDlg
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
17-Jul-1994 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
#ifndef NO_PRAGMAS
|
|
#pragma data_seg(".text", "CODE")
|
|
#endif
|
|
static const char txtNewSearcher[] = "NewSearcher";
|
|
static const char txtDeleteSearcher[] = "DeleteSearcher";
|
|
static const char txtOpenIndex[] = "OpenIndex";
|
|
static const char txtSaveGroup[] = "SaveGroup";
|
|
static const char txtLoadGroup[] = "LoadGroup";
|
|
static const char txtIsValidIndex[] = "IsValidIndex";
|
|
static const char txtDiscardIndex[] = "DiscardIndex";
|
|
static const char txtSetDirectoryLocator[] = "SetDirectoryLocator";
|
|
static const char txtRegisterAnimator[] = "RegisterAnimator";
|
|
|
|
#ifdef _HILIGHT
|
|
static const char txtNewHiliter[] = "NewHiliter";
|
|
static const char txtDeleteHiliter[] = "DeleteHiliter";
|
|
static const char txtScanDisplayText[] = "ScanDisplayText";
|
|
static const char txtClearDisplayText[] = "ClearDisplayText";
|
|
static const char txtCountHilites[] = "CountHilites";
|
|
static const char txtQueryHilites[] = "QueryHilites";
|
|
#endif
|
|
#ifndef NO_PRAGMAS
|
|
#pragma data_seg()
|
|
#endif
|
|
|
|
// Some error codes we may get from FTSrch
|
|
|
|
#define OUT_OF_MEMORY ((UINT) -6)
|
|
#define OUT_OF_DISK ((UINT) -20)
|
|
|
|
HWND STDCALL CreateFindTab(HWND hwndParentDlg, UINT fsIndex)
|
|
{
|
|
BOOL fAsked = FALSE;
|
|
CWaitCursor cwait;
|
|
CEnable disableCancel(GetDlgItem(hwndParentDlg, IDCANCEL));
|
|
CEnable disableDisplay(GetDlgItem(hwndParentDlg, IDOK));
|
|
CEnable disableTab(GetDlgItem(hwndParentDlg, ID_TABCONTROL));
|
|
|
|
if (fsIndex != FTS_NORMAL_INDEX && hsrch) {
|
|
RemoveHiliter(&hhiliter);
|
|
|
|
pDeleteSearcher(hsrch);
|
|
hsrch = 0;
|
|
}
|
|
#ifdef _PRIVATE
|
|
CTimeReport report("Find startup time:");
|
|
#endif
|
|
|
|
StartAllOver:
|
|
if (!hsrch) {
|
|
if (!pNewSearcher) {
|
|
if (!LoadSearchDll()) {
|
|
|
|
// Can't use GetStringResource because ReportMissingDll does
|
|
|
|
char szDll[MAX_PATH];
|
|
GetStringResource2(sidFtsDll, szDll);
|
|
ReportMissingDll(szDll);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
ASSERT(pNewSearcher && pDeleteSearcher && pOpenIndex && pOpenTabDialog && pSetDirectoryLocator);
|
|
#ifdef _HILIGHT
|
|
ASSERT(pNewHiliter && pDeleteHiliter && pScanDisplayText && pClearDisplayText
|
|
&& pCountHilites && pQueryHilites
|
|
);
|
|
#endif
|
|
|
|
pSetDirectoryLocator(hwndParentDlg);
|
|
|
|
hsrch = pNewSearcher();
|
|
if (!hsrch)
|
|
return NULL;
|
|
|
|
if (fsIndex == FTS_RE_INDEX) {
|
|
if (!AskAboutIndexes(hwndParentDlg))
|
|
return NULL;
|
|
hsrch = pNewSearcher();
|
|
if (!hsrch)
|
|
return NULL;
|
|
}
|
|
|
|
char szGroupFile[MAX_PATH];
|
|
lstrcpy(szGroupFile, pszGidFile);
|
|
ChangeExtension(szGroupFile, txtGrpExtension);
|
|
|
|
if (hwndAnimate || StartAnimation(sidLoadingFTS))
|
|
pRegAnimate(NextAnimation, hwndAnimate);
|
|
SetForegroundWindow(hwndAnimate); // make certain animation is on top
|
|
|
|
if (pTblFiles->CountStrings() > 2) { // do we have a group?
|
|
FM fmGrp = FmNewExistSzDir(szGroupFile,
|
|
DIR_CUR_HELP | DIR_SILENT_INI | DIR_CURRENT | DIR_PATH | DIR_SILENT_REG);
|
|
if (fmGrp) {
|
|
if (fsIndex != FTS_NORMAL_INDEX)
|
|
DeleteFile(fmGrp);
|
|
else
|
|
{
|
|
ERRORCODE ec;
|
|
|
|
ec= pLoadGroup(hsrch, fmGrp);
|
|
|
|
if (ec >= 0)
|
|
{
|
|
RemoveFM(&fmGrp);
|
|
pRegAnimate(NULL, NULL);
|
|
goto RocknRoll; // we've got everything we need
|
|
}
|
|
|
|
if (ec == OUT_OF_MEMORY || ec == OUT_OF_DISK)
|
|
{
|
|
RemoveFM(&fmGrp);
|
|
RemoveHiliter(&hhiliter);
|
|
pRegAnimate(NULL, NULL);
|
|
StopAnimation();
|
|
pDeleteSearcher(hsrch);
|
|
hsrch = NULL;
|
|
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
DeleteFile(fmGrp); // bad group
|
|
RemoveFM(&fmGrp);
|
|
}
|
|
}
|
|
|
|
BOOL fOpenIndexFailure = FALSE;
|
|
BOOL fSeenOneIndex = FALSE;
|
|
|
|
for (int index = 2; index <= pTblFiles->CountStrings(); index += 2) {
|
|
BYTE type = pFileInfo[index / 2 - 1].filetype;
|
|
char szName[MAX_PATH];
|
|
#ifdef _DEBUG // copy it early
|
|
lstrcpy(szName, pTblFiles->GetPointer(index));
|
|
#endif
|
|
if (type & (CHFLAG_MISSING | CHFLAG_LINK | CHFLAG_FTS_ASKED))
|
|
continue;
|
|
|
|
lstrcpy(szName, pTblFiles->GetPointer(index));
|
|
ChangeExtension(szName, txtFtsExtension);
|
|
|
|
CFM fm(szName,
|
|
DIR_CUR_HELP | DIR_SILENT_INI | DIR_CURRENT | DIR_PATH | DIR_SILENT_REG);
|
|
|
|
// This will also fail if we run out of memory
|
|
|
|
if (!fm.fm) {
|
|
|
|
/*
|
|
* At this point, we're either out of memory (unlikely),
|
|
* or we have a .HLP file without a matching .FTS file and we
|
|
* have NOT asked the user if they want it. At this point, we
|
|
* should bail out, put up a dialog box asking for permission
|
|
* to generate a .FTS file for ALL missing ones, and when
|
|
* completed, restart this for() loop.
|
|
*/
|
|
|
|
pRegAnimate(NULL, NULL);
|
|
goto CreateOrDie;
|
|
}
|
|
else if (!(type & CHFLAG_FTS_AVAIL)) {
|
|
pFileInfo[index / 2 - 1].filetype |= CHFLAG_FTS_AVAIL;
|
|
fDirtyInfo = TRUE; // we need to update the .GID file
|
|
}
|
|
|
|
int idIndex;
|
|
DWORD time1, time2;
|
|
|
|
time1 = pFileInfo[index / 2 - 1].timestamp;
|
|
time2 = 0;
|
|
|
|
if (!time1)
|
|
{
|
|
WIN32_FIND_DATA fd;
|
|
HANDLE hfd;
|
|
|
|
if ((hfd = FindFirstFile(pTblFiles->GetPointer(index), &fd)) ==
|
|
INVALID_HANDLE_VALUE)
|
|
pFileInfo[index / 2 - 1].filetype |= CHFLAG_MISSING;
|
|
else
|
|
{
|
|
AdjustForTimeZoneBias(&fd.ftLastWriteTime.dwLowDateTime);
|
|
|
|
time1= pFileInfo[index / 2 - 1].timestamp = fd.ftLastWriteTime.dwLowDateTime;
|
|
FindClose(hfd);
|
|
}
|
|
}
|
|
|
|
idIndex = pOpenIndex(hsrch, PszFromGh(fm.fm), NULL, NULL,
|
|
&time1, &time2);
|
|
|
|
if (idIndex == OUT_OF_MEMORY || idIndex == OUT_OF_DISK)
|
|
{
|
|
RemoveHiliter(&hhiliter);
|
|
pRegAnimate(NULL, NULL);
|
|
StopAnimation();
|
|
pDeleteSearcher(hsrch);
|
|
hsrch = NULL;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
if (idIndex < 0)
|
|
{
|
|
|
|
/*
|
|
* Either an error occurred (the fts file is invalid) or
|
|
* the time/date stamp for the fts file doesn't match the
|
|
* help file. Delete the fts file and force a rebuild.
|
|
*/
|
|
|
|
fOpenIndexFailure = TRUE;
|
|
if (idIndex >= 0)
|
|
pDiscardIndex(hsrch, idIndex);
|
|
if (!DeleteFile(PszFromGh(fm.fm))) {
|
|
|
|
// BUGBUG: We can't regenerate -- need an error message
|
|
|
|
pFileInfo[index / 2 - 1].filetype &= ~CHFLAG_FTS_AVAIL;
|
|
pFileInfo[index / 2 - 1].filetype |= CHFLAG_BAD_RO_FTS;
|
|
}
|
|
else
|
|
fOpenIndexFailure = TRUE;
|
|
continue;
|
|
}
|
|
SetFileIndex(index / 2 - 1, idIndex);
|
|
ASSERT(GetFileIndex(index / 2 - 1) == idIndex);
|
|
|
|
if (pTblFiles->CountStrings() > 2)
|
|
fDirtyInfo = TRUE;
|
|
fSeenOneIndex = TRUE;
|
|
pRegAnimate(NULL, NULL);
|
|
}
|
|
|
|
pRegAnimate(NULL, NULL);
|
|
|
|
/*
|
|
* If we haven't added a single index, then create one now or
|
|
* return a failure.
|
|
*/
|
|
|
|
if (!fSeenOneIndex) {
|
|
CreateOrDie:
|
|
if (!fAsked) {
|
|
if (!AskAboutIndexes(hwndParentDlg)) {
|
|
|
|
// Failure means the user cancelled
|
|
|
|
RemoveHiliter(&hhiliter);
|
|
|
|
pDeleteSearcher(hsrch);
|
|
hsrch = NULL;
|
|
|
|
return (HWND) -1; // special value to indicate cancelation
|
|
}
|
|
fAsked = TRUE;
|
|
ASSERT(!hsrch);
|
|
goto StartAllOver;
|
|
}
|
|
else {
|
|
RemoveHiliter(&hhiliter);
|
|
|
|
pDeleteSearcher(hsrch);
|
|
hsrch = NULL;
|
|
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (fOpenIndexFailure) {
|
|
|
|
/*
|
|
* One or more of the index files are invalid and have been
|
|
* deleted. We must regenerate the missing ones.
|
|
*/
|
|
|
|
RemoveHiliter(&hhiliter);
|
|
|
|
pDeleteSearcher(hsrch);
|
|
hsrch = NULL;
|
|
if (!fAsked && AskAboutIndexes(hwndParentDlg)) {
|
|
fAsked = TRUE;
|
|
ASSERT(!hsrch);
|
|
goto StartAllOver;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
if (pTblFiles->CountStrings() > 2)
|
|
pSaveGroup(hsrch, szGroupFile);
|
|
|
|
pSetDirectoryLocator(NULL);
|
|
}
|
|
|
|
RocknRoll:
|
|
|
|
// if (fsIndex == FTS_RE_INDEX) {
|
|
// return hwndFindTab;
|
|
// }
|
|
if (fsIndex == FTS_BUILD_DEFAULT) {
|
|
return (HWND) 1;
|
|
}
|
|
|
|
if (hsrch) {
|
|
hwndFindTab = pOpenTabDialog(hwndParentDlg, (DWORD) hsrch, 0);
|
|
if (hwndFindTab) {
|
|
|
|
#ifdef _HILIGHT
|
|
GetHiliter();
|
|
#endif
|
|
|
|
// REVIEW: not necessary for build 163 and beyond
|
|
|
|
SetWindowLong(hwndFindTab, GWL_STYLE,
|
|
GetWindowLong(hwndFindTab, GWL_STYLE) | DS_3DLOOK);
|
|
ChangeDlgFont(hwndFindTab);
|
|
|
|
CheckDialogSize(hwndParentDlg, hwndFindTab);
|
|
|
|
// Force the dialog box on top and display it
|
|
|
|
SetWindowPos(hwndFindTab, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW |
|
|
SWP_NOMOVE | SWP_NOSIZE);
|
|
}
|
|
else {
|
|
RemoveHiliter(&hhiliter);
|
|
|
|
pDeleteSearcher(hsrch);
|
|
hsrch = 0;
|
|
}
|
|
|
|
StopAnimation();
|
|
return hwndFindTab;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef _HILIGHT
|
|
HHILITER GetHiliter()
|
|
{
|
|
if (hhiliter)
|
|
return hhiliter;
|
|
|
|
ASSERT(pNewHiliter);
|
|
|
|
if (hsrch)
|
|
hhiliter = pNewHiliter(hsrch);
|
|
|
|
return hhiliter;
|
|
}
|
|
|
|
static void STDCALL RemoveHiliter(HHILITER* phhiliter)
|
|
{
|
|
ASSERT(phhiliter);
|
|
if (*phhiliter) {
|
|
pDeleteHiliter(*phhiliter);
|
|
*phhiliter = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: LoadSearchDll
|
|
|
|
PURPOSE: Load full-text search dll
|
|
|
|
PARAMETERS:
|
|
void
|
|
|
|
RETURNS: TRUE if dll found and all function addresses obtained
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
17-Jul-1994 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
BOOL STDCALL LoadSearchDll(void)
|
|
{
|
|
if (!pNewSearcher) {
|
|
HINSTANCE hmodule;
|
|
if ((hmodule = (HINSTANCE) HFindDLL(GetStringResource(sidFtsDll), TRUE))) {
|
|
pNewSearcher =
|
|
(NEWSEARCHER) GetProcAddress(hmodule, txtNewSearcher);
|
|
pDeleteSearcher =
|
|
(DELETESEARCHER) GetProcAddress(hmodule, txtDeleteSearcher);
|
|
pOpenIndex =
|
|
(OPENINDEX) GetProcAddress(hmodule, txtOpenIndex);
|
|
pOpenTabDialog =
|
|
(OPENTABDIALOG) GetProcAddress(hmodule, txtOpenTabDialog);
|
|
pSaveGroup =
|
|
(SAVEGROUP) GetProcAddress(hmodule, txtSaveGroup);
|
|
pLoadGroup =
|
|
(LOADGROUP) GetProcAddress(hmodule, txtLoadGroup);
|
|
pIsValidIndex =
|
|
(ISVALIDINDEX) GetProcAddress(hmodule, txtIsValidIndex);
|
|
pDiscardIndex =
|
|
(DISCARDINDEX) GetProcAddress(hmodule, txtDiscardIndex);
|
|
pSetDirectoryLocator =
|
|
(SETDIRECTORYLOCATOR) GetProcAddress(hmodule, txtSetDirectoryLocator);
|
|
pRegAnimate =
|
|
(REGISTERANIMATOR) GetProcAddress(hmodule, txtRegisterAnimator);
|
|
#ifdef _HILIGHT
|
|
pNewHiliter =
|
|
(NEWHILITER) GetProcAddress(hmodule, txtNewHiliter);
|
|
pDeleteHiliter =
|
|
(DELETEHILITER) GetProcAddress(hmodule, txtDeleteHiliter);
|
|
pScanDisplayText =
|
|
(SCANDISPLAYTEXT) GetProcAddress(hmodule, txtScanDisplayText);
|
|
pClearDisplayText =
|
|
(CLEARDISPLAYTEXT) GetProcAddress(hmodule, txtClearDisplayText);
|
|
pCountHilites =
|
|
(COUNTHILITES) GetProcAddress(hmodule, txtCountHilites);
|
|
pQueryHilites =
|
|
(QUERYHILITES) GetProcAddress(hmodule, txtQueryHilites);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
ASSERT(pNewHiliter);
|
|
ASSERT(pDeleteHiliter);
|
|
ASSERT(pScanDisplayText);
|
|
ASSERT(pClearDisplayText);
|
|
ASSERT(pCountHilites);
|
|
ASSERT(pQueryHilites);
|
|
|
|
if (!pNewSearcher || !pDeleteSearcher || !pOpenIndex || !pOpenTabDialog
|
|
|| !pSaveGroup || !pLoadGroup || !pIsValidIndex || !pSetDirectoryLocator
|
|
#ifdef _HILIGHT
|
|
|
|
|| !pNewHiliter || !pDeleteHiliter || !pScanDisplayText
|
|
|| !pClearDisplayText || !pCountHilites || !pQueryHilites
|
|
#endif
|
|
)
|
|
return FALSE; // either no dll, or its a corrupted one
|
|
return TRUE;
|
|
}
|
|
|
|
const int DLG_LEFT_INDENT = 10;
|
|
const int DLG_TOP_INDENT = 30;
|
|
|
|
static void STDCALL CheckDialogSize(HWND hwndPropSheet, HWND hwndTab)
|
|
{
|
|
if (!hwndTab)
|
|
return;
|
|
|
|
RECT rcTabChild, rcPropSheet;
|
|
GetWindowRect(hwndTab, &rcTabChild);
|
|
GetWindowRect(GetDlgItem(hwndPropSheet, ID_TABCONTROL), &rcPropSheet);
|
|
|
|
int padWidth;
|
|
int padHeight;
|
|
if (RECT_WIDTH(rcTabChild) + (DLG_LEFT_INDENT * 2) >
|
|
RECT_WIDTH(rcPropSheet))
|
|
padWidth = (RECT_WIDTH(rcTabChild) + (DLG_LEFT_INDENT * 2)) -
|
|
RECT_WIDTH(rcPropSheet);
|
|
else
|
|
padWidth = 0;
|
|
|
|
if (RECT_HEIGHT(rcTabChild) + DLG_TOP_INDENT + DLG_LEFT_INDENT >
|
|
RECT_HEIGHT(rcPropSheet))
|
|
padHeight = (RECT_HEIGHT(rcTabChild) + DLG_TOP_INDENT +
|
|
DLG_LEFT_INDENT) - RECT_HEIGHT(rcPropSheet);
|
|
else
|
|
padHeight = 0;
|
|
|
|
if (padWidth || padHeight) {
|
|
WRECT rcParent;
|
|
RECT rcDisplay, rcPrint, rcCancel;
|
|
|
|
GetWindowWRect(hwndPropSheet, &rcParent);
|
|
GetWindowRect(GetDlgItem(hwndPropSheet, IDOK), &rcDisplay);
|
|
GetWindowRect(GetDlgItem(hwndPropSheet, IDC_PRINT), &rcPrint);
|
|
GetWindowRect(GetDlgItem(hwndPropSheet, IDCANCEL), &rcCancel);
|
|
|
|
rcParent.cx += padWidth;
|
|
rcPropSheet.right += padWidth;
|
|
|
|
rcParent.cy += padHeight;
|
|
rcPropSheet.bottom += padHeight;
|
|
|
|
OffsetRect(&rcDisplay, padWidth, padHeight);
|
|
OffsetRect(&rcPrint, padWidth, padHeight);
|
|
OffsetRect(&rcCancel, padWidth, padHeight);
|
|
|
|
CheckWindowPosition(&rcParent, FALSE);
|
|
MoveClientWindow(hwndPropSheet, GetDlgItem(hwndPropSheet, ID_TABCONTROL),
|
|
&rcPropSheet, FALSE);
|
|
MoveClientWindow(hwndPropSheet, GetDlgItem(hwndPropSheet, IDOK),
|
|
&rcDisplay, FALSE);
|
|
MoveClientWindow(hwndPropSheet, GetDlgItem(hwndPropSheet, IDC_PRINT),
|
|
&rcPrint, FALSE);
|
|
MoveClientWindow(hwndPropSheet, GetDlgItem(hwndPropSheet, IDCANCEL),
|
|
&rcCancel, FALSE);
|
|
MoveWindow(hwndPropSheet, rcParent.left, rcParent.top,
|
|
rcParent.cx, rcParent.cy, TRUE);
|
|
|
|
GetWindowRect(hwndTab, &rcTabChild);
|
|
GetWindowRect(GetDlgItem(hwndPropSheet, ID_TABCONTROL), &rcPropSheet);
|
|
|
|
InvalidateRect(hwndPropSheet, NULL, TRUE);
|
|
}
|
|
|
|
// BUGBUG: top setting must be determined from the tab
|
|
|
|
OffsetRect(&rcTabChild, (rcPropSheet.left - rcTabChild.left) + 10,
|
|
(rcPropSheet.top - rcTabChild.top) + 30);
|
|
MoveClientWindow(hwndPropSheet, hwndTab, &rcTabChild, FALSE);
|
|
}
|
|
|
|
static void STDCALL ClosePropertySheet(HWND hwndPropDlg, int result)
|
|
{
|
|
if (IsValidWindow(hwndTabSub)) {
|
|
if (hwndTabSub == hwndFindTab)
|
|
SendMessage(hwndTabSub, WM_CLOSE, 0, 0);
|
|
else {
|
|
ASSERT(IsValidWindow(hwndTabSub));
|
|
DestroyWindow(hwndTabSub);
|
|
}
|
|
}
|
|
hwndTabSub = NULL;
|
|
pSrchClass->result = result;
|
|
pSrchClass->fMsgLoop = FALSE;
|
|
EnableWindows();
|
|
if (IsValidWindow(hwndPropDlg))
|
|
DestroyWindow(hwndPropDlg);
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: ChangeDlgFont
|
|
|
|
PURPOSE: Change all dialog controls to use a small font -- same
|
|
font as is used in navigation button. Not necessary for
|
|
Chicago build 162 and on, but recommended for NT.
|
|
|
|
PARAMETERS:
|
|
hwndDlg
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
22-Jul-1994 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
class CBroadCastChildren
|
|
{
|
|
public:
|
|
|
|
CBroadCastChildren(HWND hwnd, UINT msgOrg, WPARAM wParamOrg = 0,
|
|
LPARAM lParamOrg = 0);
|
|
|
|
UINT msg;
|
|
WPARAM wParam;
|
|
LPARAM lParam;
|
|
};
|
|
|
|
extern "C" void STDCALL ChangeDlgFont(HWND hwndDlg)
|
|
{
|
|
ASSERT(hfontSmallSys);
|
|
if (!fIsThisNewShell4)
|
|
CBroadCastChildren foo(hwndDlg, WM_SETFONT, (WPARAM) hfontSmallSys, FALSE);
|
|
SetFocus(hwndDlg);
|
|
}
|
|
|
|
static BOOL __stdcall EnumChildProc(HWND hwnd, LPARAM lval);
|
|
|
|
CBroadCastChildren::CBroadCastChildren(HWND hwnd, UINT msgOrg,
|
|
WPARAM wParamOrg, LPARAM lParamOrg)
|
|
{
|
|
msg = msgOrg;
|
|
wParam = wParamOrg;
|
|
lParam = lParamOrg;
|
|
|
|
EnumChildWindows(hwnd, (WNDENUMPROC) EnumChildProc, (LPARAM) (PSTR) this);
|
|
}
|
|
|
|
#define pchild ((CBroadCastChildren *) lval)
|
|
|
|
static BOOL __stdcall EnumChildProc(HWND hwnd, LPARAM lval)
|
|
{
|
|
SendMessage(hwnd, pchild->msg, pchild->wParam, pchild->lParam);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: ReportMissingDll
|
|
|
|
PURPOSE: Complain about a missing dll only if we haven't complained
|
|
about it before.
|
|
|
|
PARAMETERS:
|
|
pszDllName
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
23-Jul-1994 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
extern "C" void STDCALL ReportMissingDll(PCSTR pszDllName)
|
|
{
|
|
static CTable* ptblMissing;
|
|
|
|
if (!ptblMissing)
|
|
ptblMissing = new CTable;
|
|
|
|
if (ptblMissing->IsStringInTable(pszDllName) ||
|
|
FIsSearchModule(pszDllName))
|
|
return;
|
|
|
|
ptblMissing->AddString(pszDllName);
|
|
char szBuf[MAX_PATH * 2];
|
|
char szDirectory[MAX_PATH];
|
|
GetSystemDirectory(szDirectory, sizeof(szDirectory));
|
|
wsprintf(szBuf, GetStringResource(wERRS_MISSING_DLL), pszDllName, szDirectory);
|
|
ErrorQch(szBuf);
|
|
}
|
|
|
|
static CTable* ptblFm;
|
|
|
|
extern "C" int STDCALL GetFmIndex(FM fm)
|
|
{
|
|
int pos;
|
|
|
|
if (!ptblFm)
|
|
ptblFm = new CTable;
|
|
|
|
pos = ptblFm->IsStringInTable((PCSTR) fm);
|
|
if (!pos)
|
|
pos = ptblFm->AddString((PCSTR) fm);
|
|
return pos;
|
|
}
|
|
|
|
extern "C" FM STDCALL GetFmPtr(int pos)
|
|
{
|
|
ASSERT(ptblFm);
|
|
|
|
return (FM) ptblFm->GetPointer(pos);
|
|
}
|
|
|
|
#ifndef NO_PRAGMAS
|
|
#pragma data_seg(".text", "CODE")
|
|
#endif
|
|
const char txtKeyMacros[] = "|MACROS";
|
|
#ifndef NO_PRAGMAS
|
|
#pragma data_seg()
|
|
#endif
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: RcGetLAFromHss
|
|
|
|
PURPOSE: Retrieve the i-th search hit from the given list. The first
|
|
hit in the list is numbered zero.
|
|
PARAMETERS:
|
|
hss -- search set
|
|
qde -- help file
|
|
iss -- hit index
|
|
qla -- destination la
|
|
pszKeyword -- keyword
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
Only works for help files -- cannot be used with a .gid file
|
|
|
|
MODIFICATION DATES:
|
|
02-Jun-1995 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
extern "C" RC STDCALL RcGetLAFromHss(HSS hss, QDE qde, ISS iss, QLA qla, PCSTR pszKeyword)
|
|
{
|
|
QSS qss;
|
|
|
|
if (hss == NULL) {
|
|
SetSearchErrorRc(rcBadHandle);
|
|
return rcBadHandle;
|
|
}
|
|
|
|
if (!IsEmptyString(pszKeyword) &&
|
|
FindKeywordMacro(pszKeyword, (HDE) qde) == rcMacroIndex)
|
|
return rcMacroIndex;
|
|
|
|
qss = (QSS) PtrFromGh(hss);
|
|
|
|
CbReadMemQLA(qla, (QB)((QSSREC)&qss->ssrecFirst + iss),
|
|
QDE_HHDR(qde).wVersionNo);
|
|
|
|
SetSearchErrorRc(rcSuccess);
|
|
return rcSuccess;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: RcGetLAFromGid
|
|
|
|
PURPOSE: Look up the address of a topic from a .GID index
|
|
|
|
PARAMETERS:
|
|
qde -- help file containing search hit
|
|
iss -- index of hit
|
|
qla -- destination for address
|
|
pszKeyword -- actual keyword
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
02-Jun-1995 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
extern "C" RC STDCALL RcGetLAFromGid(QDE qde, ISS iss, QLA qla,
|
|
PCSTR pszKeyword)
|
|
{
|
|
ASSERT(iss >= 0);
|
|
if (qde->hss == NULL) {
|
|
SetSearchErrorRc(rcBadHandle);
|
|
return rcBadHandle;
|
|
}
|
|
MASTER_TITLE_RECORD mtr;
|
|
MASTER_RECKW* prec = HssToReckw(qde->hss);
|
|
|
|
// We copy the structure because qde may go away and take qde-hss with
|
|
// it.
|
|
|
|
CopyMemory(&mtr, &prec->mtr[iss], sizeof(MASTER_TITLE_RECORD));
|
|
|
|
#ifdef _DEBUG
|
|
// for debugging purposes
|
|
|
|
PSTR pszFile = pTblFiles->GetPointer(mtr.idHelpFile);
|
|
#endif
|
|
|
|
FM fm = FmNew(pTblFiles->GetPointer(mtr.idHelpFile));
|
|
if (!fm)
|
|
return rcBadHandle;
|
|
if (FSameFile((HDE) qde, fm))
|
|
RemoveFM(&fm);
|
|
else {
|
|
fDelayShow = TRUE;
|
|
if (!FReplaceHde(txtMain, &fm, NULL)) {
|
|
RemoveFM(&fm);
|
|
return rcBadHandle;
|
|
}
|
|
}
|
|
ASSERT(!fm);
|
|
#ifdef _DEBUG
|
|
QDE qdeDebug = (QDE) PtrFromGh(HdeGetEnv());
|
|
#endif
|
|
|
|
// REVIEW: keyword macros use -1 as the address I believe, so we should
|
|
// be able to ignore this check if mtr.addr != -1
|
|
|
|
if (mtr.addr == -1 && !IsEmptyString(pszKeyword) &&
|
|
FindKeywordMacro(pszKeyword,
|
|
HdeGetEnv()) == rcMacroIndex)
|
|
return rcMacroIndex;
|
|
|
|
CbReadMemQLA(qla, (QB) &mtr.addr,
|
|
QDE_HHDR((QDE) PtrFromGh(HdeGetEnv())).wVersionNo);
|
|
return rcSuccess;
|
|
}
|
|
|
|
static RC STDCALL FindKeywordMacro(PCSTR pszKeyword, HDE hde)
|
|
{
|
|
HBT hbtKeyMacros;
|
|
RC rc;
|
|
|
|
if (!IsEmptyString(pszKeyword)) {
|
|
hbtKeyMacros = HbtOpenBtreeSz(txtRose, QDE_HFS(QdeFromGh(hde)),
|
|
fFSOpenReadOnly);
|
|
if (hbtKeyMacros) {
|
|
HASH hash = HashFromSz(pszKeyword);
|
|
PSTR pszMacro = (PSTR) LhAlloc(LMEM_FIXED, MAX_KEY_MACRO);
|
|
BTPOS btpos;
|
|
|
|
rc = RcLookupByKey(hbtKeyMacros, (KEY) (LPVOID) &hash, &btpos,
|
|
pszMacro);
|
|
if (rc == rcNoExists) {
|
|
// Deal with case where we are in between keys in a btree
|
|
|
|
if (FValidPos(&btpos)) {
|
|
LONG lBogus;
|
|
BTPOS btposNew;
|
|
|
|
rc = RcOffsetPos(hbtKeyMacros, &btpos, (LONG) -1,
|
|
(QL) &lBogus, &btposNew);
|
|
if (rc == rcSuccess)
|
|
rc = RcLookupByPos(hbtKeyMacros, &btposNew,
|
|
(KEY) (QL) &lBogus, pszMacro);
|
|
}
|
|
else
|
|
rc = RcLastHbt(hbtKeyMacros, 0, pszMacro, NULL);
|
|
}
|
|
if (rc == rcSuccess)
|
|
Execute(pszMacro);
|
|
|
|
FreeLh(pszMacro);
|
|
RcCloseBtreeHbt(hbtKeyMacros);
|
|
return (rc == rcSuccess) ? rcMacroIndex : rcFailure;
|
|
}
|
|
}
|
|
return rcFailure;
|
|
}
|
|
|
|
static PCSTR FASTCALL FtsIndexToFile(int index)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_FILES; i++) {
|
|
if (GetFileIndex(i) == index) {
|
|
#ifdef _DEBUG
|
|
PSTR psz = pTblFiles->GetPointer((i * 2) + 2);
|
|
#endif
|
|
return pTblFiles->GetPointer((i * 2) + 2);
|
|
}
|
|
}
|
|
|
|
// If we get here, index from FTS sent to us doesn't match what was
|
|
// returned when we added the index.
|
|
|
|
ASSERT(i < MAX_FILES);
|
|
return txtZeroLength;
|
|
}
|
|
|
|
static PCSTR FASTCALL FtsIndexToTitle(int index)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_FILES; i++) {
|
|
if (GetFileIndex(i) == index) {
|
|
PSTR psz = pTblFiles->GetPointer((i * 2) + 1);
|
|
if (!psz || !*psz) {
|
|
|
|
/*
|
|
* If this is the only file, then we typically do not have
|
|
* a title stored in pTblFiles, so we need to grab the
|
|
* current help's title.
|
|
*/
|
|
|
|
if (pTblFiles->CountStrings() <= 2) {
|
|
psz = QDE_RGCHTITLE((QDE) HdeGetEnv());
|
|
if (!*psz)
|
|
psz = pTblFiles->GetPointer((i * 2) + 2);
|
|
}
|
|
else
|
|
psz = pTblFiles->GetPointer((i * 2) + 2);
|
|
}
|
|
return psz;
|
|
}
|
|
}
|
|
|
|
// If we get here, index from FTS sent to us doesn't match what was
|
|
// returned when we added the index.
|
|
|
|
ASSERT(i < MAX_FILES);
|
|
return txtZeroLength;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: FtsWizardProc
|
|
|
|
PURPOSE: Dialog for choosing which files to index
|
|
|
|
PARAMETERS:
|
|
hwndDlg
|
|
msg
|
|
wParam
|
|
lParam
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
07-Aug-1994 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
extern "C" DLGRET FtsWizardProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HWND hwndIncludeList, hwndIgnoreList, hwnd;
|
|
int pos, i, index;
|
|
char szName[MAX_PATH];
|
|
// DWORD msgResult = 0;
|
|
LPWIZSHEET lpWizSheet;
|
|
LPPROPSHEETPAGE ppsp;
|
|
|
|
switch (msg) {
|
|
case WM_PAINT:
|
|
{
|
|
// Only Chicago understands how to paint static bitmaps!
|
|
// The code does the painting for the other opsys's
|
|
if (!fIsThisNewShell4)
|
|
{
|
|
HBITMAP hOldBitmap;
|
|
BITMAP bmInfo;
|
|
HDC hDC,hMemDC;
|
|
RECT rct;
|
|
|
|
LPPOINT lppnt = (LPPOINT) &rct;
|
|
|
|
GetWindowRect(GetDlgItem(hwndDlg,IDC_WIZBMP),&rct);
|
|
ScreenToClient(hwndDlg, lppnt++); // Convert to the dlg client coordinates
|
|
ScreenToClient(hwndDlg,lppnt);
|
|
|
|
hDC = GetDC(GetDlgItem(hwndDlg, IDC_WIZBMP)); // Get a DC to draw to
|
|
hMemDC = CreateCompatibleDC(hDC); // and a memDC to select into
|
|
|
|
ppsp = (LPPROPSHEETPAGE) GetWindowLong(hwndDlg, DWL_USER);
|
|
ASSERT(ppsp);
|
|
lpWizSheet = (LPWIZSHEET) ppsp->lParam; // Set up pointer to my data
|
|
GetObject(lpWizSheet->wd->hWizBMP,sizeof(bmInfo),&bmInfo); // Get the size info
|
|
|
|
hOldBitmap = (HBITMAP)SelectObject(hMemDC,lpWizSheet->wd->hWizBMP); // Select into MemDc
|
|
StretchBlt(hDC,0,0,rct.right - rct.left,rct.bottom - rct.top, // Blt it to the window
|
|
hMemDC,0,0,bmInfo.bmWidth,bmInfo.bmHeight,SRCCOPY);
|
|
SelectObject(hMemDC,hOldBitmap); // Unselect the bitmap
|
|
|
|
ReleaseDC(GetDlgItem(hwndDlg,IDC_WIZBMP),hDC); // Release the DC
|
|
DeleteDC(hMemDC); // Delete the memDC
|
|
ValidateRect(hwndDlg,&rct); // Validate the drawn region
|
|
}
|
|
return FALSE; // False causes paint to continue
|
|
}
|
|
break;
|
|
|
|
case WM_INITDIALOG:
|
|
{
|
|
|
|
CWaitCursor cwait;
|
|
|
|
SetWindowLong(hwndDlg, DWL_USER, lParam);
|
|
ppsp = (LPPROPSHEETPAGE) lParam;
|
|
lpWizSheet = (LPWIZSHEET) ppsp->lParam; // Set up pointer to my data
|
|
|
|
// set the loword to the current page number;
|
|
ftsFlags.dwWizStat = MAKELPARAM(LOWORD(ppsp->lParam),LOWORD(ftsFlags.dwWizStat));
|
|
ChangeDlgFont(hwndDlg);
|
|
ASSERT(hfontDefault);
|
|
|
|
PSTR pStrText = (PSTR) LhAlloc(LMEM_FIXED, WIZ_MEM_REQ);
|
|
|
|
int iStrID = (lpWizSheet->nID - IDD_WIZ_FTS_EXPRESS) * WIZ_PAGE_SEP + sidWizPage0_0;
|
|
|
|
*pStrText = '\0';
|
|
for (int i = 0; i < WIZ_STR_PAGES; i++)
|
|
strcat(pStrText,GetStringResource(iStrID + i));
|
|
ASSERT(strlen(pStrText) < WIZ_MEM_REQ);
|
|
|
|
SetWindowText(GetDlgItem(hwndDlg, IDC_WIZ_MAIN_STATIC),pStrText);
|
|
|
|
if (fIsThisNewShell4)
|
|
SendMessage(GetDlgItem(hwndDlg,IDC_WIZBMP), STM_SETIMAGE,
|
|
IMAGE_BITMAP, (LPARAM) lpWizSheet->wd->hWizBMP);
|
|
|
|
switch(lpWizSheet->nID)
|
|
{
|
|
case IDD_WIZ_FTS_EXPRESS:
|
|
lpWizSheet->wd->flgs = ftsFlags; // Set up default flags
|
|
CheckDlgButton(hwndDlg, IDC_WIZ_MIN_SIZE, TRUE);
|
|
lpWizSheet->wd->bExpress = IDC_WIZ_MIN_SIZE;
|
|
break;
|
|
|
|
case IDD_WIZ_FTS_INCLUDE_1LIST:
|
|
hwndIncludeList = GetDlgItem(hwndDlg, IDC_INCLUDE_1LIST);
|
|
SendMessage(hwndIncludeList, WM_SETFONT, (WPARAM) hfontDefault, FALSE);
|
|
for (index = 2; index <= pTblFiles->CountStrings(); index += 2) \
|
|
{
|
|
PSTR pszTitle = pTblFiles->GetPointer(index - 1);
|
|
if (!*pszTitle)
|
|
{
|
|
GetFmParts((FM) pTblFiles->GetPointer(index),
|
|
szName, PARTBASE | PARTEXT);
|
|
pszTitle = szName;
|
|
}
|
|
#ifdef _DEBUG
|
|
PSTR pszFile = pTblFiles->GetPointer(index);
|
|
#endif
|
|
|
|
BYTE type = pFileInfo[index / 2 - 1].filetype;
|
|
if (type & (CHFLAG_MISSING | CHFLAG_LINK))
|
|
continue;
|
|
// hwnd = (type & CHFLAG_FTS_ASKED) ? hwndIgnoreList :
|
|
// hwndIncludeList;
|
|
pos = SendMessage(hwndIncludeList, LB_ADDSTRING,
|
|
0, (LPARAM) pszTitle);
|
|
if (pos != LB_ERR)
|
|
{
|
|
SendMessage(hwndIncludeList,LB_SETSEL,!(type & CHFLAG_FTS_ASKED),(LPARAM) pos);
|
|
SendMessage(hwndIncludeList, LB_SETITEMDATA, pos, index);
|
|
}
|
|
}
|
|
break;
|
|
case IDD_WIZ_FTS_INCLUDE :
|
|
// Fill the include and ignore lists with the help titles
|
|
|
|
hwndIncludeList = GetDlgItem(hwndDlg, IDC_INCLUDE);
|
|
hwndIgnoreList = GetDlgItem(hwndDlg, IDC_EXCLUDE);
|
|
SendMessage(hwndIncludeList, WM_SETFONT, (WPARAM) hfontDefault, FALSE);
|
|
SendMessage(hwndIgnoreList, WM_SETFONT, (WPARAM) hfontDefault, FALSE);
|
|
for (index = 2; index <= pTblFiles->CountStrings(); index += 2) \
|
|
{
|
|
PSTR pszTitle = pTblFiles->GetPointer(index - 1);
|
|
if (!*pszTitle)
|
|
{
|
|
GetFmParts((FM) pTblFiles->GetPointer(index),
|
|
szName, PARTBASE | PARTEXT);
|
|
pszTitle = szName;
|
|
}
|
|
#ifdef _DEBUG
|
|
PSTR pszFile = pTblFiles->GetPointer(index);
|
|
#endif
|
|
|
|
BYTE type = pFileInfo[index / 2 - 1].filetype;
|
|
if (type & (CHFLAG_MISSING | CHFLAG_LINK))
|
|
continue;
|
|
hwnd = (type & CHFLAG_FTS_ASKED) ? hwndIgnoreList :
|
|
hwndIncludeList;
|
|
pos = SendMessage(hwnd, LB_ADDSTRING,
|
|
0, (LPARAM) pszTitle);
|
|
if (pos != LB_ERR)
|
|
SendMessage(hwnd, LB_SETITEMDATA, pos, index);
|
|
}
|
|
break;
|
|
|
|
case IDD_WIZ_FTS_SIMILARITY :
|
|
CheckDlgButton(hwndDlg, IDC_SIMILARITY_YES, ftsFlags.fSimilarity);
|
|
CheckDlgButton(hwndDlg, IDC_SIMILARITY_NO, !ftsFlags.fSimilarity);
|
|
break;
|
|
case IDD_WIZ_FTS_UNTITLED :
|
|
CheckDlgButton(hwndDlg, IDC_INCLUDE_UNTITLED, ftsFlags.fUntitled);
|
|
CheckDlgButton(hwndDlg, IDC_EXCLUDE_UNTITLED, !ftsFlags.fUntitled);
|
|
break;
|
|
case IDD_WIZ_FTS_PHRASE :
|
|
CheckDlgButton(hwndDlg, IDC_PHRASE_YES, ftsFlags.fFphrase);
|
|
CheckDlgButton(hwndDlg, IDC_PHRASE_NO, !ftsFlags.fFphrase);
|
|
break;
|
|
case IDD_WIZ_FTS_MATCHING :
|
|
CheckDlgButton(hwndDlg, IDC_DISPLAY_MATCHING, ftsFlags.fPhraseFeedBack);
|
|
CheckDlgButton(hwndDlg, IDC_NO_DISPLAY_MATCHING, !ftsFlags.fPhraseFeedBack);
|
|
break;
|
|
case IDD_WIZ_FTS_END :
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case WM_COMMAND:
|
|
{
|
|
ppsp = (LPPROPSHEETPAGE) GetWindowLong(hwndDlg, DWL_USER);
|
|
ASSERT(ppsp);
|
|
lpWizSheet = (LPWIZSHEET) ppsp->lParam; // Set up pointer to my data
|
|
|
|
switch(lpWizSheet->nID)
|
|
{
|
|
case IDD_WIZ_FTS_EXPRESS:
|
|
break;
|
|
case IDD_WIZ_FTS_INCLUDE_1LIST :
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_SELECTALL:
|
|
hwndIncludeList = GetDlgItem(hwndDlg, IDC_INCLUDE_1LIST);
|
|
SendMessage(hwndIncludeList,LB_SETSEL,TRUE,(LPARAM) -1); // Select them all
|
|
}
|
|
|
|
break;
|
|
case IDD_WIZ_FTS_INCLUDE :
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_EXCLUDE:
|
|
switch (HIWORD(wParam))
|
|
{
|
|
case LBN_SELCHANGE:
|
|
case LBN_SELCANCEL:
|
|
EnableWindow(GetDlgItem(hwndDlg, IDC_ADD_FILES),
|
|
SendMessage((HWND) lParam, LB_GETSELCOUNT, 0, 0));
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case IDC_INCLUDE:
|
|
switch (HIWORD(wParam))
|
|
{
|
|
case LBN_SELCHANGE:
|
|
case LBN_SELCANCEL:
|
|
EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE_FILES),
|
|
SendMessage((HWND) lParam, LB_GETSELCOUNT, 0, 0));
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case IDC_REMOVE_FILES:
|
|
if (HIWORD(wParam) == BN_CLICKED)
|
|
OnFtsMove(hwndDlg, FALSE);
|
|
break;
|
|
|
|
case IDC_ADD_FILES:
|
|
if (HIWORD(wParam) == BN_CLICKED)
|
|
OnFtsMove(hwndDlg, TRUE);
|
|
break;
|
|
|
|
|
|
}
|
|
break;
|
|
case IDD_WIZ_FTS_SIMILARITY :
|
|
break;
|
|
case IDD_WIZ_FTS_UNTITLED :
|
|
break;
|
|
case IDD_WIZ_FTS_PHRASE :
|
|
break;
|
|
case IDD_WIZ_FTS_MATCHING :
|
|
break;
|
|
case IDD_WIZ_FTS_END :
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case WM_NOTIFY:
|
|
ppsp = (LPPROPSHEETPAGE) GetWindowLong(hwndDlg, DWL_USER);
|
|
ASSERT(ppsp);
|
|
lpWizSheet = (LPWIZSHEET) ppsp->lParam; // Set up pointer to my data
|
|
|
|
switch(((NMHDR FAR *)lParam)->code)
|
|
{
|
|
// case PSN_APPLY:
|
|
// break;
|
|
|
|
case PSN_RESET:
|
|
ftsFlags.dwWizStat = FALSE;
|
|
break;
|
|
|
|
case PSN_WIZFINISH:
|
|
lpWizSheet->wd->flgs.dwWizStat = TRUE;
|
|
if (lpWizSheet->wd->bExpress == IDC_WIZ_MIN_SIZE)
|
|
{
|
|
ftsFlags.fFphrase = FALSE;
|
|
ftsFlags.fPhraseFeedBack = FALSE;
|
|
ftsFlags.fSimilarity = FALSE;
|
|
goto Express;
|
|
}
|
|
else if (lpWizSheet->wd->bExpress == IDC_WIZ_MAXIMUM)
|
|
{
|
|
ftsFlags.fFphrase = TRUE;
|
|
ftsFlags.fPhraseFeedBack = TRUE;
|
|
ftsFlags.fSimilarity = TRUE;
|
|
Express:
|
|
ftsFlags.fUntitled = FALSE;
|
|
|
|
pSrchClass->pInclude = (int*) LhAlloc(LMEM_FIXED,
|
|
(pTblFiles->CountStrings()/2 + 1) * sizeof(int));
|
|
|
|
for (i = 0, index = 2; index <= pTblFiles->CountStrings(); index += 2)
|
|
{
|
|
BYTE type = pFileInfo[index / 2 - 1].filetype;
|
|
if (type & (CHFLAG_MISSING | CHFLAG_LINK))
|
|
continue;
|
|
pSrchClass->pInclude[i++] = index;
|
|
}
|
|
pSrchClass->pInclude[i] = -1;
|
|
}
|
|
else
|
|
{
|
|
ftsFlags = lpWizSheet->wd->flgs;
|
|
}
|
|
break;
|
|
|
|
// case PSN_KILLACTIVE:
|
|
// break;
|
|
|
|
case PSN_WIZBACK:
|
|
switch(lpWizSheet->nID)
|
|
{
|
|
case IDD_WIZ_FTS_INCLUDE_1LIST :
|
|
case IDD_WIZ_FTS_INCLUDE :
|
|
if (pSrchClass->pInclude)
|
|
FreeLh(pSrchClass->pInclude);
|
|
if (pSrchClass->pIgnore)
|
|
FreeLh(pSrchClass->pIgnore);
|
|
pSrchClass->pInclude = NULL;
|
|
pSrchClass->pIgnore = NULL;
|
|
break;
|
|
|
|
case IDD_WIZ_FTS_END :
|
|
// Okay the logic here is a little weird but it goes like this...
|
|
// If the express bit is set then we came from the opening page
|
|
// else if the feedback bit is set we know we displayed the similar page
|
|
// else if the phrase is set we know we displayed the matching page
|
|
// otherwise we displayed the phrase page before going to the final page
|
|
if (lpWizSheet->wd->bExpress)
|
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_WIZ_FTS_EXPRESS);
|
|
else if (lpWizSheet->wd->flgs.fPhraseFeedBack)
|
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_WIZ_FTS_SIMILARITY);
|
|
else if (lpWizSheet->wd->flgs.fFphrase)
|
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_WIZ_FTS_MATCHING);
|
|
else
|
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_WIZ_FTS_PHRASE);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case PSN_WIZNEXT:
|
|
switch(lpWizSheet->nID)
|
|
{
|
|
case IDD_WIZ_FTS_EXPRESS:
|
|
if (IsDlgButtonChecked(hwndDlg, IDC_WIZ_MIN_SIZE))
|
|
lpWizSheet->wd->bExpress = IDC_WIZ_MIN_SIZE;
|
|
else if (IsDlgButtonChecked(hwndDlg, IDC_WIZ_MAXIMUM))
|
|
lpWizSheet->wd->bExpress = IDC_WIZ_MAXIMUM;
|
|
else
|
|
lpWizSheet->wd->bExpress = 0;
|
|
if (lpWizSheet->wd->bExpress)
|
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_WIZ_FTS_END);
|
|
break;
|
|
|
|
case IDD_WIZ_FTS_INCLUDE_1LIST :
|
|
{
|
|
// First remove any old list if they exist...
|
|
if (pSrchClass->pInclude)
|
|
FreeLh(pSrchClass->pInclude);
|
|
pSrchClass->pInclude = NULL;
|
|
ASSERT(!pSrchClass->pInclude);
|
|
if (pSrchClass->pIgnore)
|
|
FreeLh(pSrchClass->pIgnore);
|
|
pSrchClass->pIgnore = NULL;
|
|
ASSERT(!pSrchClass->pIgnore);
|
|
|
|
hwndIncludeList = GetDlgItem(hwndDlg, IDC_INCLUDE_1LIST);
|
|
int iLBContent = SendMessage(hwndIncludeList, LB_GETCOUNT, 0, 0); // Get total in LB
|
|
|
|
if (iLBContent > 0) // Are there any entries in the listbox?
|
|
{
|
|
// Get some memory so we can tell the selected and unselected entries apart
|
|
BOOL *pLBContent = (BOOL*) lcCalloc((iLBContent) * sizeof(BOOL));
|
|
|
|
pos = SendMessage(hwndIncludeList, LB_GETSELCOUNT, 0, 0); // How many are selected?
|
|
if (pos > 0)
|
|
{
|
|
|
|
int *pSelected = (int*) LhAlloc(LMEM_FIXED,(pos + 1) * sizeof(int));
|
|
int *pMem = pSelected;
|
|
|
|
// Start by pulling off the selected items
|
|
SendMessage(hwndIncludeList,LB_GETSELITEMS,(WPARAM)pos,(LPARAM) pSelected);
|
|
|
|
|
|
pSrchClass->pInclude = (int*) LhAlloc(LMEM_FIXED,(pos + 1) * sizeof(int));
|
|
for (i = 0; i < pos; i++,pSelected++) {
|
|
|
|
pSrchClass->pInclude[i] = SendMessage(hwndIncludeList,LB_GETITEMDATA, *pSelected, 0);
|
|
*(pLBContent + *pSelected) = 1; // Flag the item as selected
|
|
}
|
|
pSrchClass->pInclude[i] = -1;
|
|
FreeLh(pMem);
|
|
}
|
|
if (iLBContent - pos > 0) { // Are there any not selected?
|
|
pSrchClass->pIgnore = (int*) LhAlloc(LMEM_FIXED,
|
|
((iLBContent-pos) + 1) * sizeof(int));
|
|
int j;
|
|
// Stick them in their own list...
|
|
for (i = 0,j = 0; (i < iLBContent) && (j < iLBContent-pos); i++) {
|
|
if (*(pLBContent + i) == 0) // Found an unselected entry?
|
|
{
|
|
pSrchClass->pIgnore[j] = SendMessage(hwndIncludeList,
|
|
LB_GETITEMDATA, i, 0);
|
|
j++;
|
|
}
|
|
}
|
|
pSrchClass->pIgnore[j] = -1;
|
|
}
|
|
FreeLh(pLBContent);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDD_WIZ_FTS_INCLUDE :
|
|
hwndIncludeList = GetDlgItem(hwndDlg, IDC_INCLUDE);
|
|
hwndIgnoreList = GetDlgItem(hwndDlg, IDC_EXCLUDE);
|
|
|
|
pos = SendMessage(hwndIncludeList, LB_GETCOUNT, 0, 0);
|
|
if (pos > 0) {
|
|
if (pSrchClass->pInclude)
|
|
FreeLh(pSrchClass->pInclude);
|
|
pSrchClass->pInclude = NULL;
|
|
ASSERT(!pSrchClass->pInclude);
|
|
pSrchClass->pInclude = (int*) LhAlloc(LMEM_FIXED,
|
|
(pos + 1) * sizeof(int));
|
|
for (i = 0; i < pos; i++) {
|
|
pSrchClass->pInclude[i] = SendMessage(hwndIncludeList,
|
|
LB_GETITEMDATA, i, 0);
|
|
}
|
|
pSrchClass->pInclude[i] = -1;
|
|
}
|
|
|
|
pos = SendMessage(hwndIgnoreList, LB_GETCOUNT, 0, 0);
|
|
if (pos > 0) {
|
|
if (pSrchClass->pIgnore)
|
|
FreeLh(pSrchClass->pIgnore);
|
|
pSrchClass->pIgnore = NULL;
|
|
ASSERT(!pSrchClass->pIgnore);
|
|
pSrchClass->pIgnore = (int*) LhAlloc(LMEM_FIXED,
|
|
(pos + 1) * sizeof(int));
|
|
for (i = 0; i < pos; i++) {
|
|
pSrchClass->pIgnore[i] = SendMessage(hwndIgnoreList,
|
|
LB_GETITEMDATA, i, 0);
|
|
}
|
|
pSrchClass->pIgnore[i] = -1;
|
|
}
|
|
break;
|
|
|
|
case IDD_WIZ_FTS_SIMILARITY :
|
|
lpWizSheet->wd->flgs.fSimilarity = IsDlgButtonChecked(hwndDlg,IDC_SIMILARITY_YES);
|
|
break;
|
|
case IDD_WIZ_FTS_UNTITLED :
|
|
lpWizSheet->wd->flgs.fUntitled = IsDlgButtonChecked(hwndDlg,IDC_INCLUDE_UNTITLED);
|
|
break;
|
|
case IDD_WIZ_FTS_PHRASE :
|
|
lpWizSheet->wd->flgs.fFphrase = IsDlgButtonChecked(hwndDlg,IDC_PHRASE_YES);
|
|
if (!lpWizSheet->wd->flgs.fFphrase)
|
|
{
|
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_WIZ_FTS_END);
|
|
lpWizSheet->wd->flgs.fPhraseFeedBack = FALSE;
|
|
lpWizSheet->wd->flgs.fSimilarity = FALSE;
|
|
}
|
|
break;
|
|
case IDD_WIZ_FTS_MATCHING :
|
|
lpWizSheet->wd->flgs.fPhraseFeedBack = IsDlgButtonChecked(hwndDlg,IDC_DISPLAY_MATCHING);
|
|
if (!lpWizSheet->wd->flgs.fPhraseFeedBack)
|
|
{
|
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_WIZ_FTS_END);
|
|
lpWizSheet->wd->flgs.fSimilarity = FALSE;
|
|
}
|
|
break;
|
|
} // end of switch statement
|
|
break;
|
|
|
|
|
|
case PSN_SETACTIVE:
|
|
{
|
|
DWORD dwFlags = 0;
|
|
|
|
switch(lpWizSheet->nID)
|
|
{
|
|
case IDD_WIZ_FTS_EXPRESS: // Page 0
|
|
dwFlags = PSWIZB_NEXT;
|
|
break;
|
|
case IDD_WIZ_FTS_END :
|
|
dwFlags = PSWIZB_FINISH | PSWIZB_BACK;
|
|
break;
|
|
case IDD_WIZ_FTS_INCLUDE :
|
|
case IDD_WIZ_FTS_INCLUDE_1LIST :
|
|
case IDD_WIZ_FTS_UNTITLED :
|
|
case IDD_WIZ_FTS_PHRASE :
|
|
case IDD_WIZ_FTS_MATCHING :
|
|
case IDD_WIZ_FTS_SIMILARITY :
|
|
dwFlags = PSWIZB_NEXT| PSWIZB_BACK;
|
|
break;
|
|
default :
|
|
dwFlags = PSWIZB_NEXT| PSWIZB_BACK | PSWIZB_FINISH;
|
|
}
|
|
PropSheet_SetWizButtons(GetParent(hwndDlg),dwFlags);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
default :
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: OnFtsMove
|
|
|
|
PURPOSE: Move all selected items from one listbox to another
|
|
|
|
PARAMETERS:
|
|
hwndDlg
|
|
fAdd -- TRUE if Adding
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
07-Aug-1994 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
static void STDCALL OnFtsMove(HWND hwndDlg, BOOL fAdd)
|
|
{
|
|
HWND hCtrlTo = GetDlgItem(hwndDlg, (fAdd ? IDC_INCLUDE : IDC_EXCLUDE));
|
|
HWND hCtrlFrom = GetDlgItem(hwndDlg, (fAdd ? IDC_EXCLUDE : IDC_INCLUDE));
|
|
int cMove = SendMessage(hCtrlFrom, LB_GETSELCOUNT, 0, 0);
|
|
int* pItems;
|
|
char szBuf[256];
|
|
|
|
if (cMove <= 0)
|
|
return;
|
|
|
|
// Prevent the list boxes from redrawing
|
|
|
|
SendMessage(hCtrlTo, WM_SETREDRAW, FALSE, 0L);
|
|
SendMessage(hCtrlFrom, WM_SETREDRAW, FALSE, 0L);
|
|
|
|
pItems = (int*) LhAlloc(LMEM_FIXED, cMove * sizeof(int));
|
|
SendMessage(hCtrlFrom, LB_GETSELITEMS, cMove, (LPARAM) pItems);
|
|
for (int iAdjust = 0; iAdjust < cMove; iAdjust++) {
|
|
SendMessage(hCtrlFrom, LB_GETTEXT, pItems[iAdjust] - iAdjust,
|
|
(LPARAM) szBuf);
|
|
int data = SendMessage(hCtrlFrom, LB_GETITEMDATA, pItems[iAdjust] - iAdjust, 0);
|
|
int pos = SendMessage(hCtrlTo, LB_ADDSTRING, 0, (LPARAM) szBuf);
|
|
SendMessage(hCtrlTo, LB_SETITEMDATA, pos, data);
|
|
SendMessage(hCtrlFrom, LB_DELETESTRING, pItems[iAdjust] - iAdjust, 0);
|
|
}
|
|
|
|
// Enable list box redrawing
|
|
|
|
SendMessage(hCtrlTo, WM_SETREDRAW, TRUE, 0L);
|
|
SendMessage(hCtrlFrom, WM_SETREDRAW, TRUE, 0L);
|
|
|
|
FreeLh(pItems);
|
|
|
|
EnableWindow(GetDlgItem(hwndDlg, IDC_ADD_FILE),
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_FILES_TO_INDEX), LB_GETSELCOUNT, 0, 0));
|
|
EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE_FILE),
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_FILES_TO_IGNORE), LB_GETSELCOUNT, 0, 0));
|
|
}
|
|
|
|
//
|
|
// Adds a page to a property sheet.
|
|
//
|
|
static void STDCALL AddPage(LPPROPSHEETHEADER ppsh, PROPSHEETPAGE *ppsp, UINT id, DLGPROC pfn, LPARAM lpwd)
|
|
{
|
|
if (ppsh->nPages < MAX_PAGES) {
|
|
|
|
ppsp->dwSize = sizeof(PROPSHEETPAGE);
|
|
ppsp->dwFlags = PSP_DEFAULT;
|
|
ppsp->hInstance = hInsNow;
|
|
ppsp->pszTemplate = MAKEINTRESOURCE(id);
|
|
ppsp->pfnDlgProc = pfn;
|
|
ppsp->lParam = (LPARAM)lpwd; // pointer to both per sheet and all sheets data
|
|
|
|
ppsh->phpage[ppsh->nPages] = pCreatePropertySheetPage(ppsp);
|
|
if (ppsh->phpage[ppsh->nPages])
|
|
ppsh->nPages++;
|
|
}
|
|
} // AddPage
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: AskAboutIndexes
|
|
|
|
PURPOSE: Ask the users which files should and should not be indexed
|
|
|
|
PARAMETERS:
|
|
hwndParent
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
07-Aug-1994 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
static BOOL STDCALL AskAboutIndexes(HWND hwndParent)
|
|
{
|
|
if (!LoadShellApi())
|
|
return FALSE;
|
|
HPROPSHEETPAGE rPages[MAX_PAGES];
|
|
PROPSHEETPAGE rpsp[MAX_PAGES];
|
|
PROPSHEETHEADER psh;
|
|
WIZDATA wd;
|
|
WIZSHEET ws[MAX_PAGES];
|
|
|
|
if (hsrch) {
|
|
RemoveHiliter(&hhiliter);
|
|
|
|
pDeleteSearcher(hsrch);
|
|
hsrch = 0;
|
|
}
|
|
|
|
psh.dwSize = sizeof(psh);
|
|
psh.dwFlags = PSH_WIZARD;
|
|
psh.hwndParent = hwndParent;
|
|
psh.hInstance = hInsNow;
|
|
psh.pszCaption = NULL;
|
|
psh.nPages = 0;
|
|
psh.nStartPage = 0;
|
|
psh.phpage = rPages;
|
|
|
|
// initialize the wizard checks to true for now
|
|
ftsFlags.fFphrase = TRUE;
|
|
ftsFlags.fPhraseFeedBack = TRUE;
|
|
ftsFlags.fSimilarity = TRUE;
|
|
ftsFlags.fUntitled = FALSE;
|
|
|
|
wd.dwPagesHit = 0;
|
|
wd.hWizBMP = LoadBitmap(hInsNow,MAKEINTRESOURCE(IDC_WIZBMP));
|
|
|
|
for (int i = 0;i < MAX_PAGES; i++)
|
|
ws[i].wd = &wd; // Point to common data
|
|
|
|
ws[0].nID = IDD_WIZ_FTS_EXPRESS;
|
|
AddPage(&psh, rpsp + 0,IDD_WIZ_FTS_EXPRESS,(DLGPROC) FtsWizardProc,(LPARAM)&ws[0]);
|
|
ws[1].nID = IDD_WIZ_FTS_INCLUDE_1LIST;
|
|
AddPage(&psh, rpsp + 1,IDD_WIZ_FTS_INCLUDE_1LIST,(DLGPROC) FtsWizardProc,(LPARAM)(LPWIZSHEET)&ws[1]);
|
|
ws[2].nID = IDD_WIZ_FTS_UNTITLED;
|
|
AddPage(&psh, rpsp + 2,IDD_WIZ_FTS_UNTITLED,(DLGPROC) FtsWizardProc,(LPARAM)(LPWIZSHEET)&ws[2]);
|
|
ws[3].nID = IDD_WIZ_FTS_PHRASE;
|
|
AddPage(&psh, rpsp + 3,IDD_WIZ_FTS_PHRASE,(DLGPROC) FtsWizardProc,(LPARAM)(LPWIZSHEET)&ws[3]);
|
|
ws[4].nID = IDD_WIZ_FTS_MATCHING;
|
|
AddPage(&psh, rpsp + 4,IDD_WIZ_FTS_MATCHING,(DLGPROC) FtsWizardProc,(LPARAM)(LPWIZSHEET)&ws[4]);
|
|
ws[5].nID = IDD_WIZ_FTS_SIMILARITY;
|
|
AddPage(&psh, rpsp + 5,IDD_WIZ_FTS_SIMILARITY,(DLGPROC) FtsWizardProc,(LPARAM)(LPWIZSHEET)&ws[5]);
|
|
ws[6].nID = IDD_WIZ_FTS_END;
|
|
AddPage(&psh, rpsp + 6,IDD_WIZ_FTS_END,(DLGPROC) FtsWizardProc,(LPARAM)(LPWIZSHEET)&ws[6]);
|
|
|
|
#ifdef _DEBUG
|
|
if (pPropertySheet(&psh) < 0) {
|
|
|
|
// First whine, then index everything using express settings
|
|
|
|
int err = GetLastError();
|
|
char szMsg[100];
|
|
wsprintf(szMsg, "PropertySheet failed: %d", err);
|
|
OkMsgBox(szMsg);
|
|
ftsFlags.fFphrase = TRUE;
|
|
ftsFlags.fPhraseFeedBack = TRUE;
|
|
ftsFlags.fSimilarity = TRUE;
|
|
ftsFlags.fUntitled = FALSE;
|
|
|
|
pSrchClass->pInclude = (int*) LhAlloc(LMEM_FIXED,
|
|
(pTblFiles->CountStrings()/2 + 1) * sizeof(int));
|
|
|
|
int index;
|
|
for (i = 0, index = 2; index <= pTblFiles->CountStrings(); index += 2)
|
|
{
|
|
BYTE type = pFileInfo[index / 2 - 1].filetype;
|
|
if (type & (CHFLAG_MISSING | CHFLAG_LINK))
|
|
continue;
|
|
pSrchClass->pInclude[i++] = index;
|
|
}
|
|
pSrchClass->pInclude[i] = -1;
|
|
ftsFlags.dwWizStat = TRUE;
|
|
}
|
|
#else
|
|
pPropertySheet(&psh);
|
|
#endif
|
|
SafeDeleteObject(wd.hWizBMP); // delete the bitmap
|
|
|
|
if (ftsFlags.dwWizStat)
|
|
{
|
|
int index, i;
|
|
FM fm;
|
|
char szName[MAX_PATH];
|
|
|
|
UINT fdwOptions= TOPIC_SEARCH | WINHELP_INDEX | USE_VA_ADDR;
|
|
|
|
if (ftsFlags.fFphrase)
|
|
fdwOptions |= PHRASE_SEARCH;
|
|
if (ftsFlags.fPhraseFeedBack)
|
|
fdwOptions |= PHRASE_FEEDBACK;
|
|
if (ftsFlags.fSimilarity)
|
|
fdwOptions |= VECTOR_SEARCH;
|
|
|
|
/*
|
|
* If any filenames have been changed to NOT have an index, then
|
|
* delete their existing (if any) .FTS file and mark them as being
|
|
* without an index.
|
|
*/
|
|
|
|
if (pSrchClass->pIgnore) {
|
|
for (i = 0; (index = pSrchClass->pIgnore[i]) != -1; i++) {
|
|
#ifdef _DEBUG
|
|
PSTR pszName = pTblFiles->GetPointer(index);
|
|
#endif
|
|
BYTE type = pFileInfo[index / 2 - 1].filetype;
|
|
if (type & (CHFLAG_MISSING | CHFLAG_LINK | CHFLAG_FTS_ASKED))
|
|
continue; // already marked to ignore
|
|
else {
|
|
|
|
// If the .FTS file exists, delete it
|
|
|
|
strcpy(szName, pTblFiles->GetPointer(index));
|
|
ChangeExtension(szName, txtFtsExtension);
|
|
fm = FmNewExistSzDir(szName,
|
|
DIR_PATH | DIR_CUR_HELP | DIR_CURRENT | DIR_SILENT_INI | DIR_SILENT_REG);
|
|
if (fm) {
|
|
if (GetFileAttributes(szName) != (DWORD) -1)
|
|
DeleteFile(szName);
|
|
DisposeFm(fm);
|
|
}
|
|
|
|
pFileInfo[index / 2 - 1].filetype &= ~(CHFLAG_FTS_AVAIL);
|
|
pFileInfo[index / 2 - 1].filetype |= CHFLAG_FTS_ASKED;
|
|
}
|
|
}
|
|
if (pSrchClass->pIgnore) {
|
|
FreeLh(pSrchClass->pIgnore);
|
|
pSrchClass->pIgnore = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Now generate the index for any files that the user has
|
|
* requested an index for, but for which we don't have an index.
|
|
*/
|
|
|
|
if (pSrchClass->pInclude) {
|
|
if (!hwndAnimate && !StartAnimation(sidCreatingFTS)) {
|
|
Error(wERRS_OOM, wERRA_RETURN);
|
|
return FALSE;
|
|
}
|
|
else if (hwndAnimate)
|
|
SetWindowText(hwndAnimate, GetStringResource(sidCreatingFTS));
|
|
|
|
for (i = 0; (index = pSrchClass->pInclude[i]) != -1; i++) {
|
|
#ifdef _DEBUG
|
|
PSTR pszName = pTblFiles->GetPointer(index);
|
|
#endif
|
|
BYTE type = pFileInfo[index / 2 - 1].filetype;
|
|
if (type & (CHFLAG_MISSING | CHFLAG_LINK))
|
|
continue;
|
|
pFileInfo[index / 2 - 1].filetype &= ~(CHFLAG_FTS_ASKED);
|
|
|
|
if (!(pFileInfo[index / 2 - 1].filetype & CHFLAG_BAD_RO_FTS))
|
|
{
|
|
strcpy(szName, pTblFiles->GetPointer(index));
|
|
ChangeExtension(szName, txtFtsExtension);
|
|
FM fm = FmNewExistSzDir(szName,
|
|
DIR_PATH | DIR_CUR_HELP | DIR_CURRENT | DIR_SILENT_INI | DIR_SILENT_REG);
|
|
|
|
if (fm) { // does index already exist?
|
|
// define vars
|
|
|
|
int idIndex;
|
|
DWORD dtime1, time2;
|
|
BOOL bInvalidTime;
|
|
|
|
// set up for time stamp check
|
|
dtime1 = pFileInfo[index / 2 - 1].timestamp;
|
|
time2 = 0;
|
|
idIndex= pOpenIndex(hsrch,fm, NULL, NULL,
|
|
&dtime1, &time2);
|
|
|
|
if (idIndex < 0)
|
|
bInvalidTime = TRUE;
|
|
else
|
|
bInvalidTime = FALSE;
|
|
|
|
if (!pIsValidIndex(fm, fdwOptions) || bInvalidTime) {
|
|
if (!DeleteFile(fm)) {
|
|
|
|
// BUGBUG: Can't delete the file, so we can't change it
|
|
// what do we do now?
|
|
|
|
pFileInfo[index / 2 - 1].filetype |= CHFLAG_FTS_ASKED;
|
|
continue;
|
|
}
|
|
}
|
|
else {
|
|
pFileInfo[index / 2 - 1].filetype |= CHFLAG_FTS_AVAIL;
|
|
RemoveFM(&fm);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
strcpy(szName, pTblFiles->GetPointer(index));
|
|
fm = FmNewExistSzDir(szName,
|
|
DIR_PATH | DIR_CUR_HELP | DIR_CURRENT | DIR_SILENT_INI | DIR_SILENT_REG);
|
|
if (!fm) {
|
|
pFileInfo[index / 2 - 1].filetype &= ~(CHFLAG_FTS_AVAIL);
|
|
pFileInfo[index / 2 - 1].filetype |= CHFLAG_MISSING;
|
|
continue;
|
|
}
|
|
|
|
FM fmCopy = FmCopyFm(fm);
|
|
HDE hde = HdeCreate(&fmCopy, NULL, deTopic);
|
|
int iResult = 0;
|
|
|
|
if (hde) {
|
|
ASSERT(fm);
|
|
|
|
iResult= GenerateIndex(hde, fm, fdwOptions);
|
|
|
|
if (!iResult)
|
|
pFileInfo[index / 2 - 1].filetype |= CHFLAG_FTS_AVAIL;
|
|
|
|
DestroyHde(hde);
|
|
}
|
|
|
|
RemoveFM(&fmCopy);
|
|
RemoveFM(&fm);
|
|
|
|
if (iResult == OUT_OF_MEMORY || iResult == OUT_OF_DISK)
|
|
{
|
|
if (pSrchClass->pInclude)
|
|
{
|
|
FreeLh(pSrchClass->pInclude);
|
|
pSrchClass->pInclude = NULL;
|
|
}
|
|
|
|
StopAnimation();
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (pSrchClass->pInclude) {
|
|
FreeLh(pSrchClass->pInclude);
|
|
pSrchClass->pInclude = NULL;
|
|
}
|
|
StopAnimation();
|
|
}
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
extern "C" void STDCALL InitializeCntTest(DWORD test)
|
|
{
|
|
if (!hfsGid)
|
|
return;
|
|
|
|
HBT hbtCntJump = HbtOpenBtreeSz(txtCntJump,
|
|
hfsGid, fFSOpenReadOnly);
|
|
if (!hbtCntJump)
|
|
return;
|
|
|
|
RcCloseBtreeHbt(hbtCntJump);
|
|
|
|
fSequence = test;
|
|
dwSequence = 0;
|
|
PostMessage(ahwnd[iCurWindow].hwndParent, MSG_NEXT_TOPIC, 0, 0);
|
|
}
|
|
|
|
extern "C" BOOL STDCALL NextCntTopic(void)
|
|
{
|
|
RC rc;
|
|
PSTR psz;
|
|
|
|
HBT hbtCntJump = HbtOpenBtreeSz(txtCntJump,
|
|
hfsGid, fFSOpenReadOnly);
|
|
if (!hbtCntJump)
|
|
return FALSE;
|
|
|
|
while (dwSequence <= (DWORD) cntFlags.cCntItems &&
|
|
GETIMAGE_TYPE(pbTree[dwSequence]) != IMAGE_TOPIC)
|
|
dwSequence++;
|
|
|
|
// Note that we deliberately let this fail when dwSequence > cntFlags.cCntItems
|
|
|
|
rc = RcLookupByKey(hbtCntJump, (KEY) (LPVOID) &dwSequence,
|
|
NULL, szSavedContext);
|
|
|
|
RcCloseBtreeHbt(hbtCntJump);
|
|
|
|
if (rc != rcSuccess) {
|
|
return FALSE;
|
|
}
|
|
|
|
dwSequence++;
|
|
|
|
if (szSavedContext[0] != chMACRO) {
|
|
ParseContentsString(szSavedContext);
|
|
psz = StrChrDBCS(szSavedContext, FILESEPARATOR);
|
|
if (psz)
|
|
*psz++ = '\0';
|
|
|
|
FJumpId((psz ? psz : ""), szSavedContext);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
CTable* ptbl16DllList;
|
|
|
|
extern "C" BOOL STDCALL AddTo16DllList(FM fm)
|
|
{
|
|
char szFile[MAX_PATH];
|
|
|
|
if (!ptbl16DllList)
|
|
ptbl16DllList = new CTable;
|
|
GetFmParts(fm, szFile, PARTBASE);
|
|
|
|
if (!ptbl16DllList->IsStringInTable(szFile))
|
|
return ptbl16DllList->AddString(szFile);
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
extern "C" BOOL STDCALL Is16Dll(LPCSTR pszFile)
|
|
{
|
|
char szFile[MAX_PATH];
|
|
GetFmParts((FM) pszFile, szFile, PARTBASE);
|
|
|
|
if (ptbl16DllList && ptbl16DllList->IsStringInTable(szFile))
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
static void STDCALL SetCntTabText(HWND hwndDlg, BOOL fOpen)
|
|
{
|
|
char szMsg[256];
|
|
CStr cszButton(fOpen ? sidCntOpen : sidCntDisplay);
|
|
CStr cszBook(fOpen ? sidBook : sidTopic);
|
|
wsprintf(szMsg, GetStringResource(sidCntInstruction),
|
|
cszBook.psz, cszButton.psz);
|
|
SetWindowText(GetDlgItem(hwndDlg, IDC_CNT_INSTRUCTIONS),
|
|
szMsg);
|
|
}
|
|
|
|
static void STDCALL PageChange(HWND hwndTab)
|
|
{
|
|
TAB_ID idCurTab = aTabIds[TabCtrl_GetCurSel(hwndTab)];
|
|
HWND hwndCurFocus;
|
|
|
|
if (idCurTab != cntFlags.idOldTab) {
|
|
CWaitCursor cursor;
|
|
hwndCurFocus = GetFocus();
|
|
if (hwndTabSub == hwndFindTab)
|
|
SendMessage(hwndTabSub, WM_CLOSE, 0, 0);
|
|
else {
|
|
ASSERT(IsValidWindow(hwndTabSub));
|
|
DestroyWindow(hwndTabSub);
|
|
}
|
|
SetWindowText(GetDlgItem(GetParent(hwndTab), IDOK),
|
|
GetStringResource(sidDisplay));
|
|
hwndTabSub = CreateTabChild(idCurTab, GetParent(hwndTab));
|
|
|
|
if (!hwndTabSub) {
|
|
hwndTabSub = CreateTabChild(aTabIds[0], GetParent(hwndTab));
|
|
TabCtrl_SetCurSel(hwndTab, 0);
|
|
cntFlags.idOldTab = aTabIds[0];
|
|
}
|
|
else
|
|
cntFlags.idOldTab = idCurTab;
|
|
// If the focus was on the tab control, keep the focus there.
|
|
SetFocus((hwndCurFocus == hwndTab) ? hwndTab : hwndTabSub);
|
|
InvalidateRect(hwndTabSub, NULL, TRUE);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: TmpCleanup
|
|
|
|
PURPOSE: Cleanup any temporary files left around after a <gasp> crash
|
|
|
|
PARAMETERS:
|
|
void
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
02-Oct-1994 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
extern "C" const char txtTmpPrefix[]; // "~wh";
|
|
|
|
extern "C" void STDCALL TmpCleanup(void)
|
|
{
|
|
char szTmpName[MAX_PATH];
|
|
|
|
if (!hfsGid)
|
|
return; // don't do this if we're creating a .gid file
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
if (i == 0)
|
|
GetTempPath(sizeof(szTmpName), szTmpName);
|
|
else {
|
|
GetWindowsDirectory(szTmpName, MAX_PATH);
|
|
AddTrailingBackslash(szTmpName);
|
|
}
|
|
|
|
{
|
|
CStr cszPath(szTmpName);
|
|
|
|
// BUGBUG: temporary hack for full-text search
|
|
|
|
strcat(szTmpName, (i == 0 ? txtTmpPrefix : "~ft"));
|
|
strcat(szTmpName, "*.tmp");
|
|
|
|
WIN32_FIND_DATA fileinfo;
|
|
HANDLE hfind = FindFirstFile(szTmpName, &fileinfo);
|
|
|
|
if (hfind != INVALID_HANDLE_VALUE) {
|
|
do {
|
|
strcpy(szTmpName, cszPath.psz);
|
|
strcat(szTmpName, fileinfo.cFileName);
|
|
DeleteFile(szTmpName);
|
|
} while (FindNextFile(hfind, &fileinfo));
|
|
FindClose(hfind);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: IsSearchAvailable
|
|
|
|
PURPOSE: Determine if ftssrch.dll is available
|
|
|
|
PARAMETERS:
|
|
void
|
|
|
|
RETURNS: TRUE if the dll is found, else FALSE
|
|
|
|
COMMENTS:
|
|
Does not determine if the dll can actually be loaded.
|
|
|
|
MODIFICATION DATES:
|
|
11-Oct-1994 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
BOOL STDCALL IsSearchAvailable(void)
|
|
{
|
|
static BOOL fSearchAvailable = -1;
|
|
|
|
// Have we already queried?
|
|
|
|
if (fSearchAvailable == TRUE)
|
|
return TRUE;
|
|
else if (fSearchAvailable == FALSE)
|
|
return FALSE;
|
|
|
|
FM fm = FmNewExistSzDir(GetStringResource(sidFtsDll),
|
|
DIR_PATH | DIR_CURRENT);
|
|
fSearchAvailable = (fm ? TRUE : FALSE);
|
|
if (fm)
|
|
FreeLh((HGLOBAL) fm);
|
|
return fSearchAvailable;
|
|
}
|
|
|
|
static void STDCALL AddTab(TC_ITEM* pti, TAB_ID tab, PSTR pszName, HWND hwndTabs)
|
|
{
|
|
aTabIds[pSrchClass->cTabs] = tab;
|
|
pti->pszText = pszName;
|
|
TabCtrl_InsertItem(hwndTabs, pSrchClass->cTabs, pti);
|
|
pSrchClass->cTabs++;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: GetTabPosition
|
|
|
|
PURPOSE: Given a Tab Id, return the tab position
|
|
|
|
PARAMETERS:
|
|
id
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
11-Oct-1994 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
extern "C" int STDCALL GetTabPosition(int id)
|
|
{
|
|
for (int i = 0; i < MAX_IDTABS; i++) {
|
|
if (aTabIds[i] == id)
|
|
return i;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
CEnable::CEnable(HWND hwnd)
|
|
{
|
|
hwndEnable = hwnd;
|
|
if (IsValidWindow(hwnd))
|
|
EnableWindow(hwnd, FALSE);
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
CEnable::~CEnable()
|
|
{
|
|
if (hwndEnable)
|
|
EnableWindow(hwndEnable, TRUE);
|
|
}
|
|
#endif
|
|
|
|
#ifdef _PRIVATE
|
|
|
|
CTimeReport::CTimeReport(PCSTR pszMessage)
|
|
{
|
|
pszMsg = lcStrDup(pszMessage ? pszMessage : "Elapsed time:");
|
|
|
|
oldTickCount = GetTickCount();
|
|
}
|
|
|
|
CTimeReport::~CTimeReport()
|
|
{
|
|
DWORD dwActualTime = (GetTickCount() - oldTickCount);
|
|
DWORD dwFinalTime = dwActualTime / 1000;
|
|
|
|
int minutes = (dwFinalTime / 60);
|
|
int seconds = (dwFinalTime - (minutes * 60L));
|
|
int tenths = (dwActualTime - (dwFinalTime * 1000)) / 100;
|
|
const PSTR szPlural = "s";
|
|
char szParentString[256];
|
|
wsprintf(szParentString, "%s %s minute%s, %d.%d second%s\r\n",
|
|
pszMsg,
|
|
FormatNumber(minutes), ((minutes == 1) ? "" : szPlural),
|
|
seconds, tenths, ((seconds == 1) ? "" : szPlural));
|
|
lcFree(pszMsg);
|
|
SendStringToParent(szParentString);
|
|
}
|
|
|
|
// The following two functions give .c modules access to the above class
|
|
|
|
static CTimeReport* pTimeReport;
|
|
|
|
extern "C" BOOL STDCALL CreateTimeReport(PCSTR pszMessage)
|
|
{
|
|
if (!pTimeReport) {
|
|
pTimeReport = new CTimeReport(pszMessage);
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE; // can only have on C-invoked time report class
|
|
}
|
|
|
|
extern "C" void STDCALL EndTimeReport(void)
|
|
{
|
|
if (pTimeReport) {
|
|
delete pTimeReport;
|
|
pTimeReport = NULL;
|
|
}
|
|
};
|
|
|
|
#endif // _PRIVATE
|
|
|
|
#ifdef _DEBUG
|
|
void STDCALL ShowCntFlags()
|
|
{
|
|
char szMsg[512];
|
|
|
|
if (cntFlags.flags & GID_CONTENTS)
|
|
SendStringToParent("GID_CONTENTS\r\n");
|
|
if (cntFlags.flags & GID_INDEX)
|
|
SendStringToParent("GID_INDEX\r\n");
|
|
if (cntFlags.flags & GID_GINDEX)
|
|
SendStringToParent("GID_GINDEX\r\n");
|
|
if (cntFlags.flags & GID_FTS)
|
|
SendStringToParent("GID_FTS\r\n");
|
|
if (cntFlags.flags & GID_NO_INDEX)
|
|
SendStringToParent("GID_NO_INDEX\r\n");
|
|
if (cntFlags.flags & GID_NO_CNT)
|
|
SendStringToParent("GID_NO_CNT\r\n");
|
|
|
|
wsprintf(szMsg, "%u items\r\n%u tabs\r\nLast tab is %u\r\n",
|
|
cntFlags.cCntItems, cntFlags.cTabs, cntFlags.idOldTab);
|
|
SendStringToParent(szMsg);
|
|
}
|
|
#endif
|