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

打印编程

开发平台:

Visual C++

  1. /*++
  2. Copyright (c) 1997-2003  Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5.     irda.c
  6. Abstract:
  7.     IRDA printing support in localmon
  8. --*/
  9. #include "precomp.h"
  10. #pragma hdrstop
  11. #include "irda.h"
  12. BOOL
  13. IsIRDAInstalled(
  14.     )
  15. {
  16.     BOOL        bRet = FALSE;
  17.     WORD        WSAVerReq = MAKEWORD(1,1);
  18.     SOCKET      hSock;
  19.     WSADATA     WSAData;
  20.     if ( WSAStartup(WSAVerReq, &WSAData) == ERROR_SUCCESS       &&
  21.          (hSock = socket(AF_IRDA, SOCK_STREAM, 0)) != INVALID_SOCKET ) {
  22.         closesocket(hSock);
  23.         bRet = TRUE;
  24.     }
  25.     WSACleanup();
  26.     return bRet;
  27. }
  28. VOID
  29. CheckAndAddIrdaPort(
  30.     __in PINILOCALMON    pIniLocalMon
  31.     )
  32. {
  33.     PINIPORT    pIniPort;
  34.     LcmEnterSplSem();
  35.     for ( pIniPort = pIniLocalMon->pIniPort ;
  36.           pIniPort && !IS_IRDA_PORT(pIniPort->pName) ;
  37.           pIniPort = pIniPort->pNext )
  38.     ;
  39.     LcmLeaveSplSem();
  40.     if ( pIniPort || !IsIRDAInstalled() )
  41.         return;
  42.     //
  43.     // Add the port to the list and write to registry
  44.     //
  45.     LcmCreatePortEntry(pIniLocalMon, szIRDA);
  46. }
  47. VOID
  48. CloseIrdaConnection(
  49.     __in    PINIPORT    pIniPort
  50.     )
  51. {
  52.     PIRDA_INFO  pIrda = (PIRDA_INFO) pIniPort->pExtra;
  53.     int ret = 0;
  54.     if ( (SOCKET)pIniPort->hFile != INVALID_SOCKET ) {
  55.         ret = closesocket((SOCKET)pIniPort->hFile);
  56.         pIniPort->hFile = (HANDLE)INVALID_SOCKET;
  57.     }
  58.     if ( pIrda ) {
  59.         //
  60.         // check if overlapped send is not complete yet
  61.         //
  62.         if ( pIrda->WsaOverlapped.hEvent )
  63.         {
  64.             //
  65.             // wait overlapped send to complete/cancel
  66.             //
  67.             if (ret == 0)
  68.             {
  69.                 WaitForSingleObject (pIrda-> WsaOverlapped.hEvent, 5*60*1000);
  70.             }
  71.             WSACloseEvent(pIrda->WsaOverlapped.hEvent);
  72.             pIrda-> WsaOverlapped.hEvent = NULL;
  73.         }
  74.         FreeSplMem(pIrda);
  75.         pIniPort->pExtra = NULL;
  76.     }
  77. }
  78. DWORD
  79. IrdaConnect(
  80.     __in    PINIPORT    pIniPort
  81.     )
  82. {
  83.     BOOL            bRet = FALSE;
  84.     WORD            WSAVerReq = MAKEWORD(1,1);
  85.     DWORD           dwIndex, dwNeeded = BUF_SIZE, dwEnableIrLPT = TRUE,
  86.                     dwLastError = ERROR_SUCCESS, dwSendPduLen;
  87.     LPSTR           pBuf = NULL;
  88.     WSADATA         WSAData;
  89.     SOCKET          Socket = INVALID_SOCKET;
  90.     IAS_QUERY       IasQuery;
  91.     PIRDA_INFO      pIrda;
  92.     PDEVICELIST     pDevList;
  93.     SOCKADDR_IRDA   PrinterAddr  = { AF_IRDA, 0, 0, 0, 0, "IrLPT" };
  94.     SPLASSERT(pIniPort->hFile == (HANDLE)INVALID_SOCKET && pIniPort->pExtra == NULL);
  95.     if ( dwLastError = WSAStartup(WSAVerReq, &WSAData) )
  96.         goto Done;
  97.     if ( !(pBuf = (LPSTR)AllocSplMem(dwNeeded)) ) {
  98.         dwLastError = GetLastError();
  99.         goto Done;
  100.     }
  101.     if ( (Socket = WSASocket(AF_IRDA, SOCK_STREAM, 0, NULL, 0,
  102.                              WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET    ||
  103.          getsockopt(Socket, SOL_IRLMP, IRLMP_ENUMDEVICES,
  104.                     (LPSTR)pBuf, (int *)&dwNeeded) == SOCKET_ERROR ) {
  105.         dwLastError = WSAGetLastError();
  106.         goto Done;
  107.     }
  108.     if ( dwNeeded > BUF_SIZE ) {
  109.         FreeSplMem(pBuf);
  110.         if ( !(pBuf = (LPSTR)AllocSplMem(dwNeeded)) ) {
  111.             dwLastError = GetLastError();
  112.             goto Done;
  113.         }
  114.         if ( getsockopt(Socket, SOL_IRLMP, IRLMP_ENUMDEVICES,
  115.                         (LPSTR)pBuf, (int *)&dwNeeded) == SOCKET_ERROR ) {
  116.             dwLastError = WSAGetLastError();
  117.             goto Done;
  118.         }
  119.     }
  120.     pDevList = (PDEVICELIST) pBuf;
  121.     //
  122.     // Any of the devices a printer?
  123.     //
  124.     for ( dwIndex = 0 ; dwIndex < pDevList->numDevice ; ++dwIndex ) {
  125.         if ( (pDevList->Device[dwIndex].irdaDeviceHints1 & PRINTER_HINT_BIT)  ||
  126.              (pDevList->Device[dwIndex].irdaDeviceHints2 & PRINTER_HINT_BIT) )
  127.             break;
  128.     }
  129.     //
  130.     // Any printers found?
  131.     //
  132.     if ( dwIndex == pDevList->numDevice ) {
  133.         dwLastError = ERROR_PRINTER_NOT_FOUND;
  134.         goto Done;
  135.     }
  136.     //
  137.     // Move printer's address into the socket address
  138.     //
  139.     memcpy(PrinterAddr.irdaDeviceID,
  140.            pDevList->Device[dwIndex].irdaDeviceID,
  141.            sizeof(PrinterAddr.irdaDeviceID));
  142.     dwIndex = 0;
  143.     dwNeeded = sizeof(dwSendPduLen);
  144.     bRet = SOCKET_ERROR != setsockopt(Socket,
  145.                                       SOL_IRLMP,
  146.                                       IRLMP_IRLPT_MODE,
  147.                                       (LPCSTR)&dwEnableIrLPT,
  148.                                       sizeof(dwEnableIrLPT))    &&
  149.            SOCKET_ERROR != connect(Socket,
  150.                                    (const struct sockaddr *)&PrinterAddr,
  151.                                    sizeof(PrinterAddr))         &&
  152.            SOCKET_ERROR != getsockopt(Socket,
  153.                                       SOL_IRLMP,
  154.                                       IRLMP_SEND_PDU_LEN,
  155.                                       (char *)&dwSendPduLen,
  156.                                       (int *)&dwNeeded) &&
  157.            SOCKET_ERROR != setsockopt(Socket,
  158.                                       SOL_SOCKET,
  159.                                       SO_SNDBUF,
  160.                                       (LPCSTR)&dwIndex,
  161.                                       sizeof(dwIndex));
  162.     if ( bRet ) {
  163.         SPLASSERT(pIniPort->pExtra == NULL);
  164.         dwNeeded = sizeof(IRDA_INFO) + dwSendPduLen;
  165.         if ( !(pIrda = (PIRDA_INFO) AllocSplMem(dwNeeded)) ) {
  166.             bRet = FALSE;
  167.             dwLastError = ERROR_NOT_ENOUGH_MEMORY;
  168.             goto Done;
  169.         }
  170.         pIniPort->hFile     = (HANDLE)Socket;
  171.         pIniPort->pExtra    = (LPBYTE)pIrda;
  172.         pIrda->dwSendPduLen = dwSendPduLen;
  173.         pIrda->pBuf         = ((LPBYTE) pIrda) + sizeof(IRDA_INFO);
  174.     } else
  175.         dwLastError = WSAGetLastError();
  176. Done:
  177.     FreeSplMem(pBuf);
  178.     if ( !bRet ) {
  179.         if ( Socket != INVALID_SOCKET )
  180.             closesocket(Socket);
  181.         FreeSplMem(pIniPort->pExtra);
  182.         pIniPort->pExtra = NULL;
  183.     }
  184.     return bRet ? ERROR_SUCCESS : dwLastError;
  185. }
  186. BOOL
  187. AbortThisJob(
  188.     __in    PINIPORT    pIniPort
  189.     )
  190. /*++
  191.         Tells if the job should be aborted. A job should be aborted if it has
  192.         been deleted or it needs to be restarted.
  193. --*/
  194. {
  195.     BOOL            bRet = FALSE;
  196.     DWORD           dwNeeded;
  197.     LPJOB_INFO_1    pJobInfo = NULL;
  198.     dwNeeded = 0;
  199.     GetJob(pIniPort->hPrinter, pIniPort->JobId, 1, NULL, 0, &dwNeeded);
  200.     if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  201.         goto Done;
  202.     if ( !(pJobInfo = (LPJOB_INFO_1) AllocSplMem(dwNeeded))     ||
  203.          !GetJob(pIniPort->hPrinter, pIniPort->JobId,
  204.                  1, (LPBYTE)pJobInfo, dwNeeded, &dwNeeded))
  205.         goto Done;
  206.     bRet = (pJobInfo->Status & JOB_STATUS_DELETING) ||
  207.            (pJobInfo->Status & JOB_STATUS_DELETED)  ||
  208.            (pJobInfo->Status & JOB_STATUS_RESTART);
  209. Done:
  210.     if ( pJobInfo )
  211.         FreeSplMem(pJobInfo);
  212.     return bRet;
  213. }
  214. VOID
  215. IrdaDisconnect(
  216.     __in    PINIPORT    pIniPort
  217.     )
  218. {
  219.     BOOL        bRet;
  220.     DWORD       dwRet, dwSent, dwFlags;
  221.     SOCKET      Socket = (SOCKET) pIniPort->hFile;
  222.     PIRDA_INFO  pIrda = (PIRDA_INFO) pIniPort->pExtra;
  223.     //
  224.     // If the job has already been cancelled close socket and quit
  225.     //
  226.     if ( Socket == INVALID_SOCKET )
  227.         goto Done;
  228.     //
  229.     // If a send is pending wait for all the data to go through indefinitly
  230.     //
  231.     if ( pIrda->WsaOverlapped.hEvent ) {
  232.         do {
  233.             dwRet = WaitForSingleObject(pIrda->WsaOverlapped.hEvent,
  234.                                         WRITE_TIMEOUT);
  235.             if ( dwRet == WAIT_TIMEOUT ) {
  236.                 //
  237.                 // If user has cancelled the job close connection
  238.                 //
  239.                 if ( AbortThisJob(pIniPort) )
  240.                     goto Done;
  241.             } else if ( dwRet != WAIT_OBJECT_0 )
  242.                 goto Done;
  243.         } while ( dwRet == WAIT_TIMEOUT );
  244.         //
  245.         // IRDA can only send the whole packet so we do not check dwSent
  246.         //
  247.     }
  248.     //
  249.     // No more sends
  250.     //
  251.     shutdown(Socket, SD_SEND);
  252. Done:
  253.     CloseIrdaConnection(pIniPort);
  254. }
  255. BOOL
  256. IrdaStartDocPort(
  257.     __inout PINIPORT    pIniPort
  258.     )
  259. {
  260.     HANDLE hToken;
  261.     DWORD  dwLastError;
  262.     //
  263.     // If remote guest is the first user to print, then the connect fails.
  264.     // Thus we need to revert to system context before calling IrdaConnect
  265.     //
  266.     hToken = RevertToPrinterSelf();
  267.     if (!hToken) {
  268.         return FALSE;
  269.     }
  270.     dwLastError = IrdaConnect(pIniPort);
  271.     ImpersonatePrinterClient(hToken);
  272.     if ( dwLastError ) {
  273.         SetLastError(dwLastError);
  274.         return FALSE;
  275.     } else
  276.         return TRUE;
  277. }
  278. BOOL
  279. IrdaWritePort(
  280.     __in                HANDLE      hPort,
  281.     __in_bcount(cbBuf)  LPBYTE      pBuf,
  282.                         DWORD       cbBuf,
  283.     __out               LPDWORD     pcbWritten
  284.     )
  285. {
  286.     INT             iRet = ERROR_SUCCESS;
  287.     DWORD           dwSent, dwFlags, dwTimeout, dwBuffered;
  288.     PINIPORT        pIniPort = (PINIPORT)hPort;
  289.     SOCKET          Socket = (SOCKET) pIniPort->hFile;
  290.     PIRDA_INFO      pIrda = (PIRDA_INFO)pIniPort->pExtra;
  291.     *pcbWritten = 0;
  292.     //
  293.     // When we have to close socket we fail the write.
  294.     // If anothe write comes through it is because user wanted to retry
  295.     //
  296.     if ( Socket == INVALID_SOCKET ) {
  297.         SPLASSERT(pIrda == NULL);
  298.         SetJob(pIniPort->hPrinter, pIniPort->JobId, 0, NULL, JOB_CONTROL_RESTART);
  299.         iRet = WSAENOTSOCK;
  300.         goto Done;
  301.     }
  302.     SPLASSERT(pIrda != NULL);
  303.     //
  304.     // This is the time spooler issued the write to us
  305.     //
  306.     pIrda->dwBeginTime = GetTickCount();
  307.     do {
  308.         //
  309.         // If event is non-NULL at the beginning we have a pending write from
  310.         // last WritePort call
  311.         //
  312.         if ( pIrda->WsaOverlapped.hEvent ) {
  313.             dwTimeout = GetTickCount() - pIrda->dwBeginTime;
  314.             //
  315.             // We want to wait for WRITE_TIMEOUT time from the time spooler
  316.             // issued the WritePort.
  317.             // If it is already more than that still check what happened to the
  318.             // write before returning
  319.             //
  320.             if ( dwTimeout > WRITE_TIMEOUT )
  321.                 dwTimeout = 0;
  322.             else
  323.                 dwTimeout = WRITE_TIMEOUT - dwTimeout;
  324.             //
  325.             // Let's wait for the timeout period for the last send to complete
  326.             //
  327.             if ( WAIT_OBJECT_0 != WaitForSingleObject(pIrda->WsaOverlapped.hEvent,
  328.                                                       dwTimeout) ) {
  329.                 iRet = ERROR_TIMEOUT;
  330.                 goto Done;
  331.             }
  332.             //
  333.             // What happened to the last send?
  334.             //
  335.             if ( WSAGetOverlappedResult(Socket, &pIrda->WsaOverlapped,
  336.                                         &dwSent, FALSE, &dwFlags) == FALSE ) {
  337.                 iRet = WSAGetLastError();
  338.                 CloseIrdaConnection(pIniPort);
  339.                 goto Done;
  340.             }
  341.             //
  342.             // IRDA can only send the whole packet so we do not check dwSent
  343.             //
  344.             //
  345.             // Reset the manual reset event and do the next send
  346.             //
  347.             WSAResetEvent(pIrda->WsaOverlapped.hEvent);
  348.             //
  349.             // Have we already sent all the data?
  350.             //
  351.             if ( cbBuf == 0 ) {
  352.                 WSACloseEvent(pIrda->WsaOverlapped.hEvent);
  353.                 pIrda->WsaOverlapped.hEvent = NULL;
  354.                 goto Done;
  355.             }
  356.         } else {
  357.             pIrda->WsaOverlapped.hEvent = WSACreateEvent();
  358.             if ( !pIrda->WsaOverlapped.hEvent ) {
  359.                 iRet = GetLastError();
  360.                 CloseIrdaConnection(pIniPort);
  361.                 goto Done;
  362.             }
  363.         }
  364.         do {
  365.             //
  366.             // Have we already sent all the data?
  367.             //
  368.             if ( cbBuf == 0 ) {
  369.                 WSACloseEvent(pIrda->WsaOverlapped.hEvent);
  370.                 pIrda->WsaOverlapped.hEvent = NULL;
  371.                 goto Done;
  372.             }
  373.             //
  374.             // Send no more than pIrda->dwSendPduLen
  375.             //
  376.             if ( cbBuf < pIrda->dwSendPduLen )
  377.                 dwBuffered = cbBuf;
  378.             else
  379.                 dwBuffered = pIrda->dwSendPduLen;
  380.             pIrda->WsaBuf.len   = dwBuffered;
  381.             pIrda->WsaBuf.buf   = (char *)pIrda->pBuf;
  382.             CopyMemory(pIrda->pBuf, pBuf, dwBuffered);
  383.             //
  384.             // We are asking a non-blocking send. Typically this will
  385.             // return with I/O pending
  386.             //
  387.             if ( WSASend(Socket, &pIrda->WsaBuf, 1, &dwSent,
  388.                          MSG_PARTIAL, &pIrda->WsaOverlapped, NULL) != NO_ERROR ) {
  389.                 iRet = WSAGetLastError();
  390.                 break;
  391.             }
  392.             pBuf        += dwSent;
  393.             cbBuf       -= dwSent;
  394.             *pcbWritten += dwSent;
  395.         } while ( iRet == NO_ERROR );
  396.         if ( iRet == WSA_IO_PENDING ) {
  397.             //
  398.             // Lie to spooler we sent the whole data. Next time we will find out
  399.             //
  400.             pBuf        += dwBuffered;
  401.             cbBuf       -= dwBuffered;
  402.             *pcbWritten += dwBuffered;
  403.             iRet = NO_ERROR;
  404.         } else {
  405.             DBG_MSG(DBG_ERROR, ("IrdaWritePort: WSASend failed %dn", iRet));
  406.             CloseIrdaConnection(pIniPort);
  407.         }
  408.     } while ( cbBuf && iRet == NO_ERROR );
  409. Done:
  410.     if ( iRet != ERROR_SUCCESS )
  411.         SetLastError(iRet);
  412.     return iRet == ERROR_SUCCESS;
  413. }
  414. VOID
  415. IrdaEndDocPort(
  416.     __in    PINIPORT    pIniPort
  417.     )
  418. {
  419.     IrdaDisconnect(pIniPort);
  420. }