home *** CD-ROM | disk | FTP | other *** search
/ Tutto per Internet / Internet.iso / soft95 / Varie / server / runner.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-04  |  21.6 KB  |  698 lines

  1. /****************************************************************************
  2. *
  3. *
  4. *    PROGRAM: WebRunner.c
  5. *
  6. *    PURPOSE: Example of Internet Server Application
  7. *
  8. *  Exports:
  9. *
  10. *  BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
  11. *
  12. *   As per the Web Server API Spec, this just returns the
  13. *   version of the spec that this server was built with.  This
  14. *   function is prototyped in httpext.h
  15. *
  16. *   BOOL WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)
  17. *
  18. *   This function does all of the work.  Once called it retrieves all of
  19. *   the environment data from the server via the GetServerVariable
  20. *   callback function, and reads all of the client data if it's not already
  21. *   available. Then it processes the request.
  22. ****************************************************************************/
  23.  
  24. // Standart includes
  25.  
  26. #include <windows.h>
  27. #include <httpext.h>
  28. #include <wininet.h>
  29. #include "runner.h"
  30.  
  31. // Variables 
  32.                         
  33. HANDLE hHeapHandle = 0;
  34.  
  35. /****************************************************************************
  36. *
  37. *    FUNCTION: GetExtensionVersion
  38. *
  39. *    PURPOSE: Standart procedure which needs to be exported from the DLL.
  40. *
  41. *    COMMENTS:   Will be called by the server.
  42. *
  43. ****************************************************************************/
  44.  
  45. BOOL WINAPI GetExtensionVersion (HSE_VERSION_INFO *pVer)
  46. {
  47.     pVer->dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
  48.  
  49.     lstrcpyn(pVer->lpszExtensionDesc,
  50.                   "Sample Internet Web Server WebRunner Application",
  51.                   HSE_MAX_EXT_DLL_NAME_LEN );
  52.  
  53.     return TRUE;
  54. } // GetExtensionVersion()
  55.  
  56.  
  57.  
  58. /****************************************************************************
  59. *
  60. *    FUNCTION:   HttpExtensionProc
  61. *
  62. *    PURPOSE: Standart procedure which needs to be exported from the DLL.
  63. *
  64. *    COMMENTS:   Will be called by the server.
  65. *
  66. ****************************************************************************/
  67.  
  68. DWORD WINAPI HttpExtensionProc (EXTENSION_CONTROL_BLOCK *pECB)
  69. {
  70.     CHAR        szBuff[4096];
  71.     CHAR        *lpszQuery;
  72.     CHAR        *lpszTemp = NULL;
  73.     CHAR        *lpszTemp2 = NULL;
  74.     CHAR         *szTempBuff2 = NULL;
  75.     CHAR        *lpszListBox = NULL;
  76.     CHAR        *szTemp1 = NULL;
  77.     CHAR        *szTemp2 = NULL; 
  78.       LPSTR       lpszTempBuff1;
  79.       BOOL        bAdmin; 
  80.     DWORD    dwLen;
  81.      DWORD    cbQuery;
  82.      int              cReturn=0,     cTab = 0;
  83.  
  84.     wsprintf ( szBuff,
  85.                  "<html>\n"
  86.                  "Content-Type: text/html\r\n"
  87.                  "\r\n"
  88.                 "<head><title>WebRunner</title></head>\n"
  89.                 "<body><h1>Welcome to WebRunner.</h1>\n"
  90.                 "<hr>\n");
  91.  
  92.     dwLen = lstrlen ( szBuff );
  93.     pECB -> ServerSupportFunction ( pECB -> ConnID,
  94.             HSE_REQ_SEND_RESPONSE_HEADER, "200 OK", &dwLen, ( LPDWORD ) 
  95.             szBuff );
  96.  
  97.     // We need to read registry to retreive mode (admin or user) and 
  98.     // available commands
  99.     if (    !(  lpszListBox = ReadRegistry ( &bAdmin ) ) )
  100.     {
  101.         // We could not retreive registry settings.
  102.           wsprintf ( szBuff, "Registry settings are corrupted!<br>\r\n" );
  103.         dwLen = lstrlen ( szBuff );
  104.         pECB -> WriteClient ( pECB -> ConnID, szBuff, &dwLen, dwLen );
  105.         return HSE_STATUS_ERROR;
  106.     }
  107.     else
  108.         lstrcpy (szBuff, "<h4>Mode:    " );
  109.  
  110.  
  111.     // Note: we can use PUT on any Web page constructed below. 
  112.     // Refer to HTML documentation in differences between GET and PUT.
  113.  
  114.     if ( bAdmin ) 
  115.     {
  116.         // We are in the administrator mode. User can enter any command.
  117.         // We need to draw  Web Page with the edit box on it.
  118.         // We don't specify any hardcoded path for runner.dll. It will allow 
  119.         // us to keep this dll us to keep this dll in any directory in the run
  120.         //  time.
  121.  
  122.         lstrcat ( szBuff, "administrator</h4><br><h2>To run your command " );
  123.         lstrcat ( szBuff, "please enter it here:</h2><p><form  " );
  124.          lstrcat ( szBuff, "action=\"runner.dll\" method=get><INPUT NAME= " );
  125.            lstrcat ( szBuff, "\"COMMAND\" VALUE=\"\" ><BR><input " );
  126.         lstrcat ( szBuff, "    type=\"submit\" value=\"Submit Entry\"><input " );
  127.         lstrcat ( szBuff, "type=\"reset\" value=\"Reset Form\">"  );
  128.          lstrcat ( szBuff, "</form><p><h2>Output:</h2><p><hr><pre> " );
  129.         dwLen = lstrlen ( szBuff );
  130.         pECB -> WriteClient ( pECB -> ConnID, szBuff, &dwLen, dwLen );
  131.     }
  132.     else
  133.     { 
  134.         // We are in the user mode. User can only enter command from the list 
  135.         // box. We need to draw  Web Page with the list box on it.
  136.           
  137.          lstrcat ( szBuff, "user</h4><br><h2> Please choose command to run:");
  138.         lstrcat ( szBuff, "</h2><p><form action=\"runner.dll\" method=get> ");
  139.         lstrcat ( szBuff, "    <SELECT NAME=\"COMMAND\" SIZE=3>");
  140.          dwLen = lstrlen(szBuff);
  141.         pECB -> WriteClient ( pECB -> ConnID, szBuff, &dwLen, dwLen);
  142.  
  143.         // Now we will output items of the list box.   lpszListBox  has been 
  144.         // retrieved from the registry before.
  145.         dwLen=lstrlen(lpszListBox);
  146.         pECB->WriteClient(pECB->ConnID, lpszListBox, &dwLen, dwLen);
  147.         
  148.         lstrcpy ( szBuff,"<p></SELECT><input type=\"submit\" value=\"Submit ");
  149.         lstrcat ( szBuff,"Entry\"><input type=\"reset\" value=\"Reset Form\">");
  150.         lstrcat ( szBuff,"</form><p><h2>Output:</h2><p><hr><pre>");
  151.         dwLen = lstrlen ( szBuff );
  152.         pECB -> WriteClient ( pECB -> ConnID, szBuff, &dwLen, dwLen);
  153.               
  154.      }
  155.  
  156.     if ( !stricmp ( pECB -> lpszMethod, "get") )
  157.         // GET
  158.         lpszQuery = pECB->lpszQueryString;          
  159.     else 
  160.     {                                                  
  161.         // POST
  162.         if ( pECB -> cbTotalBytes == 0)                   
  163.         {
  164.             // No Query at all
  165.                 wsprintf ( szBuff, "You command was empty<br>\r\n" );
  166.             dwLen = lstrlen ( szBuff );
  167.             pECB -> WriteClient ( pECB -> ConnID, szBuff, &dwLen, dwLen );
  168.             return HSE_STATUS_ERROR;
  169.         }
  170.         else
  171.         {
  172.             // Start processing of input information here.
  173.             if( ! ( lpszTemp = ( CHAR * ) LocalAlloc ( LPTR, 
  174.                                           pECB -> cbTotalBytes ) ) )    
  175.                 return HSE_STATUS_ERROR;
  176.             strcpy ( lpszTemp,  ( CHAR * ) pECB -> lpbData );
  177.             if ( ( cbQuery = pECB -> cbTotalBytes - pECB -> cbAvailable) > 0 )
  178.                 pECB -> ReadClient ( pECB -> ConnID,  ( LPVOID ) 
  179.                               ( lpszTemp + pECB -> cbAvailable ), &cbQuery );
  180.             //
  181.             // For POST requests, two terminating characters are added to the 
  182.             // end of the data. Ignore them by placing a null in the string.
  183.             //
  184.             * ( lpszTemp + pECB -> cbTotalBytes - 2 ) = '\0';
  185.             lpszQuery = lpszTemp;
  186.         }
  187.     }
  188.  
  189.     // At  this point   lpszQuery  has a full parametr string supplied to the 
  190.     // server.  We will need to parse this string to get a value assosiated 
  191.     // with the  "COMMAND". We will then execute this command. 
  192.     // Acctual command will be stored in lpszTemp2
  193.  
  194.      lpszTemp2 = GetParamValue ( lpszQuery, "COMMAND" );
  195.      LocalFree ( lpszTemp ); 
  196.      
  197.  
  198.     
  199.     if(lpszTemp2)
  200.     {
  201.         // Server was supplied with the acctual command.
  202.         // Do all processing here.
  203.         // We need to spoofing verification for user mode only. 
  204.         // Since user can fake a list box on the page and supply not 
  205.         // authorized command to execute, we need to check if this 
  206.         // command in the registry.
  207.  
  208.         if ((! strstr ( lpszListBox, lpszTemp2 ) ) && !bAdmin )
  209.         {
  210.             wsprintf (szBuff, 
  211.                       "<h2>Command: <i>%s</i> is not in the list box. %s%s%s",
  212.                       lpszTemp2, "<br>You are not authorized to run it.",
  213.                       "<br>\r\n", ENDPAGE);   
  214.             dwLen = lstrlen ( szBuff );
  215.             pECB -> WriteClient ( pECB -> ConnID, szBuff, &dwLen, dwLen );
  216.             pECB -> ServerSupportFunction ( pECB -> ConnID, 
  217.                           HSE_REQ_DONE_WITH_SESSION, "200 OK", 
  218.                           NULL, NULL );
  219.             return HSE_STATUS_SUCCESS;
  220.         }
  221.         // We need to deallocate registry buffer when we done with it.
  222.            // Spoofing verification was the last time when we used it.
  223.  
  224.         LocalFree ( ( HLOCAL ) lpszListBox ); 
  225.  
  226.         // Now it is time to execute the command.
  227.         // lpszTempBuff1 is a pointer to command output buffer. 
  228.         dwLen = RunApp ( lpszTemp2, ( LPSTR * ) &lpszTempBuff1 );
  229.  
  230.         if ( !dwLen )
  231.         {
  232.              lstrcpy ( szBuff, "Create failed<br>\r\n" );    
  233.             dwLen = lstrlen ( szBuff );
  234.             pECB -> WriteClient ( pECB -> ConnID, szBuff, 
  235.                           &dwLen, dwLen);
  236.             return HSE_STATUS_ERROR;
  237.         }
  238.         {
  239.             // We need to strip all enter character to avoid empty 
  240.             // lines in the command output. We will use <pre></pre>
  241.             // tags to simulate exact output text on the Web page.
  242.             DWORD i;
  243.             for ( i = 0; i < dwLen; i++ ) 
  244.                 if ( lpszTempBuff1 [i] == '\r' ) 
  245.                     lpszTempBuff1[i] = ' ';
  246.         }
  247.         pECB -> WriteClient ( pECB -> ConnID, lpszTempBuff1, &dwLen, dwLen );
  248.         dwLen = lstrlen ( ENDPAGE );
  249.         pECB -> WriteClient ( pECB -> ConnID, ENDPAGE, &dwLen, dwLen );
  250.         pECB -> ServerSupportFunction( pECB->ConnID,
  251.                       HSE_REQ_DONE_WITH_SESSION, "200 OK", NULL, NULL );
  252.     }
  253.     else
  254.     {
  255.         // If we are here then one of two situation a had place
  256.         // 1. HTML file did not have a COMMAND value.
  257.         // This is only the case it HTML was manualy edited incorrectly.
  258.         // 2. Emty command was emtpy.
  259.         wsprintf ( szBuff, " There is no COMMAND field in HTML source"
  260.                                      " or empty command was entered<br>\r\n" );
  261.         dwLen = lstrlen ( szBuff );
  262.         pECB -> WriteClient ( pECB -> ConnID, szBuff, &dwLen, dwLen );
  263.         return HSE_STATUS_ERROR;
  264.     }
  265.     FreeOutBuffer(lpszTempBuff1);
  266.     return HSE_STATUS_SUCCESS;
  267. }   // End of Program.
  268.  
  269.  
  270.  
  271. /****************************************************************************
  272. *
  273. *    FUNCTION: GetParamValue
  274. *
  275. *    PURPOSE: This function return value assosiated with lpszParam in the
  276. *                lpszQuery string.
  277. *
  278. *    COMMENTS: 
  279. *              If  lpszQuery   does not have  lpszParam  in it or no value
  280. *             is assisiated with with  lpszParam  NULL will be return.
  281. *             Example: 
  282. *               lpszQuery [ ] = "COMMAND1=Test1&COMMAND2=Test2"
  283. *                 lpszParam [ ] = "COMMAND2"
  284. *                  Return string: Test2
  285. *
  286. *
  287. ****************************************************************************/
  288.  
  289. CHAR * GetParamValue(CHAR *lpszQuery, CHAR *lpszParam)
  290. {
  291.  
  292.     CHAR *pValueStart = NULL;
  293.     CHAR *pValueEnd = NULL;
  294.     CHAR *lpszValue = NULL;
  295.     CHAR *szTemp1 = NULL;
  296.      ULONG cbValue;
  297.  
  298.     //
  299.     // Find the value passed in by the client for some particular 
  300.     // parameter within the query string. 
  301.     //
  302.     // Don't forget to free the returned new string!
  303.     //
  304.  
  305.     //
  306.     // First we find the occurance of the parameter, add the length of the
  307.     // parameter name, and then add one for the "=" character put between
  308.     // the parameter and the value; this locates the value.
  309.     //
  310.  
  311.     pValueStart = strstr ( lpszQuery, lpszParam );
  312.     if ( ! pValueStart )            // parameter doesn't exist
  313.         return NULL;
  314.  
  315.     pValueStart += strlen ( lpszParam ) + 1;
  316.   
  317.     //
  318.     // Now determine the length of the value string.
  319.     //
  320.  
  321.     pValueEnd = strchr(pValueStart, '&');
  322.     if (pValueEnd)        
  323.         // if this wasn't the last param in the list
  324.         cbValue = pValueEnd - pValueStart;
  325.     else    
  326.         // this was the last param in the list
  327.         cbValue = strlen(pValueStart);
  328.  
  329.     // Return NULL if we  have zero lenght string.
  330.     if ( !cbValue ) return NULL;
  331.     if ( ! ( lpszValue = (CHAR *) LocalAlloc ( LPTR, cbValue + 1 ) ) )  
  332.         return NULL;
  333.     strncat ( lpszValue, pValueStart, cbValue ); 
  334.  
  335.     // Finally lpszValue has needed value.
  336.  
  337.  
  338.     //
  339.     // Now replace "+" characters with " " characters adn
  340.     // "%xx" (hexadecemal) to the ASCII representation.
  341.     // 
  342.  
  343.     szTemp1 = lpszValue;
  344.     while ( * szTemp1 )
  345.     {
  346.         if ( *szTemp1 ==  '+' )  *szTemp1 = ' ';
  347.         szTemp1++;
  348.     }
  349.     EscapeToAscii(lpszValue);
  350.     return lpszValue;
  351. } // GetParamValue
  352.  
  353.  
  354.  
  355. /****************************************************************************
  356. *
  357. *    FUNCTION: EscapeToAscii
  358. *
  359. *    PURPOSE: This function calls HexToAscii for each occurance of %xx in the 
  360. *              parametr string.
  361. *
  362. *    COMMENTS: 
  363. *
  364. ****************************************************************************/
  365.  
  366. void EscapeToAscii (CHAR *lpEscape) 
  367. {
  368.     int i, j;
  369.     for (i = 0, j = 0; lpEscape [j] ; ++i, ++j ) 
  370.     {
  371.         if ( ( lpEscape [i] = lpEscape [j] ) == '%' ) 
  372.         {
  373.             lpEscape [ i ] = HexToAscii ( &lpEscape [j+1] );
  374.             j+=2;
  375.         }
  376.     }
  377.     lpEscape[i] = '\0';
  378. }
  379.  
  380.  
  381. /****************************************************************************
  382. *
  383. *    FUNCTION: HexToAscii
  384. *
  385. *    PURPOSE: This function will replace %xx (hexadecemal) symbols to the 
  386. *              ASCII representation by calling HexToAscii .
  387. *
  388. *    COMMENTS: 
  389. *
  390. ****************************************************************************/
  391.  
  392. CHAR HexToAscii ( CHAR *lpString) 
  393. {
  394.   CHAR CH;
  395.   CH = ( lpString [0] >= 'A' ? ( ( lpString [0] & 0xDF ) - 'A' ) + 10 :  
  396.        ( lpString [0] - '0' ) );
  397.   CH *= 16;
  398.   CH += ( lpString [1] >= 'A' ? ( ( lpString [1] & 0xDF ) - 'A' ) + 10 :  
  399.        ( lpString [1] - '0' ) );
  400.   return(CH);
  401. }
  402.  
  403. /****************************************************************************
  404. *
  405. *    FUNCTION: RunApp
  406. *
  407. *    PURPOSE: Starts a process to run the command line specified
  408. *
  409. *    COMMENTS:
  410. *
  411. *
  412. ****************************************************************************/
  413. DWORD RunApp(LPSTR input, LPSTR * output)
  414. {
  415.     STARTUPINFO StartupInfo;
  416.     PROCESS_INFORMATION ProcessInfo;
  417.     SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), 
  418.                               NULL,   // NULL security descriptor
  419.                               TRUE};  // Inherit handles (necessary!)
  420.     HANDLE hReadHandle, hWriteHandle, hErrorHandle;
  421.     LPSTR outputbuffer, lpOutput;
  422.     DWORD AvailableOutput;
  423.     BOOL TimeoutNotReached = TRUE;
  424.     DWORD BytesRead;
  425.     OVERLAPPED PipeOverlapInfo = {0,0,0,0,0};
  426.  
  427.     // Create the heap if it doesn't already exist
  428.     if (hHeapHandle == 0)
  429.     {
  430.         if ((hHeapHandle = HeapCreate(0,
  431.                                  8192,
  432.                                  0)) == NULL) return 0;
  433.     }
  434.     
  435.     // Create buffer to receive stdout output from our process
  436.     if ((outputbuffer = HeapAlloc(hHeapHandle,
  437.                              HEAP_ZERO_MEMORY,
  438.                              4096)) == NULL) return 0;
  439.     *output = outputbuffer;
  440.  
  441.     // Check input parameter
  442.     if (input == NULL)
  443.     {
  444.         lstrcpy(outputbuffer, "RUNAPP ERROR: No command line specified");
  445.         return lstrlen(outputbuffer);
  446.     }
  447.  
  448.     // Zero init process startup struct
  449.     FillMemory(&StartupInfo, sizeof(StartupInfo), 0);
  450.  
  451.     StartupInfo.cb = sizeof(StartupInfo);
  452.     StartupInfo.dwFlags = STARTF_USESTDHANDLES;  // Use the our stdio handles
  453.     
  454.     // Create pipe that will xfer process' stdout to our buffer
  455.     if (!CreatePipe(&hReadHandle,
  456.                    &hWriteHandle,
  457.                    &sa,
  458.                    0)) 
  459.     {
  460.         lstrcpy(outputbuffer, "RUNAPP ERROR: Could not redirect STDIO");
  461.         return lstrlen(outputbuffer);
  462.     }
  463.     // Set process' stdout to our pipe
  464.     StartupInfo.hStdOutput = hWriteHandle;
  465.     
  466.     // We are going to duplicate our pipe's write handle
  467.     // and pass it as stderr to create process.  The idea
  468.     // is that some processes have been known to close
  469.     // stderr which would also close stdout if we passed
  470.     // the same handle.  Therefore we make a copy of stdout's
  471.     // pipe handle.
  472.     if (!DuplicateHandle(GetCurrentProcess(),
  473.                     hWriteHandle,
  474.                     GetCurrentProcess(),
  475.                     &hErrorHandle,
  476.                     0,
  477.                     TRUE,
  478.                     DUPLICATE_SAME_ACCESS))
  479.     {
  480.         lstrcpy(outputbuffer,"RUNAPP ERROR: Could not duplicate STDIO handle");
  481.         return lstrlen(outputbuffer);
  482.     }
  483.     StartupInfo.hStdError = hErrorHandle;
  484.  
  485.     // Initialize our OVERLAPPED structure for our I/O pipe reads
  486.     PipeOverlapInfo.hEvent = CreateEvent(NULL,
  487.                                          TRUE,
  488.                                          FALSE,
  489.                                          NULL);
  490.     if (PipeOverlapInfo.hEvent == NULL)
  491.     {
  492.         lstrcpy(outputbuffer, "RUNAPP ERROR: Could not create I/O Event");
  493.         return lstrlen(outputbuffer);
  494.     }
  495.  
  496.     // Create the Process!
  497.     if (!CreateProcess(NULL,                 // name included in command line
  498.                       input,                 // Command Line
  499.                       NULL,                     // Default Process Sec. Attribs
  500.                       NULL,                     // Default Thread Sec. Attribs
  501.                       TRUE,                     // Inherit stdio handles
  502.                       NORMAL_PRIORITY_CLASS, // Creation Flags
  503.                       NULL,                     // Use this process' environment
  504.                       NULL,                     // Use the current directory
  505.                       &StartupInfo,
  506.                       &ProcessInfo))
  507.     {
  508.         lstrcpy(outputbuffer, "RUNAPP ERROR: Could not create process");
  509.         return lstrlen(outputbuffer);
  510.     }
  511.  
  512.     // lpOutput is moving output pointer
  513.     lpOutput = outputbuffer;
  514.     AvailableOutput = HeapSize(hHeapHandle,
  515.                                0,
  516.                                outputbuffer);
  517.     // Close the write end of our pipe (both copies)
  518.     // so it will die when the child process terminates
  519.     CloseHandle(hWriteHandle);
  520.     CloseHandle(hErrorHandle);
  521.  
  522.     while (TimeoutNotReached)
  523.     {
  524.         // Keep a read posted on the output pipe
  525.         if (ReadFile(hReadHandle,
  526.                 lpOutput,
  527.                 AvailableOutput,
  528.                 &BytesRead,
  529.                 &PipeOverlapInfo) == TRUE)
  530.         {
  531.             // Already received data...adjust buffer pointers
  532.             AvailableOutput-=BytesRead;
  533.             lpOutput += BytesRead;
  534.             if (AvailableOutput == 0)
  535.             {
  536.                 // We used all our buffer,  allocate more
  537.                 LPSTR TempBufPtr = HeapReAlloc(hHeapHandle,
  538.                                          HEAP_ZERO_MEMORY,
  539.                                          outputbuffer,
  540.                                          HeapSize(hHeapHandle,
  541.                                                   0,
  542.                                                   outputbuffer) + 4096);
  543.  
  544.                 if (TempBufPtr == NULL)
  545.                 {
  546.                     // Copy error message to end of buffer
  547.                     lstrcpy(outputbuffer 
  548.                             + HeapSize(hHeapHandle,0, outputbuffer) 
  549.                             - lstrlen(MEMERROR) - 1, 
  550.                             MEMERROR);
  551.                     return lstrlen(outputbuffer);
  552.                 }
  553.                 // Fix pointers in case ouir buffer moved
  554.                 outputbuffer = TempBufPtr;
  555.                 lpOutput = outputbuffer + BytesRead;
  556.                 AvailableOutput = HeapSize(hHeapHandle, 0, outputbuffer) - BytesRead;
  557.                 *output = outputbuffer;
  558.             }
  559.         }
  560.         else
  561.         {
  562.             // Switch on ReadFile result
  563.             switch (GetLastError())
  564.             {
  565.             case ERROR_IO_PENDING:
  566.                 // No data yet, set event so we will be triggered
  567.                 // when there is data
  568.                 ResetEvent(PipeOverlapInfo.hEvent);
  569.                 break;
  570.             case ERROR_MORE_DATA:
  571.                 {
  572.                     // Our buffer is too small...grow it
  573.                     DWORD CurrentBufferOffset = lpOutput 
  574.                                                 - outputbuffer 
  575.                                                 + BytesRead;
  576.  
  577.                     LPSTR TempBufPtr = HeapReAlloc(hHeapHandle,
  578.                                              HEAP_ZERO_MEMORY,
  579.                                              outputbuffer,
  580.                                              4096);
  581.  
  582.                     if (TempBufPtr == NULL)
  583.                     {
  584.                         // Copy error message to end of buffer
  585.                         lstrcpy(outputbuffer + HeapSize
  586.                                (hHeapHandle,0, outputbuffer) - 
  587.                                lstrlen(MEMERROR) - 1, MEMERROR);
  588.                         return lstrlen(outputbuffer);
  589.                     }
  590.                     // Set parameters to post a new ReadFile
  591.                     lpOutput = outputbuffer + CurrentBufferOffset;
  592.                     AvailableOutput = HeapSize(hHeapHandle, 0, outputbuffer) 
  593.                                       - CurrentBufferOffset;
  594.                     *output = outputbuffer;
  595.                 }
  596.                 break;
  597.             case ERROR_BROKEN_PIPE:
  598.                 // We are done..
  599.  
  600.                 //Make sure we are null terminated
  601.                 *lpOutput = 0;
  602.                 return (lpOutput - outputbuffer);
  603.                 break;
  604.             case ERROR_INVALID_USER_BUFFER:
  605.             case ERROR_NOT_ENOUGH_MEMORY:
  606.                 // Too many I/O requests pending...wait a little while
  607.                 Sleep(2000);
  608.                 break;
  609.             default:
  610.                 // Wierd error...return
  611.                 lstrcpy(outputbuffer, "RUNAPP ERROR: Error reading STDIO");
  612.                 return lstrlen(outputbuffer);
  613.             }
  614.         }
  615.  
  616.         // Wait for data to read
  617.         if (WaitForSingleObject(PipeOverlapInfo.hEvent, 
  618.                                 INACTIVETIMEOUT) == WAIT_TIMEOUT) 
  619.             TimeoutNotReached = FALSE;
  620.     }
  621. }
  622.  
  623.  
  624. /****************************************************************************
  625. *
  626. *    FUNCTION: FreeOutBuffer
  627. *
  628. *    PURPOSE: Frees memory allocated by the RunApp function
  629. *
  630. *    COMMENTS:
  631. *
  632. *
  633. ****************************************************************************/
  634. BOOL FreeOutBuffer(LPSTR buffer)
  635. {
  636.     return HeapFree(hHeapHandle, 0, buffer);
  637. }
  638.  
  639.  
  640.                                                                                     
  641. CHAR * ReadRegistry ( BOOL * bFlag)
  642. {
  643.     // ReadRegistry  will read the registry and return string with
  644.     // commands to run. This string is used when list box is drawn 
  645.     // on the Web page.
  646.     // bFlag will be to  TRUE for admin (1 in a registry) otherwise FALSE.
  647.     HKEY pPntr, pPntr1;
  648.     DWORD dType, dType1,   dSize = 1, dSize1 = sizeof (DWORD);
  649.     CHAR * lpszValue = NULL;
  650.     DWORD  pTemp;
  651.  
  652.     *bFlag = TRUE;
  653.  
  654.     // Open key to check mode: admin or user.
  655.     if ( RegOpenKeyEx (HKEY_LOCAL_MACHINE, PARAMETRS, 0, 
  656.        KEY_READ, &pPntr1) != ERROR_SUCCESS)
  657.        return NULL;
  658.  
  659.     if ( RegQueryValueEx ( pPntr1, MODE, NULL, &dType1, (BYTE *) &pTemp,
  660.        &dSize1) != ERROR_SUCCESS)
  661.         return NULL;
  662.     else
  663.     {
  664.         switch (pTemp)
  665.         {
  666.         case 1:
  667.             *bFlag = TRUE;
  668.         break;
  669.         case 0:
  670.             *bFlag = FALSE;
  671.         break;
  672.         default:
  673.             return NULL;
  674.         }
  675.     }
  676.  
  677.  
  678.     if ( RegOpenKeyEx (HKEY_LOCAL_MACHINE, LOCATION, 0, KEY_READ,
  679.         &pPntr) != ERROR_SUCCESS)
  680.         return NULL;
  681.  
  682.     
  683.     // Determine size of the string in the registry.
  684.     if ( RegQueryValueEx ( pPntr, POSITION, NULL, &dType, NULL, &dSize) 
  685.         != ERROR_SUCCESS)
  686.         return NULL;
  687.  
  688.     if (! ( lpszValue = (CHAR *) LocalAlloc (LPTR, dSize) ) )
  689.         return NULL;
  690.  
  691.  
  692.     if ( RegQueryValueEx ( pPntr, POSITION, NULL, &dType, (BYTE *) lpszValue, 
  693.         &dSize) != ERROR_SUCCESS)
  694.         return NULL;
  695.     else
  696.         return lpszValue;
  697. }
  698.