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.
 
 
 
 
 
 

1015 lines
41 KiB

//*-----------------------------------------------------------------------
//| MODULE: MATCH.C
//| PROJECT: Windows Comparison Tool
//|
//| PURPOSE: This module contains the comparison routines used to
//| compare the contents of dialogs/menus from the file or
//| dynamically created information.
//|
//| REVISION HISTORY:
//| 04-16-92 w-steves TestDlgs (2.0) code Complete
//| 12-13-90 garysp Fixed up error codes see wcterr.h
//|
//| 11-27-90 randyki Implemented new comparison scheme,
//| clarified logged results
//| 11-07-90 randyki Cleaned up, incorporate coding
//| standards, created rev history
//| 10-09-90 garysp Created file
//*-----------------------------------------------------------------------
#include "enghdr.h"
#pragma hdrstop ("engpch.pch")
//------------------------------------------------------------------------
// Define the OutDebug macro on definition of the DEBUG macro
//------------------------------------------------------------------------
#ifdef DEBUG
#define OutDebug(N) OutputDebugString(N)
#else
#define OutDebug(N)
#endif
//------------------------------------------------------------------------
// Define the szFormat and RC macros depending on the operating
// environment (RC stands for Rect Coords)
//------------------------------------------------------------------------
#ifdef WIN
#define szFormat "%%s(%%d,%%d)x(%%d,%%d) "
#define RC(var) var.xLeft, var.yMin, var.xRight, var.yLast
#else
#define szFormat "%%s(%%ld,%%ld)x(%%ld,%%ld) "
#define RC(var) var.xLeft, var.yLast, var.xRight, var.yMin
#endif
//------------------------------------------------------------------------
// Define the fClose macro (invert the return value of _lclose())
//------------------------------------------------------------------------
#define fClose(x) (!_lclose(x))
//------------------------------------------------------------------------
// Define the EndCompare macro - spit out the footer and return the given
// value
//------------------------------------------------------------------------
#define EndCompare(rv) {OutputFooter(lpLog); return rv;}
//------------------------------------------------------------------------
// MATCH.C specific constants
//------------------------------------------------------------------------
#define CR_FUZZY 1 // fuzzy match
#define CR_MIC 2 // more in comp dialog
#define CR_CNF 4 // control(s) not found
//------------------------------------------------------------------------
// Function Prototypes
//------------------------------------------------------------------------
INT CompareControls (LPCTLDEF, LPCTLDEF, INT, INT, INT);
VOID LogControl (HFILE, LPCTLDEF, LPSTR);
VOID LogFuzzyMatch (HFILE, LPCTLDEF, LPCTLDEF);
//------------------------------------------------------------------------
// MATCH.C specific global variables
//------------------------------------------------------------------------
INT fCompFull; // Full Dlg Compare flag
INT fCompRes; // Comparison results
INT nCtlBase; // # controls in base dialog
INT nCtlComp; // # controls in compare dialog
INT nCtlFuzzy; // # fuzzy matched controls
INT nCtlExcess; // # excess controls (more in comp)
INT nCtlNotFnd; // # base controls not found
//*------------------------------------------------------------------------
//| FileLength
//|
//| PURPOSE: Determine the length of a file.
//|
//| ENTRY: hFile - Handle to file whose size is to be found
//|
//| EXIT: (long) Size of file in bytes
//*------------------------------------------------------------------------
LONG FileLength(HFILE hFile)
{
LONG lCurPos;
LONG lFileLen;
// Find the current file position so we don't screw it up
//--------------------------------------------------------------
lCurPos = M_llseek(hFile, 0L, 1);
// Find the end of the file
//--------------------------------------------------------------
lFileLen = M_llseek(hFile, 0L, 2);
// Seek back to the original file position
//--------------------------------------------------------------
M_llseek(hFile, lCurPos, 0);
return ( lFileLen );
}
//*------------------------------------------------------------------------
//| fOpenFile
//|
//| PURPOSE: Opens file and moves to the end of the file
//| if _lopen fails then do a _lcreat()
//|
//| ENTRY: lpsz - Name of file to open
//|
//| EXIT: Handle of opened file, or -1 if failed
//*------------------------------------------------------------------------
HFILE fOpenFile(LPSTR lpsz)
{
HFILE hFile;
// Attempt a normal open
//--------------------------------------------------------------
hFile = M_lopen(lpsz, OF_READWRITE);
// If normal open failed, do the _lcreat call
//--------------------------------------------------------------
if (hFile == -1)
hFile = M_lcreat(lpsz, 0);;
// Seek to end of file (if one of the above opens worked
//--------------------------------------------------------------
if (hFile != -1)
M_llseek(hFile, 0L, 2);
return( hFile );
}
//*------------------------------------------------------------------------
//| fLogStrToFile
//|
//| PURPOSE: Output a line of text into an open file.
//|
//| ENTRY: hFile - Handle of file to write string to
//| lpszOutText - String to write to file
//|
//| EXIT: TRUE if all characters in the string are written to the
//| file, or FALSE if not. File pointer is left at the end
//| of the file after the write.
//*------------------------------------------------------------------------
BOOL fLogStrToFile(HFILE hFile, LPSTR lpszOutText)
{
INT i;
LPSTR lpszTmp = lpszOutText;
// Output the string to the debug terminal....
//--------------------------------------------------------------
OutDebug( lpszOutText );
// Make sure the file handle is valid
// (CONSIDER: make a real check for a bad handle here?)
//--------------------------------------------------------------
if (hFile == -1)
return ( FALSE );
// Write the text to the file at the current file position
//--------------------------------------------------------------
i = M_lwrite(hFile, lpszOutText, lstrlen(lpszOutText));
// Put the file position
//--------------------------------------------------------------
M_llseek(hFile, 0L, 2);
// Return the success of the operation
//--------------------------------------------------------------
return (i < lstrlen(lpszOutText)) ? FALSE: TRUE;
}
//*------------------------------------------------------------------------
//| LogControl
//|
//| PURPOSE: Log a control to the log file -- output all the
//| information contained in the given control
//|
//| ENTRY: hFile - Handle of log file to write information to
//| pctrl - control to log to file
//| lpszInfo - text to send to log file before control
//|
//| EXIT: NONE
//*------------------------------------------------------------------------
VOID LogControl(HFILE hFile, LPCTLDEF pctrl, LPSTR lpszInfo)
{
INT i=0;
CHAR szTmpBuf[cchTextMac * 2];
CHAR szFmt[80];
// Output Header, Text Names, and Class names
//--------------------------------------------------------------
i += fLogStrToFile(hFile, lpszInfo);
i += fLogStrToFile(hFile, "\tTEXT : ");
i += fLogStrToFile(hFile, (LPSTR)pctrl->rgText);
i += fLogStrToFile(hFile, (LPSTR)"\r\n\tCLASS: ");
i += fLogStrToFile(hFile, (LPSTR)pctrl->rgClass);
i += fLogStrToFile(hFile, (LPSTR)"\r\n");
// Create the format string using the szFormat macro
//--------------------------------------------------------------
wsprintf(szFmt, szFormat);
// Output the rectangle using the RC macro
//--------------------------------------------------------------
wsprintf(szTmpBuf, szFmt, (LPSTR)"\tRECT : ", RC(pctrl->dcr) );
i += fLogStrToFile(hFile, (LPSTR)szTmpBuf);
i += fLogStrToFile(hFile, (LPSTR)"\r\n");
// Output the state and flags
//--------------------------------------------------------------
if (!lstrcmpi((LPSTR)(pctrl->rgClass), "MenuItem"))
wsprintf(szTmpBuf,"\tCHECKED: %d, GRAYED: %d, INACTIVE: %d\r\n\r\n",
(INT)(pctrl->nState & MF_CHECKED),
(INT)(pctrl->nState & MF_GRAYED) ,
(INT)(pctrl->nState & MF_ENABLED));
else
wsprintf(szTmpBuf,"\tCHECKED: %d, VISIBLE: %d, ENABLED: %d\r\n\r\n",
(pctrl->nState & STATE_CHECKED) ? 1 : 0,
(pctrl->nState & STATE_VISIBLE) ? 1 : 0,
(pctrl->nState & STATE_ENABLED) ? 1 : 0);
i += fLogStrToFile(hFile, (LPSTR)szTmpBuf);
}
//*---------------------------------------------------------------------
//| LogFuzzyMatch
//|
//| PURPOSE: Log a fuzzy match to the log file. Output information
//| contained in both the Base Control and the Compare
//| Control.
//|
//| ENTRY: hFile - Handle of log file
//| pctrlBase - base control
//| pctrlCmp - compare control
//|
//| EXIT: NONE
//*---------------------------------------------------------------------
VOID LogFuzzyMatch(HFILE hFile, LPCTLDEF pctrlBase, LPCTLDEF pctrlCmp)
{
INT i=0;
CHAR szTmpBuf[cchTextMac * 2];
CHAR szFmt[80];
INT wCompareErr;
// Compare the Control again to determine what has failed
// Compare every field except Tab Order because Tab order
// check can only be done with all other controls. If
// everything passes then Tab Order Check failed in the
// exact match pass. (not always though. If something fails,
// we cannot tell whether tab order check failed or not)
//-----------------------------------------------------------
wCompareErr = CompareControls (pctrlBase, pctrlCmp, 0, 0,
MATCH_CASE|MATCH_CLASS|MATCH_NAME|
MATCH_RECT|MATCH_STATE);
// Output Text Names
//-----------------------------------------------------------
i += fLogStrToFile(hFile, "FUZZY MATCH (base => cmp):\r\n ");
if (lstrcmp (pctrlBase->rgText, pctrlCmp->rgText))
i += fLogStrToFile(hFile, "*");
i += fLogStrToFile(hFile, "\tTEXT : '");
i += fLogStrToFile(hFile, pctrlBase->rgText);
i += fLogStrToFile(hFile, "' => '");
i += fLogStrToFile(hFile, pctrlCmp->rgText);
i += fLogStrToFile(hFile, "'\r\n ");
// Output Class names
//-----------------------------------------------------------
if (lstrcmp (pctrlBase->rgClass, pctrlBase->rgClass))
i += fLogStrToFile(hFile, "*");
i += fLogStrToFile(hFile, "\tCLASS : '");
i += fLogStrToFile(hFile, (LPSTR)pctrlBase->rgClass);
i += fLogStrToFile(hFile, (LPSTR) "' => '");
i += fLogStrToFile(hFile, (LPSTR)pctrlCmp->rgClass);
i += fLogStrToFile(hFile, (LPSTR) "'\r\n ");
// Create the format string using the szFormat macro
//--------------------------------------------------------------
wsprintf(szFmt, szFormat);
// Output the base rectangle, using the RC macro
//--------------------------------------------------------------
if (memcmp ((LPSTR)&pctrlBase->dcr, (LPSTR)&pctrlCmp->dcr,
sizeof(DCR)))
i += fLogStrToFile(hFile, "*");
wsprintf(szTmpBuf, szFmt, (LPSTR)"\tRECT : ", RC(pctrlBase->dcr) );
i += fLogStrToFile(hFile, szTmpBuf);
// Output the compare rectangle, again using the RC macro
//--------------------------------------------------------------
wsprintf(szTmpBuf, szFmt, (LPSTR)"=> ", RC(pctrlCmp->dcr) );
i += fLogStrToFile(hFile, szTmpBuf);
i += fLogStrToFile(hFile, "\r\n");
// Output the state and flags for each control. Under the current
// implementation, since this is a fuzzy match these will always
// be the same, but the checking for the difference flagging is
// still implemented for changes in the future (UNDONE:)
//--------------------------------------------------------------
if (!lstrcmpi((LPSTR)(pctrlBase->rgClass), "MenuItem"))
wsprintf(szTmpBuf, " %c\tChecked : %d => %d\r\n"
" %c\tGrayed : %d => %d\r\n"
" %c\tEnabled : %d => %d\r\n",
(pctrlBase->nState & MF_CHECKED) ==
(pctrlCmp->nState & MF_CHECKED) ? ' ' : '*',
(INT)(pctrlBase->nState & MF_CHECKED),
(INT)(pctrlCmp->nState & MF_CHECKED),
(pctrlBase->nState & MF_GRAYED) ==
(pctrlCmp->nState & MF_GRAYED) ? ' ' : '*',
(INT)(pctrlBase->nState & MF_GRAYED) ,
(INT)(pctrlCmp->nState & MF_GRAYED) ,
(pctrlBase->nState & MF_ENABLED) ==
(pctrlCmp->nState & MF_ENABLED) ? ' ' : '*',
(INT)(pctrlBase->nState & MF_ENABLED) ,
(INT)(pctrlCmp->nState & MF_ENABLED));
else
wsprintf(szTmpBuf, " %c\tChecked : %d => %d\r\n"
" %c\tVisible : %d => %d\r\n"
" %c\tEnabled : %d => %d\r\n",
(pctrlBase->nState & STATE_CHECKED) ==
(pctrlCmp->nState & STATE_CHECKED) ? ' ' : '*',
(pctrlBase->nState & STATE_CHECKED) ? 1 : 0,
(pctrlCmp->nState & STATE_CHECKED) ? 1 : 0,
(pctrlBase->nState & STATE_VISIBLE) ==
(pctrlCmp->nState & STATE_VISIBLE) ? ' ' : '*',
(pctrlBase->nState & STATE_VISIBLE) ? 1 : 0 ,
(pctrlCmp->nState & STATE_VISIBLE) ? 1 : 0 ,
(pctrlBase->nState & STATE_ENABLED) ==
(pctrlCmp->nState & STATE_ENABLED) ? ' ' : '*',
(pctrlBase->nState & STATE_ENABLED) ? 1 : 0 ,
(pctrlCmp->nState & STATE_ENABLED) ? 1 : 0);
i += fLogStrToFile(hFile, szTmpBuf);
// Output what has fail during the Exact Match Compare
//----------------------------------------------------
if (wCompareErr & MATCH_CLASS)
{
wsprintf(szTmpBuf, "-- Class names do not match.\r\n");
i += fLogStrToFile(hFile, szTmpBuf);
}
if (wCompareErr & MATCH_NAME)
{
if (wCompareErr & MATCH_CASE)
{
wsprintf(szTmpBuf,"-- Case sensitive name check failed.\r\n");
i += fLogStrToFile(hFile, szTmpBuf);
}
else
{
wsprintf(szTmpBuf,"-- Case insensitive name check failed.\r\n");
i += fLogStrToFile(hFile, szTmpBuf);
}
}
if (wCompareErr & MATCH_RECT)
{
wsprintf(szTmpBuf, "-- Controls are of different size.\r\n");
i += fLogStrToFile(hFile, szTmpBuf);
}
if (wCompareErr == 0)
{
wsprintf(szTmpBuf, "-- Tab order check failed.\r\n");
i += fLogStrToFile(hFile, szTmpBuf);
}
if (wCompareErr & MATCH_STATE)
{
wsprintf(szTmpBuf, "-- Control States do not match.\r\n");
i += fLogStrToFile(hFile, szTmpBuf);
}
// Output one blank line
//----------------------------------
wsprintf(szTmpBuf, "\r\n");
i += fLogStrToFile(hFile, szTmpBuf);
}
//*-------------------------------------------------------------------------
//| CompareControls
//|
//| PURPOSE: Compare two controls.
//|
//| ENTRY: pctrlBase - base control to compare against
//| pctrlCmp - control to compare
//| wMatchStyle - Match Preference Bits
//|
//| EXIT: 0 if Successful; otherwise Error Code
//*-------------------------------------------------------------------------
INT CompareControls (LPCTLDEF pctrlBase, LPCTLDEF pctrlCmp,
INT wOrderBase, INT wOrderCmp, INT wMatchStyle)
{
INT i = 0;
static INT cOrderBase = 0;
static INT cOrderCmp = 0;
// Used for Tab order and Control order Check
//---------------------------------------------------
if (wOrderBase == 0) cOrderBase = 0;
if (wOrderCmp == 0) cOrderCmp = 0;
if (pctrlBase->lStyleBits & WS_TABSTOP) cOrderBase++;
if (pctrlCmp ->lStyleBits & WS_TABSTOP) cOrderCmp++;
// Compare Control Class (Always case insensitive)
//---------------------------------------------------------------
if (wMatchStyle & MATCH_CLASS)
if (_fstricmp(pctrlBase->rgClass, pctrlCmp->rgClass))
i += MATCH_CLASS;
// Compare Control Name
//---------------------------------------------------------------
if (wMatchStyle & MATCH_CASE)
{
// Case Sensitive
//----------------------------
if (wMatchStyle & MATCH_NAME)
{
// Compare Text Values - Must be identical
//-------------------------------------------------------
if (lstrcmp((LPSTR)pctrlBase->rgText,(LPSTR)pctrlCmp->rgText))
{
i += MATCH_CASE;
i += MATCH_NAME;
}
}
}
else
// Case Insensitive
//---------------------------
if (wMatchStyle & MATCH_NAME)
if (_fstricmp(pctrlBase->rgText, pctrlCmp->rgText))
i += MATCH_NAME;
// Compare Control Rectangle Coor
//-------------------------------------------------------------
if (wMatchStyle & MATCH_RECT)
// Compare Rectangles
//-------------------------------------------------------
if (memcmp ((LPSTR)&pctrlBase->dcr, (LPSTR)&pctrlCmp->dcr,
SIZEOF_DCR))
i += MATCH_RECT;
// Compare Control Tab Order
//-------------------------------------------------------------
if (wMatchStyle & MATCH_TAB)
// Compare TabOrder
//-------------------------------------------------------
if ((pctrlBase->lStyleBits & WS_TABSTOP) &&
(pctrlCmp ->lStyleBits & WS_TABSTOP) &&
(i == 0))
if (cOrderBase != cOrderCmp)
i += MATCH_TAB;
if (wMatchStyle & MATCH_STATE)
// Compare State, Visible, and Enabled -- these must be the same
// in any case.
//---------------------------------------------------------------
if (pctrlBase->nState != pctrlCmp->nState)
i += MATCH_STATE;
return ( (i == 0)? 0 : i );
}
//*-------------------------------------------------------------------------
//| OutputFooter
//|
//| PURPOSE: Output a comparison footer to the given log file, complete
//| with all results of the prior comparison.
//|
//| ENTRY: lpszLog - Pointer to name of log file to write footer to
//|
//| EXIT: None
//*-------------------------------------------------------------------------
VOID FARPRIVATE OutputFooter (LPSTR lpszLog)
{
HFILE hFile;
CHAR szStrBuf[256];
// File i/o errors during logging are ignored
//------------------------------------------------------------------
hFile = fOpenFile (lpszLog);
// If the comparison was a full dialog comparison, then the output
// format strings are a different set
//------------------------------------------------------------------
if (fCompFull)
{
// The first case is an exact match - if exact, then only
// one line is output -- the rest of the if's will fail
// UNDONE: Make this more efficient
//----------------------------------------------------------
if (fCompRes == WCT_NOERR)
{
wsprintf (szStrBuf,
">> EXACT MATCH: %d controls compared\r\n",
nCtlBase);
fLogStrToFile (hFile, szStrBuf);
}
// The rest can be a combination
//----------------------------------------------------------
if (fCompRes & CR_FUZZY)
{
wsprintf (szStrBuf,
">> FUZZY MATCH: %d of %d controls fuzzy\r\n",
nCtlFuzzy, nCtlBase);
fLogStrToFile (hFile, szStrBuf);
}
if (fCompRes & CR_MIC)
{
wsprintf (szStrBuf,
">> MORE CONTROLS IN COMPARE DIALOG: "
"%d compared, %d excess\r\n",
nCtlBase, nCtlExcess);
fLogStrToFile (hFile, szStrBuf);
}
if (fCompRes & CR_CNF)
{
wsprintf (szStrBuf,
">> %d OF %d CONTROLS NOT FOUND\r\n",
nCtlNotFnd, nCtlBase);
fLogStrToFile (hFile, szStrBuf);
}
}
else
{
// The first case is an exact match - if exact, then only
// one line is output -- the rest of the if's will fail
// UNDONE: Make this more efficient
//----------------------------------------------------------
if (fCompRes == WCT_NOERR)
{
wsprintf (szStrBuf,
">> EXACT MATCH: %d controls found in "
"%d total compare controls\r\n",
nCtlBase, nCtlComp);
fLogStrToFile (hFile, szStrBuf);
}
// The rest can be a combination
//----------------------------------------------------------
if (fCompRes & CR_FUZZY)
{
wsprintf (szStrBuf,
">> FUZZY MATCH: %d controls found in "
"%d total compare controls, %d fuzzy\r\n",
nCtlBase, nCtlComp, nCtlFuzzy);
fLogStrToFile (hFile, szStrBuf);
}
if (fCompRes & CR_CNF)
{
wsprintf (szStrBuf,
">> CONTROLS NOT FOUND: "
"%d of %d base controls not found in "
"%d compare controls\r\n",
nCtlNotFnd, nCtlBase, nCtlComp);
fLogStrToFile (hFile, szStrBuf);
}
}
fLogStrToFile (hFile, "--------------------------------");
fLogStrToFile (hFile, "--------------------------------\r\n");
fClose (hFile);
}
//*-------------------------------------------------------------------------
//| OutputHeader
//|
//| PURPOSE: Output a header to the given log file, complete with time
//| and date of compare.
//|
//| ENTRY: lpszLog - Pointer to name of log file to write header to
//|
//| EXIT: None
//*-------------------------------------------------------------------------
VOID FARPRIVATE OutputHeader (LPSTR lpszLog)
{
HFILE hFile;
static CHAR szDTBuf[16]; // STATIC to ensure DS points to it
CHAR szStrBuf[80];
hFile = fOpenFile(lpszLog);
wsprintf (szStrBuf, "----------------------%sDIALOG COMPARISON: ",
(LPSTR)(fCompFull ? "FULL " : "-----"));
fLogStrToFile (hFile, szStrBuf);
_strdate (szDTBuf);
fLogStrToFile (hFile, szDTBuf);
fLogStrToFile (hFile, " ");
_strtime (szDTBuf);
fLogStrToFile (hFile, szDTBuf);
fLogStrToFile (hFile, "\r\n");
fClose(hFile);
}
//*-------------------------------------------------------------------------
//| fCompareMem
//|
//| PURPOSE: Perform the comparison of two control arrays
//|
//| ENTRY: lpBase - Pointer to base (source) control array
//| cBase - Number of controls in base array
//| lpComp - Pointer to compare (target) control array
//| cComp - Number of controls in compare array
//| fFull - Full dialog comparison flag (TRUE -> full dialog)
//| lpLog - Pointer to error log file
//|
//| EXIT: The return value indicates the result of the comparison
//*-------------------------------------------------------------------------
INT FARPUBLIC fCompareMem(LPCTLDEF lpBase, INT cBase,
LPCTLDEF lpComp, INT cComp,
INT fFull, LPSTR lpLog)
{
INT i, j;
HANDLE hMatchBuf = NULL, hCompBuf = NULL;
HFILE hFile;
LONG FAR *lpMatchBuf;
LPSTR lpCompBuf;
INT cMatchCount=0;
// Set up the comparison variables
//--------------------------------------------------------------
fCompFull = fFull;
fCompRes = WCT_NOERR;
nCtlBase = cBase;
nCtlComp = cComp;
nCtlFuzzy = 0;
nCtlExcess = 0;
nCtlNotFnd = 0;
// Output the comparison header to the log file
//--------------------------------------------------------------
OutputHeader (lpLog);
// If there are no controls in the base array, return WCT_NOERR
//--------------------------------------------------------------
if (!cBase)
EndCompare (WCT_NOERR);
// Setup match buffer; (array of long integers)
// use to keep track of which elements match which
// LOWORD(lpMatchBuf[x]) = Element number in lpComp.
// HIWORD(lpMatchBuf[x]) = Match type 0 - none, 1 - exact, 2 fuzzy
// where x is the corresponding element in lpBase
//--------------------------------------------------------------
hMatchBuf = GlobalAlloc( GMEM_ZEROINIT | GMEM_MOVEABLE,
cBase * sizeof(LONG) );
if (hMatchBuf == NULL)
return (WCT_OUTOFMEMORY);
lpMatchBuf = (LONG FAR *)GlobalLock(hMatchBuf);
if (lpMatchBuf == NULL)
{
GlobalFree (hMatchBuf);
return (WCT_OUTOFMEMORY);
}
// Bug fix: TestDlgs1.0
// if cComp = 0, this routine will return 0, forgot to check
// the number of control in array.
// If there are no control in the comp array, return WCT_CTLNOTFOUND
//------------------------------------------------------------------
if(!cComp)
{
fCompRes |= CR_CNF;
nCtlNotFnd = cBase;
EndCompare (WCT_CTLNOTFOUND);
}
// Set up compare buffer - (array of characters) used to keep
// track of the compare controls which are matched (exact OR
// fuzzy) and which are not.
//--------------------------------------------------------------
hCompBuf = GlobalAlloc (GMEM_ZEROINIT | GMEM_MOVEABLE,
cComp * sizeof(CHAR));
if (hCompBuf == NULL)
{
GlobalUnlock (hMatchBuf);
GlobalFree (hMatchBuf);
return (WCT_OUTOFMEMORY);
}
lpCompBuf = (LPSTR)GlobalLock (hCompBuf);
if (lpCompBuf == NULL)
{
GlobalUnlock (hMatchBuf);
GlobalFree (hMatchBuf);
GlobalFree (hCompBuf);
return (WCT_OUTOFMEMORY);
}
// Loop through finding exact matches and marking them
// accordingly.
//--------------------------------------------------------------
for (i = 0; i < cComp; i++)
if (!lpCompBuf[i])
for (j = 0; j < cBase; j++)
if ( (lpMatchBuf[j] == 0) &&
!CompareControls(lpBase+j, lpComp+i, j, i,
(INT)(lMatchPref >> 16)) )
{
lpMatchBuf[j] = (LONG)i | (1L << 16);
lpCompBuf[i] = (CHAR)1;
cMatchCount ++;
break;
}
// If not all controls in the base array were found, loop
// through looking for fuzzy matches and marking them
//--------------------------------------------------------------
if (cMatchCount != cBase)
{
for (i = 0; i < cComp; i++)
if (!lpCompBuf[i])
for (j = 0; j < cBase; j++)
if ( (lpMatchBuf[j] == 0) &&
!CompareControls(lpBase+j, lpComp+i,
j, i, (INT)lMatchPref) )
{
lpMatchBuf[j] = (LONG)i | (2L << 16);
lpCompBuf[i] = (CHAR)1;
cMatchCount ++;
nCtlFuzzy++;
break;
}
}
// Open the log file
//--------------------------------------------------------------
hFile = fOpenFile (lpLog);
// Log all fuzzy matches in MatchBuf (if any)
//--------------------------------------------------------------
if (nCtlFuzzy)
{
for (i=0; i < cBase; i++)
if (HIWORD(lpMatchBuf[i]) == (WORD)2)
LogFuzzyMatch (hFile, lpBase+i,
lpComp+LOWORD(lpMatchBuf[i]));
fCompRes |= CR_FUZZY;
}
// If this is a full dialog compare, log out all unmatched
// controls in the compare dialog
//--------------------------------------------------------------
if (fFull)
{
nCtlExcess = cComp - cBase;
if (nCtlExcess)
fCompRes |= CR_MIC;
for (i=0; i < cComp; i++)
if (!lpCompBuf[i])
LogControl (hFile, lpComp+i,
"UNMATCHED COMPARE CONTROL:\r\n");
}
// Log all base controls not found (if any)
//--------------------------------------------------------------
if (cMatchCount < cBase)
{
fCompRes |= CR_CNF;
nCtlNotFnd = cBase - cMatchCount;
for (i=0; i < cBase; i++)
if (!lpMatchBuf[i])
LogControl (hFile, lpBase+i,
"BASE CONTROL NOT FOUND:\r\n");
}
// Close the log file
//--------------------------------------------------------------
if (hFile != -1)
fClose(hFile);
// Release buffer memory, log the footer, and return appropriate
// result code
//--------------------------------------------------------------
GlobalUnlock(hMatchBuf);
GlobalFree(hMatchBuf);
GlobalUnlock(hCompBuf);
GlobalFree(hCompBuf);
OutputFooter (lpLog);
if (fCompRes == 0)
return (WCT_NOERR);
if (fCompRes & CR_CNF)
return (WCT_CTLNOTFOUND);
if (fCompRes & CR_MIC)
return (WCT_EXCESS);
return (WCT_FUZZY);
}
//*--------------------------------------------------------------------------
//| fDoCompare
//|
//| PURPOSE: Given a handle to a window and an index into the dialog
//| file, compare the two as dialogs. This means capturing
//| the CHILDREN of the hWnd window and, if the fTotal flag is
//| set, the window itself, into the hGTarget buffer, and
//| reading the dialog information (offset nDlg) from the file
//| into the hGSource buffer. Then, the two arrays are compared.
//|
//| First, however, the dialog info in the file is checked to see
//| if it is menu information. If so, we remember that fact, so
//| that we pump the window handle given for the right information.
//|
//| NOTE: nDlg is 1-based.
//|
//| OTHER NOTE: If nDlg = 0, the controls in the array indicated
//| by hDynDlg are used in the comparison (as the source)
//|
//| ENTRY: szFullFName - Name of dialog file
//| hWnd - Handle of window to compare (target)
//| nDlg - Index into the file of source (0 -> dynamic)
//| fTotal - TRUE -> parent hWnd is added to target
//| szLogFile - Name of results log file
//| hDynDlg - Handle of dynamic dialog control array
//| nDynCount - Number of controls in the dynamic dialog
//|
//| EXIT: Result of comparison
//*--------------------------------------------------------------------------
INT FARPUBLIC fDoCompare (LPSTR szFullFName, HWND hWnd, INT nDlg, INT fTotal,
LPSTR szLogFile, HANDLE hDynDlg, INT nDynCount)
{
INT nTargetCount = 0;
INT nSourceCount = 0;
INT fFullDlg, retval, i, j, cbMax, nGrabType;
CHAR szDsc[cchMaxDsc];
HANDLE hGSource, hGTarget;
LPCTLDEF lpSrcCtl, lpTrgCtl;
// First, get the dialog information from the dialog file, at
// index nDlg. This includes whether or not this is a full
// dialog compare. Note that we don't have to do this if we
// are doing a dynamic dialog compare.
//-----------------------------------------------------------
if (nDlg)
{
i = fDialogInfo(szFullFName, nDlg, (LPSTR)szDsc,
(INT FAR *)&nSourceCount, (INT FAR *)&fFullDlg);
if (i != WCT_NOERR)
{
OutDebug ("Unable to get dialog information");
return (WCT_OUTOFMEMORY);
}
// Allocate memory for source (add 1 to ensure + size)
//-------------------------------------------------------
i = fInitBlock((HANDLE FAR *)&hGSource, nSourceCount+1);
if (i != WCT_NOERR)
{
OutDebug ("Could not allocate for hGSource");
return (WCT_OUTOFMEMORY);
}
// Read the information from the file into the source
// array. Note that lpSrcCtl is locked from this point
// to the end of this routine.
//-------------------------------------------------------
lpSrcCtl = (LPCTLDEF)GlobalLock (hGSource);
if (!lpSrcCtl)
{
OutDebug ("Can't lock hGSource!");
GlobalFree (hGSource);
return (WCT_OUTOFMEMORY);
}
cbMax = nSourceCount * sizeof(CTLDEF);
i = fGetControls ((LPSTR) szFullFName, nDlg,
(WORD) cbMax, (LPSTR) lpSrcCtl);
if (i != nSourceCount)
{
OutDebug ("fGetControls failed");
GlobalUnlock (hGSource);
GlobalFree (hGSource);
return (WCT_OUTOFMEMORY);
}
}
else
{
// nDlg = 0 means this is a dynamic dialog compare. All
// we have to do here is lock down the handle we were
// given (and make sure to check for the success of the
// lock, in case the user passed in an invalid handle).
// We also have to check the sign of the dynamic dialog
// count -- if negative, treat this as a "full dialog"
// comparison.
//-------------------------------------------------------
lpSrcCtl = (LPCTLDEF)GlobalLock (hDynDlg);
if (lpSrcCtl == NULL)
{
OutDebug ("Can't lock dynamic handle!\n\r");
return (WCT_OUTOFMEMORY);
}
nSourceCount = abs(nDynCount);
fFullDlg = (nSourceCount < 0);
}
// Check to see if the class name of the first control in the
// array is "MenuItem". If so, this is a menu, not a dialog
// type, so set the nGrabType variable accordingly
//------------------------------------------------------------
if (!lstrcmpi(((LPCTLDEF)lpSrcCtl)[0].rgClass, "MenuItem"))
nGrabType = PUMP_MENU;
else
nGrabType = PUMP_ALL;
// All the information in the source array is set up and
// locked. Next, allocate memory for the target (just 1 - it
// will grow as we grab children with fPumpHandleForInfo)
//------------------------------------------------------------
j = fInitBlock ((HANDLE FAR *)&hGTarget, 1);
if (j != WCT_NOERR)
{
OutDebug ("Could not allocate for hGTarget");
if (nDlg)
{
GlobalUnlock (hGSource);
GlobalFree (hGSource);
}
return (WCT_OUTOFMEMORY);
}
// Grab all the child windows from hWnd with fPumpHandleForInfo
//-------------------------------------------------------------
i=fPumpHandleForInfo (hWnd, hGTarget, (INT FAR *)&nTargetCount,
nGrabType);
if (i != WCT_NOERR)
{
OutDebug ("PumpHandle failed");
GlobalFree (hGTarget);
if (nDlg)
{
GlobalUnlock (hGSource);
GlobalFree (hGSource);
}
return ( i );
}
// Check the fTotal flag - if TRUE, and we are NOT comparing menu
// information, add the parent (hWnd) to the list
//--------------------------------------------------------------
if ( (fTotal) && (nGrabType != PUMP_MENU) )
{
i = fAddControlToList (hWnd, hGTarget, (INT FAR *)&nTargetCount,
NULL);
if (i != WCT_NOERR)
{
OutDebug ("Error adding parent to hGSource");
GlobalFree( hGTarget );
if (nDlg)
{
GlobalUnlock( hGSource );
GlobalFree (hGSource );
}
return ( i );
}
}
// The hGTarget buffer is established. Lock it down for the
// comparison
//--------------------------------------------------------------
lpTrgCtl = (LPCTLDEF)GlobalLock (hGTarget);
// Okay, it's time to do the comparison. Pass everything off to
// fCompareMem.
//--------------------------------------------------------------
retval = fCompareMem(lpSrcCtl, nSourceCount, lpTrgCtl, nTargetCount,
fFullDlg, szLogFile);
// Unlock and free up memory, and exit
//--------------------------------------------------------------
GlobalUnlock (hGTarget);
GlobalFree (hGTarget);
if (nDlg)
{
GlobalUnlock (hGSource);
GlobalFree (hGSource);
}
return (retval);
}
//*-------------------------------------------------------------------------
//| fPutMatchPref
//|
//| PURPOSE: Save Match Preference to wMatchPref globol variable
//|
//| ENTRY: wMatchBits - Preference bits
//|
//| EXIT: None
//*-------------------------------------------------------------------------
VOID FARPUBLIC fPutMatchPref(LONG lMatchBits)
{
lMatchPref = lMatchBits;
}
//*-------------------------------------------------------------------------
//| fGetMatchPref
//|
//| PURPOSE: Export Match Preference from wMatchPref globol variable
//|
//| ENTRY: None
//|
//| EXIT: Match Bits (WORD)
//*-------------------------------------------------------------------------
LONG FARPUBLIC fGetMatchPref(VOID)
{
return lMatchPref;
}