mirror of https://github.com/tongzx/nt5src
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.
1164 lines
35 KiB
1164 lines
35 KiB
/*****************************************************************************\
|
|
* MODULE: ppinfo.c
|
|
*
|
|
* This module contains the print-information routines.
|
|
*
|
|
*
|
|
* Copyright (C) 1996-1997 Microsoft Corporation
|
|
* Copyright (C) 1996-1997 Hewlett Packard
|
|
*
|
|
* History:
|
|
* 09-Jun-1993 JonMarb Created
|
|
* 07-Oct-1996 HWP-Guys Initiated port from win95 to winNT
|
|
*
|
|
\*****************************************************************************/
|
|
|
|
|
|
#include "precomp.h"
|
|
#include "priv.h"
|
|
|
|
/*****************************************************************************\
|
|
* ppprn_IppGetRsp (Local Callback Routine)
|
|
*
|
|
* Retrieves a GetPrinter response from the IPP server
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL CALLBACK ppinfo_IppGetRsp(
|
|
CAnyConnection *pConnection,
|
|
HINTERNET hReq,
|
|
PCINETMONPORT pIniPort,
|
|
LPARAM lParam)
|
|
{
|
|
HANDLE hIpp;
|
|
DWORD dwRet;
|
|
DWORD cbRd;
|
|
LPBYTE lpDta;
|
|
DWORD cbDta;
|
|
LPIPPRET_PRN lpRsp;
|
|
DWORD cbRsp;
|
|
BYTE bBuf[MAX_IPP_BUFFER];
|
|
BOOL bRet = FALSE;
|
|
|
|
|
|
if (hIpp = WebIppRcvOpen(IPP_RET_GETPRN)) {
|
|
|
|
while (TRUE) {
|
|
|
|
cbRd = 0;
|
|
if (pIniPort->ReadFile (pConnection, hReq, (LPVOID)bBuf, sizeof(bBuf), &cbRd) && cbRd) {
|
|
|
|
dwRet = WebIppRcvData(hIpp, bBuf, cbRd, (LPBYTE*)&lpRsp, &cbRsp, &lpDta, &cbDta);
|
|
|
|
switch (dwRet) {
|
|
|
|
case WEBIPP_OK:
|
|
|
|
if (!lpRsp) {
|
|
SetLastError (ERROR_INVALID_DATA);
|
|
}
|
|
else if ((bRet = lpRsp->bRet) == FALSE)
|
|
SetLastError(lpRsp->dwLastError);
|
|
else {
|
|
|
|
pIniPort->SetPowerUpTime (lpRsp->pi.ipp.dwPowerUpTime);
|
|
((LPPRINTER_INFO_2)lParam)->Status = lpRsp->pi.pi2.Status;
|
|
((LPPRINTER_INFO_2)lParam)->cJobs = lpRsp->pi.pi2.cJobs;
|
|
((LPPRINTER_INFO_2)lParam)->pPrinterName = memAllocStr(lpRsp->pi.pi2.pPrinterName);
|
|
((LPPRINTER_INFO_2)lParam)->pDriverName = memAllocStr(lpRsp->pi.pi2.pDriverName);
|
|
}
|
|
|
|
WebIppFreeMem(lpRsp);
|
|
|
|
goto EndGetRsp;
|
|
|
|
case WEBIPP_MOREDATA:
|
|
|
|
// Need to do another read to fullfill our header-response.
|
|
//
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DBG_MSG(DBG_LEV_ERROR, (TEXT("ppinfo_IppGetRsp - Err : Receive Data Error (dwRet=%d, LE=%d)"),
|
|
dwRet, WebIppGetError(hIpp)));
|
|
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
|
|
goto EndGetRsp;
|
|
}
|
|
|
|
} else {
|
|
|
|
goto EndGetRsp;
|
|
}
|
|
}
|
|
|
|
EndGetRsp:
|
|
|
|
WebIppRcvClose(hIpp);
|
|
|
|
} else {
|
|
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* ppinfo_Get (Local Routine)
|
|
*
|
|
* Gets printer info from server.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL ppinfo_Get(
|
|
PCINETMONPORT pIniPort,
|
|
LPPRINTER_INFO_2 ppi2)
|
|
{
|
|
PIPPREQ_GETPRN pgp;
|
|
REQINFO ri;
|
|
DWORD dwRet;
|
|
LPBYTE lpIpp;
|
|
DWORD cbIpp;
|
|
LPCTSTR lpszUri;
|
|
BOOL bRet = FALSE;
|
|
|
|
lpszUri = pIniPort->GetPortName();
|
|
|
|
|
|
// Create our ipp-reqest-structure.
|
|
//
|
|
if (pgp = WebIppCreateGetPrnReq(0, lpszUri)) {
|
|
|
|
// Convert the reqest to IPP, and perform the
|
|
// post.
|
|
//
|
|
ZeroMemory(&ri, sizeof(REQINFO));
|
|
ri.cpReq = CP_UTF8;
|
|
ri.idReq = IPP_REQ_GETPRN;
|
|
|
|
ri.fReq[0] = IPP_REQALL;
|
|
ri.fReq[1] = IPP_REQALL;
|
|
|
|
dwRet = WebIppSndData(IPP_REQ_GETPRN,
|
|
&ri,
|
|
(LPBYTE)pgp,
|
|
pgp->cbSize,
|
|
&lpIpp,
|
|
&cbIpp);
|
|
|
|
|
|
// The request-structure has been converted to IPP format,
|
|
// so it is ready to go to the server.
|
|
//
|
|
if (dwRet == WEBIPP_OK) {
|
|
|
|
bRet = pIniPort->SendReq(lpIpp,
|
|
cbIpp,
|
|
ppinfo_IppGetRsp,
|
|
(LPARAM)ppi2,
|
|
TRUE);
|
|
|
|
WebIppFreeMem(lpIpp);
|
|
|
|
} else {
|
|
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
}
|
|
|
|
WebIppFreeMem(pgp);
|
|
|
|
} else {
|
|
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* _ppinfo_set_str (Local Routine)
|
|
*
|
|
* Copies strings into a Win32 format buffer -- a structure at the front of
|
|
* the buffer and strings packed into the end.
|
|
*
|
|
* On entry, *buf should point to the last available byte in the buffer.
|
|
*
|
|
\*****************************************************************************/
|
|
VOID _ppinfo_set_str(
|
|
LPTSTR *dest,
|
|
LPCTSTR src,
|
|
LPTSTR *buf)
|
|
{
|
|
if (src != NULL) {
|
|
|
|
// Place string at end of buffer. This performs pointer
|
|
// arithmatic, so the offsets are TCHAR in size.
|
|
//
|
|
(*buf) -= lstrlen(src);
|
|
|
|
DBG_ASSERT( ((DWORD_PTR)dest < (DWORD_PTR)*buf) ,
|
|
(TEXT("String fill overrun in _ppinfo_set_str"))
|
|
);
|
|
|
|
lstrcpy(*buf, src);
|
|
|
|
|
|
// Place string address in structure and save pointer to new
|
|
// last available byte.
|
|
//
|
|
*dest = *buf;
|
|
(*buf)--;
|
|
|
|
} else {
|
|
|
|
*dest = TEXT('\0');
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* _ppinfo_describe_provider (Local Routine)
|
|
*
|
|
* Fills a PRINTER_INFO_1 structure with information about the print provider.
|
|
* Returns TRUE if successful. Otherwise, it returns FALSE. Extended error
|
|
* information is available from GetLastError.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL _ppinfo_describe_provider(
|
|
LPPRINTER_INFO_1 pInfo,
|
|
DWORD cbSize,
|
|
LPDWORD pcbNeeded,
|
|
LPDWORD pcbReturned)
|
|
{
|
|
LPTSTR pszString;
|
|
|
|
|
|
// Calculate the space needed (in bytes) that is necessary to
|
|
// store the information for the print-processor.
|
|
//
|
|
*pcbNeeded = sizeof(PRINTER_INFO_1) +
|
|
utlStrSize(g_szDescription) +
|
|
utlStrSize(g_szProviderName) +
|
|
utlStrSize(g_szComment);
|
|
|
|
if (*pcbNeeded > cbSize) {
|
|
|
|
*pcbReturned = 0;
|
|
|
|
DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: _describe_provider: Not enough memory")));
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Initialize the fields which do not need to copy strings.
|
|
//
|
|
pInfo->Flags = (PRINTER_ENUM_ICON1 | PRINTER_ENUM_CONTAINER);
|
|
|
|
//
|
|
// Hide this provider from the UI, there is nothing underneath to enumerate.
|
|
//
|
|
#if WINNT32
|
|
pInfo->Flags |= PRINTER_ENUM_HIDE;
|
|
#endif
|
|
|
|
// Set the string information. First set the (pszString) pointer
|
|
// to the first location at the end of the buffer which will store
|
|
// the string.
|
|
//
|
|
pszString = ENDOFBUFFER(pInfo, cbSize);
|
|
|
|
_ppinfo_set_str(&pInfo->pDescription, g_szDescription , &pszString);
|
|
_ppinfo_set_str(&pInfo->pName , g_szProviderName, &pszString);
|
|
_ppinfo_set_str(&pInfo->pComment , g_szComment , &pszString);
|
|
|
|
|
|
// Return the number of structures copied.
|
|
//
|
|
*pcbReturned = 1;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* _ppinfo_net_get_info (Local Routine)
|
|
*
|
|
* Fills a supplied PRINTER_INFO_2 structure with all the information
|
|
* we can dig up on the specified IPP1 print server.
|
|
*
|
|
* Takes a pointer to PPRINTER_INFO_2 which is allocated to be the correct size
|
|
*
|
|
* Returns TRUE if successful, FALSE if otherwise.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL _ppinfo_net_get_info(
|
|
IN PCINETMONPORT pIniPort,
|
|
OUT PPRINTER_INFO_2 *ppInfo,
|
|
OUT LPDWORD lpBufAllocated,
|
|
IN ALLOCATORFN pAllocator)
|
|
{
|
|
PRINTER_INFO_2 pi2;
|
|
PPRINTER_INFO_2 pInfo;
|
|
LPTSTR pszString;
|
|
LPCTSTR pszPortName;
|
|
DWORD dwAllocSize;
|
|
BOOL bRet = FALSE;
|
|
|
|
|
|
// Make a server-call to get the printer-information.
|
|
//
|
|
DBG_ASSERT( ppInfo, (TEXT("_ppinfo_net_get_info passed in NULL LPPI2 *")) );
|
|
DBG_ASSERT( pAllocator, (TEXT("_ppinfo_net_get_info passed in NULL Allocator")) );
|
|
DBG_ASSERT( lpBufAllocated, (TEXT("_ppinfo_net_get_info passed in NULL buffer allocated return size")) );
|
|
|
|
*ppInfo = NULL; // NULL out ppInfo, just in case
|
|
*lpBufAllocated = 0; // Set allocated size to zero
|
|
|
|
ZeroMemory(&pi2, sizeof(PRINTER_INFO_2));
|
|
|
|
if (!ppinfo_Get(pIniPort, &pi2))
|
|
goto BailOut;
|
|
|
|
pszPortName = pIniPort->GetPortName();
|
|
|
|
dwAllocSize = ( ( pi2.pPrinterName ? lstrlen( pi2.pPrinterName) + 1 : 0) +
|
|
( pszPortName ? lstrlen( pszPortName ) + 1 : 0) +
|
|
( pi2.pDriverName ? lstrlen( pi2.pDriverName ) + 1 : 0) +
|
|
7 * 1 ) * sizeof(TCHAR) + sizeof(PRINTER_INFO_2);
|
|
|
|
pInfo = (PPRINTER_INFO_2)pAllocator( dwAllocSize );
|
|
|
|
if (NULL == pInfo)
|
|
goto Cleanup;
|
|
|
|
pszString = ENDOFBUFFER( pInfo, dwAllocSize );
|
|
|
|
// Set non-string entries.
|
|
//
|
|
pInfo->cJobs = pi2.cJobs;
|
|
pInfo->Status = pi2.Status;
|
|
pInfo->pDevMode = NULL;
|
|
pInfo->pSecurityDescriptor = NULL;
|
|
#if 0
|
|
pInfo->Attributes = PRINTER_ATTRIBUTE_SHARED;
|
|
#else
|
|
pInfo->Attributes = PRINTER_ATTRIBUTE_NETWORK;
|
|
#endif
|
|
pInfo->Priority = pi2.Priority;
|
|
pInfo->StartTime = pi2.StartTime;
|
|
pInfo->UntilTime = pi2.UntilTime;
|
|
pInfo->AveragePPM = pi2.AveragePPM;
|
|
|
|
|
|
// Set any remaining fields that we can't fill to reasonable values.
|
|
//
|
|
_ppinfo_set_str(&pInfo->pPrinterName , pi2.pPrinterName , &pszString);
|
|
_ppinfo_set_str(&pInfo->pShareName , g_szEmptyString , &pszString);
|
|
_ppinfo_set_str(&pInfo->pPortName , pszPortName , &pszString);
|
|
_ppinfo_set_str(&pInfo->pDriverName , pi2.pDriverName , &pszString);
|
|
_ppinfo_set_str(&pInfo->pComment , g_szEmptyString , &pszString);
|
|
_ppinfo_set_str(&pInfo->pLocation , g_szEmptyString , &pszString);
|
|
_ppinfo_set_str(&pInfo->pSepFile , g_szEmptyString , &pszString);
|
|
_ppinfo_set_str(&pInfo->pPrintProcessor, g_szEmptyString , &pszString);
|
|
_ppinfo_set_str(&pInfo->pDatatype , g_szEmptyString , &pszString);
|
|
_ppinfo_set_str(&pInfo->pParameters , g_szEmptyString , &pszString);
|
|
|
|
*lpBufAllocated = dwAllocSize; // Set the size to what we have allocated
|
|
*ppInfo = pInfo; // Return the allocated structure
|
|
// Since we've allocated our strings in ppinfo_get, we will need
|
|
// to explicitly free them.
|
|
//
|
|
|
|
bRet = TRUE;
|
|
|
|
Cleanup:
|
|
|
|
if (pi2.pPrinterName) memFreeStr(pi2.pPrinterName);
|
|
if (pi2.pDriverName) memFreeStr(pi2.pDriverName);
|
|
|
|
BailOut:
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* _ppinfo_calc_level1 (Local Routine)
|
|
*
|
|
* Calculates the amount of buffer space needed to store a single level 1
|
|
* GetPrinter() result buffer.
|
|
*
|
|
\*****************************************************************************/
|
|
DWORD _ppinfo_calc_level1(
|
|
PPRINTER_INFO_2 pSrcInfo)
|
|
{
|
|
DWORD cbSize;
|
|
|
|
//
|
|
// Figure out how many bytes of buffer space we're going to need.
|
|
//
|
|
cbSize = sizeof(PRINTER_INFO_1) +
|
|
utlStrSize(g_szEmptyString) + // description
|
|
utlStrSize(pSrcInfo->pPrinterName) + // name
|
|
utlStrSize(pSrcInfo->pComment); // comment
|
|
|
|
return cbSize;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* _ppinfo_calc_level2 (Local Routine)
|
|
*
|
|
* Calculates the amount of buffer space needed to
|
|
* store a single level 2 GetPrinter() result buffer.
|
|
*
|
|
\*****************************************************************************/
|
|
DWORD _ppinfo_calc_level2(
|
|
LPCTSTR pszServerName,
|
|
PPRINTER_INFO_2 pSrcInfo)
|
|
{
|
|
DWORD cbSize;
|
|
LPDEVMODE pDevmode;
|
|
|
|
//
|
|
// Figure out how many bytes of buffer space we're going to need.
|
|
//
|
|
cbSize = sizeof(PRINTER_INFO_2) +
|
|
utlStrSize(pszServerName) + // Server Name
|
|
utlStrSize(pSrcInfo->pPrinterName) + // Printer Name
|
|
utlStrSize(pSrcInfo->pShareName) + // Share Name
|
|
utlStrSize(pSrcInfo->pPortName) + // Port Name
|
|
utlStrSize(pSrcInfo->pDriverName) + // Driver Name
|
|
utlStrSize(pSrcInfo->pComment) + // Comment
|
|
utlStrSize(pSrcInfo->pLocation) + // Location
|
|
utlStrSize(pSrcInfo->pSepFile) + // Separator file
|
|
utlStrSize(pSrcInfo->pPrintProcessor) + // Print processor
|
|
utlStrSize(pSrcInfo->pDatatype) + // Data type
|
|
utlStrSize(pSrcInfo->pParameters); // Parameters
|
|
|
|
if (pSrcInfo->pDevMode != NULL) {
|
|
pDevmode = pSrcInfo->pDevMode;
|
|
cbSize += pDevmode->dmSize + pDevmode->dmDriverExtra;
|
|
}
|
|
|
|
return cbSize;
|
|
}
|
|
|
|
|
|
#if WINNT32
|
|
/*****************************************************************************\
|
|
* _ppinfo_calc_level4 (Local Routine)
|
|
*
|
|
* Calculates the amount of buffer space needed to
|
|
* store a single level 4 GetPrinter() result buffer.
|
|
*
|
|
\*****************************************************************************/
|
|
DWORD _ppinfo_calc_level4(
|
|
PPRINTER_INFO_2 pSrcInfo)
|
|
{
|
|
DWORD cbSize;
|
|
|
|
//
|
|
// Figure out how many bytes of buffer space we're going to need.
|
|
//
|
|
cbSize = sizeof(PRINTER_INFO_4) +
|
|
utlStrSize(pSrcInfo->pPrinterName) + // Printer Name
|
|
utlStrSize(pSrcInfo->pServerName);
|
|
|
|
|
|
return cbSize;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*****************************************************************************\
|
|
* _ppinfo_calc_level2 (Local Routine)
|
|
*
|
|
* Calculates the amount of buffer space needed to
|
|
* store a single level 5 GetPrinter() result buffer.
|
|
*
|
|
\*****************************************************************************/
|
|
DWORD _ppinfo_calc_level5(
|
|
PPRINTER_INFO_2 pSrcInfo)
|
|
{
|
|
DWORD cbSize;
|
|
|
|
|
|
//
|
|
// Figure out how many bytes of buffer space we're going to need.
|
|
//
|
|
cbSize = sizeof(PRINTER_INFO_5) +
|
|
utlStrSize(pSrcInfo->pPrinterName) + // Printer Name
|
|
utlStrSize(pSrcInfo->pPortName);
|
|
|
|
|
|
return cbSize;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* _ppinfo_build_level1 (Local Routine)
|
|
*
|
|
* Given a pointer to a source PRINTER_INFO_2 structure, a
|
|
* destination PRINTER_INFO_1 structure and a pointer to the
|
|
* start of string storage space, fills the PRINTER_INFO_1 structure.
|
|
*
|
|
* Called by GetPrinter and EnumPrinters, level 1. Returns an
|
|
* LPSTR pointer to the last available data byte remaining in the
|
|
* buffer.
|
|
*
|
|
\*****************************************************************************/
|
|
LPTSTR _ppinfo_build_level1(
|
|
PPRINTER_INFO_2 pSrcInfo,
|
|
PPRINTER_INFO_1 pDstInfo,
|
|
LPTSTR pszString)
|
|
{
|
|
// Flags.
|
|
//
|
|
pDstInfo->Flags = PRINTER_ENUM_CONTAINER;
|
|
|
|
#if WINNT32
|
|
pDstInfo->Flags |= PRINTER_ENUM_HIDE;
|
|
#endif
|
|
|
|
// Description
|
|
//
|
|
// CODEWORK - The Win32 structure has a field for "description" that has
|
|
// no equivalent in the network printer info structure. What do we
|
|
// really want here? For now, I'm copying in an empty string as a
|
|
// placeholder.
|
|
//
|
|
_ppinfo_set_str(&pDstInfo->pDescription, g_szEmptyString , &pszString);
|
|
_ppinfo_set_str(&pDstInfo->pName , pSrcInfo->pPrinterName, &pszString);
|
|
_ppinfo_set_str(&pDstInfo->pComment , pSrcInfo->pComment , &pszString);
|
|
|
|
return pszString;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* _ppinfo_build_level2 (Local Routine)
|
|
*
|
|
* Given a server name, a pointer to a source PRINTER_INFO_2
|
|
* structure, a destination PRINTER_INFO_2 structure and a pointer to
|
|
* the start of string storage space, fills the PRINTER_INFO_2 structure.
|
|
*
|
|
* Called by GetPrinter and EnumPrinters, level 2. Returns an
|
|
* LPTSTR pointer to the last available data char in the data buffer.
|
|
*
|
|
\*****************************************************************************/
|
|
LPTSTR _ppinfo_build_level2(
|
|
LPCTSTR pszServerName,
|
|
PPRINTER_INFO_2 pSrcInfo,
|
|
PPRINTER_INFO_2 pDstInfo,
|
|
LPTSTR pszString)
|
|
{
|
|
|
|
// Set non-string entries.
|
|
//
|
|
pDstInfo->pSecurityDescriptor = NULL;
|
|
pDstInfo->Attributes = pSrcInfo->Attributes;
|
|
pDstInfo->Priority = pSrcInfo->Priority;
|
|
pDstInfo->DefaultPriority = pSrcInfo->Priority;
|
|
pDstInfo->StartTime = pSrcInfo->StartTime;
|
|
pDstInfo->UntilTime = pSrcInfo->UntilTime;
|
|
pDstInfo->Status = pSrcInfo->Status;
|
|
pDstInfo->cJobs = pSrcInfo->cJobs;
|
|
pDstInfo->AveragePPM = pSrcInfo->AveragePPM;
|
|
|
|
|
|
// Copy the required data to the Win 32 PRINTER_INFO_2 structure.
|
|
//
|
|
// SPECWORK - several of these fields are filled with "" placeholders.
|
|
// We probably need to put real information in some of them.
|
|
// The current inetpp protocol does not supply this information to us.
|
|
//
|
|
_ppinfo_set_str(&pDstInfo->pServerName , pszServerName , &pszString);
|
|
_ppinfo_set_str(&pDstInfo->pPrinterName , pSrcInfo->pPrinterName , &pszString);
|
|
_ppinfo_set_str(&pDstInfo->pShareName , pSrcInfo->pShareName , &pszString);
|
|
_ppinfo_set_str(&pDstInfo->pPortName , pSrcInfo->pPortName , &pszString);
|
|
_ppinfo_set_str(&pDstInfo->pDriverName , pSrcInfo->pDriverName , &pszString);
|
|
_ppinfo_set_str(&pDstInfo->pComment , pSrcInfo->pComment , &pszString);
|
|
_ppinfo_set_str(&pDstInfo->pLocation , pSrcInfo->pLocation , &pszString);
|
|
_ppinfo_set_str(&pDstInfo->pSepFile , pSrcInfo->pSepFile , &pszString);
|
|
_ppinfo_set_str(&pDstInfo->pPrintProcessor, pSrcInfo->pPrintProcessor, &pszString);
|
|
_ppinfo_set_str(&pDstInfo->pDatatype , pSrcInfo->pDatatype , &pszString);
|
|
_ppinfo_set_str(&pDstInfo->pParameters , pSrcInfo->pParameters , &pszString);
|
|
|
|
// If a devmode exist, then it will need to be copied as well.
|
|
//
|
|
if (pSrcInfo->pDevMode != NULL) {
|
|
|
|
memCopy((LPSTR *)&pDstInfo->pDevMode,
|
|
(LPSTR)pSrcInfo->pDevMode,
|
|
pSrcInfo->pDevMode->dmSize + pSrcInfo->pDevMode->dmDriverExtra,
|
|
(LPSTR *)&pszString);
|
|
|
|
} else {
|
|
|
|
pDstInfo->pDevMode = NULL;
|
|
}
|
|
|
|
return pszString;
|
|
}
|
|
|
|
|
|
#if WINNT32
|
|
/*****************************************************************************\
|
|
* _ppinfo_build_level4 (Local Routine)
|
|
*
|
|
* Given a server name, a pointer to a source PRINTER_INFO_2
|
|
* structure, a destination PRINTER_INFO_5 structure and a pointer to
|
|
* the start of string storage space, fills the PRINTER_INFO_4 structure.
|
|
*
|
|
* Called by GetPrinter and EnumPrinters, level 2. Returns an
|
|
* LPTSTR pointer to the last available data char in the data buffer.
|
|
*
|
|
\*****************************************************************************/
|
|
LPTSTR _ppinfo_build_level4(
|
|
PPRINTER_INFO_2 pSrcInfo,
|
|
PPRINTER_INFO_4 pDstInfo,
|
|
LPTSTR pszString)
|
|
{
|
|
// Set non-string entries.
|
|
//
|
|
pDstInfo->Attributes = pSrcInfo->Attributes;
|
|
|
|
|
|
// Copy the required data to the Win 32 PRINTER_INFO_4 structure.
|
|
//
|
|
_ppinfo_set_str(&pDstInfo->pPrinterName, pSrcInfo->pPrinterName, &pszString);
|
|
_ppinfo_set_str(&pDstInfo->pServerName , pSrcInfo->pServerName , &pszString);
|
|
|
|
return pszString;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*****************************************************************************\
|
|
* _ppinfo_build_level5 (Local Routine)
|
|
*
|
|
* Given a server name, a pointer to a source PRINTER_INFO_2
|
|
* structure, a destination PRINTER_INFO_5 structure and a pointer to
|
|
* the start of string storage space, fills the PRINTER_INFO_5 structure.
|
|
*
|
|
* Called by GetPrinter and EnumPrinters, level 2. Returns an
|
|
* LPTSTR pointer to the last available data char in the data buffer.
|
|
*
|
|
\*****************************************************************************/
|
|
LPTSTR _ppinfo_build_level5(
|
|
PPRINTER_INFO_2 pSrcInfo,
|
|
PPRINTER_INFO_5 pDstInfo,
|
|
LPTSTR pszString)
|
|
{
|
|
// Set non-string entries.
|
|
//
|
|
pDstInfo->Attributes = pSrcInfo->Attributes;
|
|
pDstInfo->DeviceNotSelectedTimeout = 0;
|
|
pDstInfo->TransmissionRetryTimeout = 0;
|
|
|
|
|
|
// Copy the required data to the Win 32 PRINTER_INFO_5 structure.
|
|
//
|
|
_ppinfo_set_str(&pDstInfo->pPrinterName, pSrcInfo->pPrinterName, &pszString);
|
|
_ppinfo_set_str(&pDstInfo->pPortName , pSrcInfo->pPortName , &pszString);
|
|
|
|
return pszString;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* _ppinfo_get_level1 (Local Routine)
|
|
*
|
|
* Given pInfo, a block of information on a printer returned by a
|
|
* DosPrintQGetInfo call, fill a PRINTER_INFO_1 structure. Returns
|
|
* TRUE if successful, FALSE otherwise. Places the number of bytes
|
|
* of (lpbBuffer) used in the DWORD pointed to by (pcbNeeded).
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL _ppinfo_get_level1(
|
|
PPRINTER_INFO_2 pSrcInfo,
|
|
LPBYTE lpbBuffer,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded)
|
|
{
|
|
// Figure out how many bytes of buffer space we're going to need.
|
|
// Set error code and return failure if we don't have enough.
|
|
//
|
|
*pcbNeeded = _ppinfo_calc_level1(pSrcInfo);
|
|
|
|
if (*pcbNeeded > cbBuf) {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Copy the required data from the structure to the Win32
|
|
// structure.
|
|
//
|
|
_ppinfo_build_level1(pSrcInfo,
|
|
(PPRINTER_INFO_1)lpbBuffer,
|
|
ENDOFBUFFER(lpbBuffer, cbBuf));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* _ppinfo_get_level2 (Local Routine)
|
|
*
|
|
* Given pInfo, a block of information on a printer returned by a
|
|
* PrintQGetInfo call, fill a PRINTER_INFO_2 structure. Returns
|
|
* TRUE if successful, FALSE otherwise. Places the number of bytes of
|
|
* (lpbBuffer) used in the DWORD pointed to by (pcbNeeded).
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL _ppinfo_get_level2(
|
|
PPRINTER_INFO_2 pSrcInfo,
|
|
LPBYTE lpbBuffer,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded)
|
|
{
|
|
// Figure out how many bytes of buffer space we're going to need.
|
|
// Set error code and return failure if we don't have enough.
|
|
//
|
|
*pcbNeeded = _ppinfo_calc_level2(g_szEmptyString, pSrcInfo);
|
|
|
|
if (*pcbNeeded > cbBuf) {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Copy the required data to the Win 32 PRINTER_INFO_2 structure.
|
|
//
|
|
_ppinfo_build_level2(g_szEmptyString,
|
|
pSrcInfo,
|
|
(PPRINTER_INFO_2)lpbBuffer,
|
|
ENDOFBUFFER(lpbBuffer, cbBuf));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#if WINNT32
|
|
/*****************************************************************************\
|
|
* _ppinfo_get_level4 (Local Routine)
|
|
*
|
|
* Given pInfo, a block of information on a printer returned by a
|
|
* PrintQGetInfo call, fill a PRINTER_INFO_4 structure. Returns
|
|
* TRUE if successful, FALSE otherwise. Places the number of bytes of
|
|
* (lpbBuffer) used in the DWORD pointed to by (pcbNeeded).
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL _ppinfo_get_level4(
|
|
PPRINTER_INFO_2 pSrcInfo,
|
|
LPBYTE lpbBuffer,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded)
|
|
{
|
|
// Figure out how many bytes of buffer space we're going to need.
|
|
// Set error code and return failure if we don't have enough.
|
|
//
|
|
*pcbNeeded = _ppinfo_calc_level4(pSrcInfo);
|
|
|
|
if (*pcbNeeded > cbBuf) {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Copy the required data to the Win 32 PRINTER_INFO_2 structure.
|
|
//
|
|
_ppinfo_build_level4(pSrcInfo,
|
|
(PPRINTER_INFO_4)lpbBuffer,
|
|
ENDOFBUFFER(lpbBuffer, cbBuf));
|
|
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*****************************************************************************\
|
|
* _ppinfo_get_level5 (Local Routine)
|
|
*
|
|
* Given pInfo, a block of information on a printer returned by a
|
|
* PrintQGetInfo call, fill a PRINTER_INFO_5 structure. Returns
|
|
* TRUE if successful, FALSE otherwise. Places the number of bytes of
|
|
* (lpbBuffer) used in the DWORD pointed to by (pcbNeeded).
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL _ppinfo_get_level5(
|
|
PPRINTER_INFO_2 pSrcInfo,
|
|
LPBYTE lpbBuffer,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded)
|
|
{
|
|
// Figure out how many bytes of buffer space we're going to need.
|
|
// Set error code and return failure if we don't have enough.
|
|
//
|
|
*pcbNeeded = _ppinfo_calc_level5(pSrcInfo);
|
|
|
|
if (*pcbNeeded > cbBuf) {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Copy the required data to the Win 32 PRINTER_INFO_2 structure.
|
|
//
|
|
_ppinfo_build_level5(pSrcInfo,
|
|
(PPRINTER_INFO_5)lpbBuffer,
|
|
ENDOFBUFFER(lpbBuffer, cbBuf));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#if WINNT32
|
|
/*****************************************************************************\
|
|
* _ppinfo_enumprinters_NT (Local Routine)
|
|
*
|
|
* This is the WinNT specific routine for EnumPrinters.
|
|
*
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL _ppinfo_enumprinters(
|
|
DWORD dwType,
|
|
LPTSTR pszName,
|
|
DWORD dwLevel,
|
|
LPBYTE pPrinterEnum,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded,
|
|
LPDWORD pcbReturned)
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
|
|
|
|
// Throw back enumeration requests that we don't handle. The routing
|
|
// layer above us is specifically looking for the ERROR_INVALID_NAME.
|
|
//
|
|
if (dwType & PRINTER_ENUM_NOTFORUS)
|
|
goto enum_name_failure;
|
|
|
|
|
|
// If the request is one that we handle, but the caller didn't supply
|
|
// a printer name, we'll fail. Again, to keep things going as the
|
|
// router expects, we must return an ERROR_INVALID_NAME condition.
|
|
//
|
|
if (utlStrSize(pszName) == 0) {
|
|
|
|
if ((dwLevel == PRINT_LEVEL_1) && (dwType & PRINTER_ENUM_NAME)) {
|
|
|
|
return _ppinfo_describe_provider((LPPRINTER_INFO_1)pPrinterEnum,
|
|
cbBuf,
|
|
pcbNeeded,
|
|
pcbReturned);
|
|
|
|
} else {
|
|
|
|
goto enum_name_failure;
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((dwLevel == PRINT_LEVEL_1) && (dwType & PRINTER_ENUM_NAME)) {
|
|
|
|
// In this case, the user has asked us to enumerate the
|
|
// printers in some domain. Until we decide what we really want
|
|
// to do. We'll simply return success with an empty enumeration.
|
|
//
|
|
|
|
goto enum_empty_success;
|
|
}
|
|
}
|
|
|
|
|
|
// Check Remote enumeration. Remote enumeration valid only if
|
|
// it's a level-1 printer.
|
|
//
|
|
if (dwType & PRINTER_ENUM_REMOTE) {
|
|
|
|
if (dwLevel != PRINT_LEVEL_1) {
|
|
|
|
goto enum_level_failure;
|
|
|
|
} else {
|
|
|
|
// In this case, the user has asked us to enumerate the
|
|
// printers in our domain. Until we decide what we really
|
|
// want to do, we'll simply return success with an empty
|
|
// enumeration.
|
|
//
|
|
goto enum_empty_success;
|
|
}
|
|
|
|
} else if (dwType & PRINTER_ENUM_CONNECTIONS) {
|
|
|
|
// In this case, the user has asked us to enumerate our favorite
|
|
// connections.
|
|
//
|
|
|
|
enum_empty_success:
|
|
|
|
*pcbNeeded = 0;
|
|
*pcbReturned = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
DBG_MSG(DBG_LEV_INFO, (TEXT("Info: PPEnumPrinters: Type(%ld) Name(%s) Level(%ld)"), dwType, pszName, dwLevel));
|
|
|
|
|
|
// Check print-levels. These are error cases. We should
|
|
// really have performed the enumeration above.
|
|
//
|
|
switch (dwLevel) {
|
|
|
|
case PRINT_LEVEL_1:
|
|
case PRINT_LEVEL_2:
|
|
|
|
enum_name_failure:
|
|
|
|
DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: PPEnumPrinters: Invalid Name")));
|
|
SetLastError(ERROR_INVALID_NAME);
|
|
break;
|
|
|
|
default:
|
|
|
|
enum_level_failure:
|
|
|
|
DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: PPEnumPrinters: Invalid Level: %d"), dwLevel));
|
|
SetLastError(ERROR_INVALID_LEVEL);
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#else
|
|
|
|
/*****************************************************************************\
|
|
* _ppinfo_enumprinters_95 (Local Routine)
|
|
*
|
|
* This is the Win95 specific routine for EnumPrinters.
|
|
*
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL _ppinfo_enumprinters(
|
|
DWORD dwType,
|
|
LPTSTR pszName,
|
|
DWORD dwLevel,
|
|
LPBYTE pPrinterEnum,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded,
|
|
LPDWORD pcbReturned)
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
|
|
// Throw back enumeration requests that we don't handle. The routing
|
|
// layer above us is specifically looking for the ERROR_INVALID_NAME.
|
|
//
|
|
if (dwType & PRINTER_ENUM_NOTFORUS)
|
|
goto enum_name_failure;
|
|
|
|
|
|
// If the request is one that we handle, but the caller didn't supply
|
|
// a printer name, we'll fail. Again, to keep things going as the
|
|
// router expects, we must return an ERROR_INVALID_NAME condition.
|
|
//
|
|
if (utlStrSize(pszName) == 0) {
|
|
|
|
if ((dwLevel == PRINT_LEVEL_1) && (dwType & PRINTER_ENUM_NAME)) {
|
|
|
|
return _ppinfo_describe_provider((LPPRINTER_INFO_1)pPrinterEnum,
|
|
cbBuf,
|
|
pcbNeeded,
|
|
pcbReturned);
|
|
|
|
} else if (dwType & PRINTER_ENUM_REMOTE) {
|
|
|
|
// In this case, the user has asked us to enumerate the printers
|
|
// in our domain. Until we decide what we really want to do, we'll
|
|
// simply return success with an empty enumeration.
|
|
//
|
|
*pcbNeeded = 0;
|
|
*pcbReturned = 0;
|
|
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
goto enum_name_failure;
|
|
}
|
|
}
|
|
|
|
DBG_MSG(DBG_LEV_INFO, (TEXT("Info: PPEnumPrinters: Type(%ld) Name(%s) Level(%ld)"), dwType, pszName, dwLevel));
|
|
|
|
|
|
// One last special case to test for -- did they ask us to
|
|
// enumerate ourselves (the provider) by name?
|
|
//
|
|
if ((dwLevel == PRINT_LEVEL_1) && (dwType & PRINTER_ENUM_NAME)) {
|
|
|
|
if (lstrcmp(pszName, g_szProviderName) == 0) {
|
|
|
|
return _ppinfo_describe_provider((LPPRINTER_INFO_1)pPrinterEnum,
|
|
cbBuf,
|
|
pcbNeeded,
|
|
pcbReturned);
|
|
}
|
|
}
|
|
|
|
|
|
// Check print-levels. These are error cases. We should
|
|
// really have performed the enumeration above.
|
|
//
|
|
switch (dwLevel) {
|
|
|
|
case PRINT_LEVEL_1:
|
|
case PRINT_LEVEL_2:
|
|
|
|
enum_name_failure:
|
|
|
|
DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: PPEnumPrinters: Invalid Name")));
|
|
SetLastError(ERROR_INVALID_NAME);
|
|
break;
|
|
|
|
default:
|
|
|
|
DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: PPEnumPrinters: Invalid Level: %d"), dwLevel));
|
|
SetLastError(ERROR_INVALID_LEVEL);
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/*****************************************************************************\
|
|
* PPEnumPrinters
|
|
*
|
|
* Enumerates the available printers. Returns TRUE if successful. Otherwise,
|
|
* it returns FALSE.
|
|
*
|
|
* NOTE: Supports level 2 PRINTER_INFO to provide Point-and-Print
|
|
* functionality.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL PPEnumPrinters(
|
|
DWORD dwType,
|
|
LPTSTR pszName,
|
|
DWORD dwLevel,
|
|
LPBYTE pPrinterEnum,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded,
|
|
LPDWORD pcbReturned)
|
|
{
|
|
DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPEnumPrinters: Type(%d) Level(%d) Name(%s)"), dwType, dwLevel, (pszName ? pszName : TEXT("<NULL>"))));
|
|
|
|
return _ppinfo_enumprinters(dwType,
|
|
pszName,
|
|
dwLevel,
|
|
pPrinterEnum,
|
|
cbBuf,
|
|
pcbNeeded,
|
|
pcbReturned);
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* PPGetPrinter
|
|
*
|
|
* Retrieves information about a printer. Returns TRUE if successful, FALSE
|
|
* if an error occurred. NOTE: Supports level 2 Printer_INFO to provide
|
|
* Point and Print functionality for Chicago.
|
|
*
|
|
\*****************************************************************************/
|
|
BOOL PPGetPrinter(
|
|
HANDLE hPrinter,
|
|
DWORD dwLevel,
|
|
LPBYTE lpbPrinter,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded)
|
|
{
|
|
PCINETMONPORT pIniPort;
|
|
PPRINTER_INFO_2 pSrcInfo;
|
|
DWORD cbSrcSize;
|
|
DWORD dwTemp;
|
|
BOOL bResult = FALSE;
|
|
|
|
DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPGetPrinter: Printer(%08lX) Level(%ld)"), hPrinter, dwLevel));
|
|
|
|
if (pcbNeeded)
|
|
*pcbNeeded = 0;
|
|
|
|
semEnterCrit();
|
|
|
|
// Make sure we have a valid printer handle.
|
|
//
|
|
if (pIniPort = utlValidatePrinterHandle(hPrinter)) {
|
|
|
|
if (pIniPort->BeginReadGetPrinterCache (&pSrcInfo)) {
|
|
|
|
// Reformat the data according to the requested info Level.
|
|
//
|
|
switch (dwLevel) {
|
|
|
|
case PRINT_LEVEL_1:
|
|
bResult = _ppinfo_get_level1(pSrcInfo, lpbPrinter, cbBuf, pcbNeeded);
|
|
break;
|
|
|
|
case PRINT_LEVEL_2:
|
|
bResult = _ppinfo_get_level2(pSrcInfo, lpbPrinter, cbBuf, pcbNeeded);
|
|
break;
|
|
|
|
#if WINNT32
|
|
case PRINT_LEVEL_4:
|
|
bResult = _ppinfo_get_level4(pSrcInfo, lpbPrinter, cbBuf, pcbNeeded);
|
|
break;
|
|
#endif
|
|
|
|
case PRINT_LEVEL_5:
|
|
bResult = _ppinfo_get_level5(pSrcInfo, lpbPrinter, cbBuf, pcbNeeded);
|
|
break;
|
|
|
|
default:
|
|
DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: PPGetPrinter: Invalid Level")));
|
|
SetLastError(ERROR_INVALID_LEVEL);
|
|
bResult = FALSE;
|
|
break;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
pIniPort->EndReadGetPrinterCache ();
|
|
|
|
if (GetLastError() == ERROR_ACCESS_DENIED) {
|
|
pIniPort->InvalidateGetPrinterCache ();
|
|
}
|
|
}
|
|
|
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
|
|
pcbNeeded &&
|
|
*pcbNeeded == 0) {
|
|
// We can't set ERROR_INSUFFICIENT_BUFFER here since it was an internal error
|
|
// and we are not reporting a size
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
|
|
semLeaveCrit();
|
|
|
|
return bResult;
|
|
}
|