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.
1565 lines
44 KiB
1565 lines
44 KiB
/*****************************************************************************
|
|
* *
|
|
* BINDING.C *
|
|
* *
|
|
* Copyright (C) Microsoft Corporation 1990 - 1994 *
|
|
* All Rights reserved. *
|
|
* *
|
|
******************************************************************************
|
|
* *
|
|
* Module Intent: Binds string versions of Macro calls to actual calls. *
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
#include "help.h"
|
|
#pragma hdrstop
|
|
|
|
#include "inc\routines.h"
|
|
#include "inc\macros.h"
|
|
#include "inc\thunk.h"
|
|
|
|
#include <malloc.h> // for bogus malloc call
|
|
#include <memory.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
_subsystem(BINDING);
|
|
|
|
/*****************************************************************************
|
|
* *
|
|
* Typedefs *
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
// These prototypes are used to cast function calls to get rid of warnings.
|
|
|
|
typedef VOID (STDCALL *INTPROC)(int);
|
|
typedef VOID (STDCALL *UINTPROC)(DWORD);
|
|
typedef VOID (STDCALL *ULONGPROC)(DWORD);
|
|
typedef VOID (STDCALL *LONGPROC)(LONG);
|
|
typedef VOID (STDCALL *WORDPROC)(WORD);
|
|
typedef VOID (STDCALL *DWORDPROC)(DWORD);
|
|
typedef VOID (STDCALL *QCHPROC)(LPSTR);
|
|
typedef VOID (STDCALL *PCHPROC)(PSTR);
|
|
typedef LONG (STDCALL *VOIDPROC)(VOID);
|
|
|
|
typedef struct
|
|
{
|
|
LONG lMacroReturn; /* Contains the return from macro. */
|
|
PSTR pchMacro; /* Points to the start of the macro */
|
|
/* to be executed. */
|
|
ME me; /* Contains an error structure */
|
|
/* which is passed to the current */
|
|
/* macro if needed. This can then */
|
|
/* be used to look up any error if */
|
|
/* an external macro error occurs. */
|
|
PSTR pszPath;
|
|
} MI, * PMI;
|
|
|
|
typedef VOID (STDCALL *PFNVAR)(PMI pmi);
|
|
typedef LONG (STDCALL *LPFNVAR)(PMI pmi);
|
|
|
|
/*
|
|
* The Internal Variable structure is used to contain the list of internal
|
|
* variables available, their types, and the functions associated with
|
|
* retrieving their current value
|
|
*/
|
|
|
|
typedef struct {
|
|
PSTR pchName; // variable name
|
|
int wReturn; // variable type
|
|
PFNVAR pfnVar; // function
|
|
} IV, * PIV;
|
|
|
|
/*****************************************************************************
|
|
* *
|
|
* Defines *
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
#define SzDLLName(pgbind) ((LPSTR)(pgbind->rgbData+pgbind->ichDLL))
|
|
|
|
|
|
/*
|
|
** The following constants are used to parse a macro expression and
|
|
** its proto-type.
|
|
*/
|
|
|
|
#define chOpenBrace '('
|
|
#define chCloseBrace ')'
|
|
#define chSeparator1 ':'
|
|
#define chSeparator2 ';'
|
|
#define chStartQuote '`'
|
|
#define chEndQuote '\''
|
|
#define chQuote '"'
|
|
#define chEscape '\\'
|
|
#define chParamSep ','
|
|
#define chReturnSep '='
|
|
#define chShortSigned 'i'
|
|
#define chShortUnsigned 'u'
|
|
#define chNearString 's'
|
|
#define chLongSigned 'I'
|
|
#define chLongUnsigned 'U'
|
|
#define chFarString 'S'
|
|
#define chVoid 'v'
|
|
|
|
/*
|
|
** The following are used as flags words when determining what type of
|
|
** return a macro proto-type specifies.
|
|
*/
|
|
|
|
#define fwANY 0 /* any return. */
|
|
#define fwSHORTNUM 1 /* short int or unsigned. */
|
|
#define fwLONGNUM 2 /* long int or unsigned. */
|
|
#define fwNEARSTRING 3 /* near pointer. */
|
|
#define fwFARSTRING 4 /* far pointer. */
|
|
#define fwVOID 5 /* void return. */
|
|
|
|
/*****************************************************************************
|
|
* *
|
|
* Macros *
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
// #define FAlpha(ch) ((((ch) >= 'A') && ((ch) <= 'Z')) || (((ch) >= 'a') && ((ch) <= 'z')))
|
|
// #define FDigit(ch) (((ch) >= '0' && (ch) <= '9'))
|
|
#define FHexnum(ch) (isdigit(ch) || ((ch) >= 'A' && (ch) <= 'F') || \
|
|
((ch) >= 'a' && (ch) <= 'f'))
|
|
#define FCIdent(ch) (isalpha(ch) || isdigit(ch) || (ch == '_'))
|
|
#define FNumParam(ch) ( ((ch) == chShortSigned) || ((ch) == chShortUnsigned) \
|
|
|| ((ch) == chLongUnsigned) || ((ch) == chLongSigned))
|
|
/*
|
|
* These functions should maybe be replaced with internal WinHelp
|
|
** functions.
|
|
*/
|
|
|
|
PMI pmi;
|
|
// UINT wReturn;
|
|
|
|
/*
|
|
** The following are expected to be found globally. Note that
|
|
** HdeGetEnv() is currently not accessable outside of WinApp.
|
|
*/
|
|
|
|
/*****************************************************************************
|
|
* *
|
|
* Prototypes *
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
static BOOL STDCALL FFindEndQuote (PMI, char);
|
|
static LONG STDCALL LIntegerParameter (PMI, int*, int);
|
|
static PSTR STDCALL pchSkip (PSTR);
|
|
static PSTR STDCALL PExtractTokenName (PCSTR);
|
|
static LPSTR STDCALL QchStringParameter (PMI, int*, int);
|
|
static DWORD STDCALL UlUnsignedParameter (PMI, int*, int);
|
|
static int STDCALL WCheckParam (char, char);
|
|
static int STDCALL WExecuteMacro (PMI, int);
|
|
|
|
/*****************************************************************************
|
|
* *
|
|
* Static Variables *
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
PMI pmi;
|
|
int* pwMacroError;
|
|
int wReturn;
|
|
extern BOOL fMacroFlag;
|
|
extern char txtUser32Dll[];
|
|
extern MAKE_CALL_CLEANUP lpCallThnkCleanup;
|
|
|
|
int rgmpWMErrWErrs[] = {
|
|
0, // wMERR_NONE
|
|
wERRS_OOM, // wMERR_MEMORY
|
|
wERRS_MACROPROB, // wMERR_PARAM
|
|
wERRS_BADFILE, // wMERR_FILE
|
|
wERRS_MACROPROB, // wMERR_ERROR
|
|
wERRS_MACROMSG // wMERR_MESSAGE
|
|
};
|
|
|
|
/* #########################################################################*/
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: LCurrentWindow
|
|
-
|
|
* Purpose: This function is called in order to retrieve the window handle
|
|
* variable.
|
|
*
|
|
* Arguments: pmi - pointer to macro information
|
|
*
|
|
* Returns: Returns a window handle.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static LONG STDCALL LCurrentWindow(PMI pmi)
|
|
{
|
|
return LGetInfo(GI_CURRHWND, NULL);
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: LAppWindow
|
|
-
|
|
* Purpose: This function is called in order to retrieve the window handle
|
|
* of the application.
|
|
*
|
|
* Arguments: pmi - pointer to macro information
|
|
*
|
|
* Returns: Returns a window handle.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static LONG STDCALL LAppWindow(PMI pmi)
|
|
{
|
|
return LGetInfo(GI_MAINHWND, NULL);
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: QchSetCurrentPath
|
|
-
|
|
* Purpose: This function is called in order to set the current path in
|
|
* the internal path variable.
|
|
*
|
|
* Arguments: pmi - pointer to macro information
|
|
*
|
|
* Returns: Returns a pointer to the internal variable containing
|
|
* the current path.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static PSTR STDCALL QchSetCurrentPath(PMI pmi)
|
|
{
|
|
HDE hde = HdeGetEnvHwnd(ahwnd[iCurWindow].hwndTopic);
|
|
if (!hde)
|
|
return NULL;
|
|
pmi->pszPath = LocalStrDup(QDE_FM(QdeFromGh(hde)));
|
|
|
|
return pmi->pszPath;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: HfsGet
|
|
-
|
|
* Purpose: Gets the handle to the file system for the current window.
|
|
*
|
|
* Arguments: pmi - pointer to macro information
|
|
*
|
|
* Returns: Returns the handle to the file system -- ghNil returned in
|
|
* case of an error.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static LONG STDCALL HfsGet(PMI pmi)
|
|
{
|
|
return LGetInfo(GI_HFS, NULL);
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: LCoForeground
|
|
-
|
|
* Purpose: Get the foreground color for the current window.
|
|
*
|
|
* Arguments: pmi - pointer to macro information
|
|
*
|
|
* Returns: Returns the foreground color
|
|
*
|
|
***************************************************************************/
|
|
|
|
static LONG STDCALL LCoForeground(PMI pmi)
|
|
{
|
|
return LGetInfo(GI_FGCOLOR, NULL);
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: LCoBackground
|
|
-
|
|
* Purpose: Gets the background color for the current window.
|
|
*
|
|
* Arguments: pmi - pointer to macro information
|
|
*
|
|
* Returns: Returns the background color
|
|
*
|
|
***************************************************************************/
|
|
|
|
static LONG STDCALL LCoBackground(PMI pmi)
|
|
{
|
|
return LGetInfo(GI_BKCOLOR, NULL);
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: LError
|
|
-
|
|
* Purpose: This function is called in order to return a pointer to the
|
|
* error structure.
|
|
*
|
|
* Arguments: pmi - pointer to macro information
|
|
*
|
|
* Returns: Returns an error structure pointer.
|
|
*
|
|
*
|
|
***************************************************************************/
|
|
|
|
static LONG STDCALL LError(PMI pmi)
|
|
{
|
|
return (LONG) (QME)&pmi->me;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: LTopicNo
|
|
-
|
|
* Purpose: Returns topic number of the current topic.
|
|
*
|
|
* Arguments: pmi - pointer to macro information
|
|
*
|
|
* Returns: success: lTopicNo; failure: -1L
|
|
*
|
|
***************************************************************************/
|
|
|
|
static LONG STDCALL LTopicNo(PMI pmi)
|
|
{
|
|
return LGetInfo(GI_TOPICNO, NULL);
|
|
}
|
|
|
|
/*
|
|
* This contains the list of internal variables available. As with
|
|
* macro names, comparison is case insensitive.
|
|
*/
|
|
|
|
#ifndef NO_PRAGMAS
|
|
#pragma data_seg(".text", "CODE")
|
|
#endif
|
|
const IV iv[] =
|
|
{
|
|
"hwndContext", fwLONGNUM, (PFNVAR) LCurrentWindow,
|
|
"hwndApp", fwLONGNUM, (PFNVAR) LAppWindow,
|
|
"qchPath", fwFARSTRING, (PFNVAR) QchSetCurrentPath,
|
|
"qError", fwFARSTRING, (PFNVAR) LError,
|
|
"lTopicNo", fwLONGNUM, (PFNVAR) LTopicNo,
|
|
"hfs", fwLONGNUM, (PFNVAR) HfsGet,
|
|
"coForeground", fwLONGNUM, (PFNVAR) LCoForeground,
|
|
"coBackground", fwLONGNUM, (PFNVAR) LCoBackground,
|
|
NULL, 0, NULL,
|
|
};
|
|
#ifndef NO_PRAGMAS
|
|
#pragma data_seg()
|
|
#endif
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: pchSkip
|
|
-
|
|
* Purpose: This function scans the given string, skipping
|
|
* characters that are considered whitespace, until either
|
|
* the end of the string or a non- white-space character is
|
|
* found.
|
|
*
|
|
* Arguments: pchMacro - near pointer into a macro string.
|
|
*
|
|
* Returns: Returns a pointer to either the end of the string, or the
|
|
* first non-whitespace character.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static PSTR STDCALL pchSkip(PSTR pchMacro)
|
|
{
|
|
for (;; pchMacro++) {
|
|
switch (*pchMacro) {
|
|
case ' ':
|
|
case '\t':
|
|
case '\n':
|
|
case '\r':
|
|
case '\f':
|
|
case '\v':
|
|
break;
|
|
|
|
default:
|
|
return pchMacro;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if DEADCODE
|
|
/***************************************************************************
|
|
*
|
|
- Name: PchSkipIntegerPch
|
|
-
|
|
* Purpose: This function scans the given string, skipping
|
|
* characters that are considered part of an unsigned
|
|
* integer, as scanned by the function ULFromQch()
|
|
* in adt\strcnv.c.
|
|
*
|
|
* Arguments: pchInteger
|
|
*
|
|
* Returns: Returns a pointer to either the end of the string, or the
|
|
* first character that is not part of the integer.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static PSTR STDCALL PchSkipIntegerPch(PSTR pchInteger)
|
|
{
|
|
|
|
// Check for "0x", indicating hexadecimal:
|
|
|
|
if (pchInteger[0] == '0' && (pchInteger[1] == 'x' || pchInteger[1] == 'X'))
|
|
{
|
|
pchInteger += 2;
|
|
while (FHexnum(*pchInteger))
|
|
pchInteger++;
|
|
}
|
|
else
|
|
while (isdigit(*pchInteger))
|
|
pchInteger++;
|
|
|
|
return pchInteger;
|
|
}
|
|
#endif
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: PExtractTokenName
|
|
-
|
|
* Purpose: This function extracts a valid token name from the given
|
|
* string. A token name must begin with either an alpha
|
|
* character, or "_", and contain only alpha-numeric or "_"
|
|
* characters.
|
|
*
|
|
* Arguments: pchMacro - near pointer into a macro string.
|
|
*
|
|
* Returns: Returns a pointer to the first character beyond the end
|
|
* of the token name found, or NULL if a token name could
|
|
* not be extracted from the string.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static PSTR STDCALL PExtractTokenName(PCSTR pchMacro)
|
|
{
|
|
if (!isalpha(*pchMacro) && (*pchMacro != '_') && (*pchMacro != '#'))
|
|
return NULL;
|
|
for (pchMacro++; FCIdent(*pchMacro) || *pchMacro == '#'; pchMacro++);
|
|
return (PSTR) pchMacro;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: LIntegerParameter
|
|
-
|
|
* Purpose: This function extracts a valid integer from the given string,
|
|
* advancing the current pointer to beyond the end of the number
|
|
* extracted.
|
|
*
|
|
* A valid integer optionally begins with "-", followed by either
|
|
* a numeric sequence, or a macro. If a macro is called, the
|
|
* return value of the macro is returned.
|
|
*
|
|
* Arguments: pmi - points to the current macro information block.
|
|
* pwMacroError - points to a buffer to contain any possible
|
|
* macro error.
|
|
* wReturn - Contains the type of return expected. This is
|
|
* used as the return type parameter to any macro
|
|
* call made.
|
|
*
|
|
* Returns: Returns the number extracted or the number returned from any
|
|
* macro call.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static LONG STDCALL LIntegerParameter(PMI pmi, int* pwMacroError, int wReturn)
|
|
{
|
|
LONG lReturn;
|
|
BOOL fPositive;
|
|
|
|
pmi->pchMacro = pchSkip(pmi->pchMacro);
|
|
if (*pmi->pchMacro == '-') {
|
|
pmi->pchMacro++;
|
|
fPositive = FALSE;
|
|
}
|
|
else
|
|
fPositive = TRUE;
|
|
if ((*pmi->pchMacro < '0') || (*pmi->pchMacro > '9')) {
|
|
*pwMacroError = WExecuteMacro(pmi, wReturn);
|
|
lReturn = pmi->lMacroReturn;
|
|
}
|
|
else {
|
|
lReturn = (LONG) strtol(pmi->pchMacro, &pmi->pchMacro, 0);
|
|
}
|
|
return fPositive ? lReturn : -lReturn;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: UlUnsignedParameter
|
|
-
|
|
* Purpose: This function extracts a valid positive number from the
|
|
* given string, advancing the current pointer to beyond the
|
|
* end of the number extracted.
|
|
*
|
|
* A valid positive number is specified either by a numeric
|
|
* sequence, or a macro. If a macro is called, the return
|
|
* value of the macro is returned.
|
|
*
|
|
* Arguments: pmi - points to the current macro information block.
|
|
* wReturn - Contains the type of return expected. This is
|
|
* used as the return type parameter to any macro
|
|
* call made.
|
|
*
|
|
* Returns: Returns the number extracted or the number returned from
|
|
* any macro call.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static DWORD STDCALL UlUnsignedParameter(PMI pmi, int* pwMacroError, int wReturn)
|
|
{
|
|
DWORD ulReturn;
|
|
|
|
pmi->pchMacro = pchSkip(pmi->pchMacro);
|
|
if ((*pmi->pchMacro < '0') || (*pmi->pchMacro > '9')) {
|
|
*pwMacroError = WExecuteMacro(pmi, wReturn);
|
|
return (DWORD)pmi->lMacroReturn;
|
|
}
|
|
|
|
ulReturn = (DWORD) strtoul(pmi->pchMacro, &pmi->pchMacro, 0);
|
|
|
|
return ulReturn;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: FFindEndQuote
|
|
-
|
|
* Purpose: This function locates a sub-string by looking for the
|
|
* specified end quotation character, and advancing the
|
|
* current pointer to that character.
|
|
*
|
|
* Arguments: pmi - Points to the current macro information block.
|
|
* chEnd - Contains the end quotation character being used
|
|
* for this sub-string.
|
|
*
|
|
* Returns: TRUE if the end quotation character was found, else FALSE if
|
|
* a (char)0 character was encountered.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static BOOL STDCALL FFindEndQuote(PMI pmi, char chEnd)
|
|
{
|
|
#ifdef DBCS
|
|
for (; *pmi->pchMacro != chEnd; pmi->pchMacro = CharNext(pmi->pchMacro)) {
|
|
#else
|
|
for (; *pmi->pchMacro != chEnd; pmi->pchMacro++) {
|
|
#endif //DBCS
|
|
switch (*pmi->pchMacro) {
|
|
case (char)0:
|
|
return FALSE;
|
|
case chEscape:
|
|
lstrcpy(pmi->pchMacro, pmi->pchMacro + 1);
|
|
break;
|
|
case chQuote:
|
|
pmi->pchMacro++;
|
|
if (!FFindEndQuote(pmi, chQuote))
|
|
return FALSE;
|
|
break;
|
|
case chStartQuote:
|
|
pmi->pchMacro++;
|
|
if (!FFindEndQuote(pmi, chEndQuote))
|
|
return FALSE;
|
|
break;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: QStringParameter
|
|
-
|
|
* Purpose: A quoted string may use either the double quoted pair
|
|
* (""), or the single left and right quote pair (`') to
|
|
* signify the start and ending of a string. When within
|
|
* the string itself, the bsol (\) may be used to
|
|
* specifically ignore the meaning of the following quoted
|
|
* character. Also, pairs of embedded quotation marks may
|
|
* occur, as long as they do not interfere with the
|
|
* character pair used to signify the start and end of the
|
|
* string itself.
|
|
*
|
|
* Arguments: pmi - Points to the current macro information block.
|
|
* pwMacroError - Points to a buffer to contain any possible
|
|
* macro error.
|
|
* wReturn - Contains the type of return expected. This
|
|
* is used as the return type parameter to any
|
|
* macro call made.
|
|
*
|
|
* Returns: Returns a pointer to the start of the string extracted or
|
|
* the pointer returned from any macro call.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static PSTR STDCALL QchStringParameter(PMI pmi, int* pwMacroError, int wReturn)
|
|
{
|
|
PSTR pchReturn;
|
|
char chEnd;
|
|
|
|
pmi->pchMacro = pchSkip(pmi->pchMacro);
|
|
switch (*pmi->pchMacro) {
|
|
case chQuote:
|
|
chEnd = chQuote;
|
|
break;
|
|
case chStartQuote:
|
|
chEnd = chEndQuote;
|
|
break;
|
|
default:
|
|
*pwMacroError = WExecuteMacro(pmi, wReturn);
|
|
return (PSTR) pmi->lMacroReturn;
|
|
}
|
|
pchReturn = ++pmi->pchMacro;
|
|
if (!FFindEndQuote(pmi, chEnd))
|
|
*pwMacroError = wERRS_UNCLOSED;
|
|
else
|
|
*(pmi->pchMacro++) = '\0';
|
|
return pchReturn;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: WCheckParam
|
|
-
|
|
* Purpose: This function makes a few error checks on the parameters to
|
|
* give better reporting information.
|
|
*
|
|
* Arguments: chType - the parameter type
|
|
* chNextChar - the first character of the next token.
|
|
*
|
|
* Returns: Returns an error value with wERRS_NONE indicating there
|
|
* is no error.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static int STDCALL WCheckParam(char chType, char chNextChar)
|
|
{
|
|
if (FNumParam(chType)) { // Numbers cannot begin with quotes
|
|
if ((chNextChar == chQuote) || (chNextChar == chStartQuote))
|
|
return wERRS_BADPARAM;
|
|
|
|
// Unsigns cannot begin with '-'
|
|
|
|
if (((chType == chShortUnsigned) || (chType == chLongUnsigned))
|
|
&& (chNextChar == '-'))
|
|
return wERRS_BADPARAM;
|
|
|
|
if (!FCIdent(chNextChar) && (chNextChar != '-'))
|
|
return wERRS_SYNTAX;
|
|
}
|
|
else /* Numbers or a minus sign mean */
|
|
{ /* type mismatch for a string */
|
|
if ((chNextChar == '-') || isdigit(chNextChar))
|
|
return wERRS_BADPARAM;
|
|
/* A string parameter must begin */
|
|
/* with a letter, an underscore */
|
|
if ( !isalpha(chNextChar) /* a double quote or a start quote*/
|
|
&& (chNextChar != '-')
|
|
&& (chNextChar != chQuote)
|
|
&& (chNextChar != chStartQuote)
|
|
)
|
|
return wERRS_SYNTAX;
|
|
}
|
|
|
|
return wERRS_NONE;
|
|
}
|
|
|
|
/* Turn off aliasing so that ugly */
|
|
/* hack will take. */
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: WExecuteMacro
|
|
-
|
|
* Purpose: This function is called to execute the specified macro
|
|
* name. A macro at the minimum contains a name followed
|
|
* by start and end parameter delimiters: "name()".
|
|
*
|
|
* In order to make life a little easier for the caller, a
|
|
* NULL function (zero length) call is permissible, and
|
|
* returns wERRS_NONE.
|
|
*
|
|
* The function expects to be able to first extract a
|
|
* valid function name and proto-type for that name, then
|
|
* push the parameters for that name onto the stack before
|
|
* calling the macro. The act of resolving macro
|
|
* paramters may entail recursively calling this function
|
|
* for an embedded macro used as a macro parameter, and
|
|
* resolving variables.
|
|
*
|
|
* Arguments: pmi - Points to the current macro information block.
|
|
* wReturn - Contains the type of return expected.
|
|
* This is used to compare against the actual
|
|
* return type of the macro. This can be set
|
|
* to fwANY, in which case any return type is
|
|
* acceptable.
|
|
*
|
|
* Returns: Returns a either wERRS_NONE if no error occurred, or an
|
|
* internal or external error number.
|
|
*
|
|
*
|
|
***************************************************************************/
|
|
|
|
#define MAX_ARGS 20 // maximum number of parameters
|
|
|
|
#ifndef RAWHIDE
|
|
#ifndef NO_PRAGMAS
|
|
#pragma data_seg(".text", "CODE")
|
|
#endif
|
|
static const char txtExecFullTextSearch[] = "ExecFullTextSearch";
|
|
static const char txtFind[] = "Find";
|
|
#ifndef NO_PRAGMAS
|
|
#pragma data_seg()
|
|
#endif
|
|
#endif
|
|
|
|
static int STDCALL WExecuteMacro(PMI pmi, int wReturn)
|
|
{
|
|
PSTR pch;
|
|
FARPROC lpfn;
|
|
int wMacroError;
|
|
PSTR pchProto;
|
|
char chPrototype[cchMAXPROTO + 1];
|
|
int wReturnType;
|
|
BOOL fMissing = FALSE;
|
|
PSTR pszTypes;
|
|
int curstack;
|
|
HDC hdc;
|
|
QDE qde;
|
|
HDE hde;
|
|
int iSaveCurWindow;
|
|
QGBIND qgbind = NULL;
|
|
DWORD argstack[MAX_ARGS];
|
|
|
|
// We need to check the safety of processing this macro
|
|
|
|
if (fMacroFlag) {
|
|
#ifdef _PRIVATE
|
|
SendStringToParent("Following macro NOT executed:\r\n");
|
|
SendStringToParent("M:");
|
|
SendStringToParent(pmi->pchMacro);
|
|
SendStringToParent("\r\n");
|
|
#endif
|
|
return wERRS_MACROREENTER;
|
|
}
|
|
|
|
// Skip white space starting macro
|
|
|
|
pmi->pchMacro = pchSkip(pmi->pchMacro);
|
|
|
|
SendStringToParent("M:");
|
|
SendStringToParent(pmi->pchMacro);
|
|
SendStringToParent("\r\n");
|
|
|
|
if (!*pmi->pchMacro) // Found end of macro string -- no execution or error
|
|
return wERRS_NONE;
|
|
|
|
// Get macro name or other token.
|
|
|
|
if ((pchProto = PExtractTokenName(pmi->pchMacro)) == NULL)
|
|
return wERRS_BADNAME;
|
|
|
|
pch = pchSkip(pchProto);
|
|
if (*pch != chOpenBrace) { // If we do not find an open brace
|
|
PIV piv;
|
|
char ch;
|
|
|
|
ch = *pch;
|
|
*pch = '\0';
|
|
{
|
|
// Get rid of blanks in the macro.
|
|
|
|
#if 0
|
|
|
|
/*
|
|
* This was in the original NTj code tree -- however, since macro names
|
|
* are never localized they will always be SBCS names.
|
|
*/
|
|
|
|
//#ifdef DBCS
|
|
char *pchEnd = pch;
|
|
|
|
while (pchEnd > pchProto) {
|
|
pchEnd = CharPrev(pchProto, pchEnd);
|
|
if (*pchEnd != ' ') {
|
|
if (IsDBCSLeadByte(*pchEnd)) {
|
|
pchEnd++;
|
|
}
|
|
*(pchEnd + 1) = '\0';
|
|
break;
|
|
}
|
|
}
|
|
// #else
|
|
#endif
|
|
char *pchEnd = pch - 1;
|
|
|
|
while (*pchEnd == ' ')
|
|
--pchEnd;
|
|
*(pchEnd + 1) = '\0';
|
|
}
|
|
|
|
// Look through local variable table
|
|
|
|
for (piv = (PIV) iv; piv->pchName != NULL; piv++) {
|
|
if (_strcmpi(piv->pchName, pmi->pchMacro) == 0) {
|
|
*pch = ch;
|
|
|
|
// Check for return type match
|
|
|
|
pmi->pchMacro = pch;
|
|
if ((wReturn != fwANY) && (wReturn != piv->wReturn)) {
|
|
switch(piv->wReturn) {
|
|
case fwSHORTNUM:
|
|
if (wReturn != fwLONGNUM)
|
|
return wERRS_MISMATCHTYPE;
|
|
else
|
|
pmi->lMacroReturn = 0x0000ffff & ((LPFNVAR)(piv->pfnVar))(pmi);
|
|
break;
|
|
|
|
case fwLONGNUM:
|
|
if (wReturn != fwSHORTNUM)
|
|
return wERRS_MISMATCHTYPE;
|
|
else
|
|
pmi->lMacroReturn = 0x0000ffff & ((LPFNVAR)(piv->pfnVar))(pmi);
|
|
break;
|
|
|
|
case fwNEARSTRING:
|
|
if (wReturn != fwFARSTRING)
|
|
return wERRS_MISMATCHTYPE;
|
|
else
|
|
pmi->lMacroReturn = ((LPFNVAR)(piv->pfnVar))(pmi);
|
|
break;
|
|
|
|
case fwFARSTRING:
|
|
if (wReturn != fwNEARSTRING)
|
|
return wERRS_MISMATCHTYPE;
|
|
else
|
|
pmi->lMacroReturn = ((LPFNVAR)(piv->pfnVar))(pmi);
|
|
break;
|
|
|
|
default:
|
|
return wERRS_MISMATCHTYPE;
|
|
}
|
|
}
|
|
pmi->lMacroReturn = ((LPFNVAR)(piv->pfnVar))(pmi);
|
|
return wERRS_NONE;
|
|
}
|
|
}
|
|
strcpy(pmi->me.rgchError, pmi->pchMacro);
|
|
return wERRS_UNDEFINEDVAR;
|
|
}
|
|
pch++;
|
|
|
|
// Null terminate function and find its prototype.
|
|
|
|
*pchProto = '\0';
|
|
|
|
FtsMacro:
|
|
if ((lpfn = QprocFindLocalRoutine(pmi->pchMacro, chPrototype)) == NULL) {
|
|
DBWIN("GlobalRoutine");
|
|
DBWIN(pmi->pchMacro);
|
|
if ((qgbind = QprocFindGlobalRoutine(pmi->pchMacro, chPrototype))
|
|
== NULL) {
|
|
if (_strcmpi(pmi->pchMacro, "ExecFullTextSearch") == 0) {
|
|
#ifndef RAWHIDE
|
|
/*
|
|
* Convert to our own full-text search macro. This only
|
|
* works if we have a .gid file, otherwise it goes to the
|
|
* keyword search.
|
|
*/
|
|
|
|
strcpy(pmi->pchMacro, "Find");
|
|
strcpy(pch, ")"); // Remove the parameters
|
|
goto FtsMacro;
|
|
#else
|
|
return wERRS_NOSRCHINFO;
|
|
#endif
|
|
}
|
|
strcpy(pmi->me.rgchError, pmi->pchMacro);
|
|
#ifndef RAWHIDE
|
|
if (_strcmpi(pmi->pchMacro, "InitRoutines") == 0)
|
|
return wERRS_NOSRCHINFO;
|
|
#endif
|
|
return wERRS_NOROUTINE; // Routine not found, return error
|
|
}
|
|
else {
|
|
lpfn = qgbind->lpfn;
|
|
}
|
|
}
|
|
|
|
pmi->pchMacro = FirstNonSpace(pch); // Skip past macro name
|
|
pchProto = chPrototype;
|
|
|
|
// Get return type if it exists
|
|
|
|
if (*pchProto && *(pchProto + 1) == chReturnSep) {
|
|
|
|
// Macro prototype is not localized, so it will always be SBCS
|
|
|
|
switch (*(pchProto++)) {
|
|
case chShortSigned:
|
|
case chShortUnsigned:
|
|
wReturnType = fwSHORTNUM;
|
|
break;
|
|
|
|
case chNearString:
|
|
wReturnType = fwNEARSTRING;
|
|
break;
|
|
|
|
case chLongSigned:
|
|
case chLongUnsigned:
|
|
wReturnType = fwLONGNUM;
|
|
break;
|
|
|
|
case chFarString:
|
|
wReturnType = fwFARSTRING;
|
|
break;
|
|
|
|
case chVoid:
|
|
wReturnType = fwVOID;
|
|
break;
|
|
|
|
default:
|
|
return wERRS_RETURNTYPE;
|
|
}
|
|
pchProto++;
|
|
}
|
|
else
|
|
wReturnType = fwVOID;
|
|
|
|
if ((wReturn != fwANY) && (wReturn != wReturnType))
|
|
{
|
|
switch(wReturnType)
|
|
{
|
|
case fwSHORTNUM:
|
|
if (wReturn != fwLONGNUM)
|
|
return wERRS_MISMATCHTYPE;
|
|
else
|
|
break;
|
|
|
|
case fwLONGNUM:
|
|
if (wReturn != fwSHORTNUM)
|
|
return wERRS_MISMATCHTYPE;
|
|
else
|
|
break;
|
|
|
|
case fwNEARSTRING:
|
|
if (wReturn != fwFARSTRING)
|
|
return wERRS_MISMATCHTYPE;
|
|
else
|
|
break;
|
|
|
|
case fwFARSTRING:
|
|
if (wReturn != fwNEARSTRING)
|
|
return wERRS_MISMATCHTYPE;
|
|
else
|
|
break;
|
|
|
|
default:
|
|
return wERRS_MISMATCHTYPE;
|
|
}
|
|
}
|
|
|
|
wMacroError = wERRS_NONE;
|
|
|
|
curstack = 0;
|
|
pszTypes = pchProto; // save the types string for thunk use
|
|
for (; *pchProto;) {
|
|
LONG lParam;
|
|
|
|
pmi->pchMacro = pchSkip(pmi->pchMacro);
|
|
|
|
if ((*pmi->pchMacro) == chCloseBrace)
|
|
fMissing = TRUE;
|
|
|
|
if (!fMissing && (wMacroError =
|
|
WCheckParam(*pchProto, *pmi->pchMacro)) != wERRS_NONE)
|
|
break;
|
|
|
|
switch (*(pchProto++)) {
|
|
case chShortSigned:
|
|
if (fMissing)
|
|
lParam = 0;
|
|
else
|
|
lParam = LIntegerParameter(pmi, &wMacroError, fwSHORTNUM);
|
|
break;
|
|
|
|
case chLongSigned:
|
|
if (fMissing)
|
|
lParam = 0;
|
|
else
|
|
lParam = LIntegerParameter(pmi, &wMacroError, fwLONGNUM);
|
|
break;
|
|
|
|
case chShortUnsigned:
|
|
if (fMissing)
|
|
lParam = 0;
|
|
else
|
|
lParam = (LONG)UlUnsignedParameter(pmi, &wMacroError,
|
|
fwSHORTNUM);
|
|
break;
|
|
|
|
case chLongUnsigned:
|
|
if (fMissing)
|
|
lParam = 0;
|
|
else
|
|
lParam = UlUnsignedParameter(pmi, &wMacroError, fwLONGNUM);
|
|
break;
|
|
|
|
case chNearString:
|
|
if (fMissing)
|
|
lParam = (LONG) txtZeroLength;
|
|
else
|
|
lParam = (LONG)QchStringParameter(pmi, &wMacroError,
|
|
fwNEARSTRING);
|
|
break;
|
|
|
|
case chFarString:
|
|
if (fMissing)
|
|
lParam = (LONG) (LPSTR) txtZeroLength;
|
|
else
|
|
lParam = (LONG) QchStringParameter(pmi, &wMacroError,
|
|
fwFARSTRING);
|
|
break;
|
|
|
|
default:
|
|
wMacroError = wERRS_BADPROTO;
|
|
break;
|
|
}
|
|
|
|
if (wMacroError != wERRS_NONE)
|
|
break;
|
|
else {
|
|
|
|
// Save in private stack so we can reverse push them
|
|
|
|
argstack[curstack++] = lParam;
|
|
|
|
if (!fMissing) {
|
|
|
|
// Move to next parameter
|
|
|
|
pmi->pchMacro = pchSkip(pmi->pchMacro);
|
|
|
|
// If ',' not there, then not enough parameters
|
|
|
|
if (*pchProto && (*(pmi->pchMacro++) != chParamSep)) {
|
|
pmi->pchMacro--;
|
|
fMissing = TRUE;
|
|
}
|
|
}
|
|
}
|
|
if (wMacroError != wERRS_NONE)
|
|
break;
|
|
}
|
|
|
|
if (wMacroError != wERRS_NONE)
|
|
return wMacroError;
|
|
|
|
if (*pmi->pchMacro != chCloseBrace)
|
|
return wERRS_CLOSEBRACE; // missing closing brace
|
|
|
|
pmi->pchMacro = pchSkip(pmi->pchMacro);
|
|
|
|
pmi->pchMacro++;
|
|
pmi->me.fwFlags = fwMERR_ABORT;
|
|
pmi->me.wError = wMERR_NONE;
|
|
*pmi->me.rgchError = '\0';
|
|
|
|
/*
|
|
UGLY HACK ALERT!!!
|
|
|
|
The following code is a VERY big (short term) hack. What is going on is
|
|
that other windows may bring up a message box or otherwise cause cause
|
|
our messages to be processed for us. 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 macro call returns. To solve this
|
|
problem in the short term, we are saving the HDS across the call. this
|
|
fix depends on the fact that LGetInfo() will return the correct HDE that
|
|
is in use by this function.
|
|
|
|
A longer term solution (but a somewhat risky one for fixing at this late
|
|
date), is to post all Execute commands so that we do not run from within
|
|
a navigator call (and therefore do not have our "guts" open).
|
|
|
|
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.
|
|
|
|
16-Jul-1994 [ralphw] Aliasing turned on -- does it work?
|
|
|
|
*/
|
|
hde = HdeGetEnvHwnd(ahwnd[iCurWindow].hwndTopic);
|
|
iSaveCurWindow = iCurWindow;
|
|
|
|
if (hde) {
|
|
qde = QdeFromGh(hde);
|
|
hdc = qde->hdc;
|
|
}
|
|
|
|
/*
|
|
* If we're a local routine or a non-thunked dll routine, then
|
|
* push the arguments.
|
|
*/
|
|
|
|
if (!qgbind || !qgbind->lpfn || (qgbind->lpfn && !qgbind->dwTag)) {
|
|
#ifdef _X86_
|
|
#ifdef _DEBUG
|
|
int save_stack;
|
|
int cur_stack;
|
|
_asm mov save_stack, esp
|
|
#endif // _DEBUG
|
|
|
|
while (--curstack >= 0) {
|
|
|
|
// Assign to parm, because _asm gags on the bracket
|
|
|
|
DWORD parm = argstack[curstack];
|
|
_asm push parm;
|
|
}
|
|
|
|
lcHeapCheck();
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)();
|
|
lcHeapCheck();
|
|
#else //_X86_
|
|
// dwtag !=0 modern
|
|
// dwtag =0 braindead
|
|
#ifndef _ALPHA_
|
|
if (!qgbind || qgbind->dwTag || _stricmp(SzDLLName(qgbind),txtUser32Dll)==0) {
|
|
#endif
|
|
switch(curstack) {
|
|
#pragma warning(disable:4087)
|
|
case 0:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)();
|
|
break;
|
|
case 1:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(argstack[0]);
|
|
break;
|
|
case 2:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(argstack[0],argstack[1]);
|
|
break;
|
|
case 3:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(argstack[0],argstack[1]
|
|
,argstack[2]);
|
|
break;
|
|
case 4:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(argstack[0],argstack[1]
|
|
,argstack[2],argstack[3]);
|
|
break;
|
|
case 5:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4]);
|
|
break;
|
|
case 6:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(argstack[0],argstack[1],
|
|
argstack[2],argstack[3],argstack[4],argstack[5]);
|
|
break;
|
|
case 7:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(argstack[0],argstack[1],
|
|
argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]);
|
|
break;
|
|
case 8:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7]);
|
|
break;
|
|
case 9:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8]);
|
|
break;
|
|
case 10:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9]);
|
|
break;
|
|
case 11:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9],argstack[10]);
|
|
break;
|
|
case 12:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9],argstack[10],argstack[11]);
|
|
break;
|
|
case 13:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9],argstack[10],argstack[11]
|
|
,argstack[12]);
|
|
break;
|
|
case 14:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9],argstack[10],argstack[11]
|
|
,argstack[12],argstack[13]);
|
|
break;
|
|
case 15:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9],argstack[10],argstack[11]
|
|
,argstack[12],argstack[13],argstack[14]);
|
|
break;
|
|
case 16:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9],argstack[10],argstack[11]
|
|
,argstack[12],argstack[13],argstack[14],argstack[15]);
|
|
break;
|
|
case 17:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9],argstack[10],argstack[11]
|
|
,argstack[12],argstack[13],argstack[14],argstack[15]
|
|
,argstack[16]);
|
|
break;
|
|
case 18:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9],argstack[10],argstack[11]
|
|
,argstack[12],argstack[13],argstack[14],argstack[15]
|
|
,argstack[16],argstack[17]);
|
|
break;
|
|
case 19:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9],argstack[10],argstack[11]
|
|
,argstack[12],argstack[13],argstack[14],argstack[15]
|
|
,argstack[16],argstack[17],argstack[18]);
|
|
break;
|
|
case 20:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9],argstack[10],argstack[11]
|
|
,argstack[12],argstack[13],argstack[14],argstack[15]
|
|
,argstack[16],argstack[17],argstack[18],argstack[19]);
|
|
break;
|
|
}
|
|
#ifndef _ALPHA_
|
|
} else {
|
|
#ifdef _MIPS_
|
|
#define XR1ARG 1,2,3,4,
|
|
#else
|
|
#define XR1ARG 1,2,3,4,5,6,7,8,
|
|
#endif
|
|
|
|
switch(curstack) {
|
|
case 0:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)();
|
|
break;
|
|
case 1:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(XR1ARG argstack[0]);
|
|
break;
|
|
case 2:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(XR1ARG argstack[0],argstack[1]);
|
|
break;
|
|
case 3:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(XR1ARG argstack[0],argstack[1]
|
|
,argstack[2]);
|
|
break;
|
|
case 4:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(XR1ARG argstack[0],argstack[1]
|
|
,argstack[2],argstack[3]);
|
|
break;
|
|
case 5:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(XR1ARG argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4]);
|
|
break;
|
|
case 6:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(XR1ARG argstack[0],argstack[1],
|
|
argstack[2],argstack[3],argstack[4],argstack[5]);
|
|
break;
|
|
case 7:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(XR1ARG argstack[0],argstack[1],
|
|
argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]);
|
|
break;
|
|
case 8:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(XR1ARG argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7]);
|
|
break;
|
|
case 9:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(XR1ARG argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8]);
|
|
break;
|
|
case 10:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(XR1ARG argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9]);
|
|
break;
|
|
case 11:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(XR1ARG argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9],argstack[10]);
|
|
break;
|
|
case 12:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(XR1ARG argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9],argstack[10],argstack[11]);
|
|
break;
|
|
case 13:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(XR1ARG argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9],argstack[10],argstack[11]
|
|
,argstack[12]);
|
|
break;
|
|
case 14:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(XR1ARG argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9],argstack[10],argstack[11]
|
|
,argstack[12],argstack[13]);
|
|
break;
|
|
case 15:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(XR1ARG argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9],argstack[10],argstack[11]
|
|
,argstack[12],argstack[13],argstack[14]);
|
|
break;
|
|
case 16:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(XR1ARG argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9],argstack[10],argstack[11]
|
|
,argstack[12],argstack[13],argstack[14],argstack[15]);
|
|
break;
|
|
case 17:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(XR1ARG argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9],argstack[10],argstack[11]
|
|
,argstack[12],argstack[13],argstack[14],argstack[15]
|
|
,argstack[16]);
|
|
break;
|
|
case 18:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(XR1ARG argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9],argstack[10],argstack[11]
|
|
,argstack[12],argstack[13],argstack[14],argstack[15]
|
|
,argstack[16],argstack[17]);
|
|
break;
|
|
case 19:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(XR1ARG argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9],argstack[10],argstack[11]
|
|
,argstack[12],argstack[13],argstack[14],argstack[15]
|
|
,argstack[16],argstack[17],argstack[18]);
|
|
break;
|
|
case 20:
|
|
pmi->lMacroReturn = ((VOIDPROC)lpfn)(XR1ARG argstack[0],argstack[1]
|
|
,argstack[2],argstack[3],argstack[4],argstack[5],argstack[6]
|
|
,argstack[7],argstack[8],argstack[9],argstack[10],argstack[11]
|
|
,argstack[12],argstack[13],argstack[14],argstack[15]
|
|
,argstack[16],argstack[17],argstack[18],argstack[19]);
|
|
break;
|
|
}
|
|
}
|
|
#endif //ALPHA
|
|
#endif // else _X86_
|
|
|
|
#ifdef _X86_
|
|
#ifdef _DEBUG
|
|
_asm mov cur_stack, esp
|
|
ASSERT(cur_stack == save_stack);
|
|
#endif // _DEBUG
|
|
#endif // _X86_
|
|
}
|
|
|
|
else {
|
|
PSTR lpBuffer = (PSTR) LhAlloc(LMEM_FIXED,
|
|
sizeof(TBLKIN) + sizeof(TBLKOUT));
|
|
|
|
if (lpBuffer == NULL) {
|
|
pmi->lMacroReturn = 0;
|
|
}
|
|
else {
|
|
|
|
/*
|
|
* We should ONLY get here if we have a thunked dll routine.
|
|
* Non-thunked dll routines should already have been called.
|
|
*/
|
|
|
|
pmi->lMacroReturn = ((MAKE_CALL) lpfn)(lpBuffer,
|
|
qgbind->dwTag, chPrototype, argstack);
|
|
FreeLh(lpBuffer);
|
|
}
|
|
}
|
|
|
|
// The macro call may have done an interfile jump, in which case hde
|
|
// is invalid.
|
|
|
|
/*
|
|
* BUGBUG: well, maybe a bug. 16-bit code had to turn off aliasing
|
|
* or the compiler would throw away the saved hdc. Need to confirm that
|
|
* in the retail build of WinHelp, the hdc is saved and restored
|
|
* correctly.
|
|
*/
|
|
|
|
if (hde && ahwnd[iSaveCurWindow].hwndTopic &&
|
|
hde == HdeGetEnvHwnd(ahwnd[iSaveCurWindow].hwndTopic)) {
|
|
qde->hdc = hdc;
|
|
}
|
|
|
|
if ((wReturn != fwANY) && (wReturn != wReturnType)) {
|
|
switch(wReturnType) {
|
|
case fwSHORTNUM:
|
|
pmi->lMacroReturn &= 0x0000ffff;
|
|
break;
|
|
|
|
case fwLONGNUM:
|
|
case fwNEARSTRING:
|
|
case fwFARSTRING:
|
|
break;
|
|
|
|
default:
|
|
return wERRS_MISMATCHTYPE;
|
|
}
|
|
}
|
|
|
|
return wMacroError;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
- Name: Execute
|
|
-
|
|
* Purpose: This function is called to execute a string containing a
|
|
* list of zero or more macro calls, separated by ":".
|
|
*
|
|
*
|
|
* Arguments: qch - Points to the macro list to execute.
|
|
*
|
|
* Returns: Returns error code from the first macro that fails
|
|
* (or 0 for success).
|
|
*
|
|
* Notes: Syntax of the string is as follows:
|
|
* list ::= NULL OR [macrolist]
|
|
* macrolist ::= [macro] OR ([macro] ":" [macrolist])
|
|
* macro ::= [name] "(" [paramlist] ")"
|
|
* name ::= (ALPHA OR "_") [namechars]
|
|
* namechars ::= NULL OR ALPHANUM OR "_"
|
|
* paramlist ::= NULL OR [params]
|
|
* params ::= [param] OR ([param] "," [params])
|
|
* param ::= [posint] OR [int] OR [string] OR [macro] OR [var
|
|
* posint ::= "0"..."9"
|
|
* int ::= ("-" ([posint] OR [macro])) OR [posint]
|
|
* string ::= (""" CHARS """) OR ("`" CHARS "'")
|
|
* var ::= "hwndContext" OR "qchPath" OR "qError"
|
|
*
|
|
* Example: call1(5, "string", -call2()):call3("string")
|
|
* call1(call1(call1(0))):call2()
|
|
*
|
|
* Syntax of the proto-type is as follows:
|
|
* proto ::= [return] [parmlist]
|
|
* return ::= NULL OR ([rettype] "=")
|
|
* parmlist ::= NULL OR [params]
|
|
* params ::= [param] OR ([param] [params])
|
|
* param ::= "i" OR "u" OR "s" OR "I" OR "U" OR "S"
|
|
* rettype ::= [param] OR "v"
|
|
*
|
|
* Example: "u=uSiS"
|
|
* "v="
|
|
* ""
|
|
* "S=uSs"
|
|
*
|
|
***************************************************************************/
|
|
|
|
int STDCALL Execute(PCSTR qch)
|
|
{
|
|
MI mi; // Macro information structure
|
|
int wMacroError; // Error from executing macro
|
|
HLOCAL hlb;
|
|
|
|
// Only Print and CopyTopic macros are allowed within context-sensitive
|
|
// help.
|
|
|
|
if (fHelp == POPUP_HELP) {
|
|
char szTmp[20];
|
|
lstrcpyn(szTmp, qch, sizeof(szTmp) - 1);
|
|
CharLower(szTmp);
|
|
if (!strstr(szTmp, "copytopic") && !strstr(szTmp, "ct") &&
|
|
!strstr(szTmp, "print")) {
|
|
HDE hde = HdeGetEnv();
|
|
if (hde)
|
|
WinHelp(NULL, QDE_FM(QdeFromGh(hde)), HELP_COMMAND,
|
|
(DWORD) qch);
|
|
PostMessage(hwndNote, WM_CLOSE, 0, 0); // Shut down the note
|
|
return wERRS_NONE;
|
|
}
|
|
}
|
|
|
|
mi.pszPath = NULL;
|
|
|
|
// REVIEW: [ralphw] do any macros really modify the macro buffer?
|
|
|
|
hlb = (HLOCAL) lcMalloc(strlen(qch) + 100); // paranoia padding
|
|
mi.pchMacro = (PSTR) PtrFromGh(hlb);
|
|
|
|
strcpy(mi.pchMacro, qch);
|
|
|
|
for (wMacroError = wERRS_NONE; *mi.pchMacro;) { // Execute first macro
|
|
wMacroError = WExecuteMacro(&mi, fwANY);
|
|
if (wMacroError != wERRS_NONE) // Stop executing if an error found
|
|
break;
|
|
|
|
if (mi.me.wError != wMERR_NONE) {
|
|
wMacroError = rgmpWMErrWErrs[mi.me.wError];
|
|
break;
|
|
}
|
|
|
|
mi.pchMacro = pchSkip(mi.pchMacro);
|
|
|
|
// ':' or ';' expected here since we are done executing the macro
|
|
|
|
if (*mi.pchMacro) {
|
|
if ((*(mi.pchMacro) != chSeparator1) &&
|
|
(*(mi.pchMacro) != chSeparator2)) {
|
|
wMacroError = wERRS_SEPARATOR;
|
|
break;
|
|
}
|
|
else
|
|
mi.pchMacro++;
|
|
}
|
|
}
|
|
|
|
if (wMacroError != wERRS_NONE) { // The DLL sent the error string
|
|
if (wMacroError == wERRS_MACROMSG) // Note International issues!!!
|
|
ErrorQch(mi.me.rgchError);
|
|
else if (wMacroError == wERRS_NOSRCHINFO)
|
|
goto SilentEnd;
|
|
else if (fHelpAuthor &&
|
|
(wMacroError == wERRS_NOROUTINE ||
|
|
wMacroError == wERRS_UNDEFINEDVAR)) {
|
|
PSTR psz = (PSTR) LhAlloc(LMEM_FIXED, strlen(mi.me.rgchError) + 100);
|
|
wsprintf(psz, GetStringResource(wMacroError), (LPSTR) mi.me.rgchError);
|
|
ErrorQch(psz);
|
|
FreeLh((HLOCAL) psz);
|
|
}
|
|
else if (fHelpAuthor && wMacroError == wERRS_BADNAME) {
|
|
PSTR psz = (PSTR) LhAlloc(LMEM_FIXED, strlen(mi.pchMacro) + 100);
|
|
wsprintf(psz, GetStringResource(wERRS_BADNAME), (LPSTR) mi.pchMacro);
|
|
ErrorQch(psz);
|
|
FreeLh((HLOCAL) psz);
|
|
}
|
|
else
|
|
PostErrorMessage(wMacroError);
|
|
}
|
|
SilentEnd:
|
|
FreeLh((HLOCAL) hlb);
|
|
lcHeapCheck();
|
|
if (mi.pszPath)
|
|
FreeLh((HLOCAL) mi.pszPath);
|
|
if (lpCallThnkCleanup != NULL)
|
|
(lpCallThnkCleanup)();
|
|
lcHeapCheck();
|
|
return wMacroError;
|
|
}
|