mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
844 lines
20 KiB
844 lines
20 KiB
/*****************************************************************************
|
|
*
|
|
* imbed.c
|
|
*
|
|
* Copyright (C) Microsoft Corporation 1990.
|
|
* All Rights reserved.
|
|
*
|
|
******************************************************************************
|
|
*
|
|
* Module Intent
|
|
*
|
|
* These are the platform-specific routines to create, destroy, and display
|
|
* an embedded window object.
|
|
*
|
|
* An embedded window is defined by a rectangle size, a module name, a class
|
|
* name, and data.
|
|
*
|
|
* The module and class names are descriptions of where to get the code
|
|
* which handles the maintainance of the window. This module is
|
|
* Windows-specific, so the module name specifies a DLL and the class name
|
|
* specifies the window class which has been defined in the DLL. The data is
|
|
* passed to the window being created by using the window title parameter of
|
|
* CreateWindow.
|
|
*
|
|
* Authorable buttons are embedded windows with the name '!'. This is
|
|
* immediately followed with the text for the button, a comma, and the
|
|
* macro or macros to assign to the button.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include "help.h"
|
|
#pragma hdrstop
|
|
|
|
#define H_WINSPECIFIC
|
|
|
|
#include "inc\imbed.h"
|
|
#include "inc\tmp.h" // until it makes it into windows.h
|
|
#include "inc\hwproc.h"
|
|
#include "inc\hinit.h"
|
|
|
|
#define NEW_HC
|
|
|
|
#define CXBUTTONEXTRA 16 // spacing between text and button
|
|
#define CYBUTTONEXTRA 7
|
|
|
|
#define MAX_DATA 200 // largest size for authorable data
|
|
|
|
#define dxDEFAULT 2
|
|
#define dyDEFAULT 2
|
|
#define NOTEXT_BTN_HEIGHT 12
|
|
#define NOTEXT_BTN_WIDTH 12
|
|
|
|
typedef struct {
|
|
SMALL_RECT rc; // MUST be small for 16-bit embedded windows
|
|
HDC hdc; // BUGBUG: 16 bit imbedded windows will expect 16 bit HDC
|
|
} RENDERINFO, *QRI;
|
|
|
|
INLINE void STDCALL RemoveBtnData(HWND hwnd);
|
|
INLINE BOOL STDCALL SaveBtnData(HWND hwnd, PSTR pszData, PSTR pszText);
|
|
static BOOL STDCALL nstrisubcmp(LPCSTR mainstring, LPCSTR substring);
|
|
LRESULT EXPORT BtnProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
static PSTR _fastcall IsThereMore(PSTR psz);
|
|
static void _fastcall FillRI(RENDERINFO* pri, POINT* ppt, POINT* pptSize);
|
|
|
|
#ifdef _DEBUG // Count of the number of embedded
|
|
int cIWindows = 0; // windows hanging around.
|
|
#endif
|
|
|
|
#ifndef NO_PRAGMAS
|
|
#pragma data_seg(".text", "CODE")
|
|
#endif
|
|
static char *atxtEmbeddedClasses[] = {
|
|
"0", "BUTTON",
|
|
NULL, NULL
|
|
};
|
|
|
|
static const char txtMSVideo[] = "MSVideo";
|
|
static const char txtMciWnd[] = "MCIWnd";
|
|
static const char txtDisabled[] = "DISABLED";
|
|
static const char txtButton[] = "BUTTON";
|
|
#ifndef NO_PRAGMAS
|
|
#pragma data_seg()
|
|
#endif
|
|
|
|
enum {
|
|
EMBED_DLL,
|
|
EMBED_BUTTON,
|
|
EMBED_MCI,
|
|
};
|
|
|
|
BTNDATA btndata[MAX_BUTTONS];
|
|
static FARPROC lpfnlButtonSubClass;
|
|
|
|
|
|
/****************************
|
|
*
|
|
* Name: HiwCreate
|
|
*
|
|
* Purpose: Loads the DLL associated with the imbedded window, and
|
|
* then creates it.
|
|
*
|
|
* Arguments: int dx: Suggested width.
|
|
* int dy: Suggested height.
|
|
* LPSTR pszModule: Name of DLL library.
|
|
* LPSTR pszClass: Name of window class.
|
|
* LPSTR pszData: Pointer to null terminated string to be
|
|
* used as data to the imbedded window.
|
|
*
|
|
* Returns: Handle to imbedded window.
|
|
*
|
|
*****************************/
|
|
|
|
#define WINHELP_WINDOW_FLAG '!'
|
|
#define MCI_WINDOW_FLAG '*'
|
|
|
|
// Aliasing must be off for this function.
|
|
|
|
#pragma optimize("a", off)
|
|
extern BOOL STDCALL bInitThunk(void);
|
|
typedef HWND (STDCALL *EMBED_CREATE)(LPSTR lpModule, LPSTR lpClass,
|
|
LPSTR lpData, int dx,
|
|
int dy, HWND hwndParent,
|
|
HINSTANCE hInst, EWDATA *lpewd,
|
|
VOID* qvCallbacks);
|
|
extern EMBED_CREATE lpEmbedCreate;
|
|
void* STDCALL QVGetCallbacks(VOID);
|
|
|
|
HIW STDCALL HiwCreate(QDE qde, LPCSTR pszModule, LPCSTR pszClass,
|
|
LPCSTR pszData)
|
|
{
|
|
HIW hiw;
|
|
HLIBMOD hlibRet;
|
|
EWDATA ewd;
|
|
int dx, dy;
|
|
HDC hdc;
|
|
char rgchHelpFile[MAX_PATH];
|
|
int fEmbedType;
|
|
char szBuf[MAX_DATA];
|
|
FM fm = NULL;
|
|
HWND hwnd;
|
|
char szCopy[MAX_PATH];
|
|
|
|
hiw.hlib = NULL;
|
|
|
|
#ifdef _DEBUG
|
|
if (*pszModule != WINHELP_WINDOW_FLAG)
|
|
{
|
|
PSTR psz = (PSTR) lcMalloc(strlen(pszModule) + strlen(pszClass) + strlen(pszData) + 50);
|
|
|
|
wsprintf(psz, " EWC:%s, %s\r\n", pszModule, pszClass);
|
|
SendStringToParent(psz);
|
|
lcFree(psz);
|
|
}
|
|
#endif
|
|
|
|
if (*pszModule == WINHELP_WINDOW_FLAG)
|
|
fEmbedType = EMBED_BUTTON;
|
|
else if (*pszModule == MCI_WINDOW_FLAG)
|
|
fEmbedType = EMBED_MCI;
|
|
else {
|
|
fEmbedType = EMBED_DLL;
|
|
|
|
if (!StrChrDBCS(pszModule, '.')) { // if no extension, force .DLL
|
|
lstrcpy(szCopy, pszModule);
|
|
lstrcat(szCopy, txtDllExtension);
|
|
pszModule = (PCSTR) szCopy;
|
|
}
|
|
hlibRet = HFindDLL(pszModule, TRUE);
|
|
|
|
if (!hlibRet) {
|
|
if (!lpEmbedCreate)
|
|
bInitThunk();
|
|
|
|
if (lpEmbedCreate) {
|
|
char szNewName[MAX_PATH];
|
|
strcpy(szNewName, pszModule);
|
|
CharUpper(szNewName); // so we can search for .dll names
|
|
|
|
if (!strstr(szNewName, txtDllExtension))
|
|
ChangeExtension(szNewName, txtDllExtension);
|
|
|
|
fm = FmNewExistSzDir(szNewName,
|
|
DIR_CUR_HELP | DIR_INI | DIR_PATH | DIR_CURRENT);
|
|
|
|
}
|
|
|
|
if (fm == NULL) {
|
|
hiw.hwnd = NULL;
|
|
return hiw;
|
|
}
|
|
}
|
|
else
|
|
hiw.hlib = hlibRet;
|
|
}
|
|
if (fEmbedType == EMBED_DLL) {
|
|
lstrcpy(rgchHelpFile, PszFromGh(QDE_FM(qde)));
|
|
ewd.szFileName = rgchHelpFile;
|
|
ewd.idVersion = 0;
|
|
ewd.szAuthorData = (LPSTR) pszData;
|
|
ewd.hfs = QDE_HFS(qde);
|
|
ewd.coFore = qde->coFore;
|
|
ewd.coBack = qde->coBack;
|
|
|
|
//BUGBUG: it's stupid to call GetDeviceCaps on every single call!
|
|
|
|
hdc = GetDC(NULL);
|
|
if (hdc)
|
|
{
|
|
dx = dxDEFAULT * GetDeviceCaps(hdc, LOGPIXELSX);
|
|
dy = dyDEFAULT * GetDeviceCaps(hdc, LOGPIXELSY);
|
|
ReleaseDC(NULL, hdc);
|
|
}
|
|
else
|
|
{
|
|
dx = dxDEFAULT * 20;
|
|
dy = dyDEFAULT * 20;
|
|
}
|
|
}
|
|
/*
|
|
UGLY HACK ALERT!!!
|
|
|
|
The following code is a VERY big (short term) hack. What is going on is
|
|
that the imbedded window may set the focus to another window or otherwise
|
|
cause a focus change. Though it is prohibited to set the focus to an
|
|
imbedded window this version, we should not RIP like we do.
|
|
|
|
Given the current state of of how we handle the HDS, it is possible to
|
|
reenter the navigator and and overwrite the current HDS before our window
|
|
creation call returns. To solve this problem in the short term, we are
|
|
saving the HDS across the call.
|
|
|
|
A longer term solution (but a somewhat risky one for fixing at this late
|
|
date), is to do the actual creation outside of layout somehow, or to
|
|
create a lock count on the HDS in the QDE.
|
|
|
|
The reason we found this problem was that the DLL set the focus to some
|
|
control in its window. This is a big NO NO for this version of
|
|
WinHelp(). I have added code to assure that the focus is put back after
|
|
the call.
|
|
|
|
Special note: aliasing must be turned off for this code to work
|
|
correctly since the compiler will throw away the
|
|
hdc assignment back to qde->hdc if aliasing is on.
|
|
*/
|
|
|
|
hdc = qde->hdc;
|
|
hwnd = GetFocus();
|
|
ASSERT(qde->hwnd || ahwnd[iCurWindow].hwndTopic);
|
|
|
|
if (fEmbedType == EMBED_DLL)
|
|
{
|
|
if (hiw.hlib)
|
|
hiw.hwnd = CreateWindow(pszClass, pszData, WS_CHILD,
|
|
0, 0, dx, dy,
|
|
(qde->deType == dePrint) ||
|
|
(qde->deType == deCopy) ? ahwnd[iCurWindow].hwndTopic :
|
|
qde->hwnd, NULL, hInsNow, (LPSTR) (QEWDATA) &ewd);
|
|
else
|
|
{
|
|
//
|
|
// This is a thunked dll, and we know where it is. Try and make the
|
|
// call.
|
|
//
|
|
// DebugBreak();
|
|
hiw.hwnd = lpEmbedCreate((PSTR) fm, (PSTR) pszClass, (PSTR) pszData, dx, dy,
|
|
(qde->deType == dePrint) ||
|
|
(qde->deType == deCopy) ? ahwnd[iCurWindow].hwndTopic :
|
|
qde->hwnd, hInsNow, &ewd, QVGetCallbacks());
|
|
if (hiw.hwnd)
|
|
AddTo16DllList(fm);
|
|
}
|
|
ASSERT(hiw.hwnd);
|
|
|
|
}
|
|
else if (fEmbedType == EMBED_MCI)
|
|
{
|
|
|
|
/*
|
|
* pszModule +1 contains the flags to use when creating the
|
|
* window. pszClass contains the flags used to specify commands to
|
|
* send to the window after it is created.
|
|
*/
|
|
|
|
lstrcpy(szBuf, pszModule + 1); // skip over the ! character
|
|
lstrcpy(szBuf + 20, pszClass); // skip over the ! character
|
|
hiw.hwnd = mmCreateMCIWindow(qde->hwnd, atol(szBuf), atol(szBuf + 20),
|
|
pszData);
|
|
}
|
|
else {
|
|
|
|
// Authorable Button
|
|
|
|
PSTR psz;
|
|
RECT rc;
|
|
DWORD dwExt;
|
|
PSTR pszButtonData = lcStrDup(pszModule + 1); // skip over the ! character
|
|
|
|
if (!pszButtonData)
|
|
OOM();
|
|
|
|
if ((psz = StrChrDBCS(pszButtonData, ',')) == NULL) {
|
|
Error(wERRS_NOSEP, wERRA_RETURN);
|
|
hiw.hwnd = NULL;
|
|
return hiw;
|
|
}
|
|
*psz++ = '\0';
|
|
|
|
// First create the button
|
|
|
|
hiw.hwnd = CreateWindow(txtButton, pszButtonData, WS_CHILD |
|
|
(_strnicmp(psz, txtDisabled, lstrlen(txtDisabled)) == 0 ?
|
|
WS_DISABLED : 0),
|
|
0, 0, 30, pszButtonData[0] ? 16 : NOTEXT_BTN_HEIGHT,
|
|
(qde->deType == dePrint || qde->deType == deCopy) ?
|
|
ahwnd[iCurWindow].hwndTopic :
|
|
qde->hwnd, (HMENU) IDEMBED_BUTTON, hInsNow, NULL);
|
|
|
|
// Now set it to the correct size
|
|
|
|
if (hiw.hwnd != NULL) {
|
|
HFONT hfont = HfontGetSmallSysFont();
|
|
if (hfont)
|
|
SendMessage(hiw.hwnd, WM_SETFONT, (WPARAM) hfont, FALSE);
|
|
|
|
if (pszButtonData[0] != '\0')
|
|
dwExt = GetTextDimensions(hiw.hwnd, pszButtonData);
|
|
else
|
|
dwExt = MAKELONG(NOTEXT_BTN_WIDTH, NOTEXT_BTN_HEIGHT);
|
|
GetWindowRect(hiw.hwnd, &rc);
|
|
MoveWindow(hiw.hwnd, rc.left, rc.top, LOWORD(dwExt),
|
|
HIWORD(dwExt), FALSE);
|
|
|
|
// Save the authorable command
|
|
|
|
SaveBtnData(hiw.hwnd, psz, pszButtonData);
|
|
|
|
// Get the system window procedure for buttons
|
|
|
|
if (lpfnlButtonWndProc == NULL)
|
|
lpfnlButtonWndProc = (FARPROC) GetWindowLong(hiw.hwnd,
|
|
GWL_WNDPROC);
|
|
SetWindowLong(hiw.hwnd, GWL_WNDPROC, (LONG) BtnProc);
|
|
}
|
|
lcFree(pszButtonData);
|
|
}
|
|
|
|
// Keep the focus on our original window
|
|
|
|
if (hwnd && (hwnd != GetFocus()))
|
|
SetFocus(hwnd);
|
|
|
|
qde->hdc = hdc;
|
|
|
|
if (!hiw.hwnd || hiw.hwnd == (HWND) -1) {
|
|
|
|
// The library will be freed when WinHelp terminates.
|
|
|
|
if (!hiw.hwnd)
|
|
hiw.hlib = NULL;
|
|
return hiw;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
cIWindows++;
|
|
#endif
|
|
|
|
if (SendMessage(hiw.hwnd, EWM_ASKPALETTE, 0, 0L))
|
|
PostMessage(qde->hwnd, EWM_FINDNEWPALETTE, 0, 0L);
|
|
|
|
return hiw;
|
|
}
|
|
|
|
#ifndef _DEBUG
|
|
#pragma optimize("a", on)
|
|
#endif
|
|
|
|
/****************************
|
|
*
|
|
* Name: PtSizeHiw
|
|
*
|
|
* Purpose: Returns the size of the display of the imbedded window.
|
|
*
|
|
* Arguments: qde: The target display
|
|
* hiw: Handle of imbedded window.
|
|
*
|
|
* Returns: Size of imbedded window.
|
|
*
|
|
***************************/
|
|
|
|
POINT STDCALL PtSizeHiw(QDE qde, HIW hiw)
|
|
{
|
|
/*
|
|
* 16 bit guys need POINTS. 32 bit guys need POINT. We send 32 bit
|
|
* and depend on our thunking mechanism to handle the 32<->16 bit
|
|
* POINT/POINTS translation.
|
|
*
|
|
* Changes here require ssyncing with the thunking system. People who
|
|
* make said changes without also changing the thunking system will be
|
|
* visited by several knuckle-draggers wearing size 14 black Oxford shoes
|
|
* in building #7. [johnhall]
|
|
*/
|
|
|
|
POINT pt;
|
|
POINT ptCopy;
|
|
|
|
if (hiw.hwnd && hiw.hwnd != (HWND) -1) {
|
|
ASSERT(IsValidWindow(hiw.hwnd));
|
|
if (!SendMessage(hiw.hwnd, EWM_SIZEQUERY, (WPARAM) qde->hdc,
|
|
(LPARAM) &pt)) {
|
|
WRECT rc;
|
|
|
|
// Use the actual window size for the base answer.
|
|
|
|
GetWindowWRect(hiw.hwnd, &rc);
|
|
ptCopy.x = rc.cx;
|
|
ptCopy.y = rc.cy;
|
|
return ptCopy;
|
|
}
|
|
// DebugBreak();
|
|
}
|
|
else if (hiw.hwnd == (HWND) -1) {
|
|
ptCopy.x = 0;
|
|
ptCopy.y = 0;
|
|
return ptCopy;
|
|
}
|
|
else {
|
|
LONG lExtent = LGetOOMPictureExtent(qde->hdc, wERRS_BAD_EMBEDDED);
|
|
ptCopy.x = LOWORD(lExtent);
|
|
ptCopy.y = HIWORD(lExtent);
|
|
return ptCopy;
|
|
}
|
|
ptCopy.x = pt.x;
|
|
ptCopy.y = pt.y;
|
|
return ptCopy;
|
|
}
|
|
|
|
/****************************
|
|
*
|
|
* Name: DisplayHiwPt
|
|
*
|
|
* Purpose: Renders the given imbedded window at the given point.
|
|
*
|
|
* Arguments: HIW hiw: Handle to imbedded window.
|
|
* POINT pt: Point at which to display it.
|
|
*
|
|
* Returns: nothing
|
|
*
|
|
***************************/
|
|
|
|
VOID STDCALL DisplayHiwPt(QDE qde, HIW hiw, POINT pt)
|
|
{
|
|
POINT ptSize = PtSizeHiw(qde, hiw);
|
|
|
|
if (hiw.hwnd && hiw.hwnd != (HWND) -1) {
|
|
ASSERT(IsValidWindow(hiw.hwnd));
|
|
if (qde->deType == dePrint) {
|
|
HBITMAP hbm;
|
|
RENDERINFO ri;
|
|
FillRI(&ri, &pt, &ptSize);
|
|
|
|
// BUGBUG: 16 bit embedded windows expect a 16-bit HDC
|
|
|
|
ri.hdc = qde->hdc;
|
|
hbm = (HBITMAP) SendMessage(hiw.hwnd, EWM_RENDER, CF_BITMAP,
|
|
(LPARAM) &ri);
|
|
if (hbm) {
|
|
BITMAP bm;
|
|
HDC hdc = CreateCompatibleDC(qde->hdc);
|
|
if (hdc && GetObject(hbm, sizeof(bm), (LPSTR) &bm) &&
|
|
SelectObject(hdc, hbm)) {
|
|
StretchBlt(qde->hdc, pt.x, pt.y, ptSize.x, ptSize.y,
|
|
hdc, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
|
|
}
|
|
if (hdc)
|
|
DeleteDC(hdc);
|
|
DeleteObject(hbm);
|
|
}
|
|
}
|
|
else {
|
|
MoveWindow(hiw.hwnd, pt.x, pt.y, ptSize.x, ptSize.y, FALSE);
|
|
ShowWindow(hiw.hwnd, SW_NORMAL);
|
|
}
|
|
}
|
|
else if (hiw.hwnd != (HWND) -1) {
|
|
|
|
RECT rc;
|
|
rc.left = pt.x;
|
|
rc.top = pt.y;
|
|
rc.right = pt.x + ptSize.x;
|
|
rc.bottom = pt.y + ptSize.y;
|
|
|
|
// Assume we're out of memory
|
|
|
|
RenderOOMPicture(qde->hdc, &rc, FALSE, wERRS_BAD_EMBEDDED);
|
|
}
|
|
}
|
|
|
|
static void FASTCALL FillRI(RENDERINFO* pri, POINT* ppt, POINT* pptSize)
|
|
{
|
|
pri->rc.Left = (INT16) ppt->x;
|
|
pri->rc.Top = (INT16) ppt->y;
|
|
pri->rc.Right = (INT16) (ppt->x + pptSize->x);
|
|
pri->rc.Bottom = (INT16) (ppt->y + pptSize->y);
|
|
}
|
|
|
|
/****************************
|
|
*
|
|
* Name: DestroyHiw
|
|
*
|
|
* Purpose: Destroys an imbedded window
|
|
*
|
|
* Arguments: HIW hiw: Handle to imbedded window.
|
|
*
|
|
* Returns: Nothing
|
|
*
|
|
***************************/
|
|
|
|
VOID STDCALL DestroyHiw(QDE qde, HIW FAR* qhiw)
|
|
{
|
|
BOOL f;
|
|
|
|
if (!qhiw->hwnd || qhiw->hwnd == (HWND) -1)
|
|
return;
|
|
|
|
f = ((qde->deType == deTopic) ||
|
|
(qde->deType == deAuto) ||
|
|
(qde->deType == deNote) ||
|
|
(qde->deType == deNSR)) &&
|
|
SendMessage(qhiw->hwnd, EWM_ASKPALETTE, 0, 0);
|
|
|
|
RemoveBtnData(qhiw->hwnd); // in case it was one of our embedded windows
|
|
if (IsValidWindow(qhiw->hwnd))
|
|
DestroyWindow(qhiw->hwnd);
|
|
qhiw->hwnd = 0;
|
|
qhiw->hlib = 0;
|
|
|
|
if (f)
|
|
SendMessage(qde->hwnd, EWM_FINDNEWPALETTE, 0, 0L);
|
|
|
|
#ifdef _DEBUG
|
|
cIWindows--;
|
|
ASSERT(cIWindows >= 0);
|
|
#endif
|
|
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: GhGetHiwData
|
|
-
|
|
* Purpose: Retrieves a global handle to an ascii string for copying
|
|
* embedded window text to the clipboard.
|
|
*
|
|
* Arguments: qde The target display (like the screen display, if used).
|
|
* hiw The embedded window.
|
|
*
|
|
* Returns: A Sharable global handle, or null. The caller is
|
|
* responsible for releasing the memory.
|
|
*
|
|
* Globals Used: none.
|
|
*
|
|
* +++
|
|
*
|
|
* Notes:
|
|
*
|
|
***************************************************************************/
|
|
|
|
GH STDCALL GhGetHiwData(QDE qde, HIW hiw)
|
|
{
|
|
RENDERINFO ri;
|
|
|
|
if (hiw.hwnd && hiw.hwnd != (HWND) -1) {
|
|
ri.rc.Left = ri.rc.Right = ri.rc.Top = ri.rc.Bottom = 0;
|
|
ri.hdc = qde->hdc;
|
|
|
|
// BUGBUG: John -- what do we do with a 16-bit help dll? Can we thunk
|
|
// the memory handle to something we can use?
|
|
|
|
return (GH) SendMessage(hiw.hwnd, EWM_RENDER, CF_TEXT, (LPARAM) &ri);
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: GetTextDimensions
|
|
|
|
PURPOSE: Get the width/height of the button
|
|
|
|
PARAMETERS:
|
|
hwnd
|
|
psz
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
04-Feb-1993 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
DWORD STDCALL GetTextDimensions(HWND hwnd, PCSTR psz)
|
|
{
|
|
HDC hdc = GetDC(hwnd);
|
|
DWORD dwRet;
|
|
HFONT hfont, hfontOld;
|
|
POINT pt;
|
|
|
|
if (hdc == NULL)
|
|
return 0L;
|
|
hfont = HfontGetSmallSysFont();
|
|
if (hfont)
|
|
hfontOld = SelectObject(hdc, hfont);
|
|
pt = GetTextSize(hdc, psz, strlen(psz));
|
|
dwRet = MAKELONG(pt.x, pt.y) +
|
|
MAKELONG(CXBUTTONEXTRA, CYBUTTONEXTRA);
|
|
if (hfont)
|
|
SelectObject(hdc, hfontOld);
|
|
ReleaseDC(hwnd, hdc);
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: SaveBtnData
|
|
|
|
PURPOSE: Save the authorable data associated with a button
|
|
|
|
PARAMETERS:
|
|
hwnd
|
|
pszData
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
07-Feb-1993 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
INLINE BOOL STDCALL SaveBtnData(HWND hwnd, PSTR pszData, PSTR pszText)
|
|
{
|
|
int i;
|
|
SHORT ch;
|
|
PSTR psz;
|
|
|
|
// Find an empty slot
|
|
|
|
for (i = 0; i < MAX_BUTTONS; i++) {
|
|
if (btndata[i].hwnd == NULL)
|
|
break;
|
|
}
|
|
|
|
if (i == MAX_BUTTONS) {
|
|
if (fHelpAuthor)
|
|
ErrorQch(GetStringResource(wERRS_TOO_MANY_BUTTONS));
|
|
|
|
return FALSE; // should probably have some kind of error message
|
|
}
|
|
|
|
psz = StrChrDBCS(pszText, ACCESS_KEY);
|
|
|
|
if (psz) {
|
|
ch = VkKeyScan(psz[1]);
|
|
btndata[i].pszText = LocalStrDup(pszText);
|
|
}
|
|
else {
|
|
ch = '\0';
|
|
btndata[i].pszText = NULL;
|
|
}
|
|
btndata[i].hwnd = hwnd;
|
|
btndata[i].ghMacro = LocalStrDup(pszData);
|
|
btndata[i].vKey = ch;
|
|
btndata[i].iWindow = (hwndNote ? -1 : iCurWindow);
|
|
return (BOOL) btndata[i].ghMacro;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: RemoveBtnData
|
|
|
|
PURPOSE: Find the data associated with the window and remove it
|
|
|
|
PARAMETERS:
|
|
hwnd
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
07-Feb-1993 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
INLINE void STDCALL RemoveBtnData(HWND hwnd)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_BUTTONS; i++) {
|
|
if (btndata[i].hwnd == hwnd) {
|
|
btndata[i].hwnd = NULL;
|
|
FreeGh(btndata[i].ghMacro);
|
|
if (btndata[i].pszText)
|
|
FreeLh(btndata[i].pszText);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: doBtnCmd
|
|
|
|
PURPOSE: Process imbedded window command
|
|
|
|
PARAMETERS:
|
|
hwnd
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
// REVIEW: most of these would go away if we had a Macro function
|
|
|
|
CLOSE - close WinHelp
|
|
JUMP - jump to specified topic in specified database
|
|
POPUP - jump to specified topic in specified database, display
|
|
in a popup
|
|
COPYTOPIC - copy current topic to the clipboard
|
|
PRINT - print the current topic
|
|
SHORTCUT - launch app, send it a message
|
|
class_name app_name wparam lparam
|
|
TCARD - send a WM_TCARD message
|
|
PSHEET - launch a property sheet
|
|
ALINK - associative link
|
|
KLINK - associative link
|
|
|
|
MODIFICATION DATES:
|
|
08-Feb-1993 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
void STDCALL doBtnCmd(HWND hwnd)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_BUTTONS; i++) {
|
|
if (btndata[i].hwnd == hwnd) {
|
|
ASSERT(btndata[i].ghMacro);
|
|
if (fHelpAuthor && !FAskFirst(PszFromGh(btndata[i].ghMacro), bLongMacro))
|
|
return;
|
|
Execute(PszFromGh(btndata[i].ghMacro));
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: BtnProc
|
|
|
|
PURPOSE: Subclassed Button procedure
|
|
|
|
PARAMETERS:
|
|
hwnd
|
|
msg
|
|
wParam
|
|
lParam
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
12-Feb-1993 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
LRESULT EXPORT BtnProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (msg) {
|
|
case WM_LBUTTONDOWN:
|
|
if (hwndNote && GetParent(hwnd) == hwndNote)
|
|
fLockPopup = TRUE;
|
|
return CallWindowProc((WNDPROC)lpfnlButtonWndProc, hwnd, msg, wParam,
|
|
lParam);
|
|
|
|
case WM_LBUTTONUP:
|
|
{
|
|
RECT rc;
|
|
POINT pt;
|
|
POINTSTOPOINT(pt, MAKEPOINTS(lParam));
|
|
GetClientRect(hwnd, &rc);
|
|
ASSERT(IsValidWindow(hwnd));
|
|
CallWindowProc((WNDPROC)lpfnlButtonWndProc, hwnd, msg, wParam, lParam);
|
|
if (hwndNote || ahwnd[iCurWindow].hwndParent)
|
|
SetFocus(hwndNote ? hwndNote : ahwnd[iCurWindow].hwndParent);
|
|
if (PtInRect(&rc, pt)) {
|
|
fLockPopup = TRUE;
|
|
GetCursorPos(&ptPopup); // in case this is a popup
|
|
doBtnCmd(hwnd);
|
|
FlushMessageQueue(0);
|
|
ptPopup.x = 0; // in case it wasn't a popup
|
|
fLockPopup = FALSE;
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
case EWM_RENDER:
|
|
if (wParam == CF_TEXT) {
|
|
int cb;
|
|
HGLOBAL gh = GlobalAlloc(GMEM_FIXED,
|
|
cb = GetWindowTextLength(hwnd) + 3);
|
|
if (gh) {
|
|
LPSTR lpsz = PszFromGh(gh);
|
|
GetWindowText(hwnd, lpsz + 1, cb);
|
|
|
|
// Bracket text in <>
|
|
|
|
*lpsz = '<';
|
|
lpsz[cb - 2] = '>';
|
|
lpsz[cb - 1] = '\0';
|
|
}
|
|
return (LRESULT) gh;
|
|
}
|
|
break;
|
|
|
|
// We add these two so that Debug windows doesn't nag about getting
|
|
// a message out of range.
|
|
|
|
case EWM_FINDNEWPALETTE:
|
|
case EWM_ASKPALETTE:
|
|
return FALSE;
|
|
|
|
default:
|
|
ASSERT(IsValidWindow(hwnd));
|
|
return CallWindowProc((WNDPROC)lpfnlButtonWndProc, hwnd, msg, wParam,
|
|
lParam);
|
|
}
|
|
}
|