home *** CD-ROM | disk | FTP | other *** search
/ PC Press 1997 July / Sezamfile97_2.iso / windows / program / ttychic.exe / NEWDIAL.C < prev    next >
Text File  |  1994-12-01  |  23KB  |  563 lines

  1. #include <stdlib.h>
  2. #include <memory.h>
  3. #include <malloc.h>
  4.  
  5. #include "session.h"
  6.  
  7.  
  8. BOOL SetupConnection();
  9. SESSIONINFO     sinfo;
  10. /* thread control mask */
  11. DWORD ThreadControl;
  12.  
  13.  
  14. /* The dialInitialize function encapsulates the three TAPI functions (lineInitialize,
  15.         lineNegotiateAPIVersion, lineOpenrequired) to obtain
  16.         a handle to a line. Once you have a line handle you can then dial or answer
  17.         calls on that line. */
  18.  
  19. LONG dialInitialize (HINSTANCE hInst, HWND hWnd)
  20. {
  21. LONG lResult;                                           /* Stores return code from TAPI calls */
  22. MSG msg;                                                        /* Identifies a message */
  23. DWORD tc = GetTickCount();              /* Timer */
  24. DWORD dwLine;
  25. LINEEXTENSIONID lineExtensionID;    /* Will be set to 0 to indicate no known extensions */
  26.  
  27.         /* zero out the SESSION INFO structure */
  28.         memset (&sinfo, 0, sizeof(SESSIONINFO));
  29.  
  30.     /* initialize tapi */
  31.     /* hLineAPP will get loaded with the application's handle to TAPI */
  32.     /* Are SESSIONINSTANCE/NAME/WINDOW from other code?*/
  33.     /* One of the main functions of lineIntitialize is to tell TAPI the name
  34.         of the call back function it should use when sending messages to your
  35.         application. */
  36.  
  37.         sinfo.lpfnCallback = LineCallBackProc;
  38.     lstrcpy (SESSIONNAME(), "Mailer");
  39.     SESSIONINSTANCE() = hInst;
  40.         SESSIONWINDOW() = hWnd;
  41.  
  42.     while ((lResult = lineInitialize(&sinfo.hApp, SESSIONINSTANCE(),
  43.             (LINECALLBACK)MakeProcInstance((FARPROC)sinfo.lpfnCallback,
  44.             SESSIONINSTANCE()), SESSIONNAME(),
  45.             &sinfo.dwNumLines)) == LINEERR_REINIT)   {
  46.  
  47.                 /* TBD - remove for Chicago */
  48.                 /* multitask */
  49.         if (PeekMessage(&msg,0,0,0,PM_REMOVE)) {
  50.             TranslateMessage(&msg);
  51.             DispatchMessage(&msg);
  52.         } /* if */
  53.  
  54.                 /* wait five seconds, then ask if they want to retry */
  55.         if (GetTickCount() - tc >= 5000) {
  56.             if (MessageBox(SESSIONWINDOW(),
  57.                         "Telephone System Is Reinitializing - Cancel to abort",
  58.                         "Error - TAPI Initialization Failed",
  59.                     MB_RETRYCANCEL) == IDCANCEL)
  60.                 break;
  61.  
  62.             tc = GetTickCount();
  63.         } /* end if */
  64.     } /* end while */
  65.  
  66.         /* error initializing telephone API */
  67.     if (lResult <0)
  68.         return lResult;
  69.  
  70.     SESSIONINITIALIZED() = TRUE;
  71.  
  72.         /* if no lines, bomb */
  73.     if (SESSIONNUMLINES() == 0) {
  74.                 lResult = SESSIONERR_NOLINES;
  75.                 goto errout;
  76.         } /* end if (no line devices found) */
  77.  
  78.         sinfo.lpLineDevCaps = (LPLINEDEVCAPS) malloc (sizeof(LINEDEVCAPS)+1000);
  79.         if (!sinfo.lpLineDevCaps)
  80.                 goto errout;
  81.         SESSIONDEVCAPSALLOCED() = TRUE;
  82.  
  83.         /* zero out the structures */
  84.         memset (sinfo.lpLineDevCaps, 0, sizeof(LINEDEVCAPS));
  85.  
  86.     /* open each line for monitoring and find one that supports LINEMEDIAMODE_DATAMODEM */
  87.     for (dwLine = 0; dwLine < SESSIONNUMLINES(); ++dwLine) {
  88.  
  89.         /* negotiate API version for each line */
  90.         lResult = lineNegotiateAPIVersion(SESSIONAPPHANDLE(), dwLine, TAPIVERSION,
  91.                     TAPIVERSION, &sinfo.dwAPIVersion, &lineExtensionID);
  92.         if (lResult)
  93.             goto errout;
  94.  
  95.                 lResult = dialGetDevCaps(dwLine);
  96.                 /* if error, bomb */
  97.         if (lResult) {
  98.                         goto errout;
  99.         } /* if */
  100.  
  101.                 /* check for supported media mode.  If not datamodem, continue to next line */
  102.                 if (!(sinfo.lpLineDevCaps->dwMediaModes & LINEMEDIAMODE_DATAMODEM))
  103.                         continue;
  104.  
  105.         /* open the line that supports data modems */
  106.         lResult = lineOpen(SESSIONAPPHANDLE(), dwLine, &sinfo.hLine, SESSIONAPIVERSION(),
  107.                                                         0L, (DWORD) 0L, LINECALLPRIVILEGE_OWNER,
  108.                                                         LINEMEDIAMODE_DATAMODEM, NULL);
  109.  
  110.                 /* if error, try next line */
  111.         if (lResult) {
  112.                         continue;
  113.         } /* if */
  114.  
  115.                 SESSIONLINEID()= dwLine;
  116.                 SESSIONLINEOPEN() = TRUE;
  117.  
  118.                 /* if we are here then we found a compatible line */
  119.                 break;
  120.  
  121.         } /* end for (each supported line) */
  122.  
  123.         return 0;
  124.  
  125. errout:
  126.         if (SESSIONINITIALIZED()) {
  127.                 lineShutdown (SESSIONAPPHANDLE());
  128.                 SESSIONINITIALIZED() = FALSE;
  129.         }
  130.         if (SESSIONDEVCAPSALLOCED()) {
  131.         free (sinfo.lpLineDevCaps);
  132.                 SESSIONDEVCAPSALLOCED() = FALSE;
  133.         }
  134.         if (SESSIONLINEOPEN()) {
  135.                 lineClose (SESSIONLINEHANDLE());
  136.                 SESSIONLINEOPEN() = FALSE;
  137.         }
  138.  
  139. } /* end function (dialInitialize) */
  140.  
  141. /* dialGetDevCaps - wrapper for lineGetDevCaps */
  142. LONG dialGetDevCaps (DWORD dwLine)
  143. {
  144. LONG lResult;
  145.  
  146.         /* get line capability info */
  147.         sinfo.lpLineDevCaps->dwTotalSize = sizeof(LINEDEVCAPS)+1000;
  148.         lResult = lineGetDevCaps(SESSIONAPPHANDLE(), dwLine,
  149.                 SESSIONAPIVERSION(), 0, sinfo.lpLineDevCaps);
  150.         if (lResult)
  151.                 return lResult;
  152.  
  153.     /* reallocate buffer if not big enough */
  154.     while (sinfo.lpLineDevCaps->dwNeededSize > sinfo.lpLineDevCaps->dwTotalSize) {
  155.                 DWORD lcbNeeded = sinfo.lpLineDevCaps->dwNeededSize;
  156.  
  157.             free((LPVOID)sinfo.lpLineDevCaps);
  158.             if ((sinfo.lpLineDevCaps = (LPLINEDEVCAPS) malloc((size_t)lcbNeeded))
  159.                     == NULL)
  160.                                 return LINEERR_NOMEM;
  161.             sinfo.lpLineDevCaps->dwTotalSize = lcbNeeded;
  162.  
  163.             /* try again */
  164.                         lResult = lineGetDevCaps(SESSIONAPPHANDLE(), dwLine,
  165.                 SESSIONAPIVERSION(), 0, sinfo.lpLineDevCaps);
  166.                         if (lResult == LINEERR_STRUCTURETOOSMALL)
  167.                                 continue;
  168.                         else if (lResult)
  169.                                 return lResult;
  170.         } /* while */
  171.  
  172.         return 0;
  173. } /* end function (dialGetDevCaps) */
  174.  
  175. /* dialMakeCall - wrapper for lineMakeCall */
  176. LONG dialMakeCall (char *szDestination)
  177. {
  178. LINECALLPARAMS callparams;
  179. LONG lResult;
  180.  
  181.         /* if already connected or in a pending state, do nothing */
  182.         if (SESSIONCONNECTED() || SESSIONPENDINGASYNC())
  183.                 return -1;
  184.  
  185.         /* zero out the structures */
  186.         memset (&callparams, 0, sizeof(LINECALLPARAMS));
  187.  
  188.         /* set call parameters */
  189.         callparams.dwBearerMode =       LINEBEARERMODE_VOICE;
  190.         callparams.dwMediaMode  =       LINEMEDIAMODE_DATAMODEM;
  191.         callparams.dwTotalSize = sizeof(LINECALLPARAMS);
  192.  
  193.  
  194.     lResult = lineMakeCall (SESSIONLINEHANDLE(), &sinfo.hCall, szDestination, 0, &callparams);
  195.  
  196.         if (lResult<0)
  197.                 return lResult;
  198.         else
  199.                 SESSIONPENDINGASYNC() = lResult;
  200.  
  201.         SESSIONMAKECALLINPROGRESS() = TRUE;
  202.  
  203.         return 0;
  204.  
  205. } /* end function (dialMakeCall) */
  206.  
  207.  
  208. /* dialDropCall - wrapper for lineDrop */
  209. LONG dialDropCall ()
  210. {
  211. LONG lResult;
  212.  
  213.         /* if not already connected, do nothing */
  214.         if (SESSIONCALLSTATE() == LINECALLSTATE_IDLE)
  215.                 return -1;
  216.  
  217.         /* close the device handle */
  218.         if (SESSIONDEVICEHANDLE())
  219.                 CloseHandle (SESSIONDEVICEHANDLE());
  220.         SESSIONDEVICEHANDLE() = NULL;
  221.  
  222.         lResult = lineDrop (SESSIONCALLHANDLE(), NULL, 0);
  223.  
  224.         SESSIONPENDINGASYNC() = lResult;
  225.         SESSIONDROPCALLINPROGRESS() = TRUE;
  226.  
  227. /* believe it or not, lineDrop is returning 0 syncronously with Unimodem! */
  228. if (!lResult) {
  229.         /* do what Unimodem should be doing */
  230.         LineCallBackProc((DWORD)SESSIONCALLHANDLE(), LINE_CALLSTATE,
  231.            0, LINECALLSTATE_IDLE, 0, 0);
  232. }
  233.  
  234.         return lResult;
  235.  
  236. } /* end function (dialDropCall) */
  237.  
  238.  
  239. /* dialLineClose - wrapper for lineClose */
  240. LONG dialLineClose ()
  241. {
  242. LONG lResult;
  243.  
  244.         if (!SESSIONLINEHANDLE())
  245.                 return -1;
  246.  
  247.         lResult = lineClose (SESSIONLINEHANDLE());
  248.  
  249.         SESSIONLINEOPEN() = FALSE;
  250.         SESSIONLINEHANDLE() = NULL;
  251.  
  252.         return lResult;
  253.  
  254. } /* end function (dialLineClose) */
  255.  
  256. /* dialDeallocCall - wrapper for lineDeallocCall */
  257. LONG dialDeallocCall ()
  258. {
  259. LONG lResult;
  260.  
  261.         if (!SESSIONCALLHANDLE())
  262.                 return -1;
  263.  
  264.         lResult = lineDeallocateCall (SESSIONCALLHANDLE());
  265.  
  266.         SESSIONCALLHANDLE() = NULL;
  267.  
  268.         return lResult;
  269.  
  270. } /* end function (dialDeallocCall) */
  271.  
  272.  
  273.  
  274. /* callback function */
  275. void FAR PASCAL LineCallBackProc(DWORD hDevice,DWORD dwMessage,
  276.            DWORD dwInstance,DWORD dwParam1,DWORD dwParam2,DWORD dwParam3)
  277. {
  278. COMMTIMEOUTS cto;
  279.  
  280.     switch (dwMessage)
  281.         {
  282.         case LINE_LINEDEVSTATE:
  283.             break;
  284.         /* process state transition */
  285.         case LINE_CALLSTATE:
  286.  
  287.                         SESSIONCALLSTATE()= dwParam1;
  288.  
  289.             if (SESSIONMAKECALLINPROGRESS()) {
  290.                                 if (SESSIONCALLHANDLE() == NULL)
  291.                                         SESSIONCALLHANDLE() = (HCALL) hDevice;
  292.                                 switch (dwParam1) {
  293.                                         case LINECALLSTATE_CONNECTED:
  294.                                                 SESSIONMAKECALLINPROGRESS() = FALSE;
  295.                                                 SESSIONCONNECTED() = TRUE;
  296.                                                 /* get the id of the COM device connected to the modem */
  297.                                                 SESSIONDEVICEHANDLE() = GetCommHandle(SESSIONCALLHANDLE(), SESSIONDEVICENAME());
  298.                                                 if (SESSIONCONNECTED( ) && SESSIONDEVICEHANDLE() )      {
  299.                                           if (!SetupConnection())
  300.                                                 MessageBox(NULL, "Settings failed!", "Mailer",
  301.                                         MB_ICONEXCLAMATION ) ;
  302.                                           cto.ReadIntervalTimeout = 50;
  303.                                                           cto.ReadTotalTimeoutMultiplier = 20;
  304.                                                           cto.ReadTotalTimeoutConstant = 200;
  305.                                                           cto.WriteTotalTimeoutMultiplier = 20;
  306.                                                           cto.WriteTotalTimeoutConstant = 200;
  307.                                                           SetCommTimeouts (SESSIONDEVICEHANDLE(), &cto);}
  308.                                                 sinfo.wOrigin = 1;              /* outbound call */
  309.                                                 return;
  310.                                 } /* end switch (on callstate) */
  311.                         } /* end if (making a call) */
  312.  
  313.             if (SESSIONANSWERCALLINPROGRESS()) {
  314.                                 if (SESSIONCALLHANDLE() == NULL)
  315.                                         SESSIONCALLHANDLE() = (HCALL) hDevice;
  316.                                 switch (dwParam1) {
  317.                                         case LINECALLSTATE_CONNECTED:
  318.                                                 SESSIONANSWERCALLINPROGRESS() = FALSE;
  319.                                                 SESSIONCONNECTED() = TRUE;
  320.                                                 /* get the id of the COM device connected to the modem */
  321.                                                 SESSIONDEVICEHANDLE() = GetCommHandle(SESSIONCALLHANDLE(), SESSIONDEVICENAME());
  322.                                // if SESSIONDEVICEHANDLE() and SESSIONCONNECTED(), set new COM parameters
  323.                                            if (SESSIONCONNECTED( ) && SESSIONDEVICEHANDLE() )   {
  324.                                                                 /* set communication params */
  325.                                           if (!SetupConnection())
  326.                                                 MessageBox( NULL, "Settings failed!", "Mailer",
  327.                                         MB_ICONEXCLAMATION ) ;
  328.                                                           cto.ReadIntervalTimeout = 50;
  329.                                                           cto.ReadTotalTimeoutMultiplier = 20;
  330.                                                           cto.ReadTotalTimeoutConstant = 200;
  331.                                                           cto.WriteTotalTimeoutMultiplier = 20;
  332.                                                           cto.WriteTotalTimeoutConstant = 200;
  333.                                                           SetCommTimeouts (SESSIONDEVICEHANDLE(), &cto);
  334.                                 }
  335.                                                 sinfo.wOrigin = 2;              /* inbound call */
  336.                                                 return;
  337.                                 } /* end switch (on callstate) */
  338.                         } /* end if (answering a call) */
  339.  
  340.  
  341.                         switch (dwParam1) {
  342.                                 case LINECALLSTATE_BUSY:
  343.                                 case LINECALLSTATE_DISCONNECTED:
  344.                                 case LINECALLSTATE_IDLE:
  345.                                         /* bug fix for disconnected which comes after idle and Unimodem needs this to
  346.                                         reset correctly */
  347.                                         dialDropCall ();
  348.                                         dialDeallocCall();
  349.                     //dialLineClose();
  350.                                         SESSIONANSWERCALLINPROGRESS() = FALSE;
  351.                                         SESSIONDROPCALLINPROGRESS() = FALSE;
  352.                                         SESSIONMAKECALLINPROGRESS() = FALSE;
  353.                                         SESSIONCONNECTED() = FALSE;
  354.                                         return;
  355.  
  356.                                 case LINECALLSTATE_OFFERING:
  357.                                 /* The call is being offered, signaling the arrival
  358.                                  of a  new call.  check if we are the owner of the call, and if we are,
  359.                                  then answer it. */
  360.                                         if (dwParam3 == LINECALLPRIVILEGE_OWNER) {
  361.                                                 if ((SESSIONPENDINGASYNC() =
  362.                                                                 lineAnswer (SESSIONCALLHANDLE() = (HCALL)hDevice, NULL, 0)) < 0) {
  363.                                                         SESSIONCALLHANDLE() = (HCALL) NULL;
  364.                                                         SESSIONPENDINGASYNC() = 0;
  365.                                                         return;
  366.                                                 }
  367.                                         } /* end if (we own this call) */
  368.                                         SESSIONANSWERCALLINPROGRESS() = TRUE;
  369.                                         break;
  370.                         } /* end switch (on call state) */
  371.             break;
  372.         case LINE_CLOSE:
  373.             break;
  374.         case LINE_REPLY:
  375.             if (SESSIONPENDINGASYNC() != dwParam1)
  376.                 break;
  377.  
  378.             if (SESSIONANSWERCALLINPROGRESS()) {/* reply message for lineAnswer */
  379.                                         if ((LONG)dwParam2 != 0)
  380.                                                 SESSIONANSWERCALLINPROGRESS() = FALSE;
  381.                                         SESSIONPENDINGASYNC() = 0;
  382.             } /* end if (answer call in progress) */
  383.  
  384.             if (SESSIONMAKECALLINPROGRESS()) {/* reply message for lineMakeCall */
  385.                                         if ((LONG)dwParam2 != 0)
  386.                                                 SESSIONMAKECALLINPROGRESS() = FALSE;
  387.                                         SESSIONPENDINGASYNC() = 0;
  388.             } /* end if (make call in progress) */
  389.  
  390.             if (SESSIONDROPCALLINPROGRESS()) {
  391.                                 if ((LONG)dwParam2 != 0)
  392.                                         SESSIONDROPCALLINPROGRESS() = FALSE;
  393.                                 SESSIONPENDINGASYNC() = 0;
  394.                         } /* end if (drop call in progress) */
  395.  
  396.             break;
  397.  
  398.         /* other messages that can be processed */
  399.         case LINE_ADDRESSSTATE:
  400.             break;
  401.         case LINE_CALLINFO:
  402.             break;
  403.         case LINE_DEVSPECIFIC:
  404.             break;
  405.         case LINE_DEVSPECIFICFEATURE:
  406.             break;
  407.         case LINE_GATHERDIGITS:
  408.             break;
  409.         case LINE_GENERATE:
  410.             break;
  411.         case LINE_MONITORDIGITS:
  412.             break;
  413.         case LINE_MONITORMEDIA:
  414.             break;
  415.         case LINE_MONITORTONE:
  416.             break;
  417.         } /* switch */
  418.  
  419. } /* LineCallBackProc */
  420.  
  421.  
  422. HANDLE GetCommHandle (HCALL htCall, char *szDeviceName)
  423. {
  424. CommID FAR *cid;
  425. VARSTRING  *vs;
  426. LONG lrc;
  427. DWORD dwSize;
  428.  
  429.         vs = (VARSTRING *) malloc (sizeof(VARSTRING));
  430.         vs->dwTotalSize = sizeof(VARSTRING);
  431.         vs->dwStringFormat = STRINGFORMAT_BINARY;
  432.  
  433.         do {
  434.                 /* get Win32 Comm handle associated with the call -  the call handle
  435.                 came from TAPI after making or answering a call */
  436.                 /* another Unimodem bug - should return structuretoosmall but instead returns
  437.                 success with needed > total */
  438.                 if ( ((lrc = lineGetID(NULL, 0L, htCall, LINECALLSELECT_CALL, vs, "comm/datamodem")) == LINEERR_STRUCTURETOOSMALL)
  439.                                 || (vs->dwTotalSize < vs->dwNeededSize)) {
  440.                         dwSize= (lrc==LINEERR_STRUCTURETOOSMALL) ? (1000) : (vs->dwNeededSize);
  441.                         free (vs);
  442.                         vs = (VARSTRING *) malloc(dwSize);
  443.                         vs->dwTotalSize = dwSize;
  444.                 } /* end if (need more space) */
  445.                 else if (lrc < 0) {
  446.                         /* handle error */
  447.                 } /* end if (error getting comm device handle) */
  448.                 else
  449.                         break; /* success  */
  450.         } while (TRUE);
  451.  
  452.         cid = (CommID FAR *) ((LPSTR)vs + vs->dwStringOffset);
  453.         lstrcpy (szDeviceName, &cid->szDeviceName[0]);
  454.  
  455.         return cid->hComm;
  456.  
  457. } /* end function (GetCommHandle) */
  458.  
  459.  
  460. /* Reading With Polling */
  461. DWORD ReadBytesFromModem(BYTE *abyBuffer, DWORD *pnBytes)
  462. {
  463. DWORD dwErrorMask;                      /* mask of error bits */
  464. COMSTAT comstat;                        /* status structure */
  465. DWORD nToRead;                          /* number of bytes to read */
  466.  
  467.         *pnBytes = 0;           /* zero read size */
  468.         /* get status of read and write queues */
  469.         ClearCommError (SESSIONDEVICEHANDLE(), &dwErrorMask, &comstat);
  470.         /* check error flags */
  471.         if (dwErrorMask) {
  472.                 /* handle error */
  473.                 return dwErrorMask;
  474.         } /* end if (error) */
  475.  
  476.         /* if too many bytes to read, just read the maximum */
  477.         if (comstat.cbInQue > MAXREADSIZE)
  478.                 nToRead = MAXREADSIZE;
  479.         else
  480.                 nToRead = comstat.cbInQue; /* otherwise read them all */
  481.  
  482.         /* if no bytes to read, return */
  483.         if (nToRead == 0)
  484.                 return 0L;
  485.  
  486.         /* read the bytes */
  487.         if (!ReadFile(SESSIONDEVICEHANDLE(), abyBuffer, nToRead, pnBytes, NULL)) {
  488.                 return GetLastError ();
  489.         } /* end if (error reading bytes) */
  490.  
  491.         return 0L;
  492.  
  493. } /* end function (ReadBytesFromModem) */
  494.  
  495.  
  496. /* write a potentially large block of data to the modem */
  497. int WriteBytesToModem(BYTE *abyByteBuffer, DWORD nToWrite)
  498. {
  499. DWORD dwErrorMask;                      /* mask of error bits */
  500. COMSTAT comstat;                        /* status structure */
  501. DWORD nActualWrite;                     /* actual num bytes written */
  502.  
  503.         do {
  504.                 /* get status TX queue */
  505.                 ClearCommError (SESSIONDEVICEHANDLE(), &dwErrorMask, &comstat);
  506.                 if (dwErrorMask) return -1;
  507.                 /* if we are under the minimum threshold of the TX queue */
  508.                 if (comstat.cbOutQue < LOWWATER) {
  509.                         /* if there is room, write æem all */
  510.                         if (LOWWATER+ nToWrite <= MAXTXSIZE) {
  511.                                 WriteFile (SESSIONDEVICEHANDLE(), abyByteBuffer, nToWrite,
  512.                                         &nActualWrite, NULL);
  513.                                 nToWrite -= nActualWrite;
  514.                                 (BYTE *)abyByteBuffer += nActualWrite;
  515.                         } /* end if (room for all the bytes in TX buf) */
  516.                         /* if too many bytes to write at once, just fill TX buf and loop */
  517.                         if (LOWWATER + nToWrite > MAXTXSIZE){
  518.                                 WriteFile (SESSIONDEVICEHANDLE(), abyByteBuffer,
  519.                                         MAXTXSIZE-comstat.cbOutQue,
  520.                                         &nActualWrite, NULL);
  521.                                 nToWrite -= nActualWrite;
  522.                                 (BYTE *)abyByteBuffer += nActualWrite;
  523.                         } /* end if (canÆt fit all the bytes in the TX queue) */
  524.                 } /* end if (bytes in output queue below minimum level) */
  525.         } while (nToWrite);
  526.  
  527.         return 0;
  528.  
  529. } /* end function (WriteBytesToModem) */
  530.  
  531. /* Read the file into a buffer
  532. */
  533. LONG BufferFile (char *szFileName, LPBYTE *ppBuffer, LPDWORD pnFileSize)
  534. {
  535. DWORD dwSize;
  536.  
  537.         if ((SESSIONSENDFILEHANDLE()=CreateFile (szFileName, GENERIC_READ, 0 /* no sharing */,
  538.                                         NULL /* default security */, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  539.                                         NULL /* no template */)) == INVALID_HANDLE_VALUE) {
  540.                 return -1;
  541.         } /* error opening file */
  542.  
  543.         if ((dwSize = GetFileSize (SESSIONSENDFILEHANDLE(), NULL)) == -1) {
  544.                 CloseHandle (SESSIONSENDFILEHANDLE());
  545.                 return -1;
  546.         } /* end if (error getting file size) */
  547.  
  548.         if ((*ppBuffer = malloc (dwSize)) == NULL) {
  549.                 CloseHandle (SESSIONSENDFILEHANDLE());
  550.                 return -1;
  551.         } /* end if (error allocating file buffer) */
  552.  
  553.         if (!ReadFile (SESSIONSENDFILEHANDLE(), *ppBuffer, dwSize, pnFileSize, NULL)) {
  554.                 CloseHandle (SESSIONSENDFILEHANDLE());
  555.                 free (*ppBuffer);
  556.                 return -1;
  557.         } /* end if (error reading file into buffer) */
  558.  
  559.         return 0;
  560.  
  561. } /* end function (BufferFile) */
  562.  
  563.