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

📄 pjlmon.c

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

Copyright (c) 1990  Microsoft Corporation
All Rights Reserved


Module Name:

Abstract:

Author:

Revision History:

--*/

#define USECOMM

#include "precomp.h"
#include <winioctl.h>
#include <ntddpar.h>


// ---------------------------------------------------------------------
// PROTO, CONSTANT, and GLOBAL
//
// ---------------------------------------------------------------------

DWORD   ProcessPJLString(PINIPORT, CHAR *, DWORD *);
VOID    ProcessParserError(DWORD);
VOID    InterpreteTokens(PINIPORT, PTOKENPAIR, DWORD);
BOOL    IsPJL(PINIPORT);
BOOL    WriteCommand(HANDLE, LPSTR);
BOOL    ReadCommand(HANDLE);

#define WAIT_FOR_WRITE                  100 // 0.1 sec
#define WAIT_FOR_DATA_TIMEOUT           100 // 0.1 sec
#define WAIT_FOR_USTATUS_THREAD_TIMEOUT 500 // 0.5 sec
#define GETDEVICEID                     IOCTL_PAR_QUERY_DEVICE_ID
#define MAX_DEVID                       1024

TCHAR   cszInstalledMemory[]    = TEXT("Installed Memory");
TCHAR   cszAvailableMemory[]    = TEXT("Available Memory");

BOOL
DllEntryPoint(
    IN HANDLE   hModule,
    IN DWORD    dwReason,
    IN LPVOID   lpRes
    )
/*++

Routine Description:
    Dll entry point

Arguments:

Return Value:

--*/
{
    UNREFERENCED_PARAMETER(lpRes);

    switch (dwReason) {

        case DLL_PROCESS_ATTACH:
            InitializeCriticalSection(&pjlMonSection);
            DisableThreadLibraryCalls(hModule);
            break;

        default:
            // do nothing
            ;
    }

    return TRUE;
}


VOID
ClearPrinterStatusAndIniJobs(
    PINIPORT    pIniPort
    )
{
    PORT_INFO_3 PortInfo3;

    if ( pIniPort->PrinterStatus ||
         (pIniPort->status & PP_PRINTER_OFFLINE) ) {

        pIniPort->PrinterStatus = 0;
        pIniPort->status &= ~PP_PRINTER_OFFLINE;

        ZeroMemory(&PortInfo3, sizeof(PortInfo3));
        SetPort(NULL, pIniPort->pszPortName, 3, (LPBYTE)&PortInfo3);
    }

    SendJobLastPageEjected(pIniPort, ALL_JOBS, FALSE);
}


VOID
RefreshPrinterInfo(
    PINIPORT    pIniPort
    )
{
    //
    // Only one thread should write to the printer at a time
    //
    if ( WAIT_OBJECT_0 != WaitForSingleObject(pIniPort->DoneWriting,
                                              WAIT_FOR_WRITE) ) {

        return;
    }

    //
    // If printer is power cycled and it does not talk back (but answers
    // PnP id) we got to clear the error on spooler to send jobs
    //
    ClearPrinterStatusAndIniJobs(pIniPort);
    if ( !IsPJL(pIniPort) ) {

        pIniPort->status &= ~PP_IS_PJL;
    }

    SetEvent(pIniPort->DoneWriting);
}


VOID
UstatusThread(
    HANDLE hPort
)
/*++

Routine Description:
    Unsolicited status information thread. This thread will continue to
    read unsolicited until it's asked to terminate, which will happen
    under one of these conditions:
        1) Receive EOJ confirmation from the printer.
        2) Timeout waiting for EOJ confirmation.
        3) The port is been closed.

Arguments:
    hPort   : IniPort structure for the port

Return Value:

--*/
{
    PINIPORT        pIniPort = (PINIPORT)((INIPORT *)hPort);
    HANDLE          hToken;

    SPLASSERT(pIniPort                              &&
              pIniPort->signature == PJ_SIGNATURE   &&
              (pIniPort->status & PP_THREAD_RUNNING) == 0);

    if ( IsPJL(pIniPort) )
        pIniPort->status |= PP_IS_PJL;


    SetEvent(pIniPort->DoneWriting);

    if ( !(pIniPort->status & PP_IS_PJL) )
        goto StopThread;

    //
    // manual-reset event, initially signal state
    //
    pIniPort->DoneReading = CreateEvent(NULL, TRUE, TRUE, NULL);

    if ( !pIniPort->DoneReading )
        goto StopThread;

    pIniPort->status |= PP_THREAD_RUNNING;

    pIniPort->PrinterStatus     = 0;
    pIniPort->status           &= ~PP_PRINTER_OFFLINE;
    pIniPort->dwLastReadTime    = 0;

    for ( ; ; ) {

        //
        // check if PP_RUN_THREAD has been cleared to terminate
        //
        if ( !(pIniPort->status & PP_RUN_THREAD) ) {

            if ( pIniPort->status & PP_INSTARTDOC ) {

                //
                // there's an active job, can't end the thread
                //
                pIniPort->status |= PP_RUN_THREAD;
            } else {

                DBGMSG(DBG_INFO,
                       ("PJLMon Read Thread for Port %ws Closing Down.\n",
                       pIniPort->pszPortName));

                pIniPort->status &= ~PP_THREAD_RUNNING;

                ClearPrinterStatusAndIniJobs(pIniPort);
                goto StopThread;
            }
        }

        //
        // check if the printer is bi-di
        //
        if (pIniPort->status & PP_IS_PJL) {

            (VOID)ReadCommand(hPort);

            //
            // If we are under error condition or if we have jobs pending
            // read status back from printer more frequently
            //
            if ( pIniPort->pIniJob                          ||
                 (pIniPort->status & PP_PRINTER_OFFLINE)    ||
                 (pIniPort->status & PP_WRITE_ERROR) ) {

                WaitForSingleObject(pIniPort->WakeUp,
                                    dwReadThreadErrorTimeout);
            } else {

                WaitForSingleObject(pIniPort->WakeUp,
                                    dwReadThreadIdleTimeoutOther);
            }

            if ( pIniPort->pIniJob &&
                 !(pIniPort->status & PP_PRINTER_OFFLINE) &&
                 !(pIniPort->status & PP_WRITE_ERROR) ) {

                //
                // Some printers are PJL bi-di, but do not send
                // EOJ. We want jobs to disappear from printman
                //
                SendJobLastPageEjected(pIniPort,
                                       GetTickCount() - dwReadThreadEOJTimeout,
                                       TRUE);
            }

            //
            // If we did not read from printer for more than a minute
            // and no more jobs talk to printer again
            //
            if ( !(pIniPort->status & PP_INSTARTDOC) &&
                 (GetTickCount() - pIniPort->dwLastReadTime) > 240000 
)
                RefreshPrinterInfo(pIniPort);

        } else {

            //
            // exit the thread if printer is not PJL bi-di capable
            //
            Sleep(2000);
            pIniPort->status &= ~PP_RUN_THREAD;
#ifdef  DEBUG
            OutputDebugStringA("Set ~PP_RUN_THREAD because printer is not bi-di\n");
#endif
        }
    }

StopThread:
    pIniPort->status &= ~PP_RUN_THREAD;
    pIniPort->status &= ~PP_THREAD_RUNNING;
    CloseHandle(pIniPort->DoneReading);

    //
    // By closing the handle and then setting it to NULL we know the main
    // thread will not end up setting a wrong event
    //
    CloseHandle(pIniPort->WakeUp);
    pIniPort->WakeUp = NULL;
}


BOOL
CreateUstatusThread(
    PINIPORT pIniPort
)
/*++

Routine Description:
    Creates the Ustatus thread

Arguments:
    pIniPort    : IniPort structure for the port

Return Value:
    TRUE on succesfully creating the thread, else FALSE
--*/
{
    HANDLE  ThreadHandle;
    DWORD   ThreadId;

    DBGMSG(DBG_INFO, ("PJLMon Read Thread for Port %ws Starting.\n",
                      pIniPort->pszPortName));

    pIniPort->status |= PP_RUN_THREAD;

    WaitForSingleObject(pIniPort->DoneWriting, INFINITE);

    pIniPort->WakeUp = CreateEvent(NULL, FALSE, FALSE, NULL);

    if ( !pIniPort->WakeUp )
        goto Fail;

    ThreadHandle = CreateThread(NULL, 16*1024,
                                (LPTHREAD_START_ROUTINE)UstatusThread,
                                pIniPort,
                                0, &ThreadId);

    if ( ThreadHandle ) {

        SetThreadPriority(ThreadHandle, THREAD_PRIORITY_LOWEST);
        CloseHandle(ThreadHandle);
        return TRUE;
    }

Fail:

    if ( pIniPort->WakeUp ) {

        CloseHandle(pIniPort->WakeUp);
        pIniPort->WakeUp = NULL;
    }

    pIniPort->status &= ~PP_RUN_THREAD;
    SetEvent(pIniPort->DoneWriting);

    return FALSE;
}


BOOL
WINAPI
PJLMonOpenPortEx(
    IN     LPTSTR       pszPortName,
    IN     LPTSTR       pszPrinterName,
    IN OUT LPHANDLE     pHandle,
    IN OUT LPMONITOR    pMonitor
)
/*++

Routine Description:
    Opens the port

Arguments:
    pszPortName     : Port name
    pszPrinterName  : Printer name
    pHandle         : Pointer to the handle to return
    pMonitor        : Port monitor function table

Return Value:
    TRUE on success, FALSE on error

--*/
{
    PINIPORT    pIniPort;
    BOOL        bRet = FALSE;
    BOOL        bInSem = FALSE;

    //
    // Validate port monitor
    //
    if ( !pMonitor                  ||
         !pMonitor->pfnOpenPort     ||
         !pMonitor->pfnStartDocPort ||
         !pMonitor->pfnWritePort    ||
         !pMonitor->pfnReadPort     ||
         !pMonitor->pfnClosePort ) {


        DBGMSG(DBG_WARNING,
               ("PjlMon: Invalid port monitors passed to OpenPortEx\n"));
        SetLastError(ERROR_INVALID_PRINT_MONITOR);
        goto Cleanup;
    }

    EnterSplSem();
    bInSem = TRUE;

    //
    // Is the port open already?
    //
    if ( pIniPort = FindIniPort(pszPortName) ) {

        SetLastError(ERROR_BUSY);
        goto Cleanup;
    }

    pIniPort = CreatePortEntry(pszPortName);
    LeaveSplSem();
    bInSem = FALSE;

    if ( pIniPort &&
         (*pMonitor->pfnOpenPort)(pszPortName, &pIniPort->hPort) ) {

        *pHandle = pIniPort;
        CopyMemory((LPBYTE)&pIniPort->fn, (LPBYTE)pMonitor, sizeof(*pMonitor));

        //
        // Create the ustatus thread always
        // If printer is not PJL it will die by itself
        // We do not want to write to the printer in this thread to determine
        //      printer is PJL since that may take several seconds to fail
        //
        CreateUstatusThread(pIniPort);
        bRet = TRUE;
    } else {

        DBGMSG(DBG_WARNING, ("PjlMon: OpenPort %s : Failed\n", pszPortName));
    }

Cleanup:
    if ( bInSem ) {

        LeaveSplSem();
    }
    SplOutSem();

    return bRet;
}


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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -