Windows NT 4.0 source code leak
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

/*****************************************************************************
*
* 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);
}
}