Advertisement

Win32 application| cout output both on console and on file

Started by July 17, 2017 03:28 AM
7 comments, last by MarcusAseth 7 years, 4 months ago

Hi everyone, the code below is my setup for opening a console in a Win32 project (using visual studio) and having the cout print stuff on it, it is mostly copy-pasted from stackoverflow with  some trial and error changes I did without being sure of what I was doing, but it works. Though now I want to understand it, code below


void debugConsole(bool create = true);

int WINAPI WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdLine, int show)
{
#if defined(DEBUG) || defined(_DEBUG)
	debugConsole();
#endif

	return 0;
}

void debugConsole(bool create)
{
	if (create)
	{
	//Create Console
	FILE* stream;
	AllocConsole();
	freopen_s(&stream, "conout$", "w", stdout);
	}
}

 

So from what I can tell, I am telling it that now the stdout stream (stuff I send using std::cout) get written (that's why the "w") to the console output, which is specified using "conout$".

So basically freopen_s job is to send a stream somewhere else?

But where is the "conout$" coming from? There is like a switch inside freopen_s that tells it the meaning of "conout$", which would be "send stuff to console"?

What is the FILE* stream sent to freopen_s doing though?

also let's say that under that line I write


freopen_s(&stream, "output.txt", "w", stdout);

I tried this out and it creates said file and put the cout output into it, which is great, but what if I want both? How do I set it up in a way than now cout content is cloned and sent both to the console and to my output file? 

Thanks :)

52 minutes ago, MarcusAseth said:

So basically freopen_s job is to send a stream somewhere else?

The documentation is here.  It closes the file pointer and re-assigns the stream, you can read more at the link.

52 minutes ago, MarcusAseth said:

But where is the "conout$" coming from? There is like a switch inside freopen_s that tells it the meaning of "conout$", which would be "send stuff to console"?

Close.  It is not handled inside that function, but it is handled by the system.

It is one of several special file names that Windows recognizes.  There are a bunch of them for things like console input/output, serial port input/output, and various other special devices and special features.  There are similar special device names on other operating systems like Linux or OSX or other systems. 

Both CONIN$ and CONOUT$ are managed by Windows so you don't have to.  Assuming they exist and haven't already been redirected in your program, that can work as you describe, sending stuff to the console.

52 minutes ago, MarcusAseth said:

I tried this out and it creates said file and put the cout output into it, which is great, but what if I want both? How do I set it up in a way than now cout content is cloned and sent both to the console and to my output file? 

The cout object is nothing particularly fancy, it is an output stream that happens to point to a specific location.  You have an output file that is also an output stream pointing to a different specific location.

If you want to write to them both, then do it:

cout << stuffToWrite;
myfile << stuffToWrite;

Advertisement

I see.

This gives me an idea, can I create my personal stream object that overload the operator<< so that when I call


MySuperCout << "important stuff" << endl;

it sends the content both to cout and to myfile as in your example above.

Seems reasonable, I go to try it out, thanks! :D

I've encountered some obstacles :S

I was thinking something like the code below should do the trick


#include <iostream>
#include <string>
#include <fstream>
using namespace std;

class MyCout {
public:
	MyCout(string filename) :mFilename{filename} {}
	MyCout& operator<<(const string s)
	{
		mMyFile.open(mFilename, ofstream::out);
		
		cout << s; 
		mMyFile << s;
		
		mMyFile.close();
		return *this;
	}
private:
	ofstream mMyFile;
	string mFilename;
};


int main()
{
	MyCout stream1("outputFile1.txt");
	stream1 << "test_test_test" << endl;

}

 

But it only works with string since I've overloaded the operator<< only for that, therefore endl don't work with it (unleass I overload for that as well).

There is a more clever way to do this, like inheriting from something similar to cout to have my own stream class while getting all the operator<< overload behaviours of the cout? :P

 

What would really solve my problem is something like this


MyCout& operator<<(WatheverType& t)
{
	cout << t;
}

the ability of having my operator<< accept every type because inside, cout and the fstream are going to handle wathever anyway.

There is any wizardry I can do with templates or something to achieve that? :S

Yes you could write something like


template <typename T> void Log(const T &t)
{
  std::cout << t;
}

that will work as expected for the reason of compile time resolve of T.

What I've did a long time ago was redirecting the standard output and error channels to achive something like you would like to using the rdbuf properties


std::ofstream out("log.txt");
std::streambuf *coutbuf = std::cout.rdbuf(); //save old buf
std::cout.rdbuf(out.rdbuf()); //redirect std::cout to file

//do all the logging between here

std::cout.rdbuf(coutbuf); //reset to standard output

using an own implementation of a buffer object that was intended to do tripple; output to file, output to game console, output to debug console whenever buffer was filled.


class logbuf : public std::streambuf 
	{
		private:
			char buffer[STREAMBUFFER_SIZE];

			int overflow(int c) 
			{
				if (!std::streambuf::traits_type::eq_int_type(c, std::streambuf::traits_type::eof())) 
				{
					*this->pptr() = std::streambuf::traits_type::to_char_type(c);
					this->pbump(1);
				}
				return this->sync()? std::streambuf::traits_type::not_eof(c): std::streambuf::traits_type::eof();
			}

			int sync() 
			{
				if (this->pbase() != this->pptr())
				{
					if(callback)
						this->callback(std::string(this->pbase(), this->pptr()));
					this->setp(this->pbase(), this->epptr());
				}
				return 0;
			}

		public:
			delegate<void (std::string)> callback;

			logbuf()
			{
				memset(buffer,0,sizeof(buffer));
				this->setp(this->buffer, this->buffer + sizeof(this->buffer) - 1);
			}
	};
      

 

Here a delegate was called whenever something was pushed into the buffer where the delegate could be bound to anything that accepts std::string as parameter and has no return type.

This code is higly obsolete so should not be used but you could get a view of how your goal could be achieved. Meanwhile I use a different approach away from the STL simply similar to C#'s string.Format function as a thread-safe templated argument to text conversion function.


#define __log(...) Log::Write(Log::Message, __VA_ARGS__)
#define __err(...) Log::Write(Log::Error, __VA_ARGS__)
...
  
__log("{0} Cores Found", GetSystemCores()); //results in '16 Cores Found'

 

Thank you for the examples Shaarigan, though actually the template example doesn't quite fit my needs because I want the ability to concatenate a series of operator<< as when you normally do a cout.

 

I went with this (code below), I've overloaded operator<< on a sstream adding my class, so when I pass it it flushes the stringstream both into cout and into my file. I can both concatenate and write a single line, seems a reasonable way to do it, right? :P


#include <Windows.h>
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
using namespace std;

struct MyCout {
	MyCout(string filename) { myFile.open(filename, ofstream::out); }
	inline stringstream& print() {
                                        string s; stream >> s;
                                        cout << s; myFile << s;
                                        return stream;
	}
	stringstream stream;
	ofstream myFile;
};
ostream& operator<<(ostream& stream, MyCout& debug) { return debug.print(); }
  
  int main()
  {
  	MyCout debug("outputFile1.txt");
	debug.stream << "test_test_test" << endl << debug;
  
  	return 0;
  }

 

Advertisement

In operator case, macro definitions could be your friend ;) but your solution seems fair enougth when working for your needs :D


#define InputOperator(type) std::ostream& operator<<(type const& tp) \
{  \
    std::cout << tp; \
    myFile << tp; \
    return *this;  \
}

InputOperator(unsigned char)
InputOperator(signed char)
InputOperator(unsigned short)
InputOperator(signed short)
InputOperator(unsigned int)
InputOperator(signed int)
InputOperator(unsigned long)
InputOperator(signed long)
InputOperator(float)
InputOperator(double)
InputOperator(const char*)
InputOperator(std::string)

 

lol it won't compile :P

 

Edit: apologize, it works, it was missing some '\' because maybe I messed up while pasting, but learned a new thing, thanks a lot! :D

This topic is closed to new replies.

Advertisement