⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pjlmon.c

📁 A language monitor provides a full duplex communications path between the print spooler and bi-direc
💻 C
📖 第 1 页 / 共 4 页
字号:
)
/*++

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 + -