2882 lines
98 KiB
C
Raw Normal View History

2001-01-01 00:00:00 +01:00
#ifdef HEADER
/******************************************************************************\
* Copyright: (c) Microsoft Corporation - 1993 - All Rights Reserved
********************************************************************************
*
* Filename: HDXDLL.C
* Purpose: Help Index Outline Custom Control
*
* Notes: The dialog editor interface has changed since Win 3.0.
* Examine NT CUSTCNTL.H to get an idea of the new interface.
*
* History:
* Date by description
* ---- -- -----------
* 11/08/93 chauv added GetRegistryString() - this should be identical to
* the same function in contents.c
* 10/20/93 chauv added CallHelp() to support Viewer/WinHelp switching.
* This functionality is only for 16-bit platform.
* 32-bit platform will be supported when Viewer is 32-bit.
* 10/18/93 chauv added ExpandUptoLevel()
* 10/13/93 chauv used HDXFILEINFO to fix *.hdx data size bug
* 10/06/93 chauv added tchar.h and DBC-enable code
* 04/25/93 v-tkback created
*
\******************************************************************************/
#endif
/******************************************************************************\
* *
* Include Files
* *
\******************************************************************************/
#define ALLOCATE
#include "hdxdll.h"
#include <stdlib.h>
#include <string.h>
#include <windowsx.h>
#include <lzexpand.h>
#ifndef _WIN32
#include "viewer.h"
#endif
#include "resource.h"
#include "..\contents.h"
// ****************************************************************************
// local variables
//
static nWinHelp = 1; // default to WinHelp system
#ifdef _WIN32
#define VWR HANDLE
#endif
static VWR Vwr = NULL;
static HWND hWndHelpDlg = NULL;
static TCHAR szProduct[_MAX_FNAME] = _T("Product");
static TCHAR szBookset[_MAX_FNAME] = _T("");
static TCHAR szHelpPath[_MAX_PATH] = _T("");
static TCHAR szLocalHelpPath[_MAX_PATH] = _T("");
static TCHAR szRemoteHelpPath[_MAX_PATH] = _T("");
static TCHAR szHelpFile[_MAX_FNAME] = _T("");
static TCHAR szEmpty[] = _T("");
static BOOL bTroubleshoot = FALSE;
static HELPINDEXITEM LastHelpItem = {0};
static int nBitmapResource = IDB_OUTLINE;
/******************************************************************************\
* *
* Function Declarations
* *
\******************************************************************************/
DWORD GetRegistryString(LPCTSTR lpszSection, LPCTSTR lpszKey, LPCTSTR lpszDefault,
LPTSTR lpszReturnBuffer, DWORD cchReturnBuffer, LPCTSTR lpszFile);
static BOOL GetHelpItemData (HELPINDEXITEM FAR *, HELPINDEX FAR *, LONG, BOOL);
static BOOL GetHelpItemExpanFlag (HELPINDEX FAR *, LONG);
static void SetHelpItemExpanFlag (HELPINDEX FAR *, LONG, BOOL);
static LONG GetHelpItemLinesMap (HELPINDEX FAR *, LONG);
static void SetHelpItemLinesMap (HELPINDEX FAR *, LONG, LONG);
static HELPINDEXITEM FAR * GetCachedHelpItem (HELPINDEX FAR *, LONG);
static ITEM_RW_OVERLAY FAR * GetHelpItemRWOverlay (HELPINDEX FAR *, LONG);
static void FAR * GAllocLock (DWORD, BOOL);
static BOOL ExpandHelpTopic(LPHELPINDEX lpHelpIndex, LPHELPINDEXITEM lpHelpItem);
BOOL WriteRegistryString(LPCTSTR lpszSection, LPCTSTR lpszKey, LPCTSTR lpszString, LPCTSTR lpszFile);
void ProcessHelpSearch(HWND hWnd, LPHELPINDEX lpHelpIndex, LONG nFilePos, UINT nListPos );
static long GetValidHelpFilePos(HELPINDEXITEM FAR * lphelpitem, LPHELPINDEX lpHelpIndex, long pos);
static BOOL IsQuickReference(void);
static void ChangeBitmap(LPHELPINDEX lpHelpIndex, int nBitmapResource);
/******************************************************************************\
* *
* mprintf() - printfs out formatted text to a message box.
* *
\******************************************************************************/
int
mprintf( UINT uStyle, UINT id, const TCHAR *pszFormat, ... )
{
TCHAR szBuffer[512];
TCHAR szFormat[512];
va_list marker; // this is added to make it work with ALPHA
// if id is zero, use first char string as format
if ( id && LoadString(hInstance, id, szFormat, sizeof(szFormat)) )
{
va_start(marker,id);
_vstprintf(szBuffer, szFormat, marker );
//_vstprintf(szBuffer, szFormat, (va_list)(&pszFormat) );
}
else
{
va_start(marker,pszFormat);
_vstprintf(szBuffer, pszFormat, marker );
//_vstprintf(szBuffer, pszFormat, (va_list)(&pszFormat+1) );
}
va_end(marker);
// the following messagebox must use NULL as the handle or it's going to bomb
// when GetFocus() happens to return a handle to a timer app which shuts down
// after a while and in turn destroys this messagebox with it.
return MessageBox( NULL, szBuffer, szHelpIndexClass, uStyle );
}
/******************************************************************************\
*
* FUNCTION: HelpIndexDlgProc (standard dialog procedure INPUTS/RETURNS)
*
* COMMENTS: This dialog comes up in response to a user requesting to
* modify the control style. This sample allows for changing
* the control's text, and this is done by modifying the
* CCSTYLE (32-bit) or CTLSTYLE (16-bit) structure pointed at by "gpccs"
* (a pointer that was passed to us by dlgedit).
*
\******************************************************************************/
PC_WNDPROCRV CALLBACK PC_EXPORT
HelpIndexDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch (msg)
{
case WM_INITDIALOG :
{
Vwr = NULL; // clear Viewer handle
#ifdef _WIN32
if (gpccs->flStyle & HS_LINES)
#else
if (gpccs->dwStyle & HS_LINES)
#endif
CheckDlgButton( hDlg, IDD_LINES, TRUE );
break;
}
case WM_COMMAND:
{
switch( LOWORD(wParam) )
{
case IDD_LINES:
{
#ifdef _WIN32
if ( IsDlgButtonChecked( hDlg, IDD_LINES ) )
gpccs->flStyle |= HS_LINES;
else
gpccs->flStyle &= ~HS_LINES;
#else
if ( IsDlgButtonChecked( hDlg, IDD_LINES ) )
gpccs->dwStyle |= HS_LINES;
else
gpccs->dwStyle &= ~HS_LINES;
#endif
break;
}
case IDOK:
case IDCANCEL:
{
EndDialog( hDlg, LOWORD(wParam) == IDOK );
break;
}
}
break;
}
default:
return FALSE;
}
return TRUE;
}
void CALLBACK PC_EXPORT SetViewerHandle(VWR vwr)
{
Vwr = vwr;
}
void CALLBACK PC_EXPORT GetViewerHandle(VWR FAR *pvwr)
{
*pvwr = Vwr;
}
/******************************************************************************\
*
* FUNCTION: HelpIndexStyle
*
* INPUTS: hWndParent - handle of parent window (dialog editor)
* pccs - pointer to a CCSTYLE structure
*
* RETURNS: TRUE if success,
* FALSE if error occured
*
* LOCAL VARS: rc - return code from DialogBox
*
\******************************************************************************/
BOOL CALLBACK PC_EXPORT
#ifdef _WIN32
HelpIndexStyle( HWND hWndParent, HANDLE hCtlStyle )
#else
HelpIndexStyle( HWND hWndParent, HANDLE hCtlStyle, LPFNSTRTOID lpfnStrToId,
LPFNIDTOSTR lpfnIdToStr )
#endif
{
/*******************/
/* Local Variables */
/*******************/
BOOL bComplete = FALSE;
DLGPROC dlgprocInst = NULL;
/**************************************************************/
/* Save the pointer to custom control style passed by DLGEDIT */
/**************************************************************/
gpccs = (PC_LPCCSTYLE) GlobalLock( hCtlStyle );
/********************************/
/* Try to create the Dialog Box */
/********************************/
dlgprocInst = (DLGPROC)MakeProcInstance( HelpIndexDlgProc, hInstance );
if ((gpccs == NULL) || hWndParent)
{
if ((bComplete = DialogBox( hInstance, _TEXT("HelpIndexStyle"), hWndParent, dlgprocInst)) == -1)
{
/***********************************/
/* Could not create the dialog box */
/***********************************/
mprintf( MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL, IDS_ERROR_HELPINDEXDLG, szNull);
//_TEXT("HelpIndexStyle(): DialogBox() failed = %d"), bComplete );
bComplete = FALSE;
}
}
FreeProcInstance( dlgprocInst );
if (gpccs != NULL)
{
GlobalUnlock( hCtlStyle );
}
/*********************/
/* Return completion */
/*********************/
return bComplete;
}
/******************************************************************************\
*
* FUNCTION: HelpIndexFlags
*
* INPUTS: dwFlags - style flag combo to be xlated to .rc text
* lpStyle - buffer to receive the translated text
* wMaxString - size of the destination buffer in bytes
*
* RETURNS: length of string copied to caller's buffer
* zero if error occured
*
\******************************************************************************/
WORD CALLBACK PC_EXPORT
HelpIndexFlags( DWORD dwFlags, LPSTR lpStyle, WORD wMaxString )
{
WORD wRet = 0;
WORD wStrLen;
LPSTR szLines = _TEXT("HS_LINES");
LPSTR szNoLines = _TEXT(" ");
if ( (dwFlags & HS_LINES) && ( ( wStrLen = _ftcslen( szLines ) ) < wMaxString ) )
{
_ftcscpy( lpStyle, szLines );
wRet = wStrLen;
}
else if ( !(dwFlags & HS_LINES )
&& ( ( wStrLen = _ftcslen( szNoLines ) ) < wMaxString ) )
{
_ftcscpy( lpStyle, szLines );
wRet = wStrLen;
}
return( wRet );
}
/******************************************************************************\
* *
* RGBtoBGR
* *
\******************************************************************************/
DWORD
RGBtoBGR( DWORD rgb )
{
return( RGB( GetBValue(rgb), GetGValue(rgb), GetRValue(rgb) ) );
}
/******************************************************************************\
* *
* FindBitmap
* *
\******************************************************************************/
HBITMAP FindBitmap(LPHELPINDEX lpHelpIndex, int nResource)
{
HBITMAP hBitmap = NULL;
HRSRC hRes = NULL;
LPBITMAPINFOHEADER lptr, lpBitmapInfo = NULL;
HGLOBAL hMem = NULL;
DWORD dw;
#ifdef _WIN32
while (1)
{
if ( hRes = FindResource(hInstance, MAKEINTRESOURCE(nResource), RT_BITMAP) )
{
dw = SizeofResource(hInstance, hRes);
if ( hRes = LoadResource(hInstance, hRes) )
{
// for 32-bit, we have to copy the loaded resource to a temp memory block
// so we can write to it. LockResource() is readonly memory.
if ( hMem = GlobalAlloc(GMEM_FIXED, dw) )
{
if ( lpBitmapInfo = GlobalLock(hMem) )
{
if ( lptr = (LPBITMAPINFOHEADER)LockResource(hRes) )
{
if ( memcpy(lpBitmapInfo, lptr, dw) )
{
// make sure to unlock and free hMem before this function returns to caller.
UnlockResource(hRes);
FreeResource(hRes);
hRes = NULL;
break;
}
else
{
lpBitmapInfo = NULL;
GlobalUnlock(hMem);
GlobalFree(hMem);
hMem = NULL;
UnlockResource(hRes);
FreeResource(hRes);
hRes = 0;
OutputDebugString("FindBitmap(): failed memcpy()\n");
break;
}
}
else
{
UnlockResource(hRes);
FreeResource(hRes);
hRes = NULL;
GlobalUnlock(hMem);
GlobalFree(hMem);
hMem = NULL;
OutputDebugString("FindBitmap(): Can't lock bitmap resource\n");
}
}
else
{
UnlockResource(hRes);
FreeResource(hRes);
hRes = NULL;
GlobalFree(hMem);
hMem = NULL;
OutputDebugString("FindBitmap(): Can't lock global memory to copy bitmap resource.\n");
}
}
else
{
UnlockResource(hRes);
FreeResource(hRes);
hRes = NULL;
OutputDebugString("FindBitmap(): Can't allocate tmp memory to copy bitmap resource.\n");
}
}
else
OutputDebugString("FindBitmap(): Can't load bitmap resource.\n");
}
else
OutputDebugString("FindBitmap(): Can't find bitmap resource.\n");
// used while(1) loop so I only have to issue error messagebox once here.
mprintf(MB_OK, IDS_ERROR_FINDBITMAP, szNull);
break;
}
if (lpBitmapInfo)
{
HDC hDC;
DWORD *lpColorTable = (DWORD *)(lpBitmapInfo + 1);
LPBYTE lpPixels = (LPSTR)( lpColorTable + 16 ); // 16 Color Bitmap!!
int nBackgroundColor = (*lpPixels & 0xF0) >> 4; // 16 Color Bitmap!!
lpColorTable[nBackgroundColor] = RGBtoBGR(GetSysColor(COLOR_WINDOW));
if ( hDC = GetDC(NULL) )
{
hBitmap = CreateDIBitmap(hDC, lpBitmapInfo, (DWORD)CBM_INIT, lpPixels,
(LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS);
if (hBitmap)
{
lpHelpIndex->nBitmapHeight = (int)lpBitmapInfo->biHeight / BITMAP_ROWS;
lpHelpIndex->nBitmapWidth = (int)lpBitmapInfo->biWidth / BITMAP_COLS;
}
else
{
OutputDebugString("FindBitmap(): failed CreateDIBitmap().\n");
mprintf(MB_OK, IDS_ERROR_FINDBITMAP, szNull);
}
ReleaseDC( NULL, hDC );
}
else
{
OutputDebugString("FindBitmap(): Failed GetDC().\n");
mprintf(MB_OK, IDS_ERROR_FINDBITMAP, szNull);
}
// unlock Temporary memory and free it
if (hMem)
{
GlobalUnlock(hMem);
GlobalFree(hMem);
hMem = NULL;
}
}
#else
if ( hRes = LoadResource( hInstance,
FindResource( hInstance, MAKEINTRESOURCE( nResource ), RT_BITMAP ) ) )
{
LPBITMAPFILEHEADER lpBitmapFileHeader;
LPBITMAPINFOHEADER lpBitmapInfo;
if ( lpBitmapInfo = (LPBITMAPINFOHEADER)LockResource( hRes ) )
//if ( lpBitmapFileHeader = (LPBITMAPFILEHEADER)LockResource( hRes ) )
{
HDC hDC;
//LPBITMAPINFOHEADER lpBitmapInfo = (LPBITMAPINFOHEADER)(lpBitmapFileHeader + sizeof(BITMAPFILEHEADER));
DWORD *lpColorTable = (DWORD *)(lpBitmapInfo + 1);
LPBYTE lpPixels = (LPSTR)( lpColorTable + 16 ); // 16 Color Bitmap!!
int nBackgroundColor = (*lpPixels & 0xF0) >> 4; // 16 Color Bitmap!!
lpColorTable[nBackgroundColor] = RGBtoBGR( GetSysColor(COLOR_WINDOW) );
if ( hDC = GetDC(NULL) )
{
hBitmap = CreateDIBitmap(hDC, lpBitmapInfo, (DWORD)CBM_INIT, lpPixels,
(LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS);
if (hBitmap)
{
lpHelpIndex->nBitmapHeight = (int)lpBitmapInfo->biHeight / BITMAP_ROWS;
lpHelpIndex->nBitmapWidth = (int)lpBitmapInfo->biWidth / BITMAP_COLS;
}
else
mprintf(MB_OK, IDS_ERROR_DRAWBITMAP, szNull);
//_TEXT("FindBitmap(%d): CreateDIBitmap() Failed!"), nResource );
ReleaseDC( NULL, hDC );
}
else
mprintf(MB_OK, IDS_ERROR_GETDC, szNull);
//_TEXT("FindBitmap(%d): GetDC(NULL) Failed!"), nResource );
UnlockResource( hRes );
}
else
mprintf(MB_OK, IDS_ERROR_LOCKRESOURCE, szNull);
//_TEXT("FindBitmap(): LoadResource( %d, RT_BITMAP ) Failed!"), nResource );
FreeResource( hRes );
}
else
mprintf(MB_OK, IDS_ERROR_LOADBITMAP, szNull);
//_TEXT("FindBitmap(): LoadResource( %d, RT_BITMAP ) Failed!"), nResource );
#endif
return hBitmap;
}
/******************************************************************************\
* *
* DestroyHelpIndex()
* *
\******************************************************************************/
LPHELPINDEX DestroyHelpIndex( LPHELPINDEX lpHelpIndex )
{
HGLOBAL hGlobal;
if ( lpHelpIndex )
{
if ( lpHelpIndex->hfileIndex )
{
LZClose( lpHelpIndex->hfileIndex );
lpHelpIndex->hfileIndex = (HFILE)NULL;
}
if ( lpHelpIndex->pIndexItemCache )
{
if (hGlobal = GlobalPtrHandle(lpHelpIndex->pIndexItemCache))
{
GlobalUnlock(hGlobal);
GlobalFree(hGlobal);
lpHelpIndex->pIndexItemCache = NULL;
}
}
if ( lpHelpIndex->pIndexRWOverlay )
{
if (hGlobal = GlobalPtrHandle(lpHelpIndex->pIndexRWOverlay))
{
GlobalUnlock(hGlobal);
GlobalFree(hGlobal);
lpHelpIndex->pIndexRWOverlay = NULL;
}
}
lpHelpIndex->nHdrBytesCt = 0;
lpHelpIndex->nHelpItemCt = 0;
if (lpHelpIndex->hdcBitmaps)
{
if (lpHelpIndex->hbmDefault)
SelectObject(lpHelpIndex->hdcBitmaps, lpHelpIndex->hbmDefault);
DeleteDC(lpHelpIndex->hdcBitmaps);
lpHelpIndex->hdcBitmaps = NULL;
}
if ( lpHelpIndex->hbmBitmaps )
{
DeleteObject( lpHelpIndex->hbmBitmaps );
lpHelpIndex->hbmBitmaps = NULL;
}
if ( lpHelpIndex->hListbox )
{
DestroyWindow( (HWND)lpHelpIndex->hListbox );
lpHelpIndex->hListbox = NULL;
}
if (hGlobal = GlobalPtrHandle(lpHelpIndex))
{
GlobalUnlock(hGlobal);
GlobalFree(hGlobal);
}
}
return NULL;
}
//******************************************************************************
static void ChangeBitmap(LPHELPINDEX lpHelpIndex, int nBitmapResource)
{
HDC hDC;
if ( hDC = GetDC(NULL) )
{
if ( lpHelpIndex->hdcBitmaps)
{
HBITMAP hBitmap;
if ( hBitmap = FindBitmap(lpHelpIndex, nBitmapResource) )
{
DeleteObject((HBITMAP)lpHelpIndex->hbmBitmaps);
lpHelpIndex->hbmBitmaps = hBitmap;
lpHelpIndex->hbmDefault = SelectObject(lpHelpIndex->hdcBitmaps, lpHelpIndex->hbmBitmaps);
// force redraw just to make sure
//InvalidateRect(lpHelpIndex->hListbox, NULL, TRUE);
}
}
else
mprintf(MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL, IDS_ERROR_DRAWBITMAP, szNull);
ReleaseDC(NULL, hDC);
}
else
mprintf(MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL, IDS_ERROR_GETDC, szNull);
}
/******************************************************************************\
* *
* BuildHelpIndex()
* *
\******************************************************************************/
LPHELPINDEX BuildHelpIndex( HWND hWnd )
{
BOOL bComplete = FALSE;
LPHELPINDEX lpHelpIndex = NULL;
HINSTANCE hinstClient = NULL;
if (hWnd)
{
#ifdef _WIN32
hinstClient = (HINSTANCE) GetWindowLong( hWnd, GWL_HINSTANCE );
#else
hinstClient = (HINSTANCE) GetWindowWord( hWnd, GWW_HINSTANCE );
#endif
if ( lpHelpIndex = (LPHELPINDEX)GAllocLock( sizeof(HELPINDEX), TRUE ) )
{
// [chauv] fixed uninitialize memory problem by calling GAllocLock(..,TRUE) to do zeroinit
lpHelpIndex->pIndexRWOverlay = (ITEM_RW_OVERLAY FAR *)GAllocLock(MAX_ITEM_OVERLAY_CT * sizeof(ITEM_RW_OVERLAY), TRUE);
if ( ( lpHelpIndex->pIndexRWOverlay )
&&
( lpHelpIndex->hListbox = CreateWindow( _TEXT("LISTBOX"), NULL,
WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_HSCROLL |
LBS_OWNERDRAWFIXED | LBS_WANTKEYBOARDINPUT |
LBS_NOTIFY | LBS_NOINTEGRALHEIGHT,
0, 0, 0, 0, hWnd, (HMENU)1, hinstClient, NULL ) )
)
{
HDC hDC;
if ( hDC = GetDC(NULL) )
{
if ( lpHelpIndex->hdcBitmaps = CreateCompatibleDC(hDC) )
{
lpHelpIndex->hbmDefault = 0;
if ( lpHelpIndex->hbmBitmaps = FindBitmap(lpHelpIndex, IDB_OUTLINE) )
{
lpHelpIndex->hbmDefault = SelectObject(lpHelpIndex->hdcBitmaps, lpHelpIndex->hbmBitmaps);
bComplete = TRUE;
}
}
else
mprintf(MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL, IDS_ERROR_DRAWBITMAP, szNull);
//_TEXT("HelpIndexWndProc(): GetCompatibleDC(\"ListBox\") failed!") );
ReleaseDC(NULL, hDC);
}
else
mprintf(MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL, IDS_ERROR_GETDC, szNull);
//_TEXT("HelpIndexWndProc(): GetDC(\"ListBox\") failed!") );
}
else
mprintf(MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL, IDS_ERROR_CREATELISTBOX, szNull);
//_TEXT("HelpIndexWndProc(): CreateWindow(\"ListBox\") failed!") );
}
else
mprintf(MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL, IDS_ERROR_LOCKHELPINDEX, szNull);
//_TEXT("HelpIndexWndProc(): GlobalAlloc() failed!") );
if ( !bComplete )
lpHelpIndex = DestroyHelpIndex( lpHelpIndex );
}
return lpHelpIndex;
}
/******************************************************************************\
* *
* FixupHelpIndexLines()
* *
\******************************************************************************/
void
FixupHelpIndexLines( LPHELPINDEX lpHelpIndex )
{
HCURSOR hOldCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) );
LONG nCurrPos;
HELPINDEXITEM helpitemCurr;
LONG nHelpLinesCurr;
LONG nHelpDepthNext;
LONG nHelpLinesNext;
nCurrPos = lpHelpIndex->nHelpItemCt - 1;
if (GetHelpItemData (&helpitemCurr, lpHelpIndex, nCurrPos, FALSE))
{
nHelpLinesCurr = 0;
SetHelpItemLinesMap( lpHelpIndex, nCurrPos, nHelpLinesCurr );
while ( --nCurrPos >= 0 )
{
nHelpDepthNext = helpitemCurr.nHelpDepth;
nHelpLinesNext = nHelpLinesCurr;
if (GetHelpItemData (&helpitemCurr, lpHelpIndex, nCurrPos, FALSE))
{
if ( helpitemCurr.nHelpDepth )
{
if ( helpitemCurr.nHelpDepth >= nHelpDepthNext )
nHelpLinesCurr |= (0x1 << (nHelpDepthNext-1));
else
nHelpLinesCurr &= ((0x1 << (helpitemCurr.nHelpDepth))-1);
}
else
nHelpLinesCurr = 0;
SetHelpItemLinesMap( lpHelpIndex, nCurrPos, nHelpLinesCurr );
}
else break;
}
}
SetCursor( hOldCursor );
}
/******************************************************************************\
* *
* LoadHelpIndexFile()
* *
\******************************************************************************/
BOOL
LoadHelpIndexFile( LPHELPINDEX lpHelpIndex, LPSTR lpszHelpIndexFile )
{
BOOL bComplete = FALSE;
HCURSOR hOldCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) );
HDXFILEINFO hdxFileInfo;
if ( ( lpHelpIndex->hfileIndex == (HFILE)NULL ) && EXISTS( lpszHelpIndexFile ) )
{
OFSTRUCT of;
UINT hInput;
if ( ( hInput = LZOpenFile(lpszHelpIndexFile, &of, OF_READ) ) != (UINT)-1)
{
if ( LZRead(hInput, (LPSTR)&hdxFileInfo, sizeof(hdxFileInfo)) )
{
if ( hdxFileInfo.size == (LONG)sizeof(HELPINDEXITEM) )
{
LONG nHelpIndex = LZSeek( hInput, 0, 2 ) - sizeof(HDXFILEINFO);
if ( nHelpIndex > 0 && !(nHelpIndex % sizeof(HELPINDEXITEM) ) )
{
lpHelpIndex->hfileIndex = hInput;
lpHelpIndex->nHdrBytesCt = sizeof (HDXFILEINFO);
lpHelpIndex->nHelpItemCt = nHelpIndex
/ sizeof(HELPINDEXITEM);
FixupHelpIndexLines( lpHelpIndex );
bComplete = TRUE;
}
else
mprintf(MB_OK, IDS_ERROR_BADDATASIZE,
//_TEXT("LoadHelpIndexFile(%s): Bad Data Size=%ld!"),
lpszHelpIndexFile, nHelpIndex);
}
else
mprintf(MB_OK, IDS_ERROR_BADRECORDSIZE,
//_TEXT("LoadHelpIndexFile(rsize=%d, %s): Bad Record Size=%d!"),
//sizeof(HELPINDEXITEM), lpszHelpIndexFile,
lpszHelpIndexFile, hdxFileInfo.size);
}
else
mprintf(MB_OK, IDS_ERROR_TRUNCATEINDEX,
//_TEXT("LoadHelpIndexFile(%s): Truncated Index File!"),
lpszHelpIndexFile );
}
else
mprintf(MB_OK, IDS_ERROR_OPENINDEXFILE,
// _TEXT("LoadHelpFile(%s): Cannot Open File!"),
lpszHelpIndexFile);
}
else
mprintf(MB_OK, IDS_ERROR_INDEXFILEMISSING,
//_TEXT("LoadHelpIndexFile(): File <%s> is missing!"),
lpszHelpIndexFile );
SetCursor( hOldCursor );
return bComplete;
}
/******************************************************************************\
* *
* SetFont()
* *
\******************************************************************************/
void SetFont(HFONT hFont, LPHELPINDEX lpHelpIndex)
{
HDC hDC;
if (lpHelpIndex->hListbox)
{
if ( hDC = GetDC(lpHelpIndex->hListbox) )
{
HFONT hFontOld;
if ( hFontOld = SelectObject(hDC, hFont) )
{
TEXTMETRIC tm;
GetTextMetrics(hDC, &tm);
lpHelpIndex->nTextHeight = tm.tmHeight;
lpHelpIndex->nLineHeight = max( lpHelpIndex->nTextHeight,
lpHelpIndex->nBitmapHeight );
SelectObject(hDC, hFontOld);
ListBox_SetItemHeight( lpHelpIndex->hListbox, 0,
lpHelpIndex->nLineHeight );
SetWindowFont(lpHelpIndex->hListbox, hFont, TRUE);
}
ReleaseDC(lpHelpIndex->hListbox, hDC);
}
else
mprintf(MB_OK, IDS_ERROR_GETDC, szNull);
//_TEXT("SetFont: GetDC(hListBox=%d) Failed!"), lpHelpIndex->hListbox );
}
}
/******************************************************************************\
* *
* FastRect()
* *
\******************************************************************************/
void
FastRect( HDC hDC, int x, int y, int cx, int cy )
{
RECT rc;
if (hDC)
{
rc.left = x;
rc.right = x+cx;
rc.top = y;
rc.bottom = y+cy;
ExtTextOut( hDC, x, y, ETO_OPAQUE, &rc, NULL, 0, NULL );
}
}
/******************************************************************************\
* *
* DrawItem()
* *
\******************************************************************************/
void DrawItem(LPHELPINDEX lpHelpIndex, LPDRAWITEMSTRUCT lpDrawItem)
{
HDC hDC;
/***************************************/
/* Make sure we have something to draw */
/***************************************/
if ( lpHelpIndex && lpDrawItem && ( lpDrawItem->itemID != (LONG)-1 ) &&
( (LONG) (lpDrawItem->itemData) < lpHelpIndex->nHelpItemCt ) )
{
LONG nFilePos = (LONG)lpDrawItem->itemData;
RECT rcDraw;
UINT xOrigin, yBitmap, xText, yText, yDrawing;
HELPINDEXITEM helpitem;
BOOL bExpandedItem = GetHelpItemExpanFlag (lpHelpIndex, nFilePos);
LONG nItemLinesMap = GetHelpItemLinesMap (lpHelpIndex, nFilePos);
if (GetHelpItemData (&helpitem, lpHelpIndex, nFilePos, TRUE))
{
if (hDC = lpDrawItem->hDC)
{
CopyRect( &rcDraw, &lpDrawItem->rcItem );
yDrawing = rcDraw.bottom - rcDraw.top;
xOrigin = rcDraw.left + (int)(helpitem.nHelpDepth * lpHelpIndex->nBitmapWidth) + LEFTMARGIN;
rcDraw.left = xOrigin + lpHelpIndex->nBitmapWidth;
yBitmap = rcDraw.top + yDrawing/2 - lpHelpIndex->nBitmapHeight/2;
yText = rcDraw.top + yDrawing/2 - lpHelpIndex->nTextHeight/2;
// don't need to check for ODA_FOCUS because we want to always draw
// the background and DrawFocusRect() to keep them in sync. This also
// cured the listbox scrolling problem.
//if ( lpDrawItem->itemAction != ODA_FOCUS )
if ( lpDrawItem->itemAction != ODA_SELECT )
{
int nRow = (int)(helpitem.nHelpDepth % BITMAP_ROWS);
int nColumn = helpitem.nHelpTopic ? SINGLE_PAGE : (bExpandedItem ? OPENED_BOOK : CLOSED_BOOK );
if ( helpitem.nHelpDepth &&
HAS_LINES( GetParent( lpHelpIndex->hListbox ) ) )
{
int nTempLevel, x, y;
DWORD dwBitMask = 0x00000001;
SetBkColor( hDC, GetSysColor( COLOR_WINDOWTEXT ) );
x = lpHelpIndex->nBitmapWidth/2 + LEFTMARGIN;
for( nTempLevel = 0;
nTempLevel < (int)helpitem.nHelpDepth;
nTempLevel++ )
{
if ( nItemLinesMap & dwBitMask )
FastRect( hDC, x, rcDraw.top, 1, yDrawing );
x += (int)(lpHelpIndex->nBitmapWidth);
dwBitMask <<= 1;
}
nTempLevel = (int)(helpitem.nHelpDepth)-1;
dwBitMask <<= 1;
x = (int)(nTempLevel * lpHelpIndex->nBitmapWidth +
lpHelpIndex->nBitmapWidth/2 + LEFTMARGIN);
y = rcDraw.bottom;
if ( !(nItemLinesMap & dwBitMask ) )
y -= lpHelpIndex->nLineHeight/2;
FastRect( hDC, x, rcDraw.top, 1, y - rcDraw.top );
FastRect( hDC, x, rcDraw.bottom - lpHelpIndex->nLineHeight/2,
lpHelpIndex->nBitmapWidth/2, 1 );
}
BitBlt( hDC, xOrigin, yBitmap,
(int)(lpHelpIndex->nBitmapWidth),
(int)(lpHelpIndex->nBitmapHeight),
lpHelpIndex->hdcBitmaps,
nColumn * (int)(lpHelpIndex->nBitmapWidth),
nRow * (int)(lpHelpIndex->nBitmapHeight),
SRCCOPY );
}
SetBkColor( hDC, GetSysColor( lpDrawItem->itemState & ODS_SELECTED ? COLOR_HIGHLIGHT : COLOR_WINDOW ) );
SetTextColor( hDC, GetSysColor( lpDrawItem->itemState & ODS_SELECTED ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT ) );
xText = rcDraw.left + 1;
if ( ExtTextOut( hDC, xText, yText, ETO_CLIPPED | ETO_OPAQUE,
&rcDraw, helpitem.szHelpTopic,
_ftcslen( helpitem.szHelpTopic ), NULL ) )
{
SIZE textsize;
if ( GetTextExtentPoint( hDC, helpitem.szHelpTopic,
_ftcslen( helpitem.szHelpTopic ),
&textsize ) &&
(xText + textsize.cx > lpHelpIndex->nMaxTextWidth) )
{
lpHelpIndex->nMaxTextWidth = xText + textsize.cx;
ListBox_SetHorizontalExtent( lpHelpIndex->hListbox,
lpHelpIndex->nMaxTextWidth );
}
}
if ( (lpDrawItem->itemState & ODS_FOCUS) &&
(lpDrawItem->itemAction != ODA_SELECT) )
DrawFocusRect( hDC, &rcDraw );
}
}
}
}
/******************************************************************************\
* *
* ShowExpanded()
* *
\******************************************************************************/
void ShowExpanded( LPHELPINDEX lpHelpIndex, UINT nMaxLevel )
{
HCURSOR hOldCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) );
if ( lpHelpIndex )
{
HWND hListbox = lpHelpIndex->hListbox;
LONG nPos = 0;
HELPINDEXITEM helpitem;
if (hListbox)
{
ListBox_ResetContent(hListbox);
if ( lpHelpIndex->nHelpItemCt > 0 )
{
SendMessage( hListbox, WM_SETREDRAW, 0, 0 );
do
{
if (GetHelpItemData(&helpitem, lpHelpIndex, nPos, FALSE))
{
SetHelpItemExpanFlag (lpHelpIndex, nPos, FALSE);
if ( (UINT)(helpitem.nHelpDepth) <= nMaxLevel )
{
if ( !helpitem.nHelpTopic && (UINT)(helpitem.nHelpDepth) < nMaxLevel )
SetHelpItemExpanFlag( lpHelpIndex, nPos, TRUE );
ListBox_AddString( hListbox, (LPVOID)nPos );
}
}
else break;
}
while( ++nPos < lpHelpIndex->nHelpItemCt );
SendMessage( hListbox, WM_SETREDRAW, 1, 0 );
InvalidateRect(hListbox, NULL, TRUE);
ListBox_SetCurSel( hListbox, 0 );
}
}
}
SetCursor( hOldCursor );
}
/******************************************************************************\
* *
* ExpandOneLevel()
* *
\******************************************************************************/
void ExpandOneLevel( LPHELPINDEX lpHelpIndex, LONG nFilePos, UINT nListPos )
{
HCURSOR hOldCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) );
HWND hListbox = lpHelpIndex->hListbox;
HELPINDEXITEM helpitem;
LONG nOrigDepth;
if (hListbox)
{
if (GetHelpItemData( &helpitem, lpHelpIndex, nFilePos, FALSE ))
{
SetHelpItemExpanFlag( lpHelpIndex, nFilePos, TRUE );
nOrigDepth = helpitem.nHelpDepth;
SendMessage( hListbox, WM_SETREDRAW, 0, 0 );
while( ++nFilePos < lpHelpIndex->nHelpItemCt )
{
if (GetHelpItemData( &helpitem, lpHelpIndex, nFilePos, FALSE ))
{
if ( helpitem.nHelpDepth > nOrigDepth )
{
if ( helpitem.nHelpDepth-1 == nOrigDepth )
ListBox_InsertString( hListbox, ++nListPos, (LPVOID)nFilePos );
}
else
break;
}
else break;
}
SendMessage( hListbox, WM_SETREDRAW, 1, 0 );
InvalidateRect(hListbox, NULL, FALSE);
}
}
SetCursor( hOldCursor );
}
// ***************************************************************************
// ExpandUptoLevel(lpHelpIndex, nLevel)
//
// purpose: call this function to expand content listbox to a certain level.
// Level must be greater than 1 to be effective since level 1 is
// the lowest and is the default level. One can do an expand ALL
// by calling this function with a very high level number.
void ExpandUptoLevel(LPHELPINDEX lpHelpIndex, LONG nLevel)
{
HCURSOR hOldCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) );
HWND hListbox = lpHelpIndex->hListbox;
HELPINDEXITEM helpitem;
LONG nCount = 0;
UINT nListPos = 0;
// just make sure and don't waste time here.
if (nLevel < 1)
return;
if (hListbox)
{
// reset listbox content first
ListBox_ResetContent( hListbox );
SendMessage( hListbox, WM_SETREDRAW, 0, 0 );
while( nCount <= lpHelpIndex->nHelpItemCt )
{
if (GetHelpItemData( &helpitem, lpHelpIndex, nCount, FALSE ))
{
// only expand if file position is less than or equal to the desired level
if ( helpitem.nHelpDepth < nLevel )
{
ListBox_InsertString( hListbox, nListPos++, (LPVOID)nCount );
// set expansion flag if it's level is one higher than the lowest expanded level
if (helpitem.nHelpDepth < nLevel-1)
SetHelpItemExpanFlag( lpHelpIndex, nCount, TRUE );
}
// next position
nCount++;
}
else break;
}
SendMessage( hListbox, WM_SETREDRAW, 1, 0 );
InvalidateRect(hListbox, NULL, FALSE);
ListBox_SetCurSel( hListbox, 0 );
}
SetCursor( hOldCursor );
}
/******************************************************************************\
* *
* CollapseOneLevel()
* *
\******************************************************************************/
void
CollapseOneLevel( LPHELPINDEX lpHelpIndex, LONG nFilePos, UINT nListPos )
{
HCURSOR hOldCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) );
HWND hListbox = lpHelpIndex->hListbox;
HELPINDEXITEM helpitem;
LONG nOrigDepth;
if (hListbox)
{
if (GetHelpItemData( &helpitem, lpHelpIndex, nFilePos, FALSE ))
{
nOrigDepth = helpitem.nHelpDepth;
SetHelpItemExpanFlag ( lpHelpIndex, nFilePos, FALSE );
++nListPos;
SendMessage( hListbox, WM_SETREDRAW, 0, 0 );
while( (nFilePos = (LONG)ListBox_GetItemData( hListbox, nListPos )) != LB_ERR )
{
if (GetHelpItemData( &helpitem, lpHelpIndex, nFilePos, FALSE ))
{
if ( helpitem.nHelpDepth > nOrigDepth )
{
if ( helpitem.nHelpTopic == 0 )
SetHelpItemExpanFlag( lpHelpIndex, nFilePos, FALSE );
ListBox_DeleteString( hListbox, nListPos );
}
else
break;
}
else break;
}
SendMessage( hListbox, WM_SETREDRAW, 1, 0 );
InvalidateRect(hListbox, NULL, TRUE);
}
}
SetCursor( hOldCursor );
}
// *****************************************************************************
LRESULT CALLBACK PC_EXPORT
HelpDirDlgProc(HWND hDlg, UINT message, WPARAM uParam, LPARAM lParam)
{
TCHAR szTemp[MAX_PATH];
TCHAR szBuf[MAX_PATH];
switch (message)
{
case WM_INITDIALOG:
hWndHelpDlg = hDlg;
GetDlgItemText(hDlg, IDC_HELPDLG_MSG, szTemp, sizeof(szTemp));
wsprintf(szBuf, szTemp, szHelpFile);
SetDlgItemText(hDlg, IDC_HELPDLG_MSG, szBuf);
SetDlgItemText(hDlg, IDC_LOCALHELP, szLocalHelpPath);
SetDlgItemText(hDlg, IDC_REMOTEHELP, szRemoteHelpPath);
SetFocus(GetDlgItem(hDlg, IDC_LOCALHELP));
return (TRUE);
case WM_COMMAND:
switch (LOWORD(uParam))
{
case IDOK:
GetDlgItemText(hDlg, IDC_LOCALHELP, szLocalHelpPath, sizeof(szLocalHelpPath));
GetDlgItemText(hDlg, IDC_REMOTEHELP, szRemoteHelpPath, sizeof(szRemoteHelpPath));
EndDialog(hDlg, TRUE);
hWndHelpDlg = NULL;
return (TRUE);
case IDCANCEL:
EndDialog(hDlg, FALSE);
hWndHelpDlg = NULL;
return (TRUE);
}
return TRUE;
}
return (FALSE); // Didn't process the message
}
/******************************************************************************\
*
* FUNCTION: HelpLookup
*
* COMMENTS: This function performs the lookup of a help / contents file
* in the specified profile section (see the WM_SETTEXT handler)
* to locate the actual path to the file.
*
* NOTE: Filename is being retrieved from the registry only if lpName is empty.
* If it's not empty, just do the path search.
*
* RETURN: pointer to NULL if helpfile is not found in the registry
* or NULL if user cancels HelpDir dialog.
*
\******************************************************************************/
LPSTR
HelpLookup(HWND hWnd, LPHELPINDEX lpHelpIndex, LPCSTR lpName, LPCSTR lpKeyword )
{
TCHAR szSection[_MAX_FNAME];
TCHAR szBuf[_MAX_FNAME];
TCHAR szDrive[_MAX_DRIVE], szDir[_MAX_DIR];
TCHAR szPname[_MAX_FNAME], szExt[_MAX_EXT];
HWND hWndTmp;
//_splitpath( lpName, NULL, NULL, szSection, NULL );
// [chauv] can no longer use lpName here because we switched over to
// using Registry instead of private profile. Now, szProfile contains
// the section key name.
// ******** this block gets help filename
// NOTE: Filename is being retrieved from the registry only if lpName is empty.
// If it's not empty, just do the path search.
if ( *lpName == _T('\0') )
{
#ifdef _WIN32
wsprintf(szSection, "%s\\%s\\%s\\%s", szRegistryKey, szProduct, szContentsSection, lpHelpIndex->szProfile);
#else
wsprintf(szSection, "%s", szProduct);
#endif
GetRegistryString(szSection, lpKeyword, lpName, szHelpFile, sizeof(szHelpFile), lpHelpIndex->szProfile );
if (_tcscmp(szHelpFile, _TEXT("")) == 0)
{
#ifdef _WIN32
mprintf(MB_OK, IDS_ERROR_SECTION,
// _TEXT("Could not find section [%s], key \"%s\"."),
szSection, lpKeyword);
#else
mprintf( MB_OK, _TEXT("Could not find section [%s], key \"%s\", in %s."),
szSection, lpKeyword, lpHelpIndex->szProfile );
#endif
return szEmpty;
}
}
else
_tcscpy(szHelpFile, lpName);
// ******** this block gets help path
wsprintf(szSection, "%s\\%s\\%s", szRegistryKey, szProduct, szDirectoriesSection);
while (1)
{
FARPROC lpProcHelpDir;
BOOL rb;
int i;
DWORD dw;
// check for local help path first
i = 1;
if ( szLocalHelpPath[0] == _T('\0') )
{
wsprintf(szBuf, "%s%u", szLocalHelpKey, i++);
GetRegistryString(szSection, szBuf, szNull, szLocalHelpPath, sizeof(szPname), lpHelpIndex->szProfile);
}
_tcscpy(szPname, szLocalHelpPath);
while (1)
{
// see if the last occurance is a '\' and do appropriate appending.
// this code prevents the next line from stripping "c:\dir\subdir" to "c:\dir"
if (_tcsrchr(szPname, _T('\\')) == (szPname + _tcslen(szPname) - 1))
_tcscat(szPname, _T("x"));
else
_tcscat(szPname, _T("\\x"));
_splitpath(szPname, szDrive, szDir, NULL, NULL);
_splitpath(szHelpFile, NULL, NULL, szPname, szExt);
_makepath(szHelpPath, szDrive, szDir, szPname, szExt);
if (EXISTS(szHelpPath))
{
// when we write, we always write to "LocalHelp1" and "RemoteHelp1"
if (szLocalHelpPath[0])
WriteRegistryString(szSection, szLocalHelpKey1, szLocalHelpPath, lpHelpIndex->szProfile);
if (szRemoteHelpPath[0])
WriteRegistryString(szSection, szRemoteHelpKey1, szRemoteHelpPath, lpHelpIndex->szProfile);
return szHelpPath;
}
// loop thru "LocalHelp1", "LocalHelp2", etc...
wsprintf(szBuf, "%s%u", szLocalHelpKey, i++);
dw = GetRegistryString(szSection, szBuf, szNull, szPname, sizeof(szPname), lpHelpIndex->szProfile);
if ( dw != ERROR_SUCCESS )
break;
}
// failed local help path, now check for remote help path
i = 1;
if ( szRemoteHelpPath[0] == _T('\0') )
{
wsprintf(szBuf, "%s%u", szRemoteHelpKey, i++);
GetRegistryString(szSection, szBuf, szNull, szRemoteHelpPath, sizeof(szPname), lpHelpIndex->szProfile);
}
_tcscpy(szPname, szRemoteHelpPath);
while (1)
{
// see if the last occurance is a '\' and do appropriate appending.
// this code prevents the next line from stripping "c:\dir\subdir" to "c:\dir"
if (_tcsrchr(szPname, _T('\\')) == (szPname + _tcslen(szPname) - 1))
_tcscat(szPname, _T("x"));
else
_tcscat(szPname, _T("\\x"));
_splitpath(szPname, szDrive, szDir, NULL, NULL);
_splitpath(szHelpFile, NULL, NULL, szPname, szExt);
_makepath(szHelpPath, szDrive, szDir, szPname, szExt);
if (EXISTS(szHelpPath))
{
// when we write, we always write to "LocalHelp1" and "RemoteHelp1"
if (szLocalHelpPath[0])
WriteRegistryString(szSection, szLocalHelpKey1, szLocalHelpPath, lpHelpIndex->szProfile);
if (szRemoteHelpPath[0])
WriteRegistryString(szSection, szRemoteHelpKey1, szRemoteHelpPath, lpHelpIndex->szProfile);
return szHelpPath;
}
// now loop thru "RemoteHelp1", "RemoteHelp2", etc...
wsprintf(szBuf, "%s%u", szRemoteHelpKey, i++);
dw = GetRegistryString(szSection, szBuf, szNull, szPname, sizeof(szPname), lpHelpIndex->szProfile);
if ( dw != ERROR_SUCCESS )
break;
}
// **** if the dialogbox is already there, skip it.
if ( (hWndTmp = FindWindow(szDlgClass, szHelpDirDlgCaption)) && IsWindow(hWndTmp) )
return NULL;
// Always send parent a close last session message so last session and
// new session can't fight each other while Help Directory dialogbox is up.
if ((hWndTmp = GetParent(hWnd)) == NULL)
hWndTmp = hWnd;
else
SendMessage(hWndTmp, WM_COMMAND, IDW_CLOSELASTSESSION, 0L);
// none of above work ? ask thru dialogbox
if (hWndTmp)
{
lpProcHelpDir = MakeProcInstance((FARPROC)HelpDirDlgProc, hInstance);
rb = DialogBox(hInstance, MAKEINTRESOURCE(IDD_HELPDIRECTORY), hWndTmp, (DLGPROC)lpProcHelpDir);
FreeProcInstance(lpProcHelpDir);
if (rb == FALSE)
break;
}
else
break;
}
return NULL;
}
// *****************************************************************************
// CallHelp() is used to substitute for original WinHelp() so it can determine if
// WinHelp or Viewer is to be used. See help on WinHelp() for parameters details.
//
static BOOL CallHelp(HWND hWnd, LPSTR lpszHelpFile, UINT fuCommand, DWORD dwData)
{
TCHAR szCommand[_MAX_FNAME];
if (hWnd == NULL)
return FALSE;
#ifdef _WIN32
wsprintf(szCommand, _TEXT("JumpHash(qchPath, %u)"), dwData);
if (bTroubleshoot)
mprintf(MB_OK, 0, "%s - %s", szCommand, lpszHelpFile);
//return WinHelp(hWnd, (LPCSTR)lpszHelpFile, fuCommand, dwData);
WinHelp(hWnd, (LPCSTR)lpszHelpFile, HELP_FORCEFILE, 0L);
//WinHelp(hWnd, (LPCSTR)lpszHelpFile, HELP_CONTEXTPOPUP, 7L);
if (!WinHelp(hWnd, (LPCSTR)lpszHelpFile, HELP_COMMAND, (DWORD)((LPSTR)szCommand)))
{
// in case the help file is not opened or correct help file is loaded,
// we force that help file to be opened/loaded then try to jump to help topic again.
WinHelp(hWnd, (LPCSTR)lpszHelpFile, HELP_FORCEFILE, 0L);
WinHelp(hWnd, (LPCSTR)lpszHelpFile, HELP_COMMAND, (DWORD)((LPSTR)szCommand));
}
switch(fuCommand)
{
case HELP_SEARCH:
WinHelp(hWnd, (LPCSTR)lpszHelpFile, HELP_COMMAND, (DWORD)(LPSTR)("Search()"));
break;
case HELP_FTSEARCH:
WinHelp(hWnd, (LPCSTR)lpszHelpFile, HELP_COMMAND, (DWORD)(LPSTR)("ExecFullTextSearch(hwndApp,qchPath,`',`')"));
break;
}
return TRUE;
#else
if (nWinHelp)
return WinHelp(hWnd, (LPCSTR)lpszHelpFile, fuCommand, dwData);
else
{
//wsprintf(szCommand, _TEXT("JumpID(`%s',`%u')"), lpszHelpFile, dwData);
wsprintf(szCommand, _TEXT("JumpID(qchPath,`%u')"), dwData);
if ((Vwr = VwrCommand(Vwr, lpszHelpFile, szCommand, cmdoptNONE)) == NULL)
Vwr = VwrCommand(Vwr, lpszHelpFile, szCommand, cmdoptNONE);
return (BOOL)Vwr;
}
#endif
}
/******************************************************************************\
* *
* ProcessItem()
* *
\******************************************************************************/
void ProcessItem(HWND hWnd, LPHELPINDEX lpHelpIndex, LONG nFilePos, UINT nListPos )
{
HELPINDEXITEM helpitem;
if ( hWnd && lpHelpIndex && (nFilePos >= 0) && (nFilePos < lpHelpIndex->nHelpItemCt) && (nListPos >= 0) )
{
if (GetHelpItemData (&helpitem, lpHelpIndex, nFilePos, TRUE))
{
// update help topic for restore last topic feature
LastHelpItem = helpitem;
if ( helpitem.nHelpTopic )
{
LPSTR lpHelpFile;
lpHelpFile = HelpLookup(hWnd, lpHelpIndex, helpitem.szHelpFile, cszHLPKey);
// if lpHelpFile is NULL, the user cancelled the help lookup
// if lpHelpFile is pointed to a null string, can't find registry value but don't
// need to report error here because HelpLookup() already done so.
if (lpHelpFile && *lpHelpFile)
CallHelp( lpHelpIndex->hListbox, lpHelpFile, HELP_CONTEXT, helpitem.nHelpTopic);
//else if (*lpHelpFile == _T('\0'))
// mprintf( MB_OK, _TEXT("No Help Available on '%s'!"), helpitem.szHelpTopic );
}
else
{
if ( !GetHelpItemExpanFlag( lpHelpIndex, nFilePos ) )
ExpandOneLevel( lpHelpIndex, nFilePos, nListPos );
else
CollapseOneLevel( lpHelpIndex, nFilePos, nListPos );
}
}
}
}
/******************************************************************************\
*
* FUNCTION: HelpIndexWndProc (standard window procedure INPUTS/RETURNS)
*
* COMMENTS: This is the window procedure for our custom control. At
* creation we alloc a HELPINDEX struct, initialize it,
* and associate it with this particular control.
*
\******************************************************************************/
LRESULT CALLBACK PC_EXPORT
HelpIndexWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
/*******************/
/* Local Variables */
/*******************/
long lResult = 0;
LPHELPINDEX lpHelpIndex = GETHELPINDEX( hWnd );
/************************************/
/* Switch Based on the Message Type */
/************************************/
switch ( uMsg )
{
/****************************/
/* Window is being created! */
/****************************/
case WM_CREATE:
{
LPCREATESTRUCT lpCreate = (LPCREATESTRUCT)lParam;
/******************************************************/
/* WM_MEASUREITEM should have created this structure! */
/******************************************************/
if ( lpHelpIndex || ( lpHelpIndex = BuildHelpIndex( hWnd ) ) )
{
/*********************************/
/* Save the help index structure */
/*********************************/
SETHELPINDEX( hWnd, lpHelpIndex );
/****************************************/
/* Initialize the font to be something! */
/****************************************/
SetFont( GetStockObject(SYSTEM_FONT), lpHelpIndex );
/***********************************/
/* See if we got a index file name */
/***********************************/
//if ( lpCreate->lpszName && *lpCreate->lpszName )
if (0)
{
/****************************************/
/* Force the outline file to be loaded. */
/****************************************/
SetWindowText( hWnd, lpCreate->lpszName );
}
}
else
lResult = -1;
break;
}
/***********************************************************/
/* Set the invisible window title(VIEWER.INI Help Section) */
/***********************************************************/
case WM_SETTEXT:
{
BOOL bLoadedIndex = FALSE;
// mprintf( MB_OK, _TEXT("Got a WM_SETTEXT( %s )"), (LPSTR)lParam );
if ( lpHelpIndex && (LPSTR)lParam )
{
LPSTR lpszToken;
LPSTR lPtr;
if ( lpszToken = _ftcstok( (LPSTR)lParam, _TEXT("|") ) )
{
_ftcsnccpy( lpHelpIndex->szProfile, lpszToken,
sizeof(lpHelpIndex->szProfile) );
//if (lpszToken = _ftcstok( NULL, _TEXT("|") ) )
// bLoadedIndex = LoadHelpIndexFile( lpHelpIndex, HelpLookup( lpHelpIndex, lpszToken, _TEXT("Contents File") ) );
//else
// [chauv] it just doesn't make sense to have this "book|contents" argument
// If you can't find the book, warn the user the book is invalid.
lPtr = HelpLookup(hWnd, lpHelpIndex, szNull, cszHDXKey);
if ( lPtr && (*lPtr != _T('\0')) )
bLoadedIndex = LoadHelpIndexFile( lpHelpIndex, lPtr);
}
else
mprintf(MB_OK, IDS_ERROR_COMMAND, (LPSTR)lParam);
//_TEXT("Invalid command argument \"%s\"."), (LPSTR)lParam);
}
else
mprintf(MB_OK, IDS_ERROR_COMMAND, (LPSTR)lParam);
// _TEXT("Invalid command argument \"%s\"."), (LPSTR)lParam);
// check LastTopic... from registry
if ( bLoadedIndex )
{
TCHAR szSection[_MAX_FNAME];
TCHAR szBuffer[_MAX_FNAME];
wsprintf(szSection, _T("%s\\%s\\%s\\%s"), szRegistryKey, szProduct, szContentsSection, szBookset);
GetRegistryString(szSection, szTopicUse, _T("1"), szBuffer, sizeof(szBuffer), lpHelpIndex->szProfile);
if (szBuffer[0] == _T('1'))
{
GetRegistryString(szSection, szTopicID, szNull, szBuffer, sizeof(szBuffer), lpHelpIndex->szProfile);
LastHelpItem.nHelpTopic = atol(szBuffer);
GetRegistryString(szSection, szTopicHelpfile, szNull, LastHelpItem.szHelpFile, sizeof(LastHelpItem.szHelpFile), lpHelpIndex->szProfile);
GetRegistryString(szSection, szTopicTitle, szNull, LastHelpItem.szHelpTopic, sizeof(LastHelpItem.szHelpTopic), lpHelpIndex->szProfile);
if (!ExpandHelpTopic(lpHelpIndex, &LastHelpItem))
ShowExpanded(lpHelpIndex, 0);
}
else
ShowExpanded(lpHelpIndex, 0);
}
DefWindowProc( hWnd, uMsg, wParam, lParam );
break;
}
/********************************************/
/* Define which font to use in drawing text */
/********************************************/
case WM_SETFONT:
{
if ( lpHelpIndex && lpHelpIndex->hListbox )
SetFont( (HFONT)wParam, lpHelpIndex );
break;
}
/*************************************************/
/* Return the current height of each lisbox line */
/*************************************************/
case WM_MEASUREITEM:
{
LPMEASUREITEMSTRUCT lpMeasureItem = (LPMEASUREITEMSTRUCT)lParam;
/******************************************/
/* See if we have built a help index yet. */
/******************************************/
if ( lpHelpIndex )
{
/**********************************/
/* Return the listbox line height */
/**********************************/
lpMeasureItem->itemHeight = max( lpHelpIndex->nBitmapHeight,
lpHelpIndex->nTextHeight );
}
break;
}
/***********************************************/
/* Draw the requested item in the listbox line */
/***********************************************/
case WM_DRAWITEM:
{
if ( lpHelpIndex )
DrawItem( lpHelpIndex, (LPDRAWITEMSTRUCT)lParam );
break;
}
/***************************************/
/* Someone hit a key on a listbox item */
/***************************************/
case WM_VKEYTOITEM:
{
/******************************************************/
/* Pass the keystroke up a level for processing first */
/******************************************************/
if ( ( lResult = SendMessage( GetParent( hWnd ), uMsg,
wParam, lParam ) ) != -2 )
{
/*****************************************/
/* See if we have a help index structure */
/*****************************************/
if ( lpHelpIndex )
{
/*******************************************/
/* Get the current selection and item data */
/*******************************************/
UINT nItem = (UINT)(lResult >= 0 ? lResult :
ListBox_GetCurSel( lpHelpIndex->hListbox ));
LONG nPos = (LONG)
ListBox_GetItemData( lpHelpIndex->hListbox, nItem );
/***********************************************/
/* If we have item data, process the keystroke */
/***********************************************/
if ( nPos >= 0 )
{
HELPINDEXITEM helpitem;
if (!GetHelpItemData (&helpitem, lpHelpIndex, nPos, FALSE))
break;
/********************************************/
/* If a special keystroke, process the item */
/********************************************/
switch( LOWORD(wParam) )
{
/*******************************/
/* Was the left arrow pressed? */
/*******************************/
case VK_LEFT:
{
/********************************/
/* Find the parent of this item */
/********************************/
LONG nPosParent = 0;
LONG nPosCand = nPos - 1;
HELPINDEXITEM helpitemParent;
while ((nPosParent == 0) && ( nPosCand > 0 ))
{
if (GetHelpItemData(&helpitemParent, lpHelpIndex, nPosCand, FALSE))
{
if ( helpitemParent.nHelpDepth < helpitem.nHelpDepth )
nPosParent = nPosCand;
nPosCand--;
}
else break;
}
if (nPosParent == 0)
if (!GetHelpItemData (&helpitemParent, lpHelpIndex, 0, FALSE))
break;
/*******************************/
/* If open, collapse one level */
/*******************************/
if (GetHelpItemExpanFlag(lpHelpIndex, nPosParent ))
{
UINT nParent = ListBox_FindString(
lpHelpIndex->hListbox, 0,
(LPVOID)nPosParent );
if ( nParent != LB_ERR )
{
CollapseOneLevel( lpHelpIndex, nPosParent,
nParent );
ListBox_SetCurSel( lpHelpIndex->hListbox,
nParent );
}
}
lResult = -2; // We ate this keystroke!
break;
}
/************************************/
/* Was the right arrow key pressed? */
/************************************/
case VK_RIGHT:
{
/*********************************/
/* If not open, expand one level */
/*********************************/
if ( !helpitem.nHelpTopic &&
( !GetHelpItemExpanFlag(lpHelpIndex, nPos) ) )
{
ExpandOneLevel( lpHelpIndex, nPos, nItem );
ListBox_SetCurSel( lpHelpIndex->hListbox,
nItem + 1 );
}
lResult = -2; // We ate this keystroke!
break;
}
/*******************************/
/* Was the return key pressed? */
/*******************************/
case VK_SPACE:
case VK_RETURN:
{
/**********************************************/
/* Process the item like a mouse double click */
/**********************************************/
ProcessItem(hWnd, lpHelpIndex, nPos, nItem );
lResult = -2; // We ate this keystroke!
break;
}
}
}
// expand level needs to reset last topic Use flag
{
TCHAR szSection[_MAX_FNAME];
wsprintf(szSection, "%s\\%s\\%s\\%s", szRegistryKey, szProduct, szContentsSection, szBookset);
WriteRegistryString(szSection, szTopicUse, _T("1"), lpHelpIndex->szProfile);
}
}
}
break;
}
/***********************************/
/* Pass the focus onto the listbox */
/***********************************/
case WM_SETFOCUS:
{
if ( lpHelpIndex && IsWindow( lpHelpIndex->hListbox ) )
SetFocus( lpHelpIndex->hListbox );
break;
}
/********************************/
/* Paint the default background */
/********************************/
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hDC = BeginPaint( hWnd, &ps );
EndPaint( hWnd, &ps );
break;
}
/*************************/
/* Window is being sized */
/*************************/
case WM_SIZE:
{
if ( lpHelpIndex && IsWindow(lpHelpIndex->hListbox) )
MoveWindow( lpHelpIndex->hListbox, 0, 0,
LOWORD(lParam), HIWORD(lParam), TRUE );
break;
}
/**********************************/
/* Did someone send us a command? */
/**********************************/
case WM_COMMAND:
{
#ifdef _WIN32
switch (LOWORD(wParam))
#else
switch (wParam)
#endif
{
// [chauv 6/10/94]
case IDD_CHANGEBITMAP:
{
if (lParam)
ChangeBitmap(lpHelpIndex, IDB_QUICKREFERENCE);
else
ChangeBitmap(lpHelpIndex, IDB_OUTLINE);
break;
}
case IDD_TROUBLESHOOT:
bTroubleshoot = TRUE;
break;
case IDD_SETHELPPATH:
_tcscpy(szLocalHelpPath, (TCHAR FAR *)(lParam));
break;
case VK_RIGHT:
{ // [chauv 10/18/93]
// added for expand up to a level feature
// lParam = level to expand up to
ExpandUptoLevel(lpHelpIndex, lParam);
// expand level needs to reset last topic Use flag
{
TCHAR szSection[_MAX_FNAME];
wsprintf(szSection, "%s\\%s\\%s\\%s", szRegistryKey, szProduct, szContentsSection, szBookset);
WriteRegistryString(szSection, szTopicUse, _T("1"), lpHelpIndex->szProfile);
}
break;
}
case IDD_SEARCH:
{
if (lpHelpIndex)
{
UINT nItem = (UINT)ListBox_GetCurSel(lpHelpIndex->hListbox);
LONG nPos = (LONG)ListBox_GetItemData(lpHelpIndex->hListbox, nItem);
if( nPos >= 0 )
ProcessHelpSearch(hWnd, lpHelpIndex, nPos, nItem);
}
break;
}
case IDD_VIEWER:
{
nWinHelp = LOWORD(lParam);
break;
}
case IDD_PRODUCTKEY:
{
_tcscpy(szProduct, (TCHAR FAR *)(lParam));
break;
}
case IDD_BOOKSETKEY:
{
_ftcscpy(szBookset, (TCHAR FAR *)(lParam));
break;
}
case IDD_JUMPID:
{
TCHAR szBuffer[_MAX_FNAME];
HELPINDEXITEM tmphelpitem;
_tcscpy(szBuffer, _tcstok((TCHAR FAR *)(lParam), _T(":")));
//if (bTroubleshoot)
// mprintf(MB_OK, 0, szBuffer);
tmphelpitem.nHelpTopic = atol(szBuffer);
_tcscpy(tmphelpitem.szHelpFile, _tcstok(NULL, _T(":")));
if (ExpandHelpTopic(lpHelpIndex, &tmphelpitem))
LastHelpItem = tmphelpitem;
//else
// ShowExpanded(lpHelpIndex, 0);
// jump topic needs to reset last topic Use flag
{
TCHAR szSection[_MAX_FNAME];
wsprintf(szSection, "%s\\%s\\%s\\%s", szRegistryKey, szProduct, szContentsSection, szBookset);
WriteRegistryString(szSection, szTopicUse, _T("1"), lpHelpIndex->szProfile);
}
break;
}
default:
{
#ifdef _WIN32
switch (GET_WM_COMMAND_CMD( wParam, lParam ))
#else
switch (HIWORD(lParam))
#endif // #ifdef _WIN32
{
case LBN_DBLCLK:
if (lpHelpIndex)
{
UINT nItem = (UINT)
ListBox_GetCurSel( lpHelpIndex->hListbox );
LONG nPos = (LONG)
ListBox_GetItemData( lpHelpIndex->hListbox, nItem );
if( nPos >= 0 )
ProcessItem(hWnd, lpHelpIndex, nPos, nItem );
// reset last topic Use flag when a topic is selected
{
TCHAR szSection[_MAX_FNAME];
wsprintf(szSection, "%s\\%s\\%s\\%s", szRegistryKey, szProduct, szContentsSection, szBookset);
WriteRegistryString(szSection, szTopicUse, _T("1"), lpHelpIndex->szProfile);
}
}
break;
}
break;
}
}
break;
}
case WM_CLOSE:
DestroyWindow(hWnd);
break;
/*****************************/
/* Window is being destroyed */
/*****************************/
case WM_DESTROY:
{
// save last help index topic
{
TCHAR szSection[_MAX_FNAME];
TCHAR szBuffer[_MAX_FNAME];
wsprintf(szSection, "%s\\%s\\%s\\%s", szRegistryKey, szProduct, szContentsSection, szBookset);
wsprintf(szBuffer, _TEXT("%u"), LastHelpItem.nHelpTopic);
WriteRegistryString(szSection, szTopicID, szBuffer, lpHelpIndex->szProfile);
WriteRegistryString(szSection, szTopicHelpfile, LastHelpItem.szHelpFile, lpHelpIndex->szProfile);
WriteRegistryString(szSection, szTopicTitle, LastHelpItem.szHelpTopic, lpHelpIndex->szProfile);
}
if (hWndHelpDlg)
SendMessage(hWndHelpDlg, WM_COMMAND, IDCANCEL, 0L);
SETHELPINDEX( hWnd, lpHelpIndex = DestroyHelpIndex( lpHelpIndex ) );
break;
}
/*********************************/
/* Some other event is happening */
/*********************************/
default:
{
lResult = DefWindowProc( hWnd, uMsg, wParam, lParam );
break;
}
}
/**************************/
/* Return the result code */
/**************************/
return lResult;
}
#ifdef _WIN32
/******************************************************************************\
*
* FUNCTION: HelpIndexSizeToText
*
* INPUTS: flStyle - control style
* flExtStyle - control extended style
* hFont - handle of font used to draw text
* pszText - control text
*
* RETURNS: Width (in pixels) control must be to accomodate text, or
* -1 if an error occurs.
*
* COMMENTS: Just no-op here
*
\******************************************************************************/
INT CALLBACK
HelpIndexSizeToText(DWORD flStyle, DWORD flExtStyle, HFONT hFont, LPSTR pszText)
{
/*******************************/
/* Return unsupported function */
/*******************************/
return -1;
}
/******************************************************************************\
*
* FUNCTION: CustomControlInfoA
*
* INPUTS: acci - pointer to an array od CCINFOA structures
*
* RETURNS: Number of controls supported by this DLL
*
* COMMENTS: See CUSTCNTL.H for more info
*
\******************************************************************************/
UINT CALLBACK
CustomControlInfoA (LPCCINFOA acci)
{
/***********************************************/
/* Are we being asked to fill out a structure? */
/***********************************************/
if ( acci )
{
/***********************/
/* Setup the structure */
/***********************/
acci->flOptions = 0;
acci->cxDefault = 40; // default width (dialog units)
acci->cyDefault = 60; // default height (dialog units)
acci->flStyleDefault = WS_CHILD | WS_VISIBLE;
acci->flExtStyleDefault = 0;
acci->flCtrlTypeMask = 0;
acci->cStyleFlags = nHelpIndexStyleFlags;
acci->aStyleFlags = aHelpIndexStyleFlags;
acci->lpfnStyle = HelpIndexStyle;
acci->lpfnSizeToText = HelpIndexSizeToText;
acci->dwReserved1 = 0;
acci->dwReserved2 = 0;
/********************/
/* Copy the strings */
/********************/
_ftcsnccpy( acci->szClass, szHelpIndexClass, sizeof(acci->szClass)-1 );
_ftcsnccpy( acci->szDesc, szHelpIndexDesc, sizeof(acci->szDesc)-1 );
_ftcsnccpy( acci->szTextDefault, szHelpIndexDefault,
sizeof(acci->szTextDefault)-1 );
}
/*******************************************************/
/* Return the number of controls that the DLL supports */
/*******************************************************/
return 1;
}
#else
/******************************************************************************\
*
* CustomControlInfo() -- see CUSTCNTL.H for more info
*
\******************************************************************************/
HANDLE CALLBACK __export
CustomControlInfo ()
{
HANDLE hMem;
LPCTLINFO pctlinfo;
//Allocate a CTLINFO struct
hMem=GlobalAlloc(GMEM_MOVEABLE, sizeof(CTLINFO));
if (hMem==NULL)
return NULL;
//Get the pointers we need.
pctlinfo=(LPCTLINFO)GlobalLock(hMem);
if (pctlinfo==NULL)
{
GlobalFree(hMem);
return NULL;
}
//Set the overall control info.
pctlinfo->wVersion=0100;
pctlinfo->wCtlTypes=1;
_ftcsnccpy( pctlinfo->szClass, szHelpIndexClass, sizeof (pctlinfo->szClass) );
pctlinfo->szClass[sizeof (pctlinfo->szClass) - 1] = 0;
_ftcsnccpy( pctlinfo->szTitle, _TEXT("profile.ini|helpfile.hlp"), sizeof (pctlinfo->szTitle) );
pctlinfo->szTitle[sizeof (pctlinfo->szTitle) - 1] = 0;
//Set the types
pctlinfo->Type[0].wType = 0;
pctlinfo->Type[0].wWidth = 40;
pctlinfo->Type[0].wHeight = 60;
pctlinfo->Type[0].dwStyle = WS_CHILD | WS_VISIBLE | HS_LINES;
_ftcsnccpy( pctlinfo->Type[0].szDescr, szHelpIndexDesc,
sizeof (pctlinfo->Type[0].szDescr) );
pctlinfo->Type[0].szDescr[sizeof (pctlinfo->Type[0].szDescr) - 1] = 0;
//Give the memory to the Dialog Editor.
GlobalUnlock(hMem);
return hMem;
}
#endif // #ifdef _WIN32
/******************************************************************************\
* *
* RegisterWindowClass()
* *
\******************************************************************************/
BOOL
RegisterWindowClass()
{
BOOL bSuccess = TRUE;
if ( !nRegistered++ )
{
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
wndclass.lpfnWndProc = HelpIndexWndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = sizeof(LPHELPINDEX);
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW );
wndclass.hbrBackground = GetStockObject( LTGRAY_BRUSH );
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szHelpIndexClass;
#ifdef _WIN32
bSuccess = RegisterClass( &wndclass ) != INVALID_ATOM;
#else
bSuccess = RegisterClass( &wndclass ) != NULL;
#endif // #ifdef _WIN32
}
return( bSuccess );
}
/******************************************************************************\
* *
* UnregisterWindowClass()
* *
\******************************************************************************/
BOOL
UnregisterWindowClass()
{
BOOL bSuccess = TRUE;
if ( !--nRegistered )
bSuccess = UnregisterClass( szHelpIndexClass, hInstance );
return( bSuccess );
}
#ifdef _WIN32
/******************************************************************************\
*
* FUNCTION: DLLEntryPoint
*
* INPUTS: hDLL - DLL module handle
* dwReason - reason being called (e.g. process attaching)
* lpReserved - reserved
*
* RETURNS: TRUE if initialization passed, or
* FALSE if initialization failed.
*
* COMMENTS: On DLL_PROCESS_ATTACH registers the HelpIndex class
*
* DLL initialization serialization is guaranteed within a
* process (if multiple threads then DLL entry points are
* serialized), but is not guaranteed across processes.
*
* When synchronization objects are created, it is necesaary
* to check the return code of GetLastError even if the create
* call succeeded. If the object existed, ERROR_ALREADY_EXISTED
* will be returned.
*
* If your DLL uses any C runtime functions then you should
* always call _CRT_INIT so that the C runtime can initialize
* itself appropriately. Failure to do this may result in
* indeterminate behavior. When the DLL entry point is called
* for DLL_PROCESS_ATTACH & DLL_THREAD_ATTACH circumstances,
* _CRT_INIT should be called before any other initilization
* is performed. When the DLL entry point is called for
* DLL_PROCESS_DETACH & DLL_THREAD_DETACH circumstances,
* _CRT_INIT should be called after all cleanup has been
* performed, i.e. right before the function returns.
*
\******************************************************************************/
/******************************************************/
/* BOOL WINAPI DLLEntryPoint( HANDLE, DWORD, LPVOID ) */
/******************************************************/
BOOL WINAPI _CRT_INIT (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved);
BOOL WINAPI
DLLEntryPoint( HANDLE hDLL, DWORD dwReason, LPVOID lpReserved )
{
BOOL bStatus = TRUE;
hInstance = (HINSTANCE)hDLL; // Save the DLL module handle.
switch ( dwReason )
{
case DLL_PROCESS_ATTACH:
{
if ( bStatus = _CRT_INIT(hDLL, dwReason, lpReserved) )
{
if ( !RegisterWindowClass() )
{
mprintf(MB_OK, IDS_ERROR_REGISTERCLASS, szNull);
//_TEXT("Failed to register Window Class!") );
bStatus = FALSE;
}
}
break;
}
case DLL_PROCESS_DETACH:
{
if ( !UnregisterWindowClass() )
{
mprintf(MB_OK, IDS_ERROR_UNREGISTERCLASS, szNull);
// _TEXT("Failed to unregister Window Class!") );
bStatus = FALSE;
}
bStatus = _CRT_INIT(hDLL, dwReason, lpReserved);
break;
}
default:
{
bStatus = _CRT_INIT(hDLL, dwReason, lpReserved);
break;
}
}
return bStatus;
}
#else
/*
* LibMain
*
* Purpose:
* DLL-specific entry point called from LibEntry. Initializes
* the DLL's heap and registers the HelpIndex custom control
* class.
*
* Parameters:
* hInstance HANDLE instance of the DLL.
* wDataSeg WORD segment selector of the DLL's data segment.
* wHeapSize WORD byte count of the heap.
* lpCmdLine LPSTR to command line used to start the module.
*
* Return Value:
* HANDLE Instance handle of the DLL.
*
*/
HANDLE FAR PASCAL LibMain(HANDLE hDLL, WORD wDataSeg,
WORD cbHeapSize, LPSTR lpCmdLine)
{
hInstance = (HINSTANCE)hDLL; // Save the DLL module handle.
if ( !RegisterWindowClass() )
{
mprintf( MB_OK, _TEXT("Failed to register Window Class!") );
hInstance = NULL;
}
if (hInstance && (0!=cbHeapSize))
UnlockData(0);
return hInstance;
}
#endif // #ifdef _WIN32
/* ===========================================================================
FUNCTIONS THAT VIRTUALIZE THE INDEX FILE FOR 16-BIT IMPLEMENTATIONS
=========================================================================== */
/* ===========================================================================
GetHelpItemData
Copies the read-only fields of an index file record to a buffer supplied by
the caller. Writable fields cannot be accessed through this function, which
does not modify these fields in the destination buffer. The writable fields
have their own read/write interfaces in the form of
GetHelpItemXxxx()/SetHelpItemXxxx() function pairs.
--------------------------------------------------------------------------- */
static BOOL // spec'd data was copied to dest buf
GetHelpItemData (
HELPINDEXITEM FAR * phelpitem, // ptr struct to fill with item data
HELPINDEX FAR * phdx, // browse context obj for curr window
LONG nFilePos, // 0-rel item index within index file
BOOL bStringsToo // T:get scalars, strings F:not strings
)
{
// request transient copy of index file rec; have data and good dest buf?
BOOL bRet = FALSE;
HELPINDEXITEM FAR * phelpitemCached = GetCachedHelpItem (phdx, nFilePos);
if (phelpitemCached && phelpitem)
{
// yes: success; copy read-only scalars to buf; strings requested too?
bRet = TRUE;
phelpitem->nHelpDepth = phelpitemCached->nHelpDepth;
phelpitem->nHelpTopic = phelpitemCached->nHelpTopic;
if (bStringsToo)
{
// yes: copy read-only strings to caller's buf
phelpitemCached->szHelpFile
[sizeof (phelpitemCached->szHelpFile) - 1] = 0;
_ftcscpy (phelpitem->szHelpFile, phelpitemCached->szHelpFile);
phelpitemCached->szHelpTopic
[sizeof (phelpitemCached->szHelpTopic) - 1] = 0;
_ftcscpy (phelpitem->szHelpTopic, phelpitemCached->szHelpTopic);
}
}
else if (! phelpitemCached)
{
mprintf(MB_OK, IDS_ERROR_READINDEX, szNull);
//_TEXT("Error reading index file!") );
}
// return success/failure code
return (bRet);
}
/* ===========================================================================
GetHelpItemExpanFlag
SetHelpItemExpanFlag
GetHelpItemLinesMap
SetHelpItemLinesMap
These functions retrieve and set data elements that -- in the original 32-bit
version of this program -- were read/write fields in the index file record.
In this 16-bit implementation, the read/write fields have been "mapped" to a
memory-resident "overlay"; see the definition of ITEM_RW_OVERLAY for more
information.
[chauv 10/18/93] 16 and 32-bit are now using the same overlay scheme
--------------------------------------------------------------------------- */
static BOOL // spec'd index file item is expanded
GetHelpItemExpanFlag (
HELPINDEX FAR * phdx, // browse context obj for curr window
LONG nFilePos // 0-rel item index within index file
) {
BOOL bRet = FALSE;
ITEM_RW_OVERLAY FAR * pitemrw = GetHelpItemRWOverlay (phdx, nFilePos);
if (pitemrw) {
bRet = ((*pitemrw & ITEMRW_EXPANDED) != 0);
}
return (bRet);
}
static void
SetHelpItemExpanFlag (
HELPINDEX FAR * phdx, // browse context obj for curr window
LONG nFilePos, // 0-rel item index within index file
BOOL bNewExpandFlag // T:mark item as currently expanded
) {
ITEM_RW_OVERLAY FAR * pitemrw = GetHelpItemRWOverlay (phdx, nFilePos);
if (pitemrw) {
if (bNewExpandFlag) {
*pitemrw |= ITEMRW_EXPANDED;
} else {
*pitemrw &= (~ITEMRW_EXPANDED);
}
}
}
static LONG // maps connec lines through item disp
GetHelpItemLinesMap (
HELPINDEX FAR * phdx, // browse context obj for curr window
LONG nFilePos // 0-rel item index within index file
) {
LONG lRet = 0;
ITEM_RW_OVERLAY FAR * pitemrw = GetHelpItemRWOverlay (phdx, nFilePos);
if (pitemrw) {
lRet = *pitemrw & ITEMRW_LINESMAP;
}
return (lRet);
}
static void
SetHelpItemLinesMap (
HELPINDEX FAR * phdx, // browse context obj for curr window
LONG nFilePos, // 0-rel item index within index file
LONG lNewLinesMap // columns where vert outline connecs go
) {
ITEM_RW_OVERLAY FAR * pitemrw = GetHelpItemRWOverlay (phdx, nFilePos);
if (pitemrw) {
*pitemrw &= (~ITEMRW_LINESMAP);
*pitemrw |= (lNewLinesMap & ITEMRW_LINESMAP);
}
}
/* ===========================================================================
GetCachedHelpItem
Returns a pointer to a buffer which contains a copy of the index file record
for the specified item. The returned buffer is subject to being recycled
without notice, so the caller should use or copy the data immediately after
regaining control.
--------------------------------------------------------------------------- */
// 1-item minicache for use if regular cache can't be allocated
static HELPINDEXITEM helpitemCacheDegen;
static HELPINDEXITEM FAR * // ptr index record; NULL if failed
GetCachedHelpItem (
HELPINDEX FAR * phdx, // browse context obj for curr window
LONG nFilePos // 0-rel item index within index file
) {
// initialize buffer ptr ("none"), cache ptr; has cache been constructed?
HELPINDEXITEM FAR * pitemRet = NULL;
HELPINDEXITEM FAR * pitemCache = phdx->pIndexItemCache;
if (pitemCache == NULL) {
// no: try to alloc cache memory; success?
// [chauv] fixed uninitialize memory problem by calling GAllocLock(..,TRUE) to do zeroinit
pitemCache = GAllocLock (BYTES_PER_CACHE, TRUE);
phdx->pIndexItemCache = pitemCache;
if (pitemCache != NULL) {
// yes: mark pages unmapped, set up arbitrary recency ordering
int nPage = 0;
while (nPage < PAGES_PER_CACHE) {
PAGEINFO FAR * ppginfo = &phdx->pageinfo[nPage];
ppginfo->nBasePos = -1;
ppginfo->nNewerPage = (nPage == 0)
? PAGES_PER_CACHE - 1 : nPage - 1;
ppginfo->nOlderPage = (nPage == PAGES_PER_CACHE - 1)
? 0 : nPage + 1;
nPage++;
}
phdx->nNewestPage = 0;
}
}
// was cache available or is it now?
if (pitemCache != NULL) {
// initiate walk of recency chain starting with most-recently-used page
int nTry = phdx->nNewestPage;
PAGEINFO FAR * ppginfo;
while ((pitemRet == NULL) && (nTry >= 0)
&& ((ppginfo = &phdx->pageinfo[nTry])->nBasePos >= 0)) {
// have mapped page; does desired rec fall in mapped area of file?
int nPosInTryPage = (int)nFilePos - ppginfo->nBasePos;
if ((0 <= nPosInTryPage) && (nPosInTryPage < ITEMS_PER_PAGE)) {
// yes: save buf ptr; was found page already most recent page?
pitemRet = &pitemCache[nTry * ITEMS_PER_PAGE + nPosInTryPage];
if (nTry != phdx->nNewestPage) {
// no: unlink it from current place in recency chain
PAGEINFO FAR * ppginfoNewer
= &phdx->pageinfo[ppginfo->nNewerPage];
PAGEINFO FAR * ppginfoOlder
= &phdx->pageinfo[ppginfo->nOlderPage];
ppginfoNewer->nOlderPage = ppginfo->nOlderPage;
ppginfoOlder->nNewerPage = ppginfo->nNewerPage;
// relink found page as most recent
ppginfo->nOlderPage = phdx->nNewestPage;
ppginfoOlder = &phdx->pageinfo[ppginfo->nOlderPage];
ppginfo->nNewerPage = ppginfoOlder->nNewerPage;
ppginfoNewer = &phdx->pageinfo[ppginfo->nNewerPage];
ppginfoOlder->nNewerPage = nTry;
ppginfoNewer->nOlderPage = nTry;
// record new most recent page in browse context object
phdx->nNewestPage = nTry;
}
} else {
// if have now searched all pages in cache, stop trying
if ((nTry = ppginfo->nOlderPage) == phdx->nNewestPage) {
nTry = -1;
}
}
}
// was the desired entry mapped into any cache page?
if (pitemRet == NULL) {
// no: remap oldest page, make it newest (chain need not change)
int nPage = phdx->pageinfo[phdx->nNewestPage].nNewerPage;
int nPosInPage = (int)nFilePos % ITEMS_PER_PAGE;
int nBasePos = (int)nFilePos - nPosInPage;
ppginfo = &phdx->pageinfo[nPage];
ppginfo->nBasePos = -1;
if (LZSeek (phdx->hfileIndex, phdx->nHdrBytesCt
+ ((LONG)nBasePos * sizeof(HELPINDEXITEM)), 0) >= 0) {
int nReadCt = LZRead (phdx->hfileIndex
, (LPSTR)(&(pitemCache[nPage * ITEMS_PER_PAGE])), BYTES_PER_PAGE);
if (nReadCt >= (nPosInPage + 1) * (int)sizeof(HELPINDEXITEM)) {
ppginfo->nBasePos = nBasePos;
phdx->nNewestPage = nPage;
pitemRet= &pitemCache[nPage * ITEMS_PER_PAGE + nPosInPage];
}
}
}
}
// if desired page wasn't and could not be mapped, try read into minicache
if (pitemRet == NULL) {
if (LZSeek (phdx->hfileIndex, phdx->nHdrBytesCt
+ (nFilePos * sizeof (HELPINDEXITEM)), 0) >= 0) {
if (LZRead (phdx->hfileIndex, (LPSTR)(&helpitemCacheDegen)
, sizeof (HELPINDEXITEM)) == sizeof (HELPINDEXITEM)) {
pitemRet = &helpitemCacheDegen;
}
}
}
// return buf ptr or NULL for failure
return (pitemRet);
}
/* ===========================================================================
GetHelpItemRWOverlay
Returns a pointer to the specified index item's entry in the index file's
read/write overlay. See ITEM_RW_OVERLAY for more information.
--------------------------------------------------------------------------- */
static ITEM_RW_OVERLAY FAR * // ptr overlay entry; NULL if out of rg
GetHelpItemRWOverlay (
HELPINDEX FAR * phdx, // browse context obj for curr window
LONG nFilePos // 0-rel item index within index file
) {
ITEM_RW_OVERLAY FAR * pitemrwRet = NULL;
if ((0 <= nFilePos) && (nFilePos < phdx->nHelpItemCt)) {
pitemrwRet = phdx->pIndexRWOverlay + nFilePos;
}
return (pitemrwRet);
}
/* ===========================================================================
GAllocLock
Encapsulates a GlobalAlloc()/GlobalLock() sequence.
--------------------------------------------------------------------------- */
static void FAR *
GAllocLock (DWORD dwByteCt, BOOL bInitToZero)
{
void FAR * pvRet = NULL;
HANDLE h = GlobalAlloc((bInitToZero ? (GHND) : (GMEM_MOVEABLE)), dwByteCt);
if (h)
{
if ((pvRet = GlobalLock (h)) == NULL)
GlobalFree (h);
}
return (pvRet);
}
// ****************************************************************************
// Get Registry string stub function
//
// Return value is the return value of RegOpenKeyEx() or RegQueryValueEx().
// except for when lpszDefault is valid and lpszSection is NULL, it returns
// ERROR_SUCCESS.
//
DWORD GetRegistryString(LPCTSTR lpszSection, LPCTSTR lpszKey, LPCTSTR lpszDefault,
LPTSTR lpszReturnBuffer, DWORD cchReturnBuffer, LPCTSTR lpszFile)
{
#ifdef _WIN32
DWORD dw = (DWORD)(~ERROR_SUCCESS);
DWORD dwType = REG_SZ;
HKEY hKey;
dw = RegOpenKeyEx(HKEY_CURRENT_USER, lpszSection, 0, KEY_ALL_ACCESS, &hKey);
if (dw == ERROR_SUCCESS)
{
dw = (DWORD)RegQueryValueEx(hKey, (LPTSTR)lpszKey, NULL, &dwType, lpszReturnBuffer, &cchReturnBuffer);
RegCloseKey(hKey);
}
if ( (dw != ERROR_SUCCESS) && (lpszDefault) )
_tcsncpy(lpszReturnBuffer, lpszDefault, cchReturnBuffer);
return dw;
#else
return (DWORD)GetPrivateProfileString(lpszSection, lpszKey, lpszDefault,
lpszReturnBuffer, cchReturnBuffer, lpszFile);
#endif
}
// ****************************************************************************
// Write Registry string stub function
BOOL WriteRegistryString(LPCTSTR lpszSection, LPCTSTR lpszKey,
LPCTSTR lpszString, LPCTSTR lpszFile)
{
#ifdef _WIN32
LONG l = ~ERROR_SUCCESS;
HKEY hKey;
if (lpszSection && *lpszSection)
{
if (RegCreateKey(HKEY_CURRENT_USER, lpszSection, &hKey) == ERROR_SUCCESS)
{
if (lpszKey && *lpszKey && lpszString)
l = RegSetValueEx(hKey, (LPTSTR)lpszKey, 0, REG_SZ, lpszString, _ftcslen(lpszString) + sizeof(TCHAR));
}
RegCloseKey(hKey);
}
return (BOOL)(l == ERROR_SUCCESS);
#else
return WritePrivateProfileString(lpszSection, lpszKey, lpszString, lpszFile);
#endif
}
// ****************************************************************************
static BOOL ExpandHelpTopic(LPHELPINDEX lpHelpIndex, LPHELPINDEXITEM lpHelpItem)
{
HCURSOR hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
BOOL bSkip = TRUE;
HWND hListbox = lpHelpIndex->hListbox;
if (hListbox)
{
if ( lpHelpIndex && (lpHelpIndex->nHelpItemCt > 0) && (lpHelpItem->szHelpFile[0] || lpHelpItem->szHelpTopic[0]) )
{
LONG nPos, pos, ndepth, opened;
HELPINDEXITEM helpitem;
// ******** find matching help topic/help file
bSkip = FALSE;
pos = 0;
while ((pos < lpHelpIndex->nHelpItemCt) && !bSkip)
{
if (GetHelpItemData (&helpitem, lpHelpIndex, pos, TRUE))
{
// if topic id is not zero try to match JumpHashID(). Otherwise, try to match
// topic title
if (lpHelpItem->nHelpTopic)
{
if (helpitem.nHelpTopic == lpHelpItem->nHelpTopic) // matched topic
{
if (_tcsicmp(helpitem.szHelpFile, lpHelpItem->szHelpFile) == 0) // matched helpfile
break; // found them both
}
}
else
{
if (_tcsicmp(helpitem.szHelpTopic, lpHelpItem->szHelpTopic) == 0)
break;
}
pos++;
}
else
bSkip = TRUE;
}
if (pos == lpHelpIndex->nHelpItemCt) // didn't find a match in the list.
bSkip = TRUE;
// ******** ====> impotant note !!!!!!!!
// dependencies for next loop - DON'T CHANGE in the middle
// pos, helpitem,...
ndepth = helpitem.nHelpDepth;
// ******** found topic, refresh the listbox
if ((pos < lpHelpIndex->nHelpItemCt) && !bSkip)
{
LONG d;
ListBox_ResetContent(hListbox);
SendMessage(hListbox, WM_SETREDRAW, 0, 0);
// ******** start at pos and go backward
nPos = pos;
d = ndepth;
// there should be only one book/chapter that's expanded and it should be one level
// above the search topic.
opened = ndepth - 1;
while ((nPos >= 0) && !bSkip)
{
if (GetHelpItemData (&helpitem, lpHelpIndex, nPos, FALSE))
{
if (helpitem.nHelpDepth <= d)
{
if (helpitem.nHelpDepth == opened)
{
opened--;
SetHelpItemExpanFlag(lpHelpIndex, nPos, TRUE);
}
else if (helpitem.nHelpTopic == 0)
SetHelpItemExpanFlag(lpHelpIndex, nPos, FALSE);
// since we are going backward, always insert string at the beginning.
ListBox_InsertString(hListbox, 0, (LPVOID)nPos);
d = helpitem.nHelpDepth;
}
nPos--;
}
else bSkip = TRUE;
}
// ******** start at pos (not including pos) and go foward
nPos = pos + 1;
d = ndepth;
// get the count so we can select this item when appropriate items have been expanded.
pos = ListBox_GetCount(hListbox) - 1; // subtract 1 because it's zero base
while ((nPos < lpHelpIndex->nHelpItemCt) && !bSkip)
{
if (GetHelpItemData (&helpitem, lpHelpIndex, nPos, FALSE))
{
if (helpitem.nHelpDepth <= d)
{
if (helpitem.nHelpTopic == 0)
SetHelpItemExpanFlag(lpHelpIndex, nPos, FALSE);
// since we are going forward, always insert string at the end.
ListBox_InsertString(hListbox, -1, (LPVOID)nPos);
d = helpitem.nHelpDepth;
}
nPos++;
}
else bSkip = TRUE;
}
SendMessage(hListbox, WM_SETREDRAW, 1, 0);
InvalidateRect(hListbox, NULL, TRUE);
if (!bSkip)
ListBox_SetCurSel(hListbox, pos );
}
}
}
SetCursor( hOldCursor );
return (BOOL)(!bSkip);
}
//******************************************************************************
void ProcessHelpSearch(HWND hWnd, LPHELPINDEX lpHelpIndex, LONG nFilePos, UINT nListPos )
{
HELPINDEXITEM helpitem;
LPSTR lpHelpFile;
UINT fuCommand = HELP_SEARCH;
if ( hWnd && lpHelpIndex && (nFilePos >= 0) && (nFilePos < lpHelpIndex->nHelpItemCt) && (nListPos >= 0) )
{
if ( GetValidHelpFilePos((HELPINDEXITEM FAR *)&helpitem, lpHelpIndex, nFilePos) >= 0 )
{
TCHAR szSection[_MAX_FNAME];
TCHAR szBuf[_MAX_FNAME];
// check to see if the help file has full text search capability
wsprintf(szSection, "%s\\%s\\%s", szRegistryKey, szProduct, szContentsSection);
GetRegistryString(szSection, cszFTSFiles, szNull, szBuf, sizeof(szBuf), lpHelpIndex->szProfile );
if (_tcsstr(_tcslwr(szBuf), _tcslwr(helpitem.szHelpFile)) )
fuCommand = HELP_FTSEARCH;
lpHelpFile = HelpLookup(hWnd, lpHelpIndex, helpitem.szHelpFile, cszHLPKey);
// if lpHelpFile is NULL, the user cancelled the help lookup
// if lpHelpFile is pointed to a null string, can't find registry value but don't
// need to report error here because HelpLookup() has already done so.
if (lpHelpFile == NULL)
return;
if (*lpHelpFile)
{
CallHelp(lpHelpIndex->hListbox, lpHelpFile, fuCommand, helpitem.nHelpTopic);
return;
}
}
}
// if it gets here, we must do default search
lpHelpFile = HelpLookup(hWnd, lpHelpIndex, "contents.hlp", cszHLPKey);
// if lpHelpFile is NULL, the user cancelled the help lookup
// if lpHelpFile is pointed to a null string, can't find registry value but don't
// need to report error here because HelpLookup() has already done so.
if (lpHelpFile && *lpHelpFile)
{
CallHelp(lpHelpIndex->hListbox, lpHelpFile, fuCommand, helpitem.nHelpTopic);
return;
}
}
// ****************************************************************************
// returns -1 if failed
static long GetValidHelpFilePos(HELPINDEXITEM FAR * lphelpitem, LPHELPINDEX lpHelpIndex, long pos)
{
HCURSOR hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
if ( lpHelpIndex && (lpHelpIndex->nHelpItemCt > 0) )
{
// ******** find next valid help filename
while (pos < lpHelpIndex->nHelpItemCt)
{
if (GetHelpItemData (lphelpitem, lpHelpIndex, pos, TRUE))
{
if (_tcslen(lphelpitem->szHelpFile) > 1)
break;
pos++;
}
else
{
pos = -1;
break;
}
}
if (pos >= lpHelpIndex->nHelpItemCt)
pos = -1;
}
else
pos = -1;
SetCursor( hOldCursor );
return pos;
}
// ****************************************************************************
BOOL IsQuickReference(void)
{
TCHAR szReg[MAX_PATH+2];
TCHAR szReturn[MAX_PATH+2];
wsprintf(szReg, _T("%s\\%s\\%s"), szRegistryKey, szProduct, szContentsSection);
GetRegistryString(szReg, szCurrentBookset, _TEXT("0"), szReturn, sizeof(szReturn), szNull);
wsprintf(szReg, _T("%s\\%s\\%s\\%s"), szRegistryKey, szProduct, szContentsSection, szReturn);
GetRegistryString(szReg, _TEXT("QuickReference"), _TEXT("0"), szReturn, sizeof(szReturn), szNull);
// don't really need to call atol() here. This is quicker...
if (szReturn[0] == _TEXT('1'))
return TRUE;
else
return FALSE;
}
/*EOF*/