/*****************************************************************************\ * 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, * dest points to the place to write the string offset in the buffer. * src points to a null terminated string, can be NULL. * *buf should point to the last available byte in the buffer. * * Asumption: * This routine assumes that the memory between dest and *buf are availabe * for the string data. * \*****************************************************************************/ VOID _ppinfo_set_str( LPTSTR *dest, LPCTSTR src, LPTSTR *buf) { if (src != NULL) { size_t uSize = lstrlen(src); // // If the destination pointer is greater than or equal to buffer pointer adjusted // by the length of the string the string will overflow the buffer. If this // happens we place a null as the destination pointer. This routine // really should return a failure code, to inform the caller an error error // happened. // if ((DWORD_PTR)dest >= (DWORD_PTR)((*buf) - uSize)) { DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: String fill overrun in _ppinfo_set_str"))); *dest = TEXT('\0'); } else { // Place string at end of buffer. This performs pointer // arithmatic, so the offsets are TCHAR in size. // (*buf) -= uSize; // // Copy the string data. // StringCchCopy(*buf, uSize+1, 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. // pInfo->Flags |= PRINTER_ENUM_HIDE; // 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; pInfo->Attributes = PRINTER_ATTRIBUTE_NETWORK; 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; } /*****************************************************************************\ * _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; } /*****************************************************************************\ * _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; pDstInfo->Flags |= PRINTER_ENUM_HIDE; // 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; } /*****************************************************************************\ * _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; } /*****************************************************************************\ * _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; } /*****************************************************************************\ * _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; } /*****************************************************************************\ * _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; } /*****************************************************************************\ * _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; } /*****************************************************************************\ * 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("")))); 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; case PRINT_LEVEL_4: bResult = _ppinfo_get_level4(pSrcInfo, lpbPrinter, cbBuf, pcbNeeded); break; 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; }