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.
 
 
 
 
 
 

647 lines
20 KiB

/****************************** MODULE HEADER *******************************
* forms.c
* Functions associated with form enumeration & manipulation.
*
*
* Copyright (C) 1992 Microsoft Corporation.
*
****************************************************************************/
#define PRINT_FORMS_INFO
#undef PRINT_FORMS_INFO
#include "rasuipch.h"
#pragma hdrstop("rasuipch.h")
#define GLOBAL_MACS
#include "gblmac.h"
#undef GLOBAL_MACS
/*
* A pair of macros to convert the spooler's form sizes to master units.
* All information from the minidriver is in master units, so that is
* the convenient unit for us. Spooler data is returned in units of
* 0.001mm.
*/
#define XTOMASTER( xx ) ((xx) = ((xx) * pdh->ptMaster.x + 12700) / 25400)
#define YTOMASTER( yy ) ((yy) = ((yy) * pdh->ptMaster.y + 12700) / 25400)
/* And we also want to go the other way! */
#define MASTERTOX( xx ) (((xx) * 25400 + pdh->ptMaster.x / 2) / pdh->ptMaster.x)
#define MASTERTOY( yy ) (((yy) * 25400 + pdh->ptMaster.y / 2) / pdh->ptMaster.y)
/*
* A macro to determine whether the paper sizes are equal. We allow
* a little slop in the comparison since the data comes from different
* sources and roundoff/truncation calculations are involved.
*/
#define EQUAL( a, b ) (((a) - (b) < 10) && ((a) - (b) > -10))
/*
* Local function prototypes.
*/
BOOL
bGetForms(
HANDLE hPrinter,
PRASDDUIINFO pRasdduiInfo /* Global Data Access */
);
void
vScanSize(
DWORD dwSelect, /* OR'ed into forms data */
short fPaperType, /* fPaperType from this PAPERSOURCE */
PRASDDUIINFO pRasdduiInfo /* Global Data Access */
);
/******************************* Function Header ****************************
* bInitForms
* Get all the forms details from the spooler, then determine which
* ones are usable with our printer. Generates an array of info
* about forms suitable for this printer.
*
* RETURNS:
* TRUE/FALSE; FALSE means big trouble.
*
* HISTORY:
* 14:31 on Mon 06 Apr 1992 -by- Lindsay Harris [lindsayh]
* First version.
*
****************************************************************************/
BOOL
bInitForms(
HANDLE hPrinter, /* Access to the spoolers's data */
PRASDDUIINFO pRasdduiInfo /* Global Data Access */
)
{
int iSrc; /* Loop index through PAPERSOURCE */
DWORD dwMask; /* Masking paper source + size */
short *psSrc; /* Scan the MODELDATA source indices */
/*
* First step is to get the forms data from the spooler.
*/
if( pRasdduiInfo->cFormInit++ > 0 )
return TRUE; /* Been here, so do nothing */
if( !bGetForms( hPrinter, pRasdduiInfo ) )
return FALSE; /* NBG */
/*
* Now enumerate the PAPERSOURCE information in the GPC data. For
* each PAPERSOURCE, loop through the PAPERSIZEs that match, and
* then scan through the spooler forms data for forms that are
* compatible. When found, set the corresponding bits in the FORM_DATA
* array.
*/
psSrc = (short *)((BYTE *)pdh + pdh->loHeap +
pModel->rgoi[ MD_OI_PAPERSOURCE ]);
if( *psSrc == (short)0 )
{
/* No paper source, so presume all PAPERSIZES are AOK */
vScanSize( (DWORD)1, (short)~0, pRasdduiInfo );
}
else
{
/* More than 1 paper source, so scan through them all. */
for( dwMask = 1 ; (iSrc = *psSrc - 1) >= 0; ++psSrc, dwMask <<= 1 )
{
PAPERSOURCE *pPSRC; /* This paper source */
pPSRC = (PAPERSOURCE *)GetTableInfoIndex( pdh, HE_PAPERSOURCE,
iSrc );
vScanSize( dwMask, pPSRC->fPaperType, pRasdduiInfo );
}
}
return TRUE;
}
/******************************** Function Header ***************************
* vEndForms
* Free any storage previously allocated by bInitForms.
*
* RETURNS:
* Nothing
*
* HISTORY:
* 15:52 on Mon 06 Apr 1992 -by- Lindsay Harris [lindsayh]
* Numero uno
*
****************************************************************************/
void
vEndForms(
PRASDDUIINFO pRasdduiInfo /* Global Data Access */
)
{
/*
* Simply HeapFree the permanent storage.
*/
if( --pRasdduiInfo->cFormInit > 0 )
return;
if( pFIBase )
{
HEAPFREE( pRasdduiInfo, 0, (LPSTR)pFIBase );
pFIBase = NULL;
}
if( pFD )
{
HEAPFREE( pRasdduiInfo, 0, (LPSTR)pFD );
pFD = NULL;
}
pRasdduiInfo->cForms = 0; /* Well, we don't have any now */
return;
}
/******************************** Function Header ***************************
* bGetForms
* Enumerate the forms via the spooler.
*
* RETURNS:
* TRUE/FALSE; FALSE for failure to get form data or memory.
*
* HISTORY:
* 15:28 on Mon 06 Apr 1992 -by- Lindsay Harris [lindsayh]
* First incarnation.
*
*****************************************************************************/
BOOL
bGetForms(
HANDLE hPrinter,
PRASDDUIINFO pRasdduiInfo /* Global Data Access */
)
{
DWORD cbNeeded; /* Number of bytes needed */
DWORD cReturned; /* Number of forms returned */
FORM_INFO_1 *pForm; /* Scanning through returned data */
FORM_DATA *pFDTmp; /* Filling in FORM_DATA stuff */
/*
* Standard technique: call first to determine how much storage
* is required, allocate the storage and then call again.
*/
if( !EnumForms( hPrinter, 1, NULL, 0, &cbNeeded, &cReturned ) )
{
if( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
{
if( pFIBase = (FORM_INFO_1 *)HEAPALLOC( pRasdduiInfo, 0, cbNeeded ) )
{
if( EnumForms( hPrinter, 1, (LPBYTE)pFIBase,
cbNeeded, &cbNeeded, &cReturned ) )
{
/*
* Allocate the number + 1 of structures needed to make
* the FORM_DATA array. This is used elsewhere.
*/
cbNeeded = (cReturned + 1) * sizeof( FORM_DATA );
if( !(pFD = (FORM_DATA *)HEAPALLOC( pRasdduiInfo, 0, cbNeeded )) )
{
vEndForms(pRasdduiInfo); /* Does the clean up */
return FALSE;
}
ZeroMemory( pFD, cbNeeded );
pForm = pFIBase;
pFDTmp = pFD;
pRasdduiInfo->cForms = cReturned; /* For setting defaults etc */
while( cReturned-- )
{
/*
* Have our structure point to the forms data,
* and also convert the forms data base into
* master units.
*/
XTOMASTER( pForm->Size.cx );
YTOMASTER( pForm->Size.cy );
pFDTmp->pFI = pForm++;
++pFDTmp;
}
}
//If EnumForms fails, return false.
else
{
RIP("Rasddui!bGetForms:2nd call to EnumForms Failed\n");
vEndForms(pRasdduiInfo); /* Does the clean up */
return FALSE;
}
return TRUE; /* AOK */
}
}
//If EnumForms fails, return false.
else
{
RIP("Rasddui!bGetForms:EnumForms returns error other than ERROR_INSUFFICIENT_BUFFER\n");
vEndForms(pRasdduiInfo); /* Does the clean up */
return FALSE;
}
}
RIP("Rasddui!bGetForms:1st call to EnumForms Failed\n");
/*
* If we reach here, one of the above if(..) statements failed,
* and that is NOT good.
*/
return FALSE; /* SHOULD NEVER HAPPEN */
}
/**************************** Function Header *******************************
* vScanSize
* Scan the array of papersize data, and for each entry that is usable
* with the paper source selection information passed in, scan the
* array of forms and mark those that can be used with that form.
*
* RETURNS:
* Nothing
*
* HISTORY:
* 10:43 on Tue 07 Apr 1992 -by- Lindsay Harris [lindsayh]
* First time around.
*
****************************************************************************/
void
vScanSize(
DWORD dwSelect, /* OR'ed into forms data */
short fPaperType, /* fPaperType from this PAPERSOURCE */
PRASDDUIINFO pRasdduiInfo /* Global Data Access */
)
{
short *psPSInd; /* Scan the PAPERSOURCE selection */
PAPERSIZE *pPS; /* Scanning PAPERSIZE data */
FORM_DATA *pForms; /* Looking through the forms data base */
psPSInd = (short *)((BYTE *)pdh + pdh->loHeap +
pModel->rgoi[ MD_OI_PAPERSIZE ]);
for( ; *psPSInd; ++psPSInd )
{
pPS = (PAPERSIZE *)GetTableInfoIndex( pdh, HE_PAPERSIZE, *psPSInd - 1 );
if( !pPS )
continue; /* Probably should not happen */
if( (pPS->fPaperType & fPaperType) == 0 )
continue; /* Not usable */
/*
* Now for the goodies. We have a valid paper size for this source,
* so look for any matching sizes in the forms data returned via
* the spooler. If found, then OR dwSelect into the forms
* data dwSource field. This allows us to display acceptable
* forms in the various paper source dialogs.
*/
for( pForms = pFD; pForms->pFI; ++pForms )
{
if( EQUAL( pForms->pFI->Size.cx, pPS->ptSize.x ) &&
EQUAL( pForms->pFI->Size.cy, pPS->ptSize.y ) )
{
pForms->dwSource |= dwSelect;
}
}
/*
* Special case: user defined paper sizes. IF the printer
* supports them, then accept ANY size form that is within
* the size limits of this printer.
*/
if( pPS->sPaperSizeID == DMPAPER_USER )
{
#ifdef PRINT_FORMS_INFO
DbgPrint("\n\nRasddui!vScanSize:STARTING DEBUG INFO FOR USER DEFINED FORMS\n\n");
DbgPrint("Model MIN DIM is Width = %d and Height = %d \n", pModel->ptMin.x,pModel->ptMin.y);
DbgPrint("Model MAX DIM is Width = %d and Height = %d \n", pModel->ptMax.x,pModel->ptMax.y);
#endif
/* Loop through checking MODELDATA page size limits */
for( pForms = pFD; pForms->pFI; ++pForms )
{
#ifdef PRINT_FORMS_INFO
DbgPrint("\nForm Name is %ws and dim is (WxL) %d X %d \n", pForms->pFI->pName, pForms->pFI->Size.cx, pForms->pFI->Size.cy);
#endif
if( pForms->pFI->Size.cx >= pModel->ptMin.x &&
pForms->pFI->Size.cy >= pModel->ptMin.y &&
pForms->pFI->Size.cx <= pModel->ptMax.x &&
((pModel->ptMax.y == -1 )?TRUE:pForms->pFI->Size.cy
<= pModel->ptMax.y) )
{
pForms->dwSource |= dwSelect;
#ifdef PRINT_FORMS_INFO
DbgPrint("Setting the user defined form,Name is %ws\n",
pForms->pFI->pName);
#endif
}
}
#ifdef PRINT_FORMS_INFO
DbgPrint("\n\nRasddui!vScanSize:ENDING DEBUG INFO FOR USER DEFINED FORMS\n\n");
#endif
}
}
return;
}
/*************************** Function Header *******************************
* vSetDefaultForms
* Initialise the relevant forms information to provide a consistent
* view of forms. This means filling in the name in the DEVMODE passed
* in, as well as at least one of the paper source fields.
*
* RETURNS:
* Nothing.
*
* HISTORY:
* 11:29 on Wed 13 Jan 1993 -by- Lindsay Harris [lindsayh]
* First version.
*
****************************************************************************/
void
vSetDefaultForms(
EXTDEVMODE *pEDM,
HANDLE hPrinter, /* Access to the printer's data */
PRASDDUIINFO pRasdduiInfo /* Global Data Access */
)
{
/*
* The default form is the first in the array of PaperSizes.
* Basically we need to set this into the first entry of the
* aFMBin[] array, and also put the name into the DEVMODE.
* This then defines at least a minimal configuration that
* is valid for this printer.
*/
short sIndex; /* Mini driver index data */
PAPERSIZE *pPS; /* The paper size information */
WCHAR awchForm[ 64 ]; /* The name of the form */
short sDefaultPaperSrcIndex = -1 ;
short sDefaultPaperSrc = 0;
#if 0
sIndex = *((short *)((BYTE *)pdh + pdh->loHeap +
pModel->rgoi[ MD_OI_PAPERSIZE ]) );
--sIndex;
pPS = (PAPERSIZE *)GetTableInfoIndex( pdh, HE_PAPERSIZE, sIndex );
#endif
pPS = (PAPERSIZE *)GetTableInfo( pdh, HE_PAPERSIZE, pEDM );
if( pPS )
sIndex = pPS->sPaperSizeID; /* The desired index */
else
sIndex = 0; /* This should not happen ever */
if( sIndex >= pRasdduiInfo->cForms )
{
if( sIndex > DMPAPER_USER )
{
/* A minidriver specific size: use that string instead */
if( iLoadStringW( &WinResData, sIndex,
awchForm, sizeof( awchForm ) ) )
{
for( sIndex = 0; sIndex < pRasdduiInfo->cForms; ++sIndex )
{
if( wcscmp( awchForm, (pFIBase + sIndex)->pName ) == 0 )
break;
}
if( sIndex >= pRasdduiInfo->cForms )
{
/* Should not happen - we did not match the form */
sIndex = 0; /* It might work */
}
}
else
{
sIndex = 0; /* Should never happen! */
}
}
else
{
#if DBG
DbgPrint( "rasdd!vSetDefaultForms: no match on default index %d\n",
sIndex );
#endif
sIndex = 0;
}
}
else
{
/*
* Reduce the value by 1: the resource IDs are one based, whereas
* we are indexing an array, and so want a 0 based value.
*/
if( --sIndex < 0 )
sIndex = 0;
}
if( sIndex == (DMPAPER_LETTER - 1) && !bIsUSA( hPrinter ) )
{
/* Letter size paper is default, and this is not USA, so use A4! */
sIndex = DMPAPER_A4 - 1; /* See above re - 1 */
}
RASUIDBGP(DEBUG_TRACE,("Rasddui!vSetDefaultForms : Default PaperSize index is %d.\n",sIndex) );
/* Put the default form in default PaperSource */
/* Make the value 1 based */
sDefaultPaperSrcIndex = pEDM->dx.rgindex[ HE_PAPERSOURCE ] + 1;
RASUIDBGP(DEBUG_TRACE,("Rasddui!vSetDefaultForms : Default PaperSrc Index is %d.\n",sDefaultPaperSrcIndex-1) );
/* Find the place of default Paper Source in FORM_MAP table. The value in rgindex[HE_PAPERSOURCE]
* is papersource index value in the minidriver. We have to find out the place of this index
* in the list. For example the list of papersource may be 1, 3, 5, 6 with 5 being the default.
* In this case FORM_MAP table entry number 3 (aFMBin[ 3 ]) has to be selected as paper source
* 5 is third in the order.
*/
if ( sDefaultPaperSrcIndex >= 1 )
{
short *psrc;
psrc = (short *)((BYTE *)pdh + pdh->loHeap +
pModel->rgoi[ MD_OI_PAPERSOURCE ] );
for( sDefaultPaperSrc = 0 ; (*psrc && (*psrc != sDefaultPaperSrcIndex) ) ; ++sDefaultPaperSrc, ++psrc )
;
RASUIDBGP(DEBUG_TRACE,("Rasddui!vSetDefaultForms : Default PaperSource is %dth item in the list.\n",sDefaultPaperSrc) );
RASUIDBGP(DEBUG_TRACE,("Rasddui!vSetDefaultForms : Default PaperSrc Index in FORM_MAP table(aFMBin[%d]) is %d.\n",sDefaultPaperSrc, aFMBin[sDefaultPaperSrc].iPSIndex) );
RASUIDBGP(DEBUG_TRACE,("Rasddui!vSetDefaultForms : Total number of Paperbins is %d.\n",NumPaperBins) );
}
if (sDefaultPaperSrc > NumPaperBins)
sDefaultPaperSrc = 0;
aFMBin[ sDefaultPaperSrc ].pfd = pFD + sIndex;
if( pEDM )
{
wcsncpy( pEDM->dm.dmFormName, aFMBin[ sDefaultPaperSrc ].pfd->pFI->pName, CCHFORMNAME );
pEDM->dm.dmFormName[ CCHFORMNAME - 1 ] = (WCHAR)0;
pEDM->dm.dmPaperWidth = (short)aFMBin[ sDefaultPaperSrc ].pfd->pFI->Size.cx;
pEDM->dm.dmPaperLength = (short)aFMBin[ sDefaultPaperSrc ].pfd->pFI->Size.cy;
pEDM->dm.dmPaperSize = sIndex;
pEDM->dm.dmFields |= DM_FORMNAME | DM_PAPERSIZE |
DM_PAPERWIDTH | DM_PAPERLENGTH;
}
return;
}
/************************** Function Header ********************************
* bAddMiniForms
* Add any minidriver defined form names. These are identified as
* having an sPaperSizeID > 256. This function should only be called
* after detecting the first installation of a minidriver.
*
* RETURNS:
* TRUE/FALSE, TRUE for success.
*
* HISTORY:
* 15:40 on Wed 13 Jan 1993 -by- Lindsay Harris [lindsayh]
* Created it, to support mini driver specific forms.
*
****************************************************************************/
BOOL
bAddMiniForms(
HANDLE hPrinter, /* Access to the printer */
BOOL bUpgrade,
PRASDDUIINFO pRasdduiInfo /* Global Data Access */
)
{
short *psPSInd; /* Scan the PAPERSOURCE selection */
PAPERSIZE *pPS; /* Scanning PAPERSIZE data */
FORM_INFO_1 fi1; /* The info the spooler wants! */
WCHAR awchForm[ 64 ]; /* The name of the form */
psPSInd = (short *)((BYTE *)pdh + pdh->loHeap +
pModel->rgoi[ MD_OI_PAPERSIZE ]);
fi1.Flags = FORM_PRINTER;
fi1.pName = awchForm;
fi1.ImageableArea.left = 0;
fi1.ImageableArea.top = 0;
for( ; *psPSInd; ++psPSInd )
{
pPS = (PAPERSIZE *)GetTableInfoIndex( pdh, HE_PAPERSIZE, *psPSInd - 1 );
if( !pPS || pPS->sPaperSizeID <= DMPAPER_USER )
continue; /* Standard rasdd defined */
if( iLoadStringW( &WinResData, pPS->sPaperSizeID,
awchForm, sizeof( awchForm ) ) == 0 )
{
#if DBG
DbgPrint( "rasddUI!bAddMiniForms: Could not load form name string for index %d\n", pPS->sPaperSizeID );
#endif
continue; /* See if there are others */
}
/*
* Now have a minidriver specific form size! This information
* needs to be communicated to the spooler.
*/
fi1.Size.cx = MASTERTOX( (long)pPS->ptSize.x );
fi1.Size.cy = MASTERTOY( (long)pPS->ptSize.y );
fi1.ImageableArea.right = fi1.Size.cx;
fi1.ImageableArea.bottom = fi1.Size.cy;
//This is the upgrade case
if (bUpgrade)
{
FORM_INFO_1 FormInfo;
DWORD dw = 0;
if ( GetForm( hPrinter, awchForm, 1,
(LPBYTE)&FormInfo,
sizeof(FORM_INFO_1), &dw ) )
{
/* This means NT 351 */
if ( FormInfo.Flags & FORM_USER )
DeleteForm(hPrinter,awchForm);
}
}
AddForm( hPrinter, 1, (BYTE *)&fi1 );
}
return TRUE;
}