winspool.c
上传用户:looem2003
上传日期:2014-07-20
资源大小:13733k
文件大小:12k
源码类别:

打印编程

开发平台:

Visual C++

  1. /*++
  2. Copyright (c) 1990-2003  Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5.     winspool.c
  6. Abstract:
  7.     Implements the spooler supported apis for printing.
  8. --*/
  9. #include "precomp.h"
  10. #pragma hdrstop
  11. WCHAR   szNULL[] = L"";
  12. WCHAR   szLcmDeviceNameHeader[] = L"\Device\NamedPipe\Spooler\";
  13. WCHAR   szWindows[] = L"windows";
  14. WCHAR   szINIKey_TransmissionRetryTimeout[] = L"TransmissionRetryTimeout";
  15. //
  16. // Timeouts for serial printing
  17. //
  18. DWORD   g_COMWriteTimeoutConstant_ms = 30000; // 30 seconds
  19. #define READ_TOTAL_TIMEOUT      5000    // 5 seconds
  20. #define READ_INTERVAL_TIMEOUT   200     // 0.2 second
  21. BOOL
  22. DeletePortNode(
  23.     __inout PINILOCALMON pIniLocalMon,
  24.     __in    PINIPORT  pIniPort
  25.     )
  26. {
  27.     PINIPORT    pPort, pPrevPort;
  28.     for( pPort = pIniLocalMon->pIniPort;
  29.          pPort && pPort != pIniPort;
  30.          pPort = pPort->pNext){
  31.         pPrevPort = pPort;
  32.     }
  33.     if (pPort) {    // found the port
  34.         if (pPort == pIniLocalMon->pIniPort) {
  35.             pIniLocalMon->pIniPort = pPort->pNext;
  36.         } else {
  37.             pPrevPort->pNext = pPort->pNext;
  38.         }
  39.         FreeSplMem(pPort);
  40.         return TRUE;
  41.     }
  42.     else            // port not found
  43.         return FALSE;
  44. }
  45. BOOL
  46. RemoveDosDeviceDefinition(
  47.     __in    PINIPORT    pIniPort
  48.     )
  49. /*++
  50. Routine Description:
  51.     Removes the NONSPOOLED.. dos device definition created by localmon
  52. Arguments:
  53.     pIniPort    : Pointer to the INIPORT
  54. Return Value:
  55.     TRUE on success, FALSE on error
  56. --*/
  57. {
  58.     WCHAR   TempDosDeviceName[MAX_PATH];
  59.     if( ERROR_SUCCESS != StrNCatBuffW( TempDosDeviceName, COUNTOF(TempDosDeviceName),
  60.                                        L"NONSPOOLED_", pIniPort->pName, NULL ))
  61.         return FALSE;
  62.     LcmRemoveColon(TempDosDeviceName);
  63.     return DefineDosDevice(DDD_REMOVE_DEFINITION, TempDosDeviceName, NULL);
  64. }
  65. BOOL
  66. ValidateDosDevicePort(
  67.     __inout PINIPORT    pIniPort
  68.     )
  69. /*++
  70. Routine Description:
  71.     Checks if the given port corresponds to a dos device.
  72.     For a dos device port the following is done:
  73.         -- Dos device definition for the NONSPOOLED.. is created
  74.         -- CreateFile is done on the NONSPOOLED.. port
  75. Arguments:
  76.     pIniPort    : Pointer to the INIPORT
  77. Return Value:
  78.     TRUE on all validations passing, FALSE otherwise
  79.     Side effect:
  80.         For dos devices :
  81.         a. CreateFile is called on the NONSPOOLED.. name
  82.         b. PP_DOSDEVPORT flag is set
  83.         c. pIniPort->pDeviceName is set to the first string found on
  84.            QueryDosDefition this could be used to see if the definition changed
  85.            (ex. when user did a net use lpt1 \serverprinter the connection
  86.                 is effective only when the user is logged in)
  87.         d. PP_COMM_PORT is set for real LPT/COM port
  88.            (ie. GetCommTimeouts worked, not a net use lpt1 case)
  89. --*/
  90. {
  91.     DCB             dcb;
  92.     COMMTIMEOUTS    cto;
  93.     WCHAR           TempDosDeviceName[MAX_PATH];
  94.     HANDLE          hToken = NULL;
  95.     WCHAR           DeviceNames[MAX_PATH];
  96.     WCHAR           DosDeviceName[MAX_PATH];
  97.     WCHAR           NewNtDeviceName[MAX_PATH];
  98.     WCHAR          *pDeviceNames=DeviceNames;
  99.     BOOL            bRet = FALSE;
  100.     LPWSTR          pDeviceName = NULL;
  101.     // if this is a COM port and we already have a file handle cached,
  102.     // bump the count and get out.
  103.     if (IS_COM_PORT(pIniPort->pName))
  104.     {
  105.         if ( (pIniPort->hFile != NULL ) &&
  106.              (pIniPort->hFile != INVALID_HANDLE_VALUE) )
  107.         {
  108.             SPLASSERT(pIniPort->cRef > 0);
  109.             bRet = TRUE;
  110.             goto Done;
  111.         }
  112.     }
  113.     hToken = RevertToPrinterSelf();
  114.     if (!hToken)
  115.        goto Done;
  116.     if( ERROR_SUCCESS != StrNCatBuffW( DosDeviceName, COUNTOF(DosDeviceName),
  117.                                        pIniPort->pName, NULL ))
  118.         goto Done;
  119.     LcmRemoveColon(DosDeviceName);
  120.     //
  121.     // If the port is not a dos device port nothing to do -- return success
  122.     //
  123.     if ( !QueryDosDevice(DosDeviceName, DeviceNames, COUNTOF (DeviceNames)) ) {
  124.         bRet = TRUE;
  125.         DBG_MSG(DBG_TRACE, ("ValidateDosDevicePort(): Unable to find port: %wsn", DosDeviceName));
  126.         goto Done;
  127.     }
  128.     pDeviceName = AllocSplStr(pDeviceNames);
  129.     if ( !pDeviceName )
  130.         goto Done;
  131.     if( ERROR_SUCCESS != StrNCatBuffW( NewNtDeviceName, COUNTOF(NewNtDeviceName),
  132.                                        szLcmDeviceNameHeader, pIniPort->pName, NULL ))
  133.         goto Done;
  134.     LcmRemoveColon(NewNtDeviceName);
  135.     //
  136.     // Search for the first non-matching name in pDeviceNames list.
  137.     //
  138.     while ( lstrcmpi(pDeviceNames, NewNtDeviceName) == 0 ) {
  139.         pDeviceNames+=wcslen(pDeviceNames)+1;
  140.     }
  141.     if( ERROR_SUCCESS != StrNCatBuffW( TempDosDeviceName, COUNTOF(TempDosDeviceName),
  142.                                        L"NONSPOOLED_", pIniPort->pName, NULL ))
  143.         goto Done;
  144.     LcmRemoveColon(TempDosDeviceName);
  145.     //
  146.     // Delete any existing definition for TempDosDeviceName. This ensures that
  147.     // there exists only one definition for the nonspooled_port device name.
  148.     //
  149.     DefineDosDevice(DDD_REMOVE_DEFINITION, TempDosDeviceName, NULL);
  150.     DefineDosDevice(DDD_RAW_TARGET_PATH, TempDosDeviceName, pDeviceNames);
  151.     ImpersonatePrinterClient(hToken);
  152.     hToken = NULL;
  153.     if( ERROR_SUCCESS != StrNCatBuffW( TempDosDeviceName, COUNTOF(TempDosDeviceName),
  154.                                        L"\\.\NONSPOOLED_", pIniPort->pName, NULL ))
  155.         goto Done;
  156.     LcmRemoveColon(TempDosDeviceName);
  157.     pIniPort->hFile = CreateFile(TempDosDeviceName,
  158.                                  GENERIC_READ | GENERIC_WRITE,
  159.                                  FILE_SHARE_READ,
  160.                                  NULL,
  161.                                  OPEN_ALWAYS,
  162.                                  FILE_ATTRIBUTE_NORMAL |
  163.                                  FILE_FLAG_SEQUENTIAL_SCAN,
  164.                                  NULL);
  165.     //
  166.     // If CreateFile fails remove redirection and fail the call
  167.     //
  168.     if ( pIniPort->hFile == INVALID_HANDLE_VALUE ) {
  169.         DBG_MSG(DBG_ERROR, 
  170.                 ("ValidateDosDevicePort(): CreateFile() failed!!!  GLE[%d]  portname: %wsn", 
  171.                 GetLastError(),
  172.                 TempDosDeviceName));
  173.         (VOID)RemoveDosDeviceDefinition(pIniPort);
  174.         goto Done;
  175.     }
  176.     pIniPort->Status |= PP_DOSDEVPORT;
  177.     SetEndOfFile(pIniPort->hFile);
  178.     if ( IS_COM_PORT (pIniPort->pName) ) {
  179.         if ( GetCommState(pIniPort->hFile, &dcb) ) {
  180.             GetCommTimeouts(pIniPort->hFile, &cto);
  181.             GetIniCommValues (pIniPort->pName, &dcb, &cto);
  182.             SetCommState (pIniPort->hFile, &dcb);
  183.             cto.WriteTotalTimeoutConstant   = g_COMWriteTimeoutConstant_ms;
  184.             cto.WriteTotalTimeoutMultiplier = 0;
  185.             cto.ReadTotalTimeoutConstant    = READ_TOTAL_TIMEOUT;
  186.             cto.ReadIntervalTimeout         = READ_INTERVAL_TIMEOUT;
  187.             SetCommTimeouts(pIniPort->hFile, &cto);
  188.             pIniPort->Status |= PP_COMM_PORT;
  189.         } else {
  190.             DBG_MSG(DBG_WARN,
  191.                    ("ERROR: Failed GetCommState pIniPort->hFile %xn",pIniPort->hFile) );
  192.         }
  193.     } else if ( IS_LPT_PORT (pIniPort->pName) ) {
  194.         if ( GetCommTimeouts(pIniPort->hFile, &cto) ) {
  195.             GetTransmissionRetryTimeoutFromRegistry (&cto.WriteTotalTimeoutConstant);
  196.             cto.WriteTotalTimeoutConstant*=1000;
  197.             SetCommTimeouts(pIniPort->hFile, &cto);
  198.             pIniPort->Status |= PP_COMM_PORT;
  199.         } else {
  200.             DBG_MSG(DBG_WARN,
  201.                    ("ERROR: Failed GetCommTimeouts pIniPort->hFile %xn",pIniPort->hFile) );
  202.         }
  203.     }
  204.     FreeSplStr( pIniPort->pDeviceName );
  205.     pIniPort->pDeviceName = pDeviceName;
  206.     bRet = TRUE;
  207. Done:
  208.     if (hToken)
  209.         ImpersonatePrinterClient(hToken);
  210.     if ( !bRet && pDeviceName )
  211.         FreeSplStr(pDeviceName);
  212.     return bRet;
  213. }
  214. BOOL
  215. FixupDosDeviceDefinition(
  216.     __inout PINIPORT    pIniPort
  217.     )
  218. /*++
  219. Routine Description:
  220.     Called before every StartDocPort for a DOSDEVPORT. The routine will check if
  221.     the dos device defintion has changed (if a user logged and his connection
  222.     is remembered). Also for a connection case the CreateFile is called since
  223.     that needs to be done per job
  224. Arguments:
  225.     pIniPort    : Pointer to the INIPORT
  226. Return Value:
  227.     TRUE on all validations passing, FALSE otherwise
  228. --*/
  229. {
  230.     WCHAR       DeviceNames[MAX_PATH];
  231.     WCHAR       DosDeviceName[MAX_PATH];
  232.     HANDLE      hToken;
  233.     //
  234.     // If the port is not a real LPT port we open it per job
  235.     //
  236.     if ( !(pIniPort->Status & PP_COMM_PORT) ||
  237.          pIniPort->hFile == INVALID_HANDLE_VALUE )
  238.         return ValidateDosDevicePort(pIniPort);
  239.     if( ERROR_SUCCESS != StrNCatBuffW( DosDeviceName, COUNTOF (DosDeviceName),
  240.                                        pIniPort->pName, NULL ))
  241.         return FALSE;
  242.     LcmRemoveColon(DosDeviceName);
  243.     hToken = RevertToPrinterSelf();
  244.     if (!hToken) {
  245.         return FALSE;
  246.     }
  247.     if ( !QueryDosDevice(DosDeviceName, DeviceNames, COUNTOF (DeviceNames) ) ) {
  248.         ImpersonatePrinterClient(hToken);
  249.         return FALSE;
  250.     }
  251.     //
  252.     // If strings are same then definition has not changed
  253.     //
  254.     if ( !lstrcmpi(DeviceNames, pIniPort->pDeviceName) )
  255.     {
  256.         ImpersonatePrinterClient(hToken);
  257.         return TRUE;
  258.     }
  259.     (VOID)RemoveDosDeviceDefinition(pIniPort);
  260.     CloseHandle(pIniPort->hFile);
  261.     pIniPort->hFile = INVALID_HANDLE_VALUE;
  262.     pIniPort->Status &= ~(PP_COMM_PORT | PP_DOSDEVPORT);
  263.     FreeSplStr(pIniPort->pDeviceName);
  264.     pIniPort->pDeviceName = NULL;
  265.     ImpersonatePrinterClient(hToken);
  266.     return ValidateDosDevicePort(pIniPort);
  267. }
  268. BOOL
  269. GetCOMPort(
  270.     __inout PINIPORT    pIniPort
  271.     )
  272. {
  273.     BOOL frc = FALSE;
  274.     LcmEnterSplSem();
  275.     frc =  ValidateDosDevicePort(pIniPort);
  276.     if (frc && (pIniPort->hFile != INVALID_HANDLE_VALUE))
  277.     {
  278.         pIniPort->cRef++;
  279.         DBG_MSG(DBG_TRACE,
  280.                 ("GetCOMPort(): increment cRef[%d] with FileHandle[%x]n", pIniPort->cRef, pIniPort->hFile));
  281.     }
  282.     else
  283.     {
  284.         // if we did not get a file handle, fail the call.
  285.         if (pIniPort->hFile == INVALID_HANDLE_VALUE)
  286.         {
  287.             frc = FALSE;
  288.             SetLastError(ERROR_PRINTER_NOT_FOUND);
  289.             DBG_MSG(DBG_ERROR, ("GetCOMPort(): Unable to get file handle!!!n"));
  290.         }
  291.         else
  292.         {
  293.             DBG_MSG(DBG_ERROR, ("GetCOMPort(): ValidateDosDevicePort() failed!!!n"));
  294.         }
  295.     }
  296.     
  297.     LcmLeaveSplSem();
  298.     return frc;
  299. } // GetCOMPort()
  300. BOOL
  301. ReleaseCOMPort(
  302.     __inout PINIPORT    pIniPort
  303.     )
  304. {
  305.     LcmEnterSplSem();
  306.     pIniPort->cRef--;
  307.     // we should always have a valid file handle
  308.     SPLASSERT(pIniPort->hFile != INVALID_HANDLE_VALUE);
  309.     DBG_MSG(DBG_TRACE,
  310.             ("ReleaseCOMPort(): cRef[%d] using FileHandle[%x]n", pIniPort->cRef, pIniPort->hFile) );
  311.     if (pIniPort->cRef > 0)
  312.     {
  313.         goto done;
  314.     }
  315.     CloseHandle(pIniPort->hFile);
  316.     pIniPort->hFile = INVALID_HANDLE_VALUE;
  317.     DBG_MSG(DBG_TRACE,
  318.             ("ReleaseCOMPort(): closed FileHandle[%x]n", pIniPort->hFile) );
  319.     if ( pIniPort->Status & PP_DOSDEVPORT )
  320.     {
  321.         (VOID)RemoveDosDeviceDefinition(pIniPort);
  322.     }
  323.     pIniPort->Status &= ~(PP_COMM_PORT | PP_DOSDEVPORT);
  324.     FreeSplStr(pIniPort->pDeviceName);
  325.     pIniPort->pDeviceName = NULL;
  326. done:
  327.     LcmLeaveSplSem();
  328.     return TRUE;
  329. } // ReleaseCOMPort