Thread: VC++ Stream Writer problems.

  1. #1
    Registered User
    Join Date
    May 2006
    Posts
    89

    VC++ Stream Writer problems.

    Okay I finally decided to try using actual managed code to handle my file writing since all the code where I am converting System::String to std::string and using filestreams is becoming very touchy. I decided now would be a good time to fix it but it looks like I'm just breaking things more. Anyway here is a piece of my code and it is throwing a System.IO.Exception every time it tried to close the stream writer. Any ideas?

    Code:
                            String^ path = "c:\\MyTest.txt";
       
    			// Delete the file if it exists.
    			if (File::Exists(path))
    				File::Delete(path);
    
    			//Create the file.
    			FileStream^ fs = File::Create(path);
    			StreamWriter^ sw = gcnew StreamWriter(fs, System::Text::Encoding::ASCII);
    
    			int cnt = 0;
    			while (!tmp->Contains("(END)") && cnt < 30){
    				connector.WriteToPipe("\r");
    				sw->WriteLine("This is a test line\n");
    				tmp = gcnew String(connector.ReadFromPipe().c_str());
    				cnt++;
    			}
    			sw->Close();
    What this would normally do write to a telnet session and readback the data until it finds (END) or has gone 30 times. the 30 times is just for my debugging write now and instead of writing tmp I am just writing a test line to make sure things are working first before I introduce more problems. I looked at 2 different tutorials on file writing with VC++ and this what I got out of it.
    thanks

    EDIT: okay it is this line -
    Code:
    tmp = gcnew String(connector.ReadFromPipe().c_str());
    but I dont understand why. All connector.ReadFromPipe() does it reads in any data from a piped PuTTy telnet session. If nothing is there it returns "NULL". Why should this be messing up my streamwriter??
    Last edited by ac251404; 10-11-2006 at 02:33 PM.

  2. #2
    Registered User SKeane's Avatar
    Join Date
    Sep 2006
    Location
    England
    Posts
    234
    If tmp is NULL, what does tmp->Contains("(END)") do ?

  3. #3
    Registered User
    Join Date
    May 2006
    Posts
    89
    tmp would hold the string "NULL" not actually null. So I would imagine it would return false.

  4. #4
    Registered User SKeane's Avatar
    Join Date
    Sep 2006
    Location
    England
    Posts
    234
    I'll rephrase that, what if gcnew fails to create a new String, what would tmp point to? What would happen if you then called tmp->Contains? Are you relying on an exception begin thrown?

    Where is tmp defined,? What value does it have before your while loop?

  5. #5
    Registered User
    Join Date
    May 2006
    Posts
    89
    Okay below is the entire function. I added some more commenting so you can see what I'm attempting but basically my main program automatically reads back from the server each time it sends out an instruction from my instructionQueue. Depending on what flags I have set, the information read back is sent to specific handler, which uses this information to adjust the instruction queue or in this case, start parsing info of the screen one line at a time. I'm trying to do this because of the stupid limitations of the server program I'm trying to retrieve reports from. You can view them, but not save them, so I'm trying to come up with a reasonable way of doing that. Hope that helps some...

    Code:
    private: void reportHandler			(String ^read){
    		String ^tmp = read;						//copy the passed in string to a temp string.
    		if(tmp->Contains("Performing")){		//if the report is being generated
    			instructionTimer->Stop();			//stop sending instructions
    
    			while (!tmp->Contains("tmp"))		//keep reading until the report is shown (need to account for possible infinite loop)
    				tmp = gcnew String(connector.ReadFromPipe().c_str());
    
    			String^ path = "c:\\MyTest.txt";	//once the report is up, setup the log file.	
       
    			// Delete the file if it exists.
    			if (File::Exists(path))
    				File::Delete(path);
    
    			//Create the file.
    			StreamWriter^ sw = File::CreateText(path);
    
    			int cnt = 0;						//setup a count for debugging/no infinite loop
    			try{
    				//at the first loop iteration tmp must contain at least "tmp" so its not "NULL"
    				while (!tmp->Contains("(END)") && cnt < 10){			//while we are not at the end of the report
    					connector.WriteToPipe("\r");						//send 'Enter'
    					sw->WriteLine("This is a test line");				//write out whatever we just recieved (for right now a test string)
    					tmp = gcnew String(connector.ReadFromPipe().c_str()); //read into tmp again
    					cnt++;												//increment	
    				}
    				sw->Flush();											//flush stream
    				sw->Close();											//close stream
    			}
    			catch ( Exception^ e )										//catch any IO Exception
    			{
    				MessageBox::Show(e->ToString(), "Exception Occured", MessageBoxButtons::OK);
    				exit(1);
    			}
    			instructionTimer->Start();									//restart our timer
    		}
    
    		if(instructionQueue.empty()){									//check for empty queue
    			instructionTimer->Stop();									//stop timer
    			RTRV_REPORT = false;										//disable flag
    			MessageBox::Show("All reports retrieved.",					//success
    						"Report Retrieval", MessageBoxButtons::OK);
    			return;
    		}
    }
    ^read is picked up from ReadFromPipe() as well, it just occurs on each tick of the instructionTimer.

    Here is ReadFromPipe() :

    Code:
    string Pconnect::ReadFromPipe(){ 
      
       DWORD dwRead;
       string ret = "NULL";
       CHAR chBuf[BUFSIZE]; 
    
       // Close the write end of the pipe before reading from the 
       // read end of the pipe. 
       if (!CloseHandle(hChildStdoutWr)) 
         std::cerr << "Closing handle failed.\n";
     
       // Read output from the child process, and write to parent's STDOUT. 
       while(true){       
        DWORD dwAvail = 0;
        
    	//check if child process ended
    	if (!::PeekNamedPipe(hChildStdoutRd, NULL, 0, NULL, &dwAvail, NULL))  
          break;
    	//check if there was no data
        if (!dwAvail)           
           break;  
        //read the file and break once the reading is complete
        if(!ReadFile( hChildStdoutRd, chBuf, BUFSIZE, &dwRead, NULL) || dwRead == 0) 
    	   break;
       }
    
       //make sure there is data to put in the string
       if(dwRead > 0)
    		ret = chBuf;
    
       return ret;
    }
    My Connector code was written in unmanaged but so far it has been working okay with my newer VC++ managed code. I hope this helps, this bug is driving me crazy.
    Also even if tmp was NULL, wouldnt that throw some kind of error when it hit the loop at a certain iteration? The exception is being thrown at sw->flush or sw->close. If I remove those lines no exception is ever thrown, but my file never gets any output either obviously.
    Last edited by ac251404; 10-12-2006 at 08:43 AM.

  6. #6
    Registered User
    Join Date
    May 2006
    Posts
    89
    Okay a bit of an update but still having trouble - I tried changing
    Code:
    tmp = gcnew String(connector.ReadFromPipe().c_str());
    to
    Code:
    tmp = gcnew String("this is a string");
    and there are no problems. So I thought maybe ReadFromPipe() was returning some garbage characters that were messing up the string creation. In order to circumvent this I added the following to ReadFromPipe()

    Code:
    std::string::iterator it;
       it = ret.begin();
       while(it != ret.end()){
    	   unsigned char c =  *it;
    	   if(!isprint(c))
    		   ret.erase(it);
    	   else
    		   it++;
       }
    
       return ret;
    So it should remove any characters that would screw anything up. Still throws an exception!
    I am down to 2 ideas and not sure how to approach either:
    1) Something about the encoding of System::String and the encoding from my input string.
    2) The size available for System::String isnt adequate. My ReadFromPipe() uses a buffer size of 4096 so I dont think it should be too big but I'm out of other ideas.

    I am really going crazy over this. It makes no sense to me at all. I mean even if tmp is getting screwed up by a bad return from the gcnew String() constructer (which is obvious since it works with a hardcoded string), if I am not even using tmp in my stream why the hell does it matter?! At the worst it should screw up my loop and throw an exception for the tmp->Contains() check, but why ohhhh why can I not flush this stream!?
    Last edited by ac251404; 10-12-2006 at 01:32 PM.

  7. #7
    carry on JaWiB's Avatar
    Join Date
    Feb 2003
    Location
    Seattle, WA
    Posts
    1,972
    Code:
     if(!ReadFile( hChildStdoutRd, chBuf, BUFSIZE, &dwRead, NULL) || dwRead == 0) 
    	   break;
       }
    
       //make sure there is data to put in the string
       if(dwRead > 0)
    		ret = chBuf;
    I'm fairly certain ReadFile doesn't null-terminate strings, which would mean you'll probably get garbage characters in 'ret.' Try:
    Code:
     if(!ReadFile( hChildStdoutRd, chBuf, BUFSIZE-1, &dwRead, NULL) || dwRead == 0) 
    	   break;
       }
      chBuf[dwRead] = '\0';
    "Think not but that I know these things; or think
    I know them not: not therefore am I short
    Of knowing what I ought."
    -John Milton, Paradise Regained (1671)

    "Work hard and it might happen."
    -XSquared

  8. #8
    Registered User
    Join Date
    May 2006
    Posts
    89
    Well it was a good thought, and I am sure it couldn't hurt to leave it in my code but still no luck.
    The following is the full exception I get:

    Code:
    System.IO.IOException: The handle is invalid.
    
      at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
      at System.IO.FileStream.WriterCore(Byte[] buffer, Int32 offset, Int32 count)
      at System.IO.FileStream.FlushWrite(Boolean calledFromFinalizer)
      at System.IO.FileStream.Flush()
      at System.IO.StreamWriter.Flush(Boolean flushStream, Coolean flushEncoder)
      at System.IO.StreamWriter.Flush()
      at blah blah blah line in my code.
    And again it occurs when I call Flush or Close. I assume it occurs when I call Close because Close flushes the stream so Flush is then called which generates the exception.

  9. #9
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    >string Pconnect::ReadFromPipe(){
    >
    > DWORD dwRead;
    In addition to what JaWiB suggested, I would set dwRead to 0 here:
    Code:
       DWORD dwRead = 0;
    Because it looks like you have a couple of breaks which would skip the code that sets dwRead.

  10. #10
    Registered User
    Join Date
    May 2006
    Posts
    89
    Okay added that but still didnt do it. Thanks for the reply tho.
    I have traced the problem to here in ReadFromPipe(). I thought it was really strange that even just calling ReadFromPipe() on some arbitrary variable cause the exception so I start commenting out all the stuff in ReadFromPipe that uses handles one line at a time. Luckily the problem was in the first few lines haha

    Code:
    // Close the write end of the pipe before reading from the 
    // read end of the pipe. 
       if (!CloseHandle(hChildStdoutWr)) 
         std::cerr << "Closing handle failed.\n";
    And I am sure you need to see what hChildStdoutWr is so here is some more code, this chunk comes from the ExecuteProccess() function -

    Code:
             //Setup security attributes
    	SECURITY_ATTRIBUTES as            = { 0 };
    	
    	as.nLength              = sizeof(as);
        as.lpSecurityDescriptor = NULL;
        as.bInheritHandle       = TRUE;
    
    	//get handle of current stdout
    	hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
    
    	//create a pipe for the child process's STDOUT
    	if(! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &as, 0))
    		std::cerr << "Stdout pipe creation failed.\n";
    
    	//Ensure write handle for STDOUT is not inherited
    	SetHandleInformation( hChildStdoutWr, HANDLE_FLAG_INHERIT, 0);
    
        STARTUPINFO         siStartupInfo = { 0 };
        PROCESS_INFORMATION piProcessInfo = { 0 };
    
        siStartupInfo.cb          = sizeof(siStartupInfo);
        siStartupInfo.hStdError   = hChildStdoutWr;
        siStartupInfo.hStdOutput  = hChildStdoutWr;
        siStartupInfo.hStdInput   = hChildStdinRd;
        siStartupInfo.dwFlags     = STARTF_USESHOWWINDOW  | STARTF_USESTDHANDLES;
        siStartupInfo.wShowWindow = SW_SHOW;
    After that it executes the program and there is some more stuff occuring with the other handles but that is everything with hChildStdoutWr. My uneducated guess is that closing the STD_OUTPUT handle also closes the handle used by StreamWriter. Make sense?
    Last edited by ac251404; 10-12-2006 at 04:12 PM.

  11. #11
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    > //Ensure write handle for STDIN is not inherited
    > SetHandleInformation( hChildStdinWr, HANDLE_FLAG_INHERIT, 0);
    Is hChildStdinWr a typo here? Because the rest of your code is only showing a hChildStdinRd or hChildStdoutWr.

    EDIT: Nevermind, I see both StdinRd and StdoutWr here also:
    if(! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &as, 0))
    Last edited by swoopy; 10-12-2006 at 03:54 PM.

  12. #12
    Registered User
    Join Date
    May 2006
    Posts
    89
    Yes, sorry I copied/pasted the wrong line there I believe, but yes there is a matching block to ensure STDOUT is not inherited.

  13. #13
    Registered User
    Join Date
    May 2006
    Posts
    89
    Okay I think it is because STDOUT is the underlying stream of StreamWriter, and when SW is flushed it flushes out the current stream and the underlying stream, but since the underlying STDOUT is closed right before the loop terminates (the last call to ReadFromPipe) Flush() has no handle to the STDOUT to flush it and thus the exception. I'm not at work yet to try but I can probably arrange it to read then write in which case it might be okay. Otherwise I'll see if I can get by without closing the stream.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. No clue how to make a code to solve problems!
    By ctnzn in forum C Programming
    Replies: 8
    Last Post: 10-16-2008, 02:59 AM
  2. Redirecting cout stream
    By Arrow Mk84 in forum C++ Programming
    Replies: 1
    Last Post: 10-08-2002, 04:17 PM
  3. Replies: 9
    Last Post: 07-01-2002, 07:50 AM
  4. What's wrong with my Stream Cipher Encryption?
    By Davros in forum C++ Programming
    Replies: 3
    Last Post: 04-18-2002, 09:51 PM
  5. DJGPP problems
    By stormswift in forum C Programming
    Replies: 2
    Last Post: 02-26-2002, 04:35 PM