home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / winnt / remote / remote.c < prev    next >
C/C++ Source or Header  |  1997-10-12  |  19KB  |  811 lines

  1.  
  2. /******************************************************************************\
  3. *       This is a part of the Microsoft Source Code Samples. 
  4. *       Copyright 1993 - 1997 Microsoft Corporation.
  5. *       All rights reserved. 
  6. *       This source code is only intended as a supplement to 
  7. *       Microsoft Development Tools and/or WinHelp documentation.
  8. *       See these sources for detailed information regarding the 
  9. *       Microsoft samples programs.
  10. \******************************************************************************/
  11.  
  12. /*++
  13.  
  14. Copyright 1993 - 1997 Microsoft Corporation
  15.  
  16. Module Name:
  17.  
  18.     Remote.c
  19.  
  20. Abstract:
  21.  
  22.     This module contains the main() entry point for Remote.
  23.     Calls the Server or the Client depending on the first parameter.
  24.  
  25.  
  26. Author:
  27.  
  28.     Rajivendra Nath  2-Jan-1993
  29.  
  30. Environment:
  31.  
  32.     Console App. User mode.
  33.  
  34. Revision History:
  35.  
  36. --*/
  37.  
  38.  
  39. #include <windows.h>
  40. #include <stdio.h>
  41. #include <stdlib.h>
  42. #include "Remote.h"
  43.  
  44. char   HostName[HOSTNAMELEN];
  45. char*  ChildCmd;
  46. char*  PipeName;
  47. char*  ServerName;
  48. char * DaclNames[ MAX_DACL_NAMES ];
  49. DWORD  DaclNameCount = 0;
  50. char * DaclDenyNames[ MAX_DACL_NAMES ];
  51. DWORD  DaclDenyNameCount = 0 ;
  52. HANDLE MyStdOut;
  53. HANDLE hAttachedProcess = INVALID_HANDLE_VALUE;
  54. HANDLE hAttachedWriteChildStdIn = INVALID_HANDLE_VALUE;
  55. HANDLE hAttachedReadChildStdOut = INVALID_HANDLE_VALUE;
  56.  
  57. BOOL   IsAdvertise;
  58. DWORD  ClientToServerFlag;
  59. BOOL   bForceTwoPipes;
  60.  
  61. char* ColorList[]={"black" ,"blue" ,"green" ,"cyan" ,"red" ,"purple" ,"yellow" ,"white",
  62.                    "lblack","lblue","lgreen","lcyan","lred","lpurple","lyellow","lwhite"};
  63.  
  64. WORD
  65. GetColorNum(
  66.     char* color
  67.     );
  68.  
  69. VOID
  70. SetColor(
  71.     WORD attr
  72.     );
  73.  
  74. BOOL
  75. GetNextConnectInfo(
  76.     char** SrvName,
  77.     char** PipeName
  78.     );
  79.  
  80.  
  81.  
  82. CONSOLE_SCREEN_BUFFER_INFO csbiOriginal;
  83.  
  84. main(
  85.     int    argc,
  86.     char** argv
  87.     )
  88. {
  89.     WORD  RunType;              // Server or Client end of Remote
  90.     DWORD len=HOSTNAMELEN;
  91.     int   i, FirstArg;
  92.  
  93.     char  sTitle[120];          // New Title
  94.     char  orgTitle[100];        // Old Title
  95.     BOOL  bPromptForArgs=FALSE; // Is /P option
  96.     WORD  wAttrib;              // Console Attributes
  97.     int   privacy;              // Allows exposing or hidng sessions to remote /q
  98.     BOOL  Deny ;
  99.  
  100.     GetComputerName((LPTSTR)HostName,&len);
  101.  
  102.     MyStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
  103.  
  104.     if (GetConsoleScreenBufferInfo(MyStdOut,&csbiOriginal)) {
  105.  
  106.         wAttrib = csbiOriginal.wAttributes;
  107.         GetConsoleTitle(orgTitle,sizeof(orgTitle));
  108.  
  109.     } else {
  110.  
  111.         //
  112.         // either stdout is a pipe, or it wasn't opened for
  113.         // GENERIC_READ along with GENERIC_WRITE, in which
  114.         // case our color manipulations will work so we need
  115.         // to pick default colors.
  116.         //
  117.  
  118.         wAttrib = FOREGROUND_GREEN |
  119.                   FOREGROUND_INTENSITY;
  120.  
  121.         orgTitle[0] = 0;
  122.     }
  123.  
  124.     privacy = PRIVACY_DEFAULT;
  125.  
  126.  
  127.  
  128.     //
  129.     // Parameter Processing
  130.     //
  131.     // For Server:
  132.     // Remote /S <Executable>  <PipeName> [Optional Params]
  133.     //
  134.     // For Client:
  135.     // Remote /C <Server Name> <PipeName> [Optional Params]
  136.     // or
  137.     // Remote /P
  138.     // This will loop continously prompting for different
  139.     // Servers and Pipename
  140.  
  141.  
  142.     if ((argc<2)||((argv[1][0]!='/')&&(argv[1][0]!='-')))
  143.     {
  144.  
  145.         DisplayServerHlp();
  146.         DisplayClientHlp();
  147.         return(1);
  148.     }
  149.  
  150.     switch(argv[1][1])
  151.     {
  152.     case 'c':
  153.     case 'C':
  154.  
  155.         //
  156.         // Is Client End of Remote
  157.         //
  158.  
  159.         if ((argc<4)||((argv[1][0]!='/')&&(argv[1][0]!='-')))
  160.         {
  161.  
  162.             DisplayServerHlp();
  163.             DisplayClientHlp();
  164.             return(1);
  165.         }
  166.  
  167.         ServerName=argv[2];
  168.         PipeName=argv[3];
  169.         FirstArg=4;
  170.         RunType=RUNTYPE_CLIENT;
  171.         break;
  172.  
  173.  
  174.     case 'q':
  175.     case 'Q':
  176.  
  177.         //
  178.         //  Query for possible conexions
  179.         //
  180.  
  181.  
  182.         if ((argc != 3)||((argv[1][0]!='/')&&(argv[1][0]!='-')))
  183.         {
  184.  
  185.             DisplayServerHlp();
  186.             DisplayClientHlp();
  187.             return(1);
  188.         }
  189.  
  190.         QueryRemotePipes(argv[2]);  //  Send ServerName as a param
  191.         return(0);
  192.  
  193.  
  194.     case 'p':
  195.     case 'P':
  196.  
  197.         //
  198.         // Is Client End of Remote
  199.         //
  200.  
  201.         bPromptForArgs=TRUE;
  202.         RunType=RUNTYPE_CLIENT;
  203.         FirstArg=2;
  204.         break;
  205.  
  206.  
  207.     case 's':
  208.     case 'S':
  209.         //
  210.         // Is Server End of Remote
  211.         //
  212.         if ((argc<4)||((argv[1][0]!='/')&&(argv[1][0]!='-')))
  213.         {
  214.  
  215.             DisplayServerHlp();
  216.             DisplayClientHlp();
  217.             return(1);
  218.         }
  219.  
  220.         ChildCmd=argv[2];
  221.         PipeName=argv[3];
  222.         FirstArg=4;
  223.  
  224.         RunType=REMOTE_SERVER;
  225.         break;
  226.  
  227.  
  228.     case 'a':
  229.     case 'A':
  230.         //
  231.         // Is Server End of Remote Attaching to existing process.
  232.         //
  233.         if ((argc<7)||((argv[1][0]!='/')&&(argv[1][0]!='-')))
  234.         {
  235.  
  236.             DisplayServerHlp();
  237.             DisplayClientHlp();
  238.             return(1);
  239.         }
  240.  
  241.         hAttachedProcess = (HANDLE) atoi(argv[2]);
  242.         hAttachedWriteChildStdIn = (HANDLE) atoi(argv[3]);
  243.         hAttachedReadChildStdOut = (HANDLE) atoi(argv[4]);
  244.         ChildCmd=argv[5]; // for display only
  245.         PipeName=argv[6];
  246.         FirstArg=7;
  247.  
  248.         RunType = REMOTE_SERVER;
  249.         privacy = PRIVACY_VISIBLE;  // presumably ntsd/*kd
  250.         break;
  251.  
  252.  
  253.     default:
  254.         DisplayServerHlp();
  255.         DisplayClientHlp();
  256.         return(1);
  257.     }
  258.  
  259.     if (RunType==REMOTE_SERVER)
  260.     {
  261.         //
  262.         // Base Name of Executable
  263.         // For setting the title
  264.         //
  265.  
  266.         char *tcmd=ChildCmd;
  267.  
  268.         while ((*tcmd!=' ')    &&(*tcmd!=0))   tcmd++;
  269.         while ((tcmd!=ChildCmd)&&(*tcmd!='\\'))tcmd--;
  270.         if (*tcmd=='\\') tcmd++;
  271.         sprintf(sTitle,"%-s  [Remote /C %s %s]",tcmd,HostName,PipeName);
  272.     }
  273.  
  274.     //
  275.     //Process Common (Optional) Parameters
  276.     //
  277.  
  278.     for (i=FirstArg;i<argc;i++)
  279.     {
  280.  
  281.         if ((argv[i][0]!='/')&&(argv[i][0]!='-'))
  282.         {
  283.             printf("Invalid parameter %s:Ignoring\n",argv[i]);
  284.             continue;
  285.         }
  286.  
  287.         switch(argv[i][1])
  288.         {
  289.         case 'l':    // Only Valid for client End
  290.         case 'L':    // Max Number of Lines to recieve from Server
  291.             i++;
  292.             if (i>=argc)
  293.             {
  294.                 printf("Incomplete Param %s..Ignoring\n",argv[i-1]);
  295.                 break;
  296.             }
  297.             LinesToSend=(DWORD)atoi(argv[i])+1;
  298.             break;
  299.  
  300.         case 't':    // Title to be set instead of the default
  301.         case 'T':
  302.             i++;
  303.             if (i>=argc)
  304.             {
  305.                 printf("Incomplete Param %s..Ignoring\n",argv[i-1]);
  306.                 break;
  307.             }
  308.             sprintf(sTitle,"%s",argv[i]);
  309.             break;
  310.  
  311.         case 'b':    // Background color
  312.         case 'B':
  313.             i++;
  314.             if (i>=argc)
  315.             {
  316.                 printf("Incomplete Param %s..Ignoring\n",argv[i-1]);
  317.                 break;
  318.             }
  319.             {
  320.                 WORD col=GetColorNum(argv[i]);
  321.                 if (col!=0xffff)
  322.                 {
  323.                     wAttrib=col<<4|(wAttrib&0x000f);
  324.                 }
  325.                 break;
  326.             }
  327.  
  328.         case 'f':    // Foreground color
  329.         case 'F':
  330.             i++;
  331.             if (i>=argc)
  332.             {
  333.                 printf("Incomplete Param %s..Ignoring\n",argv[i-1]);
  334.                 break;
  335.             }
  336.             {
  337.                 WORD col=GetColorNum(argv[i]);
  338.                 if (col!=0xffff)
  339.                 {
  340.                     wAttrib=col|(wAttrib&0x00f0);
  341.                 }
  342.                 break;
  343.             }
  344.  
  345.         case 'v':
  346.         case 'V':
  347.             privacy = PRIVACY_VISIBLE;
  348.             break;
  349.  
  350.         case '-':
  351.             if( (argv[i][2] == 'v')
  352.                 || (argv[i][2] == 'V'))
  353.                 privacy = PRIVACY_NOT_VISIBLE;
  354.             else
  355.                 printf("Unknown Parameter=%s %s\n",argv[i-1],argv[i]);
  356.             break;
  357.  
  358.         case 'q':
  359.         case 'Q':
  360.             ClientToServerFlag|=0x80000000;
  361.             break;
  362.  
  363.         case 'u':
  364.         case 'U':
  365.             if ( (argv[i][2] == 'd') ||
  366.                  (argv[i][2] == 'D' ) )
  367.             {
  368.                 Deny = TRUE ;
  369.             }
  370.             else
  371.             {
  372.                 Deny = FALSE ;
  373.             }
  374.  
  375.             i++ ;
  376.  
  377.             if ( i >= argc )
  378.             {
  379.                 printf( "Incomplete Param %s..Ignoring\n", argv[i-1] );
  380.                 break;
  381.             }
  382.  
  383.             if ( Deny )
  384.             {
  385.                 if (DaclDenyNameCount == MAX_DACL_NAMES )
  386.                 {
  387.                     printf("Too many names specified (max %d).  Ignoring user %s\n",
  388.                             MAX_DACL_NAMES, argv[i] );
  389.  
  390.                     break;
  391.                 }
  392.  
  393.                 DaclDenyNames[ DaclDenyNameCount++ ] = argv[i];
  394.  
  395.             }
  396.             else
  397.             {
  398.                 if (DaclNameCount == MAX_DACL_NAMES )
  399.                 {
  400.                     printf("Too many names specified (max %d).  Ignoring user %s\n",
  401.                             MAX_DACL_NAMES, argv[i] );
  402.  
  403.                     break;
  404.                 }
  405.  
  406.                 DaclNames[ DaclNameCount++ ] = argv[i];
  407.  
  408.             }
  409.  
  410.             break;
  411.  
  412.         case '2':
  413.             bForceTwoPipes = TRUE;
  414.             break;
  415.  
  416.         default:
  417.             printf("Unknown Parameter=%s %s\n",argv[i-1],argv[i]);
  418.             break;
  419.  
  420.         }
  421.  
  422.     }
  423.  
  424.     //
  425.     //Now Set various Parameters
  426.     //
  427.  
  428.     //
  429.     //Colors
  430.     //
  431.  
  432.     SetColor(wAttrib);
  433.  
  434.     if (RunType==RUNTYPE_CLIENT)
  435.     {
  436.         BOOL done=FALSE;
  437.         BOOL gotinfo;
  438.  
  439.         //
  440.         // Set Client end defaults and start client
  441.         //
  442.  
  443.         while(!done)
  444.         {
  445.             if (!bPromptForArgs ||
  446.                 (gotinfo = GetNextConnectInfo(&ServerName,&PipeName))
  447.                )
  448.             {
  449.                 sprintf(sTitle,"Remote /C %s %s",ServerName,PipeName);
  450.                 SetConsoleTitle(sTitle);
  451.  
  452.                 //
  453.                 // Start Client (Client.C)
  454.                 //
  455.                 Client(ServerName,PipeName);
  456.             }
  457.             done = !bPromptForArgs || !gotinfo;
  458.         }
  459.     }
  460.  
  461.     if (RunType==REMOTE_SERVER)
  462.     {
  463.         if (privacy == PRIVACY_VISIBLE ||
  464.              (privacy == PRIVACY_DEFAULT && IsKdString(ChildCmd))) {
  465.  
  466.             sprintf(sTitle, "%s visible", sTitle);
  467.             IsAdvertise = TRUE;
  468.         }
  469.  
  470.         SetConsoleTitle(sTitle);
  471.  
  472.         i = OverlappedServer(ChildCmd, PipeName);
  473.     }
  474.  
  475.     //
  476.     //Reset Colors
  477.     //
  478.     SetColor(csbiOriginal.wAttributes);
  479.     SetConsoleTitle(orgTitle);
  480.  
  481.     return i;
  482. }
  483.  
  484. /*************************************************************/
  485. VOID
  486. ErrorExit(
  487.     char* str
  488.     )
  489. {
  490.     extern PSZ pszPipeName;
  491.     DWORD dwErr;
  492.  
  493.     dwErr = GetLastError();
  494.  
  495.     printf("REMOTE error %d: %s\n", dwErr, str);
  496.  
  497.     #if DBG
  498.     {
  499.         char szMsg[1024];
  500.  
  501.         sprintf(szMsg, "REMOTE error %d: %s\n", dwErr, str);
  502.         OutputDebugString(szMsg);
  503.  
  504.         if (pszPipeName) {               // ad-hoc:  if server
  505.             if (IsDebuggerPresent()) {
  506.                 DebugBreak();
  507.             }
  508.         }
  509.     }
  510.     #endif
  511.  
  512.     exit(1);
  513. }
  514.  
  515. /*************************************************************/
  516. VOID
  517. DisplayClientHlp()
  518. {
  519.     printf("\n"
  520.            "   To Start the CLIENT end of REMOTE\n"
  521.            "   ---------------------------------\n"
  522.            "   Syntax : REMOTE /C <ServerName> <Unique Id> [Param]\n"
  523.            "   Example: REMOTE /C %s imbroglio\n"
  524.            "            This would connect to a server session on %s with Id\n"
  525.            "            \"imbroglio\" if there is a REMOTE /S <\"Cmd\"> imbroglio\n"
  526.            "            running on %s.\n\n"
  527.            "   To Exit: %cQ (Leaves the Remote Server Running)\n"
  528.            "   [Param]: /L <# of Lines to Get>\n"
  529.            "   [Param]: /F <Foreground color eg blue, lred..>\n"
  530.            "   [Param]: /B <Background color eg cyan, lwhite..>\n"
  531.            "\n"
  532.            "   To Query the visible sessions on a server\n"
  533.            "   -----------------------------------------\n"
  534.            "   Syntax:  REMOTE /Q %s\n"
  535.            "            This would retrieve the available <Unique Id>s\n"
  536.            "            visible connections on the computer named %s.\n"
  537.            "\n",
  538.            HostName, HostName, HostName, COMMANDCHAR, HostName, HostName);
  539. }
  540. /*************************************************************/
  541.  
  542. VOID
  543. DisplayServerHlp()
  544. {
  545.     printf("\n"
  546.            "   To Start the SERVER end of REMOTE\n"
  547.            "   ---------------------------------\n"
  548.            "   Syntax : REMOTE /S <\"Cmd\">     <Unique Id> [Param]\n"
  549.            "   Example: REMOTE /S \"i386kd -v\" imbroglio\n"
  550.            "            To interact with this \"Cmd\" from some other machine,\n"
  551.            "            start the client end using:  REMOTE /C %s imbroglio\n\n"
  552.            "   To Exit: %cK \n"
  553.            "   [Param]: /F  <Foreground color eg yellow, black..>\n"
  554.            "   [Param]: /B  <Background color eg lblue, white..>\n"
  555.            "   [Param]: /U  username or groupname\n"
  556.            "                specifies which users or groups may connect\n"
  557.            "                may be specified more than once, e.g\n"
  558.            "                /U user1 /U group2 /U user2\n"
  559.            "   [Param]: /UD username or groupname\n"
  560.            "                specifically denies access to that user or group\n"
  561.            "   [Param]: /V  Makes this session visible to remote /Q\n"
  562.            "   [Param]: /-V Hides this session from remote /q (invisible)\n"
  563.            "                By default, if \"Cmd\" looks like a debugger,\n"
  564.            "                the session is visible, otherwise not\n"
  565.            "\n",
  566.            HostName, COMMANDCHAR);
  567. }
  568.  
  569. WORD
  570. GetColorNum(
  571.     char *color
  572.     )
  573. {
  574.     int i;
  575.  
  576.     _strlwr(color);
  577.     for (i=0;i<16;i++)
  578.     {
  579.         if (strcmp(ColorList[i],color)==0)
  580.         {
  581.             return(i);
  582.         }
  583.     }
  584.     return ((WORD)atoi(color));
  585. }
  586.  
  587. VOID
  588. SetColor(
  589.     WORD attr
  590.     )
  591. {
  592.     COORD  origin={0,0};
  593.     DWORD  dwrite;
  594.     FillConsoleOutputAttribute
  595.     (
  596.         MyStdOut,attr,csbiOriginal.dwSize.
  597.         X*csbiOriginal.dwSize.Y,origin,&dwrite
  598.     );
  599.     SetConsoleTextAttribute(MyStdOut,attr);
  600. }
  601.  
  602. BOOL
  603. GetNextConnectInfo(
  604.     char** SrvName,
  605.     char** PipeName
  606.     )
  607. {
  608.     char *s;
  609.     static char szServerName[64];
  610.     static char szPipeName[32];
  611.  
  612.     try
  613.     {
  614.         ZeroMemory(szServerName,64);
  615.         ZeroMemory(szPipeName,32);
  616.         SetConsoleTitle("Remote - Prompting for next Connection");
  617.         printf("Debugger machine (server): ");
  618.         fflush(stdout);
  619.  
  620.         if (((*SrvName=gets(szServerName))==NULL)||
  621.              (strlen(szServerName)==0))
  622.         {
  623.             return(FALSE);
  624.         }
  625.  
  626.         if (szServerName[0] == COMMANDCHAR &&
  627.             (szServerName[1] == 'q' || szServerName[1] == 'Q')
  628.            )
  629.         {
  630.             return(FALSE);
  631.         }
  632.  
  633.         if (s = strchr( szServerName, ' ' )) {
  634.             *s++ = '\0';
  635.             while (*s == ' ') {
  636.                 s += 1;
  637.             }
  638.             *PipeName=strcpy(szPipeName, s);
  639.             printf(szPipeName);
  640.             fflush(stdout);
  641.         }
  642.         if (strlen(szPipeName) == 0) {
  643.             printf("Target machine (pipe)    : ");
  644.             fflush(stdout);
  645.             if ((*PipeName=gets(szPipeName))==NULL)
  646.             {
  647.                 return(FALSE);
  648.             }
  649.         }
  650.  
  651.         if (s = strchr(szPipeName, ' ')) {
  652.             *s++ = '\0';
  653.         }
  654.  
  655.         if (szPipeName[0] == COMMANDCHAR &&
  656.             (szPipeName[1] == 'q' || szPipeName[1] == 'Q')
  657.            )
  658.         {
  659.             return(FALSE);
  660.         }
  661.         printf("\n\n");
  662.     }
  663.  
  664.     except(EXCEPTION_EXECUTE_HANDLER)
  665.     {
  666.         return(FALSE);  // Ignore exceptions
  667.     }
  668.     return(TRUE);
  669. }
  670.  
  671.  
  672. /*************************************************************/
  673.  
  674. VOID
  675. Errormsg(
  676.     char* str
  677.     )
  678. {
  679.     printf("Error (%d) - %s\n",GetLastError(),str);
  680. }
  681.  
  682. /*************************************************************/
  683.  
  684. BOOL
  685. IsKdString(
  686.     char* string
  687.     )
  688. {
  689.  
  690.     char* start;
  691.  
  692.     //
  693.     // some heuristic for uninvented yet platforms
  694.     // if the first word has "kd" in it ok
  695.     //
  696.  
  697.     if(    ((start = strstr(string, "kd")) != NULL)
  698.         || ((start = strstr(string, "dbg")) != NULL)
  699.         || ((start = strstr(string, "remoteds")) != NULL)
  700.         || ((start = strstr(string, "ntsd")) != NULL)
  701.         || ((start = strstr(string, "cdb")) != NULL) )
  702.     {
  703.         // is it in the first word?
  704.         while(--start > string)
  705.         {
  706.             if((*start == ' ') || (*start == '\t'))
  707.             {
  708.                 while(--start > string)
  709.                     if((*start != '\t') || (*start != ' '))
  710.                         return(FALSE);
  711.             }
  712.         }
  713.         return TRUE;
  714.     }
  715.     return(FALSE);
  716. }
  717.  
  718.  
  719. //
  720. // WriteFileSynch is a synchronous WriteFile for overlapped
  721. // file handles.  As a special case, two-pipe client operation
  722. // sets fAsyncPipe FALSE and this routine then passes NULL
  723. // for lpOverlapped.
  724. //
  725.  
  726. BOOL
  727. FASTCALL
  728. WriteFileSynch(
  729.     HANDLE  hFile,
  730.     LPVOID  lpBuffer,
  731.     DWORD   cbWrite,
  732.     LPDWORD lpNumberOfBytesWritten,
  733.     DWORD   dwFileOffset,
  734.     LPOVERLAPPED lpO
  735.     )
  736. {
  737.     BOOL Success;
  738.  
  739.  
  740.     lpO->OffsetHigh = 0;
  741.     lpO->Offset = dwFileOffset;
  742.  
  743.     Success =
  744.         WriteFile(
  745.             hFile,
  746.             lpBuffer,
  747.             cbWrite,
  748.             lpNumberOfBytesWritten,
  749.             fAsyncPipe ? lpO : NULL
  750.             );
  751.  
  752.     if ( ! Success ) {
  753.  
  754.         if (ERROR_IO_PENDING == GetLastError()) {
  755.  
  756.             Success =
  757.                 GetOverlappedResult(
  758.                     hFile,
  759.                     lpO,
  760.                     lpNumberOfBytesWritten,
  761.                     TRUE
  762.                     );
  763.         }
  764.     }
  765.  
  766.     return Success;
  767. }
  768.  
  769.  
  770. BOOL
  771. FASTCALL
  772. ReadFileSynch(
  773.     HANDLE  hFile,
  774.     LPVOID  lpBuffer,
  775.     DWORD   cbRead,
  776.     LPDWORD lpNumberOfBytesRead,
  777.     DWORD   dwFileOffset,
  778.     LPOVERLAPPED lpO
  779.     )
  780. {
  781.     BOOL Success;
  782.  
  783.     lpO->OffsetHigh = 0;
  784.     lpO->Offset = dwFileOffset;
  785.  
  786.     Success =
  787.         ReadFile(
  788.             hFile,
  789.             lpBuffer,
  790.             cbRead,
  791.             lpNumberOfBytesRead,
  792.             fAsyncPipe ? lpO : NULL
  793.             );
  794.  
  795.     if ( ! Success ) {
  796.  
  797.         if (ERROR_IO_PENDING == GetLastError()) {
  798.  
  799.             Success =
  800.                 GetOverlappedResult(
  801.                     hFile,
  802.                     lpO,
  803.                     lpNumberOfBytesRead,
  804.                     TRUE
  805.                     );
  806.         }
  807.     }
  808.  
  809.     return Success;
  810. }
  811.