/*++ Copyright (c) 1990-1994 Microsoft Corporation Module Name: local.c Abstract: This module provides all the public exported APIs relating to Printer and Job management for the Local Print Providor Author: Dave Snipp (DaveSn) 15-Mar-1991 Revision History: 16-Jun-1992 JohnRo net print vs. UNICODE. July 1994 MattFe Caching --*/ #include #include #include #include #include #include #include #include #include #include #include // DBGMSG #include #include #define NOTIFY_TIMEOUT 10000 DWORD LMStartDocPrinter( HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo ) { PWSPOOL pSpool=(PWSPOOL)hPrinter; WCHAR szFileName[MAX_PATH]; PDOC_INFO_1 pDocInfo1=(PDOC_INFO_1)pDocInfo; QUERY_PRINT_JOB_INFO JobInfo; IO_STATUS_BLOCK Iosb; VALIDATEW32HANDLE( pSpool ); if (pSpool->Status) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } pSpool->Status |= WSPOOL_STATUS_STARTDOC; if(StrNCatBuff(szFileName, COUNTOF(szFileName), pSpool->pServer, L"\\", pSpool->pShare, NULL) != ERROR_SUCCESS) { return FALSE; } pSpool->hFile = CreateFile(szFileName, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (pSpool->hFile == INVALID_HANDLE_VALUE) { EnterSplSem(); DeleteEntryfromLMCache(pSpool->pServer, pSpool->pShare); LeaveSplSem(); DBGMSG( DBG_WARNING, ("Failed to open %ws\n", szFileName)); pSpool->Status &= ~WSPOOL_STATUS_STARTDOC; SetLastError(ERROR_INVALID_NAME); return FALSE; } if (pDocInfo1 && pDocInfo1->pDocName && (wcslen(pDocInfo1->pDocName) < MAX_PATH)) { if (NtFsControlFile(pSpool->hFile, NULL, NULL, NULL, &Iosb, FSCTL_GET_PRINT_ID, NULL, 0, &JobInfo, sizeof(JobInfo)) == ERROR_SUCCESS){ RxPrintJobSetInfo(pSpool->pServer, JobInfo.JobId, 3, (LPBYTE)pDocInfo1->pDocName, wcslen(pDocInfo1->pDocName)*sizeof(WCHAR) + sizeof(WCHAR), PRJ_COMMENT_PARMNUM); } else { DBGMSG( DBG_WARN, ("NtFsControlFile failed %ws\n", szFileName)); } } return TRUE; } BOOL LMStartPagePrinter( HANDLE hPrinter ) { PWSPOOL pSpool = (PWSPOOL)hPrinter; VALIDATEW32HANDLE( pSpool ); return FALSE; } BOOL LMWritePrinter( HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten ) { PWSPOOL pSpool=(PWSPOOL)hPrinter; DWORD cWritten, cTotal; DWORD rc; LPBYTE pByte=pBuf; VALIDATEW32HANDLE( pSpool ); if (!(pSpool->Status & WSPOOL_STATUS_STARTDOC)) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (pSpool->hFile == INVALID_HANDLE_VALUE) { *pcWritten = 0; SetLastError(ERROR_INVALID_HANDLE); return FALSE; } cWritten = cTotal = 0; while (cbBuf) { rc = WriteFile(pSpool->hFile, pByte, cbBuf, &cWritten, NULL); if (!rc) { rc = GetLastError(); DBGMSG(DBG_WARNING, ("Win32 Spooler: Error writing to server, Error %d\n", rc)); cTotal+=cWritten; *pcWritten=cTotal; return FALSE; } else if (!cWritten) { DBGMSG(DBG_ERROR, ("Spooler: Amount written is zero !!!\n")); } cTotal+=cWritten; cbBuf-=cWritten; pByte+=cWritten; } *pcWritten = cTotal; return TRUE; } BOOL LMEndPagePrinter( HANDLE hPrinter ) { PWSPOOL pSpool = (PWSPOOL)hPrinter; VALIDATEW32HANDLE( pSpool ); return FALSE; } BOOL LMAbortPrinter( HANDLE hPrinter ) { PWSPOOL pSpool=(PWSPOOL)hPrinter; VALIDATEW32HANDLE( pSpool ); // Abort Printer remoteley won't work until we maintain state information // on a per handle basis. For PDK, this is good enough #ifdef LATER WORD parm = 0; PRIDINFO PridInfo; DosDevIOCtl(&PridInfo, (LPSTR)&parm, SPOOL_LMGetPrintId, SPOOL_LMCAT, hSpooler); RxPrintJobDel(NULL, PridInfo.uJobId); #endif return TRUE; } BOOL LMReadPrinter( HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pNoBytesRead ) { PWSPOOL pSpool=(PWSPOOL)hPrinter; VALIDATEW32HANDLE( pSpool ); return 0; UNREFERENCED_PARAMETER(pBuf); UNREFERENCED_PARAMETER(pNoBytesRead); } BOOL LMEndDocPrinter( HANDLE hPrinter ) { PWSPOOL pSpool=(PWSPOOL)hPrinter; VALIDATEW32HANDLE( pSpool ); if (!(pSpool->Status & WSPOOL_STATUS_STARTDOC)) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } pSpool->Status &= ~WSPOOL_STATUS_STARTDOC; if (pSpool->hFile != INVALID_HANDLE_VALUE) { CloseHandle(pSpool->hFile); pSpool->hFile = INVALID_HANDLE_VALUE; } return TRUE; } BOOL LMAddJob( HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded ) { PWSPOOL pSpool=(PWSPOOL)hPrinter; DWORD cb; WCHAR szFileName[MAX_PATH]; LPBYTE pEnd; LPADDJOB_INFO_1 pAddJob=(LPADDJOB_INFO_1)pData; VALIDATEW32HANDLE( pSpool ); if(StrNCatBuff(szFileName, COUNTOF(szFileName), pSpool->pServer, L"\\", pSpool->pShare, NULL) != ERROR_SUCCESS) { return(FALSE); } cb = wcslen(szFileName)*sizeof(WCHAR) + sizeof(WCHAR) + sizeof(ADDJOB_INFO_1); if (cb > cbBuf) { *pcbNeeded=cb; SetLastError(ERROR_INSUFFICIENT_BUFFER); return(FALSE); } pEnd = (LPBYTE)pAddJob+cbBuf; pEnd -= wcslen(szFileName)*sizeof(WCHAR)+sizeof(WCHAR); pAddJob->Path = wcscpy((LPWSTR)pEnd, szFileName); pAddJob->JobId = (DWORD)-1; return TRUE; } BOOL LMScheduleJob( HANDLE hPrinter, DWORD JobId ) { PWSPOOL pSpool=(PWSPOOL)hPrinter; VALIDATEW32HANDLE( pSpool ); JobId = JobId; return TRUE; } DWORD LMGetPrinterData( HANDLE hPrinter, LPTSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded ) { PWSPOOL pSpool=(PWSPOOL)hPrinter; VALIDATEW32HANDLE( pSpool ); return FALSE; } DWORD LMSetPrinterData( HANDLE hPrinter, LPTSTR pValueName, DWORD Type, LPBYTE pData, DWORD cbData ) { PWSPOOL pSpool=(PWSPOOL)hPrinter; VALIDATEW32HANDLE( pSpool ); return FALSE; } BOOL LMClosePrinter( HANDLE hPrinter ) { PWSPOOL pSpool=(PWSPOOL)hPrinter; PLMNOTIFY pLMNotify = &pSpool->LMNotify; BOOL bReturnValue = FALSE; VALIDATEW32HANDLE( pSpool ); EnterSplSem(); if (pSpool->Status & WSPOOL_STATUS_STARTDOC) EndDocPrinter(hPrinter); if (pLMNotify->ChangeEvent) { if (pLMNotify->ChangeEvent != INVALID_HANDLE_VALUE) { CloseHandle(pLMNotify->ChangeEvent); } else { LMFindClosePrinterChangeNotification(hPrinter); } } FreepSpool( pSpool ); bReturnValue = TRUE; LeaveSplSem(); return bReturnValue; } DWORD LMWaitForPrinterChange( HANDLE hPrinter, DWORD Flags ) { PWSPOOL pSpool = (PWSPOOL)hPrinter; PLMNOTIFY pLMNotify = &pSpool->LMNotify; HANDLE ChangeEvent; DWORD bReturnValue = FALSE; EnterSplSem(); // // !! LATER !! // // We have no synchronization code in win32spl. This opens us // up to AVs if same handle is used (ResetPrinter validates; // Close closes; ResetPrinter tries to use handle boom.) // Here's one more case: // if (pLMNotify->ChangeEvent) { SetLastError(ERROR_ALREADY_WAITING); goto Error; } // Allocate memory for ChangeEvent for LanMan Printers // This event is pulsed by LMSetJob and any othe LM // function that modifies the printer/job status // LMWaitForPrinterChange waits on this event // being pulsed. ChangeEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (!ChangeEvent) { DBGMSG(DBG_WARNING, ("CreateEvent( ChangeEvent ) failed: Error %d\n", GetLastError())); goto Error; } pLMNotify->ChangeEvent = ChangeEvent; LeaveSplSem(); WaitForSingleObject(pLMNotify->ChangeEvent, NOTIFY_TIMEOUT); CloseHandle(ChangeEvent); // // !! LATER !! // // We shouldn't return that everything changed; we should // return what did. // return Flags; Error: LeaveSplSem(); return 0; } BOOL LMFindFirstPrinterChangeNotification( HANDLE hPrinter, DWORD fdwFlags, DWORD fdwOptions, HANDLE hNotify, PDWORD pfdwStatus) { PWSPOOL pSpool = (PWSPOOL)hPrinter; PLMNOTIFY pLMNotify = &pSpool->LMNotify; EnterSplSem(); pLMNotify->hNotify = hNotify; pLMNotify->fdwChangeFlags = fdwFlags; pLMNotify->ChangeEvent = INVALID_HANDLE_VALUE; *pfdwStatus = PRINTER_NOTIFY_STATUS_ENDPOINT | PRINTER_NOTIFY_STATUS_POLL; LeaveSplSem(); return TRUE; } BOOL LMFindClosePrinterChangeNotification( HANDLE hPrinter) { PWSPOOL pSpool = (PWSPOOL)hPrinter; PLMNOTIFY pLMNotify = &pSpool->LMNotify; SplInSem(); if (pLMNotify->ChangeEvent != INVALID_HANDLE_VALUE) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } pLMNotify->hNotify = NULL; pLMNotify->ChangeEvent = NULL; return TRUE; } VOID LMSetSpoolChange( PWSPOOL pSpool) { PLMNOTIFY pLMNotify; pLMNotify = &pSpool->LMNotify; EnterSplSem(); if (pLMNotify->ChangeEvent) { if (pLMNotify->ChangeEvent == INVALID_HANDLE_VALUE) { // // FindFirstPrinterChangeNotification used. // ReplyPrinterChangeNotification(pLMNotify->hNotify, pLMNotify->fdwChangeFlags, NULL, NULL); } else { SetEvent(pLMNotify->ChangeEvent); } } LeaveSplSem(); }