📄 pjlmon.c
字号:
)
/*++
Routine Description:
Read a command from the port
Arguments:
hPort : Port handle
Return Value:
TRUE on successfully reading one or more commands, FALSE on error
--*/
{
PINIPORT pIniPort = (PINIPORT)((INIPORT *)hPort);
DWORD cbRead, cbToRead, cbProcessed, cbPrevious;
char string[CBSTRING];
DWORD status;
BOOL bRet=FALSE;
cbPrevious = 0;
ResetEvent(pIniPort->DoneReading);
cbToRead = CBSTRING - 1;
for ( ; ; ) {
if ( !PJLMonReadPort(hPort, &string[cbPrevious], cbToRead, &cbRead) )
break;
if ( cbRead ) {
string[cbPrevious + cbRead] = '\0';
status = ProcessPJLString(pIniPort, string, &cbProcessed);
if ( cbProcessed )
bRet = TRUE;
if (status == STATUS_END_OF_STRING ) {
if ( cbProcessed )
strcpy(string, string+cbProcessed);
cbPrevious = cbRead + cbPrevious - cbProcessed;
}
} else {
SPLASSERT(!cbPrevious);
}
if ( status != STATUS_END_OF_STRING && cbRead != cbToRead )
break;
cbToRead = CBSTRING - cbPrevious - 1;
if ( cbToRead == 0 )
DBGMSG(DBG_ERROR,
("ReadCommand cbToRead is 0 (buffer too small)\n"));
Sleep(WAIT_FOR_DATA_TIMEOUT);
}
SetEvent(pIniPort->DoneReading);
//
// Update the time we last read from printer
//
if ( bRet )
pIniPort->dwLastReadTime = GetTickCount();
return bRet;
}
BOOL
WINAPI
PJLMonGetPrinterDataFromPort(
HANDLE hPort,
DWORD ControlID,
LPTSTR pValueName,
LPTSTR lpInBuffer,
DWORD cbInBuffer,
LPTSTR lpOutBuffer,
DWORD cbOutBuffer,
LPDWORD lpcbReturned
)
/*++
Routine Description:
GetPrinter data from port. Supports predefined commands/valuenames.
When we support Value name commands (not supported by DeviceIoControl)
we should check for startdoc -- MuhuntS
This monitor function supports the following two functionalities,
1. Allow spooler or language monitor to call DeviceIoControl to get
information from the port driver vxd, i.e. ControlID != 0.
And only port monitor support this functionality, language monitor
doesn't, so language monitor just pass this kind of calls down to
port monitor.
2. Allow app or printer driver query language monitor for some device
information by specifying some key names that both parties understand,
i.e. ControlID == 0 && pValueName != 0. So when printer driver call
DrvGetPrinterData DDI, gdi will call spooler -> language monitor
to get specific device information, for example, UNIDRV does this
to get installed printer memory from PJL printers thru PJLMON.
Only language monitor support this functionality,
port monitor doesn't.
Arguments:
hPort : Port handle
ControId : Control id
pValueName : Value name
lpInBuffer : Input buffer for the command
cbinBuffer : Input buffer size
lpOutBuffer : Output buffer
cbOutBuffer : Output buffer size
lpcbReturned : Set to the amount of data in output buffer on success
Return Value:
TRUE on success, FALSE on error
--*/
{
PINIPORT pIniPort = (PINIPORT)((INIPORT *)hPort);
BOOL bRet = FALSE, bStopUstatusThread = FALSE;
SPLASSERT(pIniPort && pIniPort->signature == PJ_SIGNATURE);
if ( ControlID ) {
if ( !pIniPort->fn.pfnGetPrinterDataFromPort ) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return (*pIniPort->fn.pfnGetPrinterDataFromPort)(
pIniPort->hPort,
ControlID,
pValueName,
lpInBuffer,
cbInBuffer,
lpOutBuffer,
cbOutBuffer,
lpcbReturned);
}
//
// Only 2 keys supported
//
if ( lstrcmpi(pValueName, cszInstalledMemory) &&
lstrcmpi(pValueName, cszAvailableMemory) ) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
//
// Wait for crrent job to print since we can't send a PJL command
// in the middle of job
//
WaitForSingleObject(pIniPort->DoneWriting, INFINITE);
// make sure the first write succeeds
// WIN95C BUG 14299, ccteng, 5/18/95
//
// The multi-language printers (4M, 4ML, 4MP, 4V, 4SI), if you print a
// PS print job, the memory resources claimed by the PS processor are not
// release until you enter PCL or reset the printer with "EscE".
//
// So if we had just printed a PS job, the available memory will be
// incorrect if we don't have the "EscE" here.
if ( (pIniPort->status & PP_IS_PJL) &&
WriteCommand(hPort, "\033E\033%-12345X@PJL INFO CONFIG\015\012") ) {
if ( !(pIniPort->status & PP_RUN_THREAD) ) {
bStopUstatusThread = TRUE;
CreateUstatusThread(pIniPort);
}
// PJLMON currently only supports the following pValueName
// 1. installed printer memory
// 2. available printer memory
if ( !lstrcmpi(pValueName, cszInstalledMemory) )
pIniPort->dwInstalledMemory = 0;
else if (!lstrcmpi(pValueName, cszAvailableMemory))
pIniPort->dwAvailableMemory = 0;
ResetEvent(pIniPort->DoneReading);
SetEvent(pIniPort->WakeUp);
WaitForSingleObject(pIniPort->DoneReading, READTHREADTIMEOUT);
WriteCommand(hPort,
"@PJL INFO MEMORY\015\012@PJL INFO STATUS\015\012");
ResetEvent(pIniPort->DoneReading);
SetEvent(pIniPort->WakeUp);
WaitForSingleObject(pIniPort->DoneReading, READTHREADTIMEOUT);
if ( bStopUstatusThread ) {
pIniPort->status &= ~PP_RUN_THREAD;
SetEvent(pIniPort->WakeUp);
}
if ( !lstrcmpi(pValueName, cszInstalledMemory) ) {
*lpcbReturned = sizeof(DWORD);
if ( lpOutBuffer &&
cbOutBuffer >= sizeof(DWORD) &&
pIniPort->dwInstalledMemory ) {
*((LPDWORD)lpOutBuffer) = pIniPort->dwInstalledMemory;
bRet = TRUE;
}
} else if ( !lstrcmpi(pValueName, cszAvailableMemory) ) {
*lpcbReturned = sizeof(DWORD);
if ( lpOutBuffer &&
cbOutBuffer >= sizeof(DWORD) &&
pIniPort->dwAvailableMemory)
{
*((LPDWORD)lpOutBuffer) = pIniPort->dwAvailableMemory;
bRet = TRUE;
}
}
if ( bStopUstatusThread ) {
while (pIniPort->WakeUp)
Sleep(WAIT_FOR_USTATUS_THREAD_TIMEOUT);
}
}
if ( !bRet )
SetLastError(ERROR_INVALID_PARAMETER);
SetEvent(pIniPort->DoneWriting);
return bRet;
}
MONITOREX MonitorEx = {
sizeof(MONITOR),
{
NULL, // EnumPrinters not supported
NULL, // OpenPort not supported
PJLMonOpenPortEx,
PJLMonStartDocPort,
PJLMonWritePort,
PJLMonReadPort,
PJLMonEndDocPort,
PJLMonClosePort,
NULL, // AddPort not supported
NULL, // AddPortEx not supported
NULL, // ConfigurePort not supported
NULL, // DeletePort not supported
PJLMonGetPrinterDataFromPort,
NULL // SetPortTimeOuts not supported
}
};
LPMONITOREX
WINAPI
InitializePrintMonitor(
IN LPTSTR pszRegistryRoot
)
/*++
Routine Description:
Fill the monitor function table. Spooler makes call to this routine
to get the monitor functions.
Arguments:
pszRegistryRoot : Registry root to be used by this dll
lpMonitor : Pointer to monitor fucntion table to be filled
Return Value:
TRUE on successfully initializing the monitor, false on error.
--*/
{
if ( !pszRegistryRoot || !*pszRegistryRoot ) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
if ( UpdateTimeoutsFromRegistry(pszRegistryRoot) != ERROR_SUCCESS ) {
return NULL;
}
return &MonitorEx;
}
#define NTOKEN 20
DWORD
ProcessPJLString(
PINIPORT pIniPort,
LPSTR pInString,
DWORD *lpcbProcessed
)
/*++
Routine Description:
Process a PJL string read from the printer
Arguments:
pIniPort : Ini port
pInString : Input string to process
lpcbProcessed : On return set to the amount of data processed
Return Value:
Status value of the processing
--*/
{
TOKENPAIR tokenPairs[NTOKEN];
DWORD nTokenParsedRet;
LPSTR lpRet;
DWORD status = 0;
lpRet = pInString;
#ifdef DEBUG
OutputDebugStringA("String to process: <");
OutputDebugStringA(pInString);
OutputDebugStringA(">\n");
#endif
for (*lpcbProcessed = 0; *pInString != 0; pInString = lpRet) {
//
// hack to determine if printer is bi-di. LJ 4 does not have p1284
// device ID so we do PCL memory query and see if it returns anything
//
if (!(pIniPort->status & PP_IS_PJL) &&
!mystrncmp(pInString, "PCL\015\012INFO MEMORY", 16) )
pIniPort->status |= PP_IS_PJL;
status = GetPJLTokens(pInString, NTOKEN, tokenPairs,
&nTokenParsedRet, &lpRet);
if (status == STATUS_REACHED_END_OF_COMMAND_OK) {
pIniPort->status |= PP_IS_PJL;
InterpreteTokens(pIniPort, tokenPairs, nTokenParsedRet);
} else {
ProcessParserError(status);
}
//
// if a PJL command straddles between buffers
//
if (status == STATUS_END_OF_STRING)
break;
*lpcbProcessed += (DWORD)(lpRet - pInString);
}
return status;
}
DWORD
SeverityFromPjlStatus(
DWORD dwPjlStatus
)
{
if ( dwPjlStatus >= 10000 && dwPjlStatus < 12000 ) {
//
// 10xyz
// 11xyz : load paper (paper available on another tray)
//
return PORT_STATUS_TYPE_WARNING;
} else if ( dwPjlStatus >= 30000 && dwPjlStatus < 31000 ) {
//
// 30xyz : Auto continuable errors
//
return PORT_STATUS_TYPE_WARNING;
} else if ( dwPjlStatus >= 35000 && dwPjlStatus < 36000 ) {
//
// 35xyz : Potential operator intervention conditions
//
return PORT_STATUS_TYPE_WARNING;
} else if ( dwPjlStatus > 40000 && dwPjlStatus < 42000 ) {
//
// 40xyz : Operator intervention required
// 41xyz : Load paper errors
//
return PORT_STATUS_TYPE_ERROR;
}
DBGMSG(DBG_ERROR,
("SeverityFromPjlStatus: Unknown status %d\n", dwPjlStatus));
return PORT_STATUS_TYPE_INFO;
}
VOID
InterpreteTokens(
PINIPORT pIniPort,
PTOKENPAIR tokenPairs,
DWORD nTokenParsed
)
/*++
Routine Description:
Interpret succesfully read PJL tokens
Arguments:
pIniPort : Ini port
tokenPairs : List of token pairs
nTokenParsed : Number of token pairs
Return Value:
None
--*/
{
DWORD i, OldStatus;
PJLTOPRINTERSTATUS *pMap;
PORT_INFO_3 PortInfo3;
DWORD dwSeverity = 0;
HANDLE hToken;
#ifdef DEBUG
char msg[CBSTRING];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -