DWORD GetPortSize( __in PLCMINIPORT pIniPort, DWORD Level ) { DWORD cb = 0; switch (Level) { case 1: cb = (DWORD) (sizeof(PORT_INFO_1) + wcslen(pIniPort->pName)*sizeof(WCHAR) + sizeof(WCHAR)); break; case 2: { LPWSTR pszLocalMonitor = NULL; LPWSTR pszPortDesc = NULL; pszLocalMonitor = (LPWSTR)AllocSplMem((MAX_PATH + 1) * sizeof(WCHAR)); pszPortDesc = (LPWSTR)AllocSplMem((MAX_PATH + 1) * sizeof(WCHAR)); if (pszLocalMonitor && pszPortDesc) { LoadString(LcmhInst, IDS_LOCALMONITORNAME, pszLocalMonitor, MAX_PATH); LoadString(LcmhInst, IDS_LOCALMONITOR, pszPortDesc, MAX_PATH); cb = (DWORD) (wcslen(pIniPort->pName) + 1 + wcslen(pszLocalMonitor) + 1 + wcslen(pszPortDesc) + 1); cb *= sizeof(WCHAR); cb += sizeof(PORT_INFO_2); } if (pszLocalMonitor) { FreeSplMem(pszLocalMonitor); pszLocalMonitor = NULL; } if (pszPortDesc) { FreeSplMem(pszPortDesc); pszPortDesc = NULL; } } break; default: cb = 0; break; } return cb; }
LPWSTR AllocSplStr( LPCWSTR pszSource ) { PWSTR pszRet = NULL; if (pszSource) { size_t len = 0; HRESULT hr = StringCchLength(pszSource, STRSAFE_MAX_CCH, &len); if (SUCCEEDED(hr)) { pszRet = (PWSTR)AllocSplMem((len + 1) * sizeof(WCHAR)); if (pszRet) { hr = StringCchCopy(pszRet, len + 1, pszSource); if (FAILED(hr)) { FreeSplMem(pszRet); pszRet = NULL; } } } } return pszRet; }
PINIPORT CreatePortEntry( LPWSTR pPortName ) { DWORD cb; PINIPORT pIniPort, pPort; cb = sizeof(INIPORT) + wcslen(pPortName)*sizeof(WCHAR) + sizeof(WCHAR); if (pIniPort = AllocSplMem(cb)) { pIniPort->pName = wcscpy((LPWSTR)(pIniPort+1), pPortName); pIniPort->cb = cb; pIniPort->pNext = 0; pIniPort->signature = IPO_SIGNATURE; if (pPort = pIniFirstPort) { while (pPort->pNext) pPort = pPort->pNext; pPort->pNext = pIniPort; } else pIniFirstPort = pIniPort; } return pIniPort; }
LPTSTR AllocSplStr( LPTSTR lpStr ) /*++ Routine Description: This function will allocate enough local memory to store the specified string, and copy that string to the allocated memory Arguments: lpStr - Pointer to the string that needs to be allocated and stored Return Value: NON-NULL - A pointer to the allocated memory containing the string FALSE/NULL - The operation failed. Extended error status is available using GetLastError. --*/ { LPTSTR lpMem; if (!lpStr) return 0; if (lpMem = AllocSplMem( (_tcslen(lpStr) + 1 )*sizeof(TCHAR))) _tcscpy(lpMem, lpStr); return lpMem; }
__user_driver PLCMINIPORT LcmCreatePortEntry( __inout PINILOCALMON pIniLocalMon, __in PWSTR pPortName ) { DWORD cb = 0; PLCMINIPORT pIniPort = NULL; PLCMINIPORT pPort = NULL; size_t cchPortName = wcslen (pPortName) + 1; if (!pPortName || wcslen(pPortName) > 247) { SetLastError(ERROR_INVALID_NAME); return NULL; } cb = (DWORD) (sizeof(LCMINIPORT) + cchPortName * sizeof (WCHAR)); pIniPort = (PLCMINIPORT)AllocSplMem(cb); if( pIniPort ) { ZeroMemory(pIniPort, cb); pIniPort->pName = (LPWSTR)(pIniPort+1); (VOID) StringCchCopy (pIniPort->pName, cchPortName, pPortName); pIniPort->cb = cb; pIniPort->cRef = 0; pIniPort->pNext = 0; pIniPort->pIniLocalMon = pIniLocalMon; pIniPort->signature = IPO_SIGNATURE; pIniPort->hFile = INVALID_HANDLE_VALUE; LcmEnterSplSem(); pPort = pIniLocalMon->pIniPort; if (pPort) { while (pPort->pNext) pPort = pPort->pNext; pPort->pNext = pIniPort; } else pIniLocalMon->pIniPort = pIniPort; LcmLeaveSplSem(); } return pIniPort; }
LPVOID ReallocSplMem( LPVOID lpOldMem, DWORD cbNew) { if (lpOldMem) return LocalReAlloc(lpOldMem, cbNew, LMEM_MOVEABLE); else return AllocSplMem(cbNew); }
/* PortExists * * Calls EnumPorts to check whether the port name already exists. * This asks every monitor, rather than just this one. * The function will return TRUE if the specified port is in the list. * If an error occurs, the return is FALSE and the variable pointed * to by pError contains the return from GetLastError(). * The caller must therefore always check that *pError == NO_ERROR. */ BOOL PortExists( _In_opt_ LPWSTR pName, _In_ LPWSTR pPortName, _Out_ PDWORD pError ) { DWORD cbNeeded = 0; DWORD cReturned = 0; DWORD cbPorts = 0; LPPORT_INFO_1 pPorts = NULL; DWORD i = 0; BOOL Found = TRUE; *pError = NO_ERROR; if (!EnumPortsW(pName, 1, NULL, 0, &cbNeeded, &cReturned)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { cbPorts = cbNeeded; pPorts = (LPPORT_INFO_1)AllocSplMem(cbPorts); if (pPorts) { if (EnumPortsW(pName, 1, (LPBYTE)pPorts, cbPorts, &cbNeeded, &cReturned)) { Found = FALSE; for (i = 0; i < cReturned; i++) { if (!lstrcmpi(pPorts[i].pName, pPortName)) { Found = TRUE; break; } } } } FreeSplMem(pPorts); } } else { Found = FALSE; } return Found; }
/*++ Title: vsntprintf Routine Description: Formats a string and returns a heap allocated string with the formated data. This routine can be used to for extremely long format strings. Note: If a valid pointer is returned the callng functions must release the data with a call to delete. Arguments: psFmt - format string pArgs - pointer to a argument list. Return Value: Pointer to formated string. NULL if error. --*/ LPSTR vsntprintf( IN LPCSTR szFmt, IN va_list pArgs ) { LPSTR pszBuff; UINT uSize = 256; for( ; ; ) { pszBuff = (LPSTR)AllocSplMem(sizeof(char) * uSize); if (!pszBuff) { break; } // // Attempt to format the string. If format succeeds, get out // of the loop. If it fails, increase buffer size and continue. // (assuming failure is due to less buffer size). // if (SUCCEEDED ( StringCchVPrintfA(pszBuff, uSize, szFmt, pArgs) ) ) { break; } FreeSplMem(pszBuff); pszBuff = NULL; // // Double the buffer size after each failure. // uSize *= 2; // // If the size is greater than 100k exit without formatting a string. // if (uSize > 100*1024) { break; } } return pszBuff; }
/* GetUnicodeString * * Easy way to get a pointer to a resource string. * (Remember to free it.) */ LPWSTR GetUnicodeString(int id) { WCHAR ResString[RESOURCE_STRING_LENGTH]; DWORD length = 0; LPWSTR pUnicode; DWORD cbUnicode; length = LoadStringW(hInst, id, ResString, sizeof(ResString)/sizeof(TCHAR)); cbUnicode = ( length * sizeof ( WCHAR ) + sizeof ( WCHAR ) ); pUnicode = AllocSplMem( cbUnicode ); if( pUnicode ) memcpy( pUnicode, ResString, cbUnicode ); return pUnicode; }
PINIXCVPORT CreateXcvPortEntry( __inout PINILOCALMON pIniLocalMon, LPCWSTR pszName, ACCESS_MASK GrantedAccess ) { DWORD cb = 0; PINIXCVPORT pIniXcvPort = NULL; PINIXCVPORT pPort = NULL; size_t cchName = wcslen (pszName) + 1; cb = (DWORD) (sizeof(INIXCVPORT) + cchName*sizeof(WCHAR)); pIniXcvPort = (PINIXCVPORT)AllocSplMem(cb); if( pIniXcvPort ) { pIniXcvPort->pszName = (LPWSTR)(pIniXcvPort+1); (VOID) StringCchCopy (pIniXcvPort->pszName, cchName, pszName); pIniXcvPort->dwMethod = 0; pIniXcvPort->cb = cb; pIniXcvPort->pNext = 0; pIniXcvPort->signature = XCV_SIGNATURE; pIniXcvPort->GrantedAccess = GrantedAccess; pIniXcvPort->pIniLocalMon = pIniLocalMon; pPort = pIniLocalMon->pIniXcvPort; if (pPort) { while (pPort->pNext) pPort = pPort->pNext; pPort->pNext = pIniXcvPort; } else pIniLocalMon->pIniXcvPort = pIniXcvPort; } return pIniXcvPort; }
LPVOID ReallocSplMem( LPVOID pOldMem, DWORD cbOld, DWORD cbNew ) { LPVOID pNewMem; pNewMem=AllocSplMem(cbNew); if (pOldMem && pNewMem) { if (cbOld) { CopyMemory( pNewMem, pOldMem, min(cbNew, cbOld)); } FreeSplMem(pOldMem); } return pNewMem; }
LPWSTR AllocSplStr( __in LPWSTR pStr ) /*++ Routine Description: This function will allocate enough local memory to store the specified string, and copy that string to the allocated memory Arguments: pStr - Pointer to the string that needs to be allocated and stored Return Value: NON-NULL - A pointer to the allocated memory containing the string FALSE/NULL - The operation failed. Extended error status is available using GetLastError. --*/ { LPWSTR pMem; DWORD cbStr; if (!pStr) { return NULL; } cbStr = wcslen(pStr)*sizeof(WCHAR) + sizeof(WCHAR); pMem = AllocSplMem( cbStr ); if (pMem) { CopyMemory( pMem, pStr, cbStr ); } return pMem; }
PINIPORT CreatePortEntry( LPWSTR pPortName ) { DWORD cb; PINIPORT pIniPort, pPort; cb = sizeof(INIPORT) + wcslen(pPortName)*sizeof(WCHAR) + sizeof(WCHAR); pIniPort=AllocSplMem(cb); if( pIniPort ) { pIniPort->pName = wcscpy((LPWSTR)(pIniPort+1), pPortName); pIniPort->cb = cb; pIniPort->pNext = 0; pIniPort->signature = IPO_SIGNATURE; // // KrishnaG -- initialized the hFile value; it will be set to // a legal value in the StartDocPort call // pIniPort->hFile = INVALID_HANDLE_VALUE; if (pPort = pIniFirstPort) { while (pPort->pNext) pPort = pPort->pNext; pPort->pNext = pIniPort; } else pIniFirstPort = pIniPort; } return pIniPort; }
BOOL AbortThisJob( _In_ PLCMINIPORT pIniPort ) /*++ Tells if the job should be aborted. A job should be aborted if it has been deleted or it needs to be restarted. --*/ { BOOL bRet = FALSE; DWORD dwNeeded = 0; LPJOB_INFO_1 pJobInfo = NULL; dwNeeded = 0; GetJob(pIniPort->hPrinter, pIniPort->JobId, 1, NULL, 0, &dwNeeded); if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) goto Done; pJobInfo = (LPJOB_INFO_1) AllocSplMem(dwNeeded); if ( !pJobInfo || !GetJob(pIniPort->hPrinter, pIniPort->JobId, 1, (LPBYTE)pJobInfo, dwNeeded, &dwNeeded)) goto Done; bRet = (pJobInfo->Status & JOB_STATUS_DELETING) || (pJobInfo->Status & JOB_STATUS_DELETED) || (pJobInfo->Status & JOB_STATUS_RESTART); Done: if ( pJobInfo ) FreeSplMem(pJobInfo); return bRet; }
DWORD GetDriverMajorVersion( LPWSTR pFileName ) { DWORD dwSize = 0; LPVOID pFileVersion; UINT uLen = 0; LPVOID pMem; DWORD dwFileOS; DWORD dwFileVersionMS; DWORD dwFileVersionLS; DWORD dwProductVersionMS; DWORD dwProductVersionLS; if (!(dwSize = GetFileVersionInfoSize(pFileName, 0))) { DBGMSG(DBG_TRACE, ("Error: GetFileVersionInfoSize failed with %d\n", GetLastError())); DBGMSG(DBG_TRACE, ("Returning back a version # 0\n")); return(0); } if (!(pMem = AllocSplMem(dwSize))) { DBGMSG(DBG_TRACE, ("AllocMem failed \n")); DBGMSG(DBG_TRACE, ("Returning back a version # 0\n")); return(0); } if (!GetFileVersionInfo(pFileName, 0, dwSize, pMem)) { FreeSplMem(pMem); DBGMSG(DBG_TRACE, ("GetFileVersionInfo failed\n")); DBGMSG(DBG_TRACE, ("Returning back a version # 0\n")); return(0); } if (!VerQueryValue(pMem, L"\\", &pFileVersion, &uLen)) { FreeSplMem(pMem); DBGMSG(DBG_TRACE, ("VerQueryValue failed \n")); DBGMSG(DBG_TRACE, ("Returning back a version # 0\n")); return(0); } // // We could determine the Version Information // DBGMSG(DBG_TRACE, ("dwFileVersionMS = %d\n", ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileVersionMS)); DBGMSG(DBG_TRACE, ("dwFileVersionLS = %d\n", ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileVersionLS)); DBGMSG(DBG_TRACE, ("dwProductVersionMS = %d\n", ((VS_FIXEDFILEINFO *)pFileVersion)->dwProductVersionMS)); DBGMSG(DBG_TRACE, ("dwProductVersionLS = %d\n", ((VS_FIXEDFILEINFO *)pFileVersion)->dwProductVersionLS)); dwFileOS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileOS; dwFileVersionMS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileVersionMS; dwFileVersionLS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileVersionLS; dwProductVersionMS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwProductVersionMS; dwProductVersionLS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwProductVersionLS; FreeSplMem(pMem); if (dwFileOS != VOS_NT_WINDOWS32) { DBGMSG(DBG_TRACE,("Returning back a version # 0\n")); return(0); } if (dwProductVersionMS == dwFileVersionMS) { // // This means this hold for all dlls Pre-Daytona // after Daytona, printer driver writers must support // version control or we'll dump them as Version 0 // drivers DBGMSG(DBG_TRACE,("Returning back a version # 0\n")); return(0); } // // Bug-Bug: suppose a third-party vendor uses a different system // methinks we should use the lower dword to have specific value // which implies he/she supports spooler version -- check with MattFe DBGMSG(DBG_TRACE,("Returning back a version # %d\n", dwFileVersionMS)); return(dwFileVersionMS); }
BOOL WINAPI PJLMonStartDocPort( IN HANDLE hPort, IN LPTSTR pszPrinterName, IN DWORD dwJobId, IN DWORD dwLevel, IN LPBYTE pDocInfo ) /*++ Routine Description: Language monitor StartDocPort Arguments: hPort : Port handle pszPrinterName : Printer name dwJobId : Job identifier dwLevel : Level of Doc info strucuture pDocInfo : Pointer to doc info structure Return Value: TRUE on success, FALSE on error --*/ { PINIPORT pIniPort = (PINIPORT)((INIPORT *)hPort); PINIJOB pIniJob = NULL; DWORD cbJob; BOOL bRet = FALSE; // // Validate parameters // if ( !pIniPort || pIniPort->signature != PJ_SIGNATURE || !pDocInfo || !pszPrinterName || !*pszPrinterName ) { SPLASSERT(pIniPort && pIniPort->signature == PJ_SIGNATURE && pDocInfo); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if ( dwLevel != 1 ) { SPLASSERT(dwLevel == 1); SetLastError(ERROR_INVALID_LEVEL); return FALSE; } // // Serialize access to the port // if ( pIniPort->status & PP_INSTARTDOC ) { SetLastError(ERROR_BUSY); return FALSE; } WaitForSingleObject(pIniPort->DoneWriting, INFINITE); cbJob = sizeof(*pIniJob) + lstrlen(pszPrinterName) * sizeof(TCHAR) + sizeof(TCHAR); pIniJob = (PINIJOB) AllocSplMem(cbJob); if ( !pIniJob ) { goto Cleanup; } pIniJob->pszPrinterName = wcscpy((LPTSTR)(pIniJob+1), pszPrinterName); if ( !OpenPrinter(pIniJob->pszPrinterName, &pIniJob->hPrinter, NULL) ) { DBGMSG(DBG_WARNING, ("pjlmon: OpenPrinter failed for %s, last error %d\n", pIniJob->pszPrinterName, GetLastError())); goto Cleanup; } pIniPort->status |= PP_INSTARTDOC; bRet = (*pIniPort->fn.pfnStartDocPort)(pIniPort->hPort, pszPrinterName, dwJobId, dwLevel, pDocInfo); if ( !bRet ) { pIniPort->status &= ~PP_INSTARTDOC; goto Cleanup; } // // If Ustatus thread is not running then check if printer understands // PJL, unless we determined that printer does not understand PJL earlier // if ( !(pIniPort->status & PP_RUN_THREAD) && !(pIniPort->status & PP_DONT_TRY_PJL) ) { if ( IsPJL(pIniPort) ) pIniPort->status |= PP_IS_PJL; else pIniPort->status &= ~PP_IS_PJL; } // // set PP_SEND_PJL flag here so the first write of the job // will try to send PJL command to initiate the job control // pIniJob->JobId = dwJobId; pIniJob->status |= PP_INSTARTDOC; if ( pIniPort->status & PP_IS_PJL ) pIniJob->status |= PP_SEND_PJL; EnterSplSem(); if ( !pIniPort->pIniJob ) { pIniPort->pIniJob = pIniJob; } else { pIniJob->pNext = pIniPort->pIniJob; pIniPort->pIniJob = pIniJob; } LeaveSplSem(); if ( (pIniPort->status & PP_IS_PJL) && !(pIniPort->status & PP_RUN_THREAD) ) { // // only create the read thread if printer is PJL capable // CreateUstatusThread(pIniPort); } Cleanup: if ( !bRet ) { SetEvent(pIniPort->DoneWriting); if ( pIniJob ) FreeIniJob(pIniJob); } return bRet; }
BOOL PrintRawJob( IN PPRINTPROCESSORDATA pData, _In_ IN LPWSTR pPrinterName) { DOC_INFO_1 DocInfo; DWORD Copies; DWORD NoRead, NoWritten; BOOL rc; HANDLE hPrinter; BYTE *ReadBuffer = NULL; BOOL bRet = FALSE; BOOL bStartDoc = FALSE; DocInfo.pDocName = pData->pDocument; /* Document name */ DocInfo.pOutputFile = pData->pOutputFile; /* Output file */ DocInfo.pDatatype = pData->pDatatype; /* Document data type */ /** Let the printer know we are starting a new document **/ if (!StartDocPrinter(pData->hPrinter, 1, (LPBYTE)&DocInfo)) { goto Done; } bStartDoc = TRUE; /** Allocate the read buffer, dynamically allocated to conserve stack space **/ ReadBuffer = (BYTE *)AllocSplMem(READ_BUFFER_SIZE); if (!ReadBuffer) { goto Done; } /** Print the data pData->Copies times **/ Copies = pData->Copies; while (Copies--) { /** Open the printer. If it fails, return. This also sets up the pointer for the ReadPrinter calls. **/ if (!OpenPrinter(pPrinterName, &hPrinter, NULL)) { goto Done; } /** Loop, getting data and sending it to the printer. This also takes care of pausing and cancelling print jobs by checking the processor's status flags while printing. **/ while ( ((rc = ReadPrinter(hPrinter, ReadBuffer, READ_BUFFER_SIZE, &NoRead)) != 0) && NoRead ) { /** If the print processor is paused, wait for it to be resumed **/ if (pData->fsStatus & PRINTPROCESSOR_PAUSED) { WaitForSingleObject(pData->semPaused, INFINITE); } /** If the job has been aborted, don't write anymore **/ if (pData->fsStatus & PRINTPROCESSOR_ABORTED) { break; } /** Write the data to the printer **/ WritePrinter(pData->hPrinter, ReadBuffer, NoRead, &NoWritten); } /** Close the printer - we open/close the printer for each copy so the data pointer will rewind. **/ ClosePrinter(hPrinter); } /* While copies to print */ bRet = TRUE; Done: /** Close the buffer we allocated **/ if (ReadBuffer) { FreeSplMem(ReadBuffer); } /** Let the printer know that we are done printing **/ if (bStartDoc) { EndDocPrinter(pData->hPrinter); } return bRet; }
BOOL SpoolerGetSpoolMessage() { DWORD dwResult; PSPOOLESC pInput; // Input buffer that receives messages from Kernel BYTE *pOutput; // Output buffer that receives data from KMxxx() spooler calls BYTE *pMem; DWORD cbOut = 0; // Size of pOutput DWORD cbIn = IN_BUF_SIZE; // Size of pInput buffer in bytes DWORD cbOutSize; if(!(pInput = (PSPOOLESC) AllocSplMem(cbIn))) { DBGMSG(DBG_WARNING, ("Error allocating pInput in SpoolerGetSpoolMessage\n")); return FALSE; } if(!(pOutput = AllocSplMem(OUT_BUF_SIZE))) { DBGMSG(DBG_WARNING, ("Error allocating pInput in SpoolerGetSpoolMessage\n")); return FALSE; } cbOutSize = OUT_BUF_SIZE; EnterCriticalSection(&ThreadCriticalSection); ++nThreads; LeaveCriticalSection(&ThreadCriticalSection); while(1) { EnterCriticalSection(&ThreadCriticalSection); ++nIdleThreads; LeaveCriticalSection(&ThreadCriticalSection); dwResult = GdiGetSpoolMessage(pInput,cbIn,(PDWORD)pOutput,cbOut); EnterCriticalSection(&ThreadCriticalSection); --nIdleThreads; LeaveCriticalSection(&ThreadCriticalSection); if(dwResult) { if( (pInput->iMsg != GDISPOOL_TERMINATETHREAD) && (pInput->iMsg != GDISPOOL_INPUT2SMALL)) { EnterCriticalSection(&ThreadCriticalSection); if(nIdleThreads == 0) { AddThread(); DBGMSG(DBG_TRACE, ("Thread Added: nIdle = %d nThreads = %d\n", nIdleThreads, nThreads)); } LeaveCriticalSection(&ThreadCriticalSection); } // check if the out buffer needs to be grown or shrunk. if ((pInput->cjOut + MAX_GRE_STRUCT_SIZE) > cbOutSize) { FreeSplMem(pOutput); pOutput = AllocSplMem(cbOutSize = pInput->cjOut + MAX_GRE_STRUCT_SIZE); if (!pOutput) { DBGMSG(DBG_WARNING, ("Error allocating pInput in SpoolerGetSpoolMessage\n")); pInput->ulRet = 0; cbOut = 0; cbOutSize = 0; continue; } } else if ((pInput->cjOut < OUT_BUF_SIZE) && (cbOutSize > OUT_BUF_SIZE)) { // we want to shrink the buffer PBYTE pbTmp = AllocSplMem(OUT_BUF_SIZE); if (pbTmp) { FreeSplMem(pOutput); pOutput = pbTmp; cbOutSize = OUT_BUF_SIZE; } } if (pInput->iMsg & GDISPOOL_API) { SPLASSERT(pInput->hSpool || pInput->iMsg == GDISPOOL_OPENPRINTER); if (pInput->iMsg != GDISPOOL_OPENPRINTER || pInput->hSpool) { if (InterlockedIncrement(&((PSPOOL)pInput->hSpool)->cThreads) > 0) { // We are already processing a message & have now gotten a ClosePrinter // We should not get here on any other API SPLASSERT(pInput->iMsg == GDISPOOL_CLOSEPRINTER); pInput->ulRet = TRUE; // Let Client terminate continue; } } } switch (pInput->iMsg) { case GDISPOOL_INPUT2SMALL: DBGMSG(DBG_TRACE,(" - buffer not big enough\n")); pMem = ReallocSplMem(pInput, cbIn, pInput->cjOut); if (!pMem) { DBGMSG(DBG_WARNING, ("Error reallocating pInput in SpoolerGetSpoolMessage\n")); pInput->ulRet = 0; } else { pInput = (PSPOOLESC) pMem; cbIn = pInput->cjOut; pInput->ulRet = 1; } break; case GDISPOOL_TERMINATETHREAD: EnterCriticalSection(&ThreadCriticalSection); // There is 1 way to get here: from a 10 minute Kernel Event timeout if(nIdleThreads > 1) { --nThreads; if (nThreads == 0) { DBGMSG(DBG_WARNING, ("SpoolerGetSpoolMessage nThreads is now ZERO\n")); } DBGMSG(DBG_TRACE, ("Thread Deleted: nIdle = %d nThreads = %d\n", nIdleThreads, nThreads)); LeaveCriticalSection(&ThreadCriticalSection); FreeSplMem(pInput); FreeSplMem(pOutput); return TRUE; } LeaveCriticalSection(&ThreadCriticalSection); break; case GDISPOOL_WRITE: DBGMSG(DBG_TRACE,(" - GDISPOOL_WRITE\n")); pInput->ulRet = DoWritePrinter( pInput, (DWORD*) pOutput ); cbOut = sizeof(DWORD); break; case GDISPOOL_OPENPRINTER: DBGMSG(DBG_TRACE,(" - GDISPOOL_OPENPRINTER\n")); DoOpenPrinter(pInput,(HANDLE*)pOutput,&cbOut); break; case GDISPOOL_STARTDOCPRINTER: DBGMSG(DBG_TRACE,(" - GDISPOOL_STARTDOCPRINTER\n")); DoStartDocPrinter(pInput); break; case GDISPOOL_STARTPAGEPRINTER: DBGMSG(DBG_TRACE,(" - GDISPOOL_STARTPAGEPRINTER\n")); pInput->ulRet = KMStartPagePrinter( pInput->hSpool ); break; case GDISPOOL_ENDPAGEPRINTER: DBGMSG(DBG_TRACE,(" - GDISPOOL_ENDPAGEPRINTER\n")); pInput->ulRet = KMEndPagePrinter( pInput->hSpool ); break; case GDISPOOL_ENDDOCPRINTER: DBGMSG(DBG_TRACE,(" - GDISPOOL_ENDDOCPRINTER\n")); pInput->ulRet = KMEndDocPrinter( pInput->hSpool ); break; case GDISPOOL_ENUMFORMS: DBGMSG(DBG_TRACE,(" - GDISPOOL_ENUMFORMS\n")); DoEnumForms(pInput, (GREENUMFORMS *) pOutput, &cbOut); break; case GDISPOOL_GETPRINTER: DBGMSG(DBG_TRACE,(" - GDISPOOL_GETPRINTER\n")); DoGetPrinter(pInput, (GREGETPRINTER *) pOutput, &cbOut); break; case GDISPOOL_GETFORM: DBGMSG(DBG_TRACE,(" - GDISPOOL_GETFORM\n")); DoGetForm(pInput, (GREGETFORM *) pOutput, &cbOut); break; case GDISPOOL_GETPRINTERDRIVER: DBGMSG(DBG_TRACE,(" - GDISPOOL_GETPRINTERDRIVER\n")); DoGetPrinterDriver(pInput,(GREGETPRINTERDRIVER*)pOutput,&cbOut); break; case GDISPOOL_GETPRINTERDATA: DBGMSG(DBG_TRACE,(" - GDISPOOL_GETPRINTERDATA\n")); DoGetPrinterData(pInput,(GREGETPRINTERDATA *) pOutput,&cbOut); break; case GDISPOOL_SETPRINTERDATA: DBGMSG(DBG_TRACE,(" - GDISPOOL_SETPRINTERDATA\n")); DoSetPrinterData(pInput,(GRESETPRINTERDATA *) pOutput,&cbOut); break; case GDISPOOL_ABORTPRINTER: DBGMSG(DBG_TRACE,(" - GDISPOOL_ABORTPRINTER\n")); pInput->ulRet = KMAbortPrinter( pInput->hSpool ); break; case GDISPOOL_CLOSEPRINTER: DBGMSG(DBG_TRACE,(" - GDISPOOL_CLOSEPRINTER\n")); pInput->ulRet = KMClosePrinter( pInput->hSpool ); break; case GDISPOOL_GETPATHNAME: DBGMSG(DBG_TRACE,(" - GDISPOOL_GETPATHNAME\n")); pInput->ulRet = DoGetPathName((WCHAR*)pInput->ajData, (WCHAR*)pOutput, &cbOut); break; default: DBGMSG(DBG_ERROR,(" - invalid message\n")); break; } if ((pInput->iMsg & GDISPOOL_API) && pInput->iMsg != GDISPOOL_CLOSEPRINTER && pInput->iMsg != GDISPOOL_OPENPRINTER && pInput->hSpool) { if (InterlockedDecrement(&((PSPOOL)pInput->hSpool)->cThreads) == 0) { DBGMSG(DBG_TRACE,(" - GDISPOOL_CLOSEPRINTER\n")); pInput->ulRet = KMClosePrinter( pInput->hSpool ); } } } } }
BOOL InternalCopyFile( HANDLE hSourceFile, PWIN32_FIND_DATA pSourceFileData, LPWSTR lpNewFileName, BOOL bFailIfExists ) /*++ Routine Description: Arguments: hSourceFile - SourceFile Handle pSourceFileData - Pointer to WIN32_FIND_DATA for the source file lpNewFileName - Supplies the name where a copy of the existing files data and attributes are to be stored. bFailIfExists - Supplies a flag that indicates how this operation is to proceed if the specified new file already exists. A value of TRUE specifies that this call is to fail. A value of FALSE causes the call to the function to succeed whether or not the specified new file exists. Return Value: TRUE - The operation was successful. FALSE/NULL - The operation failed. Extended error status is available using GetLastError. --*/ { DWORD dwSourceFileAttributes; BOOL bReturnValue = FALSE; HANDLE hTargetFile = INVALID_HANDLE_VALUE; DWORD dwLowFileSize, dwHighFileSize; LPVOID pBuffer; DWORD cbBufferSize = BUFFER_SIZE; DWORD cbBytesRead; DWORD cbBytesWritten; DWORD dwSourceFilePointer; SPLASSERT( hSourceFile != NULL && hSourceFile != INVALID_HANDLE_VALUE && pSourceFileData != NULL && lpNewFileName != NULL ); #if DBG // <<<<< DEBUG ONLY >>>>>> // // ASSERTION Check Source File Pointer is Zero. // dwSourceFilePointer = SetFilePointer( hSourceFile, 0, NULL, FILE_CURRENT ); if ( dwSourceFilePointer != 0xffffffff ) { SPLASSERT( dwSourceFilePointer == 0 ); } #endif // DBG // // Alloc I/O Buffer // pBuffer = AllocSplMem( BUFFER_SIZE ); if ( pBuffer == NULL ) goto InternalCopyFileExit; // // Create TagetFile with same File Attributes // hTargetFile = CreateFile( lpNewFileName, GENERIC_WRITE, FILE_SHARE_EXCLUSIVE, NULL, bFailIfExists ? CREATE_NEW : CREATE_ALWAYS, pSourceFileData->dwFileAttributes | FILE_FLAG_SEQUENTIAL_SCAN, NULL ); if ( hTargetFile != INVALID_HANDLE_VALUE ) { // // Copy The Data // while (( bReturnValue = ReadFile( hSourceFile, pBuffer, cbBufferSize, &cbBytesRead, NULL )) && cbBytesRead != 0 ) { // // Add Code to Build CheckSum Here // bReturnValue = WriteFile( hTargetFile, pBuffer, cbBytesRead, &cbBytesWritten, NULL ); if ( bReturnValue == FALSE || cbBytesWritten != cbBytesRead ) { bReturnValue = FALSE; break; } } if ( bReturnValue ) { // // Set TargetFile Times to be the same as the Source File // bReturnValue = SetFileTime( hTargetFile, &pSourceFileData->ftCreationTime, &pSourceFileData->ftLastAccessTime, &pSourceFileData->ftLastWriteTime ); // // Verify that the file size is correct. // if ( bReturnValue ) { dwLowFileSize = GetFileSize( hTargetFile, &dwHighFileSize ); if ( dwLowFileSize != pSourceFileData->nFileSizeLow || dwHighFileSize != pSourceFileData->nFileSizeHigh ) { DBGMSG(DBG_ERROR, ("InternalCopyFile: sizes do not match for %ws: (%d %d) and (%d %d)", lpNewFileName, pSourceFileData->nFileSizeHigh, pSourceFileData->nFileSizeLow, dwHighFileSize, dwLowFileSize)); bReturnValue = FALSE; SetLastError(ERROR_FILE_INVALID); } } // // Add Code here to Verify the CheckSum is correct. // } CloseHandle( hTargetFile ); } FreeSplMem( pBuffer ); InternalCopyFileExit: if ( !bReturnValue ) { DBGMSG( DBG_WARN, ("InternalCopyFile hSourceFile %x %ws error %d\n", hSourceFile, lpNewFileName, GetLastError() )); SPLASSERT( GetLastError() != ERROR_SUCCESS ); } return bReturnValue; }
HANDLE CreatePrinterHandle( LPWSTR pPrinterName, PINIPRINTER pIniPrinter, PINIPORT pIniPort, PINIPORT pIniNetPort, PINIJOB pIniJob, DWORD TypeofHandle, HANDLE hPort, PPRINTER_DEFAULTS pDefaults, PINISPOOLER pIniSpooler, DWORD AccessRequested, LPBYTE pSplClientInfo, DWORD dwLevel, HANDLE hReadFile ) { PSPOOL pSpool = NULL; BOOL bStatus = FALSE; HANDLE hReturnHandle = NULL; LPDEVMODE pDevMode = NULL; PSPLCLIENT_INFO_1 pSplClientInfo1 = (PSPLCLIENT_INFO_1)pSplClientInfo; SPLASSERT( pIniSpooler->signature == ISP_SIGNATURE ); if ( dwLevel && ( dwLevel != 1 || !pSplClientInfo) ) { DBGMSG(DBG_ERROR, ("CreatePrintHandle: Invalid client info %x - %d\n", pSplClientInfo, dwLevel)); pSplClientInfo = NULL; } try { pSpool = (PSPOOL)AllocSplMem( SPOOL_SIZE ); if ( pSpool == NULL ) { DBGMSG( DBG_WARNING, ("CreatePrinterHandle failed to allocate SPOOL %d\n", GetLastError() )); leave; } pSpool->signature = SJ_SIGNATURE; pSpool->pIniPrinter = pIniPrinter; pSpool->hReadFile = hReadFile; // // We get other useful info like build #, client architecture // we do not need this info now -- so we do not put it in PSPOOL // if ( (TypeofHandle & PRINTER_HANDLE_REMOTE) ) { if ( !pSplClientInfo ) { TypeofHandle |= PRINTER_HANDLE_3XCLIENT; } else if ( dwLevel == 1 ) { SPLASSERT(pSplClientInfo1->pUserName && pSplClientInfo1->pMachineName); pSpool->pUserName = AllocSplStr(pSplClientInfo1->pUserName); pSpool->pMachineName = AllocSplStr(pSplClientInfo1->pMachineName); if ( !pSpool->pUserName || !pSpool->pMachineName ) { DBGMSG(DBG_WARNING, ("CreatePrinterHandle: could not allocate memory for user name or machine name\n")); } } } if ( TypeofHandle & PRINTER_HANDLE_SERVER ) { bStatus = ValidateObjectAccess( SPOOLER_OBJECT_SERVER, AccessRequested, pSpool, pIniSpooler ); } else { bStatus = ValidateObjectAccess( SPOOLER_OBJECT_PRINTER, AccessRequested, pSpool, pIniSpooler ); } if ( !bStatus ) { SetLastError(ERROR_ACCESS_DENIED); leave; } MapGenericToSpecificAccess(SPOOLER_OBJECT_PRINTER, pSpool->GrantedAccess, &pSpool->GrantedAccess); pSpool->pIniPort = pIniPort; pSpool->pIniNetPort = pIniNetPort; pSpool->pIniJob = pIniJob; pSpool->TypeofHandle = TypeofHandle; pSpool->hPort = hPort; pSpool->Status = 0; pSpool->pDevMode = NULL; pSpool->pName = AllocSplStr( pPrinterName ); if ( pSpool->pName == NULL ) { leave; } pSpool->pIniSpooler = pIniSpooler; if ( pIniPrinter ) { if ( pDefaults ) { // // Allocate DevMode // if ( pDefaults->pDevMode ) { pDevMode = pDefaults->pDevMode; } else { pDevMode = pIniPrinter->pDevMode; } if ( pDevMode != NULL ) { pSpool->pDevMode = AllocSplMem( pDevMode->dmSize + pDevMode->dmDriverExtra ); if ( pSpool->pDevMode == NULL ) { DBGMSG(DBG_WARNING, ("CreatePrinterHandle failed allocation for devmode %d\n", GetLastError() )); leave; } memcpy( pSpool->pDevMode, pDevMode, pDevMode->dmSize + pDevMode->dmDriverExtra ); } } // // Allocate Datype and Print Processor // if ( pDefaults && pDefaults->pDatatype ) { pSpool->pDatatype = AllocSplStr( pDefaults->pDatatype ); pSpool->pIniPrintProc = FindDatatype( pIniPrinter->pIniPrintProc, pSpool->pDatatype ); } else { pSpool->pDatatype = AllocSplStr( pIniPrinter->pDatatype ); pSpool->pIniPrintProc = pIniPrinter->pIniPrintProc; } if ( pSpool->pIniPrintProc == NULL ) { DBGMSG( DBG_WARNING,("CreatePrinterHandle failed to PrintProcessor for datatype %ws %d\n", pSpool->pDatatype, GetLastError() )); leave; } SPLASSERT( pSpool->pIniPrintProc->signature == IPP_SIGNATURE ); pSpool->pIniPrintProc->cRef++; if ( pSpool->pDatatype == NULL ) { DBGMSG( DBG_WARNING,("CreatePrinterHandle failed to allocate DataType %x\n", GetLastError() )); leave; } } // Add us to the linked list of handles for this printer. // This will be scanned when a change occurs on the printer, // and will be updated with a flag indicating what type of // change it was. // There is a flag for each handle, because we cannot guarantee // that all threads will have time to reference a flag in the // INIPRINTER before it is updated. if ( TypeofHandle & PRINTER_HANDLE_PRINTER ) { pSpool->pNext = pSpool->pIniPrinter->pSpool; pSpool->pIniPrinter->pSpool = pSpool; } else if ( TypeofHandle & PRINTER_HANDLE_SERVER ) { // // For server handles, hang them off the global IniSpooler: // pSpool->pNext = pIniSpooler->pSpool; pIniSpooler->pSpool = pSpool; INCSPOOLERREF( pIniSpooler ); } // Note Only PRINTER_HANDLE_PRINTER are attatched to the // pIniPrinter, since those are the handle which will require // change notifications. if ( pSpool->pIniPrinter != NULL ) { INCPRINTERREF( pSpool->pIniPrinter ); } hReturnHandle = (HANDLE)pSpool; } finally { if ( hReturnHandle == NULL ) { // Failure CleanUP if ( pSpool != NULL ) { FreeSplStr(pSpool->pUserName); FreeSplStr(pSpool->pMachineName); FreeSplStr( pSpool->pName ) ; FreeSplStr( pSpool->pDatatype ); if ( pSpool->pIniPrintProc != NULL ) pSpool->pIniPrintProc->cRef--; if ( pSpool->pDevMode ) FreeSplMem( pSpool->pDevMode ); FreeSplMem( pSpool ); pSpool = NULL; } } } return hReturnHandle; }
PUCHAR GetPrinterInfo(IN HANDLE hPrinter, IN ULONG StructLevel, OUT PULONG pErrorCode) { ULONG reqbytes, alloc_size; PUCHAR ptr_info, pTempPtr_info = NULL; USHORT retry = 2; alloc_size = BASE_PRINTER_BUFFER_SIZE; ptr_info = (PUCHAR)AllocSplMem(alloc_size); if (!ptr_info) { *pErrorCode = ERROR_NOT_ENOUGH_MEMORY; return NULL; } while (retry--) { if (GetPrinter( hPrinter, StructLevel, (PUCHAR)ptr_info, alloc_size, &reqbytes) == TRUE) { *pErrorCode = 0; return (PUCHAR)ptr_info; } // // GetPrinter failed - if not because of insufficient buffer, fail // the call. Otherwise, up our hint, re-allocate and try again. // *pErrorCode = GetLastError(); if (*pErrorCode != ERROR_INSUFFICIENT_BUFFER) { FreeSplMem(ptr_info); return NULL; } // // Reallocate the buffer and re-try (note that, because we // allocated the buffer as LMEM_FIXED, the LMEM_MOVABLE does // not return a movable allocation, it just allows realloc // to return a different pointer. // FreeSplMem(ptr_info); ptr_info = NULL; pTempPtr_info = (PUCHAR)AllocSplMem(reqbytes); alloc_size = reqbytes; if (pTempPtr_info) { ptr_info = pTempPtr_info; pTempPtr_info = NULL; } else { // // If the realloc failed we break out of the loop so that we // can cleanup and return error code. // break; } } if (ptr_info) { FreeSplMem(ptr_info); } *pErrorCode = ERROR_NOT_ENOUGH_MEMORY; return NULL; }
BOOL SplOpenPrinter( LPWSTR pPrinterName, LPHANDLE pPrinterHandle, LPPRINTER_DEFAULTS pDefaults, PINISPOOLER pIniSpooler, LPBYTE pSplClientInfo, DWORD dwLevel ) /*++ Routine Description: OpenPrinter can open any of the following by specifying a string in pPrinterName:- Server \\MachineName NULL Job PrinterName, Job xxxx Port PortName, Port Printer PrinterName ShareName \\MachineName\PrinterName \\MachineName\ShareName PrinterName, UpgradeToken ShareName, UpgradeToken Note for Printer there are two Types 1 - Regular LocalPrinter 2 - DownLevel Connection Printer For type 2 a LocalPrinter exists ( pIniPrinter ) but its port does not have a monitor associated with it. In this case we also open the port ( typically \\share\printer of a remote machine ) before we return success. GUI Applications usually use Server and Printer Type Job and Port are used by Print Processors:- A print processor will Open a Job then read the job using ReadPrinter. A print processor will output to a Port by opening the PortName, Port and using WritePrinter. Usually these strings "PrinterName, Job xxx" "PortName, Port" are passed to the print processor by the spooler and are currently not documented. We do know that some OEMs have figured out the extentions and we might break someone if we change them. Type UpgradeToken is used by a Printer Driver:- Used when we need to upgrade a printer's settings from an older version of the driver to a newer one (see drvupgrd.c for details). This was added in NT 3.51. Arguments: pPrinterName - PrinterName ( see above for different types of PrinterName ) pPrinterHandle - Address to put hPrinter on Success pDefaults - Optional, allows user to specify Datatype, DevMode, DesiredAccess. pIniSpooler - handle of spooler on which the open should occur. ( see SDK Online Help for full explanation ) Return Value: TRUE - *pPrinterHandle will have a PrinterHandle FALSE - use GetLastError --*/ { PINIPRINTER pIniPrinter = NULL; PINIPORT pIniPort = NULL; PINIPORT pIniNetPort = NULL; DWORD LastError = 0; LPWSTR pName = pPrinterName+2; WCHAR string[MAX_UNC_PRINTER_NAME + PRINTER_NAME_SUFFIX_MAX]; PINIJOB pIniJob = NULL; HANDLE hReadFile = INVALID_HANDLE_VALUE; DWORD TypeofHandle = 0; LPWSTR pSecondPart = NULL; HANDLE hPort = INVALID_PORT_HANDLE; DWORD OpenPortError = NO_ERROR; BOOL bRemoteUserPrinterNotShared = FALSE; DWORD MachineNameLength; DWORD RouterReturnValue = ROUTER_UNKNOWN; DWORD AccessRequested; #if DBG // // On DBG builds, force last error to zero so we can catch people // that don't set it when they should. // SetLastError( ERROR_SUCCESS ); #endif // // Reject "" - pointer to a NULL string. // if ( pPrinterName && !pPrinterName[0] ) { SetLastError(ERROR_INVALID_NAME); return ROUTER_UNKNOWN; } // // Check for SERVER Opens. // // If the printer name was NULL or our own MachineName, then // the caller wants a handle to the server. // if( MyName( pPrinterName, pIniSpooler )){ return CreateServerHandle( pPrinterName, pPrinterHandle, pDefaults, pIniSpooler ); } DBGMSG( DBG_TRACE, ( "OpenPrinter(%ws)\n", pPrinterName )); EnterSplSem(); // // For the Mars folks who will come in with the same printer // connection, do a DeletePrinterCheck; this will allow // Mars connections that have been deleted to be proceed // to the Mars print providor // if (( pIniPrinter = FindPrinter( pPrinterName )) || ( pIniPrinter = FindPrinterShare( pPrinterName, pIniSpooler ))) { DeletePrinterCheck( pIniPrinter ); pIniPrinter = NULL; } // // The strategy for the rest of this code is to walk through each // different printer handle type, searching for a match. // // RouterReturnValue will be set to the current state of routing. // If a section recognizes and "owns" a printer and successfully // opens it, it sets RouterReturnValue to ROUTER_SUCCESS and // jumps to DoneRouting which allocs the handle. // // If it recoginzes the printer but fails to open it, and // guarentees that no one else (localspl code or other providers) // will recognize it, it should set RouterReturnValue to // ROUTER_STOP_ROUTING. We will quit at this point. // // If it doesn't recognize the printer, set RouterReturnValue // to ROUTER_UNKNOWN and we will keep looking. // // // Try regular printer name: "My Printer" "TestPrinter." // RouterReturnValue = OpenLocalPrinterName( pPrinterName, pIniSpooler, &TypeofHandle, &pIniPrinter, &pIniPort, &pIniNetPort, &hPort, &OpenPortError, pDefaults ); // // Note: Don't check for interactive users, since anyone using the // name without the server prefix must be local anyway. // The server does this and must not be marked as remote, since // its AddJob calls will fail. // if( RouterReturnValue != ROUTER_UNKNOWN ){ goto DoneRouting; } SPLASSERT( !TypeofHandle && !pIniPrinter && !pIniPort && !pIniNetPort && !pIniJob && !hPort ); // // Try LocalPrinter with an extention e.g. // // PortName, Port // PrinterName, Job xxxx // PrinterName, UpgradeToken // // See if the name includes a comma. Look for qualifiers: // Port Job LocalOnly UpgradeToken // wcscpy( string, pPrinterName ); if( pSecondPart = wcschr( string, L',' )){ // // Turn into 2 strings // First PrintName // pSecondPart points to the rest. // *pSecondPart++ = 0; // // Get rid of Leading Spaces // while ( *pSecondPart == L' ' && *pSecondPart != 0 ) { pSecondPart++; } SPLASSERT( *pSecondPart ); // // PrintName, UpgradeToken // RouterReturnValue = CheckPrinterUpgradeToken( string, pSecondPart, &TypeofHandle, &pIniPrinter, pIniSpooler ); if( RouterReturnValue != ROUTER_UNKNOWN ){ goto DoneRouting; } SPLASSERT( !TypeofHandle && !pIniPrinter && !pIniPort && !pIniNetPort && !pIniJob && !hPort ); // // PortName, Port // RouterReturnValue = CheckPrinterPortToken( string, pSecondPart, &TypeofHandle, &pIniPrinter, &pIniPort, &pIniJob, pDefaults, pIniSpooler ); if( RouterReturnValue != ROUTER_UNKNOWN ){ goto DoneRouting; } SPLASSERT( !TypeofHandle && !pIniPrinter && !pIniPort && !pIniNetPort && !pIniJob && !hPort ); // // PrinterName, Job ### // RouterReturnValue = CheckPrinterJobToken( string, pSecondPart, &TypeofHandle, &pIniPrinter, &pIniJob, &hReadFile, pIniSpooler ); if( RouterReturnValue != ROUTER_UNKNOWN ){ goto DoneRouting; } SPLASSERT( !TypeofHandle && !pIniPrinter && !pIniPort && !pIniNetPort && !pIniJob && !hPort ); } // // Try local printer qualified by \\ServerName: // "\\ServerName\PrinterName" "\\ServerName\ShareName." // wcscpy( string, pPrinterName ); if( string[0] == L'\\' && string[1] == L'\\' && ( pName = wcschr( &string[2], L'\\')) ) { *pName = L'\0'; pName++; if ( MyName(string, pIniSpooler) ) { // // Check local printer. // RouterReturnValue = OpenLocalPrinterName( pName, pIniSpooler, &TypeofHandle, &pIniPrinter, &pIniPort, &pIniNetPort, &hPort, &OpenPortError, pDefaults ); if( RouterReturnValue == ROUTER_SUCCESS ){ // // On success, determine whether the user is remote or local. // Note: we only do this for fully qualified names // (\\server\share), since using just the share or printer // name can only succeed locally. // if( ( pIniSpooler->SpoolerFlags & SPL_REMOTE_HANDLE_CHECK ) && !IsInteractiveUser() ) { TypeofHandle |= PRINTER_HANDLE_REMOTE; } // // This is a remote open. // // If the printer is not shared, ensure the caller // has Administer access to the printer. // // bugbug! // // The following seems to belong to the inside of the above "if" clause. As it is, if // an interactive user calls in with UNC name, we require him to have ADMIN access if the // printer is not shared; but if he uses the printer friendly name, we let him go. // if( !( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED )){ bRemoteUserPrinterNotShared = TRUE; } } else { // // Since we matched the server but didn't find the printer, // we should stop routing. // RouterReturnValue = ROUTER_STOP_ROUTING; SetLastError( ERROR_INVALID_PRINTER_NAME ); } // // Both cases we are done routing since we found our // server name prefix. // goto DoneRouting; } } // // We have completed all routing. Anything other than success // should exit now. // DoneRouting: if( RouterReturnValue == ROUTER_SUCCESS) { // // It's an error if the printer is pending deletion or pending creation. // SPLASSERT( pIniPrinter ); if ( (( pIniPrinter->Status & PRINTER_PENDING_DELETION ) && ( pIniSpooler->SpoolerFlags & SPL_FAIL_OPEN_PRINTERS_PENDING_DELETION ) && ( pIniPrinter->cJobs == 0 )) || ( pIniPrinter->Status & PRINTER_PENDING_CREATION ) ) { RouterReturnValue = ROUTER_STOP_ROUTING; SetLastError( ERROR_INVALID_PRINTER_NAME ); goto DoneRouting; } // // When the printer is opened, access type may be specified in // pDefaults. If no defaults are supplied (or request access // is unspecified), we use PRINTER_ACCESS_USE. // // Future calls with the handle will check against both the // current user privileges on this printer but also this initial // access. (Even if the user is an admin of the printer, unless // they open the printer with PRINTER_ALL_ACCESS, they can't // administer it. // // If the user requires more access, the printer must be reopened. // AccessRequested = ( !pDefaults || !pDefaults->DesiredAccess ) ? PRINTER_READ : pDefaults->DesiredAccess; // // If the user is remote and the printer is not shared, only allow // administrators succeed. // // This allows administrators to admin printers even if they // are not shared, and prevents non-admins from opening non-shared // printers. // if( bRemoteUserPrinterNotShared && !(AccessRequested & PRINTER_ACCESS_ADMINISTER )) { PSPOOL pSpool; // Get a quick and dirty pSpool to pass in pSpool = (PSPOOL)AllocSplMem( SPOOL_SIZE ); if( pSpool == NULL ) { DBGMSG( DBG_WARNING, ("SplOpenPrinter failed to allocate memory %d\n", GetLastError() )); RouterReturnValue = ROUTER_STOP_ROUTING; goto WrapUp; } pSpool->signature = SJ_SIGNATURE; pSpool->pIniPrinter = pIniPrinter; // Add admin request, and see if user has the right. AccessRequested |= PRINTER_ACCESS_ADMINISTER; if( !ValidateObjectAccess( SPOOLER_OBJECT_PRINTER, AccessRequested, pSpool, pIniSpooler )) { SetLastError(ERROR_ACCESS_DENIED); RouterReturnValue = ROUTER_STOP_ROUTING; } AccessRequested &= ~PRINTER_ACCESS_ADMINISTER; // clean up FreeSplMem( pSpool ); // If the user had no ADMIN privilege, fail the open call. if( RouterReturnValue == ROUTER_STOP_ROUTING ) goto WrapUp; } // // Create the printer handle that we will return to the user. // *pPrinterHandle = CreatePrinterHandle( pPrinterName, pIniPrinter, pIniPort, pIniNetPort, pIniJob, TypeofHandle, hPort, pDefaults, pIniSpooler, AccessRequested, pSplClientInfo, dwLevel, hReadFile ); if( *pPrinterHandle ){ // // Update the OpenPortError. // ((PSPOOL)*pPrinterHandle)->OpenPortError = OpenPortError; } else { SPLASSERT( GetLastError( )); RouterReturnValue = ROUTER_STOP_ROUTING; } } WrapUp: LeaveSplSem(); // // Don't have an SplOutSem as we could be called recursively. // switch( RouterReturnValue ){ case ROUTER_SUCCESS: DBGMSG( DBG_TRACE, ("OpenPrinter returned handle %x\n", *pPrinterHandle)); SPLASSERT( *pPrinterHandle ); break; case ROUTER_UNKNOWN: SPLASSERT( !TypeofHandle && !pIniPrinter && !pIniPort && !pIniNetPort && !pIniJob && !hPort ); // // hPort should not be valid. If it is, we have leaked a handle. // SPLASSERT( !hPort ); SPLASSERT( hReadFile == INVALID_HANDLE_VALUE ); DBGMSG( DBG_TRACE, ( "OpenPrinter failed, invalid name %s\n", pPrinterName )); SetLastError( ERROR_INVALID_NAME ); break; case ROUTER_STOP_ROUTING: LastError = GetLastError(); SPLASSERT( LastError ); // // On failure, we may have opened a port or file handle. We need // to close it since we won't return a valid handle, and // so ClosePrinter will never get called. // if( hPort != INVALID_PORT_HANDLE ) { ClosePrinter( hPort ); } if ( hReadFile != INVALID_HANDLE_VALUE ) { CloseHandle( hReadFile ); } DBGMSG( DBG_TRACE, ("OpenPrinter %s failed: Error %d\n", pPrinterName, GetLastError())); SetLastError( LastError ); break; } return RouterReturnValue; }
/*++ ******************************************************************* O p e n P r i n t P r o c e s s o r Routine Description: Arguments: pPrinterName => name of printer we are opening for pPrintProcessorOpenData => information used for opening the print processor Return Value: PPRINTPROCESSORDATA => processor data of opened processor if successful NULL if failed - caller uses GetLastError for reason NOTE: OpenPrinter will be called iff this returns a valid handle (and we're not journal) ******************************************************************* --*/ HANDLE OpenPrintProcessor( _In_ LPWSTR pPrinterName, _In_ PPRINTPROCESSOROPENDATA pPrintProcessorOpenData ) { PPRINTPROCESSORDATA pData; LPWSTR *pMyDatatypes = Datatypes; DWORD uDatatype = 0; HANDLE hPrinter = 0; HDC hDC = 0; PDEVMODEW pDevmode = NULL; DWORD dwNewDevmodeSize = 0; /** If the caller passed a NULL for the open data, fail the call. pPrintProcessorOpenData->pDevMode can be NULL **/ if (!pPrintProcessorOpenData || !pPrintProcessorOpenData->pDatatype || !*pPrintProcessorOpenData->pDatatype) { SetLastError(ERROR_INVALID_PARAMETER); return NULL; } /** Search for the data type index we are opening for **/ while (*pMyDatatypes) { if (!_wcsicmp(*pMyDatatypes,pPrintProcessorOpenData->pDatatype)) { break; } pMyDatatypes++; uDatatype++; } /** Allocate a buffer for the print processor data to return **/ pData = (PPRINTPROCESSORDATA)AllocSplMem(sizeof(PRINTPROCESSORDATA)); if (!pData) { ODS(("Alloc failed in OpenPrintProcessor, while printing on %ws\n", pPrinterName)); return NULL; } ZeroMemory ( pData, sizeof (PRINTPROCESSORDATA) ); /** Open the processor accordingly **/ switch (uDatatype) { case PRINTPROCESSOR_TYPE_RAW: if (!OpenPrinter(pPrinterName, &hPrinter, NULL)) goto Fail; break; case PRINTPROCESSOR_TYPE_EMF_50_1: case PRINTPROCESSOR_TYPE_EMF_50_2: case PRINTPROCESSOR_TYPE_EMF_50_3: if(pPrintProcessorOpenData->pDevMode) { if ( ! SUCCEEDED ( DWordAdd(pPrintProcessorOpenData->pDevMode->dmSize, pPrintProcessorOpenData->pDevMode->dmDriverExtra, &dwNewDevmodeSize) ) || (NULL == (pDevmode=(PDEVMODE)AllocSplMem( dwNewDevmodeSize ) ) ) ) { goto Fail; } memcpy(pDevmode, pPrintProcessorOpenData->pDevMode, pPrintProcessorOpenData->pDevMode->dmSize+ pPrintProcessorOpenData->pDevMode->dmDriverExtra); } break; case PRINTPROCESSOR_TYPE_TEXT: if ((hDC = CreateDC( L"", pPrinterName, L"", pPrintProcessorOpenData->pDevMode)) == NULL) goto Fail; break; default: SetLastError(ERROR_INVALID_DATATYPE); goto Fail; } /** Fill in the print processors information **/ pData->cb = sizeof(PRINTPROCESSORDATA); pData->signature = PRINTPROCESSORDATA_SIGNATURE; pData->JobId = pPrintProcessorOpenData->JobId; pData->hPrinter = hPrinter; pData->semPaused = CreateEvent(NULL, TRUE, TRUE,NULL); pData->uDatatype = uDatatype; pData->hDC = hDC; pData->Copies = 1; pData->TabSize = BASE_TAB_SIZE; /** Allocate and fill in the processors strings **/ pData->pPrinterName = AllocSplStr(pPrinterName); pData->pDatatype = AllocSplStr(pPrintProcessorOpenData->pDatatype); pData->pDocument = AllocSplStr(pPrintProcessorOpenData->pDocumentName); pData->pOutputFile = AllocSplStr(pPrintProcessorOpenData->pOutputFile); pData->pParameters = AllocSplStr(pPrintProcessorOpenData->pParameters); pData->pDevmode = pDevmode; pData->pPrinterNameFromOpenData = AllocSplStr(pPrintProcessorOpenData->pPrinterName); // // Check for validity of pData. In the AllocSplStr above, if RHS is non-null, then LHS // should be non-null. // if ( NULL == pData->semPaused || ( NULL != pPrinterName && NULL == pData->pPrinterName ) || ( NULL != pPrintProcessorOpenData->pDatatype && NULL == pData->pDatatype ) || ( NULL != pPrintProcessorOpenData->pDocumentName && NULL == pData->pDocument ) || ( NULL != pPrintProcessorOpenData->pOutputFile && NULL == pData->pOutputFile ) || ( NULL != pPrintProcessorOpenData->pParameters && NULL == pData->pParameters ) || ( NULL != pPrintProcessorOpenData->pPrinterName && NULL == pData->pPrinterNameFromOpenData) ) { goto Fail; } /** Parse the parameters string **/ if (pData->pParameters) { ULONG value; USHORT length = sizeof(ULONG); /** Look to see if there is a COPIES=n key/value in the Parameters field of this job. This tells us the number of times to play the data. **/ if (pData->pParameters) { GetKeyValue(pData->pParameters, pCopiesKey, VALUE_ULONG, &length, &value); if (length == sizeof(ULONG)) { pData->Copies = value; } } /** If this is a text job, see if the tab size is in there **/ if (uDatatype == PRINTPROCESSOR_TYPE_TEXT) { length = sizeof(ULONG); GetKeyValue(pData->pParameters, pTabsKey, VALUE_ULONG, &length, &value); if ((length == sizeof(ULONG)) && value) { pData->TabSize = value; } } } /* If we have a parameter string */ /** If we are doing copies, we need to check to see if this is a direct or spooled job. If it is direct, then we can't do copies because we can't rewind the data stream. **/ if (pData->Copies > 1) { ULONG Error; PPRINTER_INFO_2 pPrinterInfo2; /** If we don't already have the printer open, open it **/ if (uDatatype != PRINTPROCESSOR_TYPE_RAW ) { OpenPrinter(pPrinterName, &hPrinter, NULL); } if (hPrinter && hPrinter != INVALID_HANDLE_VALUE) { /** Get the printer info - this returns an allocated buffer **/ pPrinterInfo2 = (PPRINTER_INFO_2)GetPrinterInfo(hPrinter, 2, &Error); /** If we couldn't get the info, be safe and don't do copies **/ if (!pPrinterInfo2) { ODS(("GetPrinter failed - falling back to 1 copy\n")); pData->Copies = 1; } else { if (pPrinterInfo2->Attributes & PRINTER_ATTRIBUTE_DIRECT) { pData->Copies = 1; } FreeSplMem((PUCHAR)pPrinterInfo2); } /** If we just opened the printer, close it **/ if (uDatatype != PRINTPROCESSOR_TYPE_RAW ) { ClosePrinter(hPrinter); } } else { pData->Copies = 1; } } return (HANDLE)pData; Fail: BReleasePPData(&pData); return FALSE; }
LPBYTE CopyIniPortToPort( __in PLCMINIPORT pIniPort, DWORD Level, __out LPBYTE pPortInfo, __inout LPBYTE pEnd ) { LPWSTR *SourceStrings = NULL; LPWSTR *pSourceStrings = NULL; PPORT_INFO_2 pPort2 = (PPORT_INFO_2)pPortInfo; LPWSTR pszLocalMonitor = NULL; LPWSTR pszPortDesc = NULL; DWORD *pOffsets = NULL; DWORD Count = 0; LPBYTE pReturnPointer = NULL; switch (Level) { case 1: pOffsets = LcmPortInfo1Strings; break; case 2: pOffsets = LcmPortInfo2Strings; break; default: goto Done; } for ( Count = 0 ; pOffsets[Count] != -1 ; ++Count ) { } SourceStrings = pSourceStrings = (LPWSTR *)AllocSplMem(Count * sizeof(LPWSTR)); if ( !SourceStrings ) { goto Done; } switch (Level) { case 1: *pSourceStrings++=pIniPort->pName; break; case 2: { pszLocalMonitor = (LPWSTR)AllocSplMem((MAX_PATH + 1) * sizeof(WCHAR)); pszPortDesc = (LPWSTR)AllocSplMem((MAX_PATH + 1) * sizeof(WCHAR)); if (pszLocalMonitor && pszPortDesc) { *pSourceStrings++=pIniPort->pName; LoadString(LcmhInst, IDS_LOCALMONITORNAME, pszLocalMonitor, MAX_PATH); LoadString(LcmhInst, IDS_LOCALMONITOR, pszPortDesc, MAX_PATH); *pSourceStrings++ = pszLocalMonitor; *pSourceStrings++ = pszPortDesc; pPort2->fPortType = PORT_TYPE_WRITE | PORT_TYPE_READ; // Reserved pPort2->Reserved = 0; } else { goto Done; } } break; default: goto Done; } pEnd = LcmPackStrings(Count, SourceStrings, pPortInfo, pOffsets, pEnd); pReturnPointer = pEnd; Done: if (SourceStrings) { FreeSplMem(SourceStrings); SourceStrings = NULL; } if (pszLocalMonitor) { FreeSplMem(pszLocalMonitor); pszLocalMonitor = NULL; } if (pszPortDesc) { FreeSplMem(pszPortDesc); pszPortDesc = NULL; } return pReturnPointer; }
/*++ ******************************************************************* P r i n t T e x t J o b Routine Description: Prints a text data job. Arguments: pData => Data structure for this job pDocumentName => Name of this document Return Value: TRUE if successful FALSE if failed - GetLastError() will return reason. ******************************************************************* --*/ BOOL PrintTextJob( IN PPRINTPROCESSORDATA pData, __in IN LPWSTR pDocumentName) { DOCINFO DocInfo; LOGFONT LogFont; CHARSETINFO CharSetInfo; HFONT hOldFont, hFont = NULL; DWORD Copies; BOOL rc; DWORD NoRead; DWORD CurrentLine; DWORD CurrentCol; HANDLE hPrinter = NULL; BYTE *ReadBufferStart = NULL; PBYTE pLineBuffer = NULL; PBYTE pReadBuffer = NULL; PBYTE pReadBufferEnd = NULL; ULONG CharHeight, CharWidth, CharsPerLine, LinesPerPage; ULONG PageWidth, PageHeight; ULONG Length, TabBase; BOOL ReadAll; TEXTMETRIC tm; DWORD fdwFlags; DWORD Encoding; DWORD SplitSize; BOOL ReturnValue = FALSE; BOOL bAbortDoc = FALSE; DWORD dwNeeded; DWORD dwNoTranslate = 0; DWORD dwNoTranslateCR = 0; DWORD dwTransparent = 0; INT iBkMode = OPAQUE; DocInfo.lpszDocName = pData->pDocument; /* Document name */ DocInfo.lpszOutput = NULL; /* Output file */ DocInfo.lpszDatatype = NULL; /* Datatype */ DocInfo.cbSize = sizeof(DOCINFO); /* Size of the structure */ // // Go figure out the size of the form on the printer. We do this // by calling GetTextMetrics, which gives us the font size of the // printer font, then getting the form size and calculating the // number of characters that will fit. In other cases we treat it as ANSI text. // Currently the codepage context is fixed to the system default codepage. // Encoding = GetACP(); // // Create FIXED PITCH font and select // hOldFont = 0; ZeroMemory(&CharSetInfo, sizeof(CHARSETINFO)); if (TranslateCharsetInfo((PDWORD)UIntToPtr(Encoding), &CharSetInfo, TCI_SRCCODEPAGE)) { ZeroMemory(&LogFont, sizeof(LOGFONT)); LogFont.lfWeight = 400; LogFont.lfCharSet = (BYTE)CharSetInfo.ciCharset; LogFont.lfPitchAndFamily = FIXED_PITCH; hFont = CreateFontIndirect(&LogFont); hOldFont = (HFONT) SelectObject(pData->hDC, hFont); } if (!GetTextMetrics(pData->hDC, &tm)) { // Essential text processing computation failed goto Done; } CharHeight = tm.tmHeight + tm.tmExternalLeading; CharWidth = tm.tmAveCharWidth; if (!CharWidth || !CharHeight) { // Essential text processing computation failed goto Done; } // // Calculate most fittable characters' number to one line. // PageWidth = GetDeviceCaps(pData->hDC, DESKTOPHORZRES); PageHeight = GetDeviceCaps(pData->hDC, DESKTOPVERTRES); CharsPerLine = PageWidth / CharWidth; LinesPerPage = PageHeight / CharHeight; if (!CharsPerLine || !LinesPerPage) { // Essential text processing computation failed goto Done; } /** Allocate a buffer for one line of text **/ pLineBuffer = (PBYTE)AllocSplMem(CharsPerLine + 5); if (!pLineBuffer) { goto Done; } /** Let the printer know we are starting a new document **/ if (!StartDoc(pData->hDC, (LPDOCINFO)&DocInfo)) { goto Done; } ReadBufferStart = (BYTE *)AllocSplMem(READ_BUFFER_SIZE); if (!ReadBufferStart) { goto Done; } /** Print the data pData->Copies times **/ Copies = pData->Copies; while (Copies--) { /** Loop, getting data and sending it to the printer. This also takes care of pausing and cancelling print jobs by checking the processor's status flags while printing. The way we do this is to read in some data from the printer. We will then pull data, one tabbed line at a time from there and print it. If the last bit of data in the buffer does not make up a whole line, we call GetTabbedLineFromBuffer() with a non- zero Length, which indicates that there are chars left from the previous read. **/ TabBase = 0; Length = 0; fdwFlags = FLAG_TRANSLATE_CR | FLAG_TRANSLATE_LF; CurrentLine = 0; CurrentCol = 0; /** Open the printer. If it fails, return. This also sets up the pointer for the ReadPrinter calls. **/ if (!OpenPrinter(pDocumentName, &hPrinter, NULL)) { hPrinter = NULL; bAbortDoc = TRUE; goto Done; } // // Call GetPrinterData to see if the queue wants no LF/CR processing. // if( GetPrinterData( hPrinter, (LPWSTR)gszNoTranslateCRLF, NULL, (PBYTE)&dwNoTranslate, sizeof( dwNoTranslate ), &dwNeeded ) == ERROR_SUCCESS ){ if( dwNoTranslate ){ fdwFlags &= ~( FLAG_TRANSLATE_CR | FLAG_TRANSLATE_LF ); } } // // Call GetPrinterData to see if the queue wants no CR processing. // if( GetPrinterData( hPrinter, (LPWSTR)gszNoTranslateCR, NULL, (PBYTE)&dwNoTranslateCR, sizeof( dwNoTranslateCR ), &dwNeeded ) == ERROR_SUCCESS ){ if( dwNoTranslateCR ){ fdwFlags &= ~FLAG_TRANSLATE_CR; if( GetPrinterData( hPrinter, (LPWSTR)gszTransparency, NULL, (PBYTE)&dwTransparent, sizeof( dwTransparent ), &dwNeeded ) == ERROR_SUCCESS ){ if( dwTransparent ){ iBkMode = SetBkMode( pData->hDC, TRANSPARENT ); } } } } if (StartPage(pData->hDC) == SP_ERROR) { bAbortDoc = TRUE; goto Done; } /** ReadAll indicates if we are on the last line of the file **/ ReadAll = FALSE; /** This next do loop continues until we have read all of the data for the print job. **/ do { if (fdwFlags & FLAG_DBCS_SPLIT) { SplitSize = (DWORD)(pReadBufferEnd - pReadBuffer); memcpy(ReadBufferStart, pReadBuffer, SplitSize); fdwFlags &= ~FLAG_DBCS_SPLIT; } else { SplitSize = 0; } rc = ReadPrinter(hPrinter, (ReadBufferStart + SplitSize), (READ_BUFFER_SIZE - SplitSize), &NoRead); if (!rc || !NoRead) { ReadAll = TRUE; } else { /** Pick up a pointer to the end of the data **/ pReadBuffer = ReadBufferStart; pReadBufferEnd = ReadBufferStart + SplitSize + NoRead; } /** This loop will process all the data that we have just read from the printer. **/ do { if (!ReadAll) { /** Length on entry holds the length of any residual chars from the last line that we couldn't print out because we ran out of characters on the ReadPrinter buffer. **/ pReadBuffer = GetTabbedLineFromBuffer( pReadBuffer, pReadBufferEnd, pLineBuffer, CharsPerLine - CurrentCol, pData->TabSize, Encoding, &Length, &TabBase, &fdwFlags ); /** If pReadBuffer == NULL, then we have exhausted the read buffer and we need to ReadPrinter again and save the last line chars. Length holds the number of characters on this partial line, so the next time we call ReadPrinter we will pickup where we left off. The only time we'll get residual chars is if: 1. The last line ends w/o ff/lf/cr ("Hello\EOF") In this case we should TextOutA the last line and then quit. (In this case, don't break here; go ahead and print, then we'll break out below in the do..while.) 2. The ReadPrinter last byte is in the middle of a line. Here we should read the next chunk and add the new characters at the end of the chars we just read. (In this case, we should break and leave Length as it is so we will read again and append to the buffer, beginning at Length.) **/ if (!pReadBuffer || (fdwFlags & FLAG_DBCS_SPLIT)) break; } /** If the print processor is paused, wait for it to be resumed **/ if (pData->fsStatus & PRINTPROCESSOR_PAUSED) { WaitForSingleObject(pData->semPaused, INFINITE); } /** If the job has been aborted, clean up and leave **/ if (pData->fsStatus & PRINTPROCESSOR_ABORTED) { ReturnValue = TRUE; bAbortDoc = TRUE; goto Done; } /** Write the data to the printer **/ /** Make sure Length is not zero **/ /** TextOut will fail if Length == 0 **/ if (Length) { /** We may have a number of newlines pending, that may push us to the next page (or even next-next page). **/ while (CurrentLine >= LinesPerPage) { /** We need a new page; always defer this to the last second to prevent extra pages from coming out. **/ if (EndPage(pData->hDC) == SP_ERROR || StartPage(pData->hDC) == SP_ERROR) { bAbortDoc = TRUE; goto Done; } CurrentLine -= LinesPerPage; } #pragma prefast(suppress:__WARNING_ANSI_APICALL, "By design. This function is inherently handling only ANSI text print jobs.") if (TextOutA(pData->hDC, CurrentCol * CharWidth, CurrentLine * CharHeight, (LPCSTR)pLineBuffer, Length) == FALSE) { ODS(("TextOut() failed\n")); bAbortDoc = TRUE; goto Done; } CurrentCol += Length; } /** Even if the length is zero, increment the line. Should happen when the character is only 0x0D or 0x0A. **/ if (fdwFlags & FLAG_CR) { CurrentCol=0; fdwFlags &= ~FLAG_CR; } if (fdwFlags & FLAG_LF) { CurrentLine++; fdwFlags &= ~FLAG_LF; } /** We need a new page. Set the current line to the end of the page. We could do a End/StartPage sequence, but this may cause a blank page to get ejected. Note: this code will avoid printing out pages that consist of formfeeds only (if you have a page with a space in it, that counts as text). **/ if (fdwFlags & FLAG_FF) { CurrentLine = LinesPerPage; CurrentCol = 0; fdwFlags &= ~FLAG_FF; } /** We have done the text out, so these characters have been successfully printed. Zero out Length so these characters won't be printed again **/ Length = 0; /** We only terminate this loop if we run out of chars or we run out of read buffer. **/ } while (pReadBuffer && pReadBuffer != pReadBufferEnd); /** Keep going until we get the last line **/ } while (!ReadAll); if (EndPage(pData->hDC) == SP_ERROR) { bAbortDoc = TRUE; goto Done; } /** Close the printer - we open/close the printer for each copy so the data pointer will rewind. **/ ClosePrinter(hPrinter); hPrinter = NULL; } /* While copies to print */ /** Let the printer know that we are done printing **/ EndDoc(pData->hDC); ReturnValue = TRUE; Done: if (dwTransparent) SetBkMode( pData->hDC, iBkMode ); if (hPrinter) ClosePrinter(hPrinter); if (bAbortDoc) AbortDoc(pData->hDC); if (pLineBuffer) FreeSplMem(pLineBuffer); if (hOldFont) { SelectObject(pData->hDC, hOldFont); DeleteObject(hFont); } if (ReadBufferStart) { FreeSplMem(ReadBufferStart); } return ReturnValue; }
BOOL EnumGeneric( IN PROC fnEnum, IN DWORD Level, IN PBYTE *ppEnumData, IN DWORD cbBuf, OUT LPDWORD pcbReturned, OUT LPDWORD pcReturned, IN PVOID Arg1, IN PVOID Arg2, IN PVOID Arg3 ) { BOOL rc; BOOL UnknownFunction = FALSE; DWORD cbRealloc; if( fnEnum == (PROC)EnumPrinters ) rc = EnumPrinters( (DWORD)Arg1, (LPTSTR)Arg2, COMMON_ARGS ); // Flags Name else if( fnEnum == (PROC)EnumJobs ) rc = EnumJobs( (HANDLE)Arg1, (DWORD)Arg2, (DWORD)Arg3, COMMON_ARGS ); // hPrinter FirstJob NoJobs else if( fnEnum == (PROC)EnumPrinterDrivers ) rc = EnumPrinterDrivers( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS ); // pName pEnvironment else if( fnEnum == (PROC)EnumForms ) rc = EnumForms( (HANDLE)Arg1, COMMON_ARGS ); // hPrinter else if( fnEnum == (PROC)EnumMonitors ) rc = EnumMonitors( (LPTSTR)Arg1, COMMON_ARGS ); // pName else if( fnEnum == (PROC)EnumPorts ) rc = EnumPorts( (LPTSTR)Arg1, COMMON_ARGS ); // pName else if( fnEnum == (PROC)EnumPrintProcessors ) rc = EnumPrintProcessors( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS ); // pName pEnvironment else if( fnEnum == (PROC)EnumPrintProcessorDatatypes ) rc = EnumPrintProcessorDatatypes( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS ); // pName pPrintProcessorName else { *ppEnumData = NULL; UnknownFunction = TRUE; DBGMSG( DBG_ERROR, ( "EnumGeneric called with unknown function\n" ) ); rc = FALSE; } if( ( rc == FALSE ) && ( UnknownFunction == FALSE ) ) { if( GetLastError( ) == ERROR_INSUFFICIENT_BUFFER ) { cbRealloc = *pcbReturned; DBGMSG( DBG_TRACE, ( "EnumGeneric: Reallocating %d (0x%x) bytes @%08x\n", cbBuf, cbBuf, *ppEnumData ) ); if( cbBuf == 0 ) *ppEnumData = AllocSplMem( cbRealloc ); else *ppEnumData = ReallocSplMem( *ppEnumData, cbRealloc ); cbBuf = cbRealloc; if( *ppEnumData ) { DBGMSG( DBG_TRACE, ( "EnumGeneric: %d (0x%x) bytes reallocated @%08x\n", cbBuf, cbBuf, *ppEnumData ) ); if( fnEnum == (PROC)EnumPrinters ) rc = EnumPrinters( (DWORD)Arg1, (LPTSTR)Arg2, COMMON_ARGS ); // Flags Name else if( fnEnum == (PROC)EnumJobs ) rc = EnumJobs( (HANDLE)Arg1, (DWORD)Arg2, (DWORD)Arg3, COMMON_ARGS ); // hPrinter FirstJob NoJobs else if( fnEnum == (PROC)EnumPrinterDrivers ) rc = EnumPrinterDrivers( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS ); // pName pEnvironment else if( fnEnum == (PROC)EnumForms ) rc = EnumForms( (HANDLE)Arg1, COMMON_ARGS ); // hPrinter else if( fnEnum == (PROC)EnumMonitors ) rc = EnumMonitors( (LPTSTR)Arg1, COMMON_ARGS ); // pName else if( fnEnum == (PROC)EnumPorts ) rc = EnumPorts( (LPTSTR)Arg1, COMMON_ARGS ); // pName else if( fnEnum == (PROC)EnumPrintProcessors ) rc = EnumPrintProcessors( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS ); // pName pEnvironment else if( fnEnum == (PROC)EnumPrintProcessorDatatypes ) rc = EnumPrintProcessorDatatypes( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS ); // pName pPrintProcessorName /* If things haven't worked out, free up the buffer. * We do this because otherwise the caller will not know * whether the pointer is valid any more, * since ReallocSplMem might have failed. */ if( rc == FALSE ) { if( *ppEnumData ) FreeSplMem( *ppEnumData ); *ppEnumData = NULL; *pcbReturned = 0; *pcReturned = 0; } /* Don't rely on pcbReturned having the same value * that was passed in: */ else *pcbReturned = cbRealloc; } } else { if( *ppEnumData ) FreeSplMem( *ppEnumData ); *ppEnumData = NULL; *pcbReturned = 0; *pcReturned = 0; rc = FALSE; } } else *pcbReturned = cbBuf; return rc; }
PINIPORT CreatePortEntry( __in LPTSTR pszPortName ) /*++ Routine Description: Creates a IniPort entry for a port. Needs to be called inside monitor critical section. Arguments: pszPortName : Name of the port Return Value: On success pointer to the IniPort stucture. On failure NULL --*/ { PINIPORT pIniPort = NULL; HANDLE DoneWriting = NULL; HANDLE DoneReading = NULL; HANDLE WakeUp = NULL; LPWSTR pszString = NULL; SplInSem(); DoneWriting = CreateEvent(NULL, FALSE, TRUE, NULL); if (!DoneWriting) { goto Fail; } WakeUp = CreateEvent(NULL, FALSE, FALSE, NULL); if (!WakeUp) { goto Fail; } // // manual-reset event, initially signal state // DoneReading = CreateEvent(NULL, TRUE, TRUE, NULL); if (!DoneReading) { goto Fail; } pIniPort = (PINIPORT) AllocSplMem(sizeof(*pIniPort)); if (!pIniPort) { goto Fail; } pszString = AllocSplStr(pszPortName); if (!pszString) { goto Fail; } pIniPort->pNext = NULL; pIniPort->signature = PJ_SIGNATURE; pIniPort->DoneWriting = DoneWriting; pIniPort->DoneReading = DoneReading; pIniPort->WakeUp = WakeUp; pIniPort->hUstatusThread= NULL; pIniPort->pszPortName = pszString; pIniPort->pNext = pIniFirstPort; pIniFirstPort = pIniPort; return pIniPort; Fail: if (DoneWriting) { CloseHandle (DoneWriting); } if (DoneReading) { CloseHandle (DoneReading); } if (WakeUp) { CloseHandle (WakeUp); } FreeSplMem (pszString); FreeSplMem (pIniPort); return NULL; }
LPBYTE CopyIniPortToPort( PINIPORT pIniPort, DWORD Level, LPBYTE pPortInfo, LPBYTE pEnd ) { LPWSTR *SourceStrings, *pSourceStrings; PPORT_INFO_2 pPort2 = (PPORT_INFO_2)pPortInfo; WCHAR szLocalMonitor[MAX_PATH+1], szPortDesc[MAX_PATH+1]; DWORD *pOffsets; DWORD Count; switch (Level) { case 1: pOffsets = PortInfo1Strings; break; case 2: pOffsets = PortInfo2Strings; break; default: DBGMSG(DBG_ERROR, ("CopyIniPortToPort: invalid level %d", Level)); return NULL; } for ( Count = 0 ; pOffsets[Count] != -1 ; ++Count ) { } SourceStrings = pSourceStrings = AllocSplMem(Count * sizeof(LPWSTR)); if ( !SourceStrings ) { DBGMSG( DBG_WARNING, ("Failed to alloc port source strings.\n")); return NULL; } switch (Level) { case 1: *pSourceStrings++=pIniPort->pName; break; case 2: *pSourceStrings++=pIniPort->pName; LoadString(hInst, IDS_LOCALMONITORNAME, szLocalMonitor, sizeof(szLocalMonitor)-1); LoadString(hInst, IDS_LOCALMONITOR, szPortDesc, sizeof(szPortDesc)-1); *pSourceStrings++ = szLocalMonitor; *pSourceStrings++ = szPortDesc; // How do i findout other types ??? pPort2->fPortType = PORT_TYPE_WRITE; // Reserved pPort2->Reserved = 0; break; default: DBGMSG(DBG_ERROR, ("CopyIniPortToPort: invalid level %d", Level)); return NULL; } pEnd = PackStrings(SourceStrings, pPortInfo, pOffsets, pEnd); FreeSplMem(SourceStrings); return pEnd; }
DWORD IrdaConnect( _In_ PLCMINIPORT pIniPort ) { BOOL bRet = FALSE; WORD WSAVerReq = MAKEWORD(1,1); DWORD dwIndex = 0, dwNeeded = BUF_SIZE, dwEnableIrLPT = TRUE, dwLastError = ERROR_SUCCESS, dwSendPduLen = 0; LPSTR pBuf = NULL; WSADATA WSAData = {0}; SOCKET Socket = INVALID_SOCKET; PIRDA_INFO pIrda = NULL; PDEVICELIST pDevList = NULL; SOCKADDR_IRDA PrinterAddr = { AF_IRDA, 0, 0, 0, 0, "IrLPT" }; SPLASSERT(pIniPort->hFile == (HANDLE)INVALID_SOCKET && pIniPort->pExtra == NULL); dwLastError = WSAStartup(WSAVerReq, &WSAData); if ( dwLastError ) goto Done; pBuf = (LPSTR)AllocSplMem(dwNeeded); if ( !pBuf ) { dwLastError = GetLastError(); goto Done; } if ( (Socket = WSASocket(AF_IRDA, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET || getsockopt(Socket, SOL_IRLMP, IRLMP_ENUMDEVICES, (LPSTR)pBuf, (int *)&dwNeeded) == SOCKET_ERROR ) { dwLastError = WSAGetLastError(); goto Done; } if ( dwNeeded > BUF_SIZE ) { FreeSplMem(pBuf); pBuf = (LPSTR)AllocSplMem(dwNeeded); if ( !pBuf ) { dwLastError = GetLastError(); goto Done; } if ( getsockopt(Socket, SOL_IRLMP, IRLMP_ENUMDEVICES, (LPSTR)pBuf, (int *)&dwNeeded) == SOCKET_ERROR ) { dwLastError = WSAGetLastError(); goto Done; } } pDevList = (PDEVICELIST) pBuf; // // Any of the devices a printer? // for ( dwIndex = 0 ; dwIndex < pDevList->numDevice ; ++dwIndex ) { if ( (pDevList->Device[dwIndex].irdaDeviceHints1 & PRINTER_HINT_BIT) || (pDevList->Device[dwIndex].irdaDeviceHints2 & PRINTER_HINT_BIT) ) break; } // // Any printers found? // if ( dwIndex == pDevList->numDevice ) { dwLastError = ERROR_PRINTER_NOT_FOUND; goto Done; } // // Move printer's address into the socket address // memcpy(PrinterAddr.irdaDeviceID, pDevList->Device[dwIndex].irdaDeviceID, sizeof(PrinterAddr.irdaDeviceID)); dwIndex = 0; dwNeeded = sizeof(dwSendPduLen); bRet = SOCKET_ERROR != setsockopt(Socket, SOL_IRLMP, IRLMP_IRLPT_MODE, (LPCSTR)&dwEnableIrLPT, sizeof(dwEnableIrLPT)) && SOCKET_ERROR != connect(Socket, (const struct sockaddr *)&PrinterAddr, sizeof(PrinterAddr)) && SOCKET_ERROR != getsockopt(Socket, SOL_IRLMP, IRLMP_SEND_PDU_LEN, (char *)&dwSendPduLen, (int *)&dwNeeded) && SOCKET_ERROR != setsockopt(Socket, SOL_SOCKET, SO_SNDBUF, (LPCSTR)&dwIndex, sizeof(dwIndex)); if ( bRet ) { SPLASSERT(pIniPort->pExtra == NULL); dwNeeded = sizeof(IRDA_INFO) + dwSendPduLen; pIrda = (PIRDA_INFO) AllocSplMem(dwNeeded); if ( !pIrda ) { bRet = FALSE; dwLastError = ERROR_NOT_ENOUGH_MEMORY; goto Done; } pIniPort->hFile = (HANDLE)Socket; pIniPort->pExtra = (LPBYTE)pIrda; pIrda->dwSendPduLen = dwSendPduLen; pIrda->pBuf = ((LPBYTE) pIrda) + sizeof(IRDA_INFO); } else dwLastError = WSAGetLastError(); Done: FreeSplMem(pBuf); if ( !bRet ) { if ( Socket != INVALID_SOCKET ) closesocket(Socket); FreeSplMem(pIniPort->pExtra); pIniPort->pExtra = NULL; } return bRet ? ERROR_SUCCESS : dwLastError; }