Winforms RichTextBox as istream - c++

I'm adapting a console based program to GUI.
The console program reads a text file and "compiles" it.
My GUI application reads the text file and displays in a RichTextBox.
I'm looking for a method to treat the RichTextBox as a C++ std::istream. This would allow me to use code from the console program without modifying it.
I searched the web and StackOverflow and didn't find any solutions for treating a RichTextBox as an std::istream.
Does anybody know of any Winforms library functions that would allow treating of RichTextBox as an std::istream?
My ideas:
Create an adapter to treat RichTextBox as a stream.
Change the console program to pass a "getline" function to the
compiler portion, and have two getline functions (one as the
std::getline, another to get a line from the RichTextBox).
Write the RichTextBox contents to a file and feed the file to the
compiler.
I'm using Visual Studio 2010 on Win 7 using ".NET" 4.0, using C++ (don't suggest any C# techniques as I'm not fluent in translating).

In real C++, you can create a stream buffer from an RTF control like this:
class RTF_buf : public std::streambuf {
std::vector<char> buffer;
public:
RTF_buf(HWND ctrl) {
DWORD len = SendMessage(ctrl, WM_GETTEXTLENGTH, 0, 0);
buffer.resize(len+1);
SendMessageA(ctrl, WM_GETTEXT, len+1, (LPARAM)&buffer[0]);
setg(&buffer[0], &buffer[0], &buffer[len]);
}
};
Note that this isn't actually restricted to an RTF control. Just for one other example, it'll also work fine with a normal EDIT control.
C++/CLI adds a few wrinkles to this. First of all, you're dealing with "wide" characters in the RichTextBox. Second, you won't (normally) start with an HWND -- you have to retrieve that from the System.Windows.Forms.RichTextBox via its Handle property. This, unfortunately, returns the HWND as an IntPtr instead of an HWND, so you have to add a cast to get it to the right type. That makes the code a little uglier, but nothing too terrible:
#include <windows.h>
#include <streambuf>
#include <iostream>
#include <vector>
#include <algorithm>
#pragma comment(lib, "user32.lib")
using namespace System;
using namespace System::Windows::Forms;
class RTF_buf : public std::wstreambuf {
std::vector<wchar_t> buffer;
public:
RTF_buf(RichTextBox^ control) {
HWND ctrl = *reinterpret_cast<HWND *>(&control->Handle);
int len = SendMessage(ctrl, WM_GETTEXTLENGTH, 0, 0);
buffer.resize(len+1);
SendMessage(ctrl, WM_GETTEXT, len+1, (LPARAM)&buffer[0]);
setg(&buffer[0], &buffer[0], &buffer[len]);
}
};
We can create a buffer and istream something like this:
RTF_buf b(this->richTextBox1);
std::wistream in(&b);
Finally, we can read data from our stream and process them like we would essentially any other (wide) stream. For example:
wchar_t ch;
while (in >> ch)
// do something with ch
So C++/CLI does add a little complexity to the task, but ultimately only a little--mostly the one line to obtain the handle of the control, and cast it to the correct type. Other than that the code for the buffer class barely needs to change at all, and instantiating and using it changes only to the extent that we're working with wide characters instead of narrow.

The proper way to create a stream plugging into the IOStreams library is to implement a stream buffer, i.e., to derive from std::streambuf or std::wstreambuf (I'm not a Windows programmer but my understanding is that most code travels in terms of wchar_t rather than char) and override the suitable virtual member functions. Assuming you can get characters in bunches (possible all in a bukl) all you'd really overload is underflow() which is called if the input buffer was exhausted. If you can get all the characters during construction you can also set up a buffer.
Once you have a stream buffer you can use a pointer to the stream buffer to initialize an std::istream. Here is a simple example which uses a memory arean passed in the constructor as its input:
#include <iostream>
#include <streambuf>
class membuf
: std::streambuf {
public:
membuf(char* buffer, std::size_t size) {
this->setg(buffer, buffer, buffer + size);
}
};
int main() {
char input[] = "hello, world!\n";
membuf sbuf(input, sizeof(input - 1));
std::istream in(&sbuf);
char buffer[100];
if (in.getline(buffer, sizeof(buffer)) {
std::cout << "read '" << buffer << "'\n";
}
else {
std::cout << "ERROR: failed to read a line but Dietmar said...!?!\n";
}
}

Related

Transform a buffer into an istream to work in existing programs

I am trying to create a native nodejs module, using NAN and c ++, I want to transform an existing program that uses std::ifstream stream (filename, std :: ifstream :: in | std :: ifstream :: binary); to load a file into a javascript module that can load a buffer and send it to c ++
The original c ++ code was made to work via command line, I don't want to have to write a file to disk, I would like to send this file using a nodejs buffer.
index.js
const fs = require('fs')
const addon = require('./build/Release/image_edit');
fs.readFile('image.png', function read(err, buffer) {
if (err) {
throw err;
}
var result = addon.edit(buffer, buffer.length);
//console.log(result)
});
main.cpp
#include <node.h>
#include <node_buffer.h>
#include <iostream>
#include <nan.h>
#include <sstream>
#include <string>
#include <fstream>
#include <streambuf>
#include <istream>
using namespace Nan;
using namespace v8;
uint32_t read(std::istream& in)
{
uint32_t v;
in.read(reinterpret_cast<char*>(&v), sizeof(v));
return v;
}
NAN_METHOD(edit) {
unsigned char*buffer = (unsigned char*) node::Buffer::Data(info[0]->ToObject());
unsigned int size = info[1]->Uint32Value();
//the closest I could to manipulating the data was using a vector
std::vector<uint32_t> png_data(buffer, buffer + size);
//The main core of the program uses the in.read function to parse the file, tb uses in.clear () and in.seekg ();
//here an example of how this is done
uint32_t count = readU32(stream);
}
NAN_MODULE_INIT(Init) {
Nan::Set(target, New<String>("edit").ToLocalChecked(),
GetFunction(New<FunctionTemplate>(edit)).ToLocalChecked());
}
NODE_MODULE(image_edit, Init)
I tried using the following code to verify that the data received is valid and if the recorded file is the same as the original, everything looks fine.
std::ofstream FILE("test.png", std::ios::out | std::ofstream::binary);
std::copy(png_data.begin(), png_data.end(), std::ostreambuf_iterator<char>(FILE));
The question is, how do I make this buffer received from nodejs into something read the same way an ifstream does, without having to drastically change the c ++ program?
The main methods called by the program in c ++ are: .seekg (), .push_back, .clear (),
This kind of thing is usually done by implementing a custom subclass of std::streambuf, and then using it to construct a std::istream.
std::istream has a constructor that takes a pointer to a std::streambuf as a parameter, so the basic outline is something like this
class my_streambuf : public std::streambuf {
// ... Your implementation of your subclass
};
my_streambuf msb{ /* Parameters to your class's constructor */ }
std::istream i{&msb};
At this point, i is an ordinary input stream and does everything that any other input stream does. You can seek it. You can read from it.
Of course, the hard part is implementing your custom subclass of std::streambuf. This is not something that can be fully described in one or two paragraphs on stackoverflow.com. You should read std::streambuf's documentation, specifically the descriptions of its virtual methods. Your custom subclass will need to reimplement std::streambuf's virtual methods and make them work with your buffer. It's likely you will not need to reimplement all the virtual methods. For some of them their default implementation will be sufficient. Some of them won't be needed, for what you end up doing with std::istream.
You will have to determine, based on you specific needs to what extent you need to reimplement which std::streambuf's virtual methods, and how.
Of course, another, easy alternative is to use your buffer to construct a std::string, and then using it to construct a std::istringstream, and call it a day. Of course, that'll be somewhat wasteful and require effectively doubling the memory used for the data, with a second copy that's owned by a throw-away std::string, and copying it. If this is a small amount of data that's probably fine, but if your buffer is very big that may not be practical, and a custom std::streambuf subclass that uses the buffer directly is your only option.
Like the other answer mentioned, you can use an std::stringstream if you don't want to go the std::streambuf route:
std::stringstream ss;
std::copy(png_data.begin(), png_data.end(), std::ostreambuf_iterator<uint32_t>(ss));
Then you just use it like an input stream.

std::cout, ostream and other kinds of getting output stream

In my project (Unreal Engine 4) I don't have an output stream - instead of this I can communicate via UE_LOG function, which works pretty much similar to printf(). The problem is that I just made a .dll library (without Unreal includes) which I want to communicate through the iostream. My idea is - inside .dll library I use standard cout to write messages into ostream, I use all of it in Unreal Engine functions, where I grab ostream in form of string and output it into UE_LOG function.
Problem is I always treated std::cout as a part of magic, without thinking what is really inside (I am pretty sure most of us did). How I can handle this? Easy ways won't work (like grabbing stringstream and outputing it into UE_LOG).
My idea is - inside .dll library I use standard cout to write messages into ostream
You actually can replace the output buffer used with std::cout with your own implementation. Use the std::ostream::rdbuf() function to do so (example from the reference docs):
#include <iostream>
#include <sstream>
int main()
{
std::ostringstream local;
auto cout_buff = std::cout.rdbuf(); // save pointer to std::cout buffer
std::cout.rdbuf(local.rdbuf()); // substitute internal std::cout buffer with
// buffer of 'local' object
// now std::cout work with 'local' buffer
// you don't see this message
std::cout << "some message";
// go back to old buffer
std::cout.rdbuf(cout_buff);
// you will see this message
std::cout << "back to default buffer\n";
// print 'local' content
std::cout << "local content: " << local.str() << "\n";
}
(in case my edit won't be positively reviewed)
From OP: Thanks to your hints I finally found how to solve my problem. Suppose I want to get stream from cout and send it to printf (because I think stdio library is superior to iostream). Here how I can do this:
#include <iostream>
#include <sstream>
#include <cstdio>
using namespace std;
class ssbuf : public stringbuf{
protected:
int sync(){
printf("My buffer: %s",this->str().c_str());
str("");
return this->stringbuf::sync();
}
};
int main(){
ssbuf *buf = new ssbuf();
cout.rdbuf(buf);
cout<<"This is out stream "<<"and you cant do anything about it"<<endl;
cout<<"(don't) "<<"Vote Trump"<<endl;
}
Code is very raw, but it does it's job. I made child class of buffer which has method sync() downcasting original virtual method sync(). Except this it works like usual buffer, just grabs all console-out stream - exactly what we wanted. The str("") inside is to clean the buffer - probably not outputted stream doesn't clean itself.
Great thanks for help! Big GRIN for you! :D

How can I reverse the output stream in c++?

What I am trying to achieve is to use the standard std::cout and if you understand, reverse the output to an input so another part of my program can read it. No I cannot just call a function in the other part of my program because every function is and must stay private so this seems the only way to do it. I did a similar thing in java by redirecting the default output stream to my own custom one but I am somewhat new to c++. This is what I did in java:
System.setOut(customPrintStream);
Does anyone know of an alternative for c++ or a way to get whatever is printed to console?
The c++ standard library supports the concept of 'reverse iterators'.
#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
int main()
{
auto s = std::string("Hello, World");
std::copy(std::rbegin(s), std::rend(s),
std::ostream_iterator<char>(std::cout));
std::cout << std::endl;
return 0;
}
expected output:
dlroW ,olleH
The streams in C++ read from and write to std::streambuf objects. You can replace the stream buffer of an std::ostream object using the rdbuf() function. For example, to capture all output written to std::cout in a std::string you could use something like this:
std::ostreamstream stream;
std::streambuf* sbuf = std::cout.rdbuf(stream.rdbuf());
// use code whose output is written to `std::cout`
std::cout.rdbuf(sbuf); // restore the original stream buffer
std::string output = stream.str();
In a real implementation you'd probably use an RAII approach to replace/restore the stream buffer. Also, you might want to use a custom stream buffer rather than a std::stringbuf but the basic remain as is.

C++: Redirecting STDOUT

In my application, I want to redirect the output that would normally go to the stdout stream to a function I define. I read that you can redirect stdio to a file, so why not to a function?
For example:
void MyHandler( const char* data );
//<<Magical redirection code>>
printf( "test" );
std::cout << "test" << std::endl;
//MyHandler should have been called with "test" twice, at this point
How can I achieve this / similar behaviour?
#Konrad Rudolph is right, you can totally do this, easily, at least for cout/cerr/clog. You don't even need your own streambuf implementation, just use an ostringstream.
// Redirect cout.
streambuf* oldCoutStreamBuf = cout.rdbuf();
ostringstream strCout;
cout.rdbuf( strCout.rdbuf() );
// This goes to the string stream.
cout << "Hello, World!" << endl;
// Restore old cout.
cout.rdbuf( oldCoutStreamBuf );
// Will output our Hello World! from above.
cout << strCout.str();
Same thing works for cerr and clog, but in my experience that will NOT work for stdout/stderr in general, so printf won't output there. cout goes to stdout, but redirecting cout will not redirect all stdout. At least, that was my experience.
If the amount of data is expected to be small, the freopen/setbuf thing works fine. I ended up doing the fancier dup/dup2 thing redirecting to a pipe.
Update: I wrote a blog post showing the dup2 method I ended up using, which you can read here. It's written for OS X, but might work in other Unix flavors. I seriously doubt it would work in Windows. Cocoa version of the same thing here.
Invoking a callback function whenever something’s written to the underlying standard output stream is hard: it requires overriding low-level, system-specific functions (on POSIX systems, it would require at least overriding write, and the way this is called might depend on the standard library implementation, so it might be different between e.g. glibc and musl).
But depending on what exactly you’re after you can solve this in C++ without resorting to low-level OS specific functions, by manipulating the C++ stream buffers directly.
For this you need to create your own std::streambuf implementation, i.e. your own stream buffer.
Once you have that, you can redirect the std::cout stream by switching the buffer:
auto buf = callback_streambuf(MyHandler);
auto pold_buffer = std::cout.rdbuf(&buf);
std::cout << "Hello" << std::cout;
// Restore original buffer:
std::cout.rdbuf(pold_buffer);
However, what this implementation won’t do is call your callback function exactly twice. Instead, the number of calls will depend on several factors, but it generally will not depend on the number of stream insertions (<<), and there is no way around that!
For the specific example above, the callback is called once, with the data "Hello\n".
The following minimal implementation illustrates how to get a streambuf to call your handler:
class callback_streambuf : public std::streambuf {
public:
callback_streambuf(std::function<void(char const*, std::streamsize)> callback) : callback(callback) {}
protected:
std::streamsize xsputn(char_type const* s, std::streamsize count) {
callback(s, count);
return count;
}
private:
std::function<void(char const*, std::streamsize)> callback;
};
This implementation has several caveats. For instance, it does the wrong thing when attempts are made to use it as an input stream. It doesn’t override overflow (since I don’t think this is ever called, although I find conflicting information about this on the internet; at any rate, adding overflow would be trivial). I didn’t implement synchronisation, so the callback will be called concurrently from multiple threads. Furthermore, there is no error handling, since the callback does not return a success status. I also had to change the signature of the callback to
void MyHandler(char const* data, std::streamsize count);
The second parameter is required since data isn’t a string, it’s a raw char buffer, so there is no way to determine its length intrinsically, and MyHandler can do nothing useful with the data without knowing its length.
Answer: Yes you can, via a dup. freopen will only reopen stdout to a file, as you talked about.
Check out How to buffer stdout in memory and write it from a dedicated thread
It's possible to disable stdin/stdout by dereferencing its pointer:
FILE fp_old = *stdout; // preserve the original stdout
*stdout = *fopen("/dev/null","w"); // redirect stdout to null
HObject m_ObjPOS = NewLibraryObject(); // call some library which prints unwanted stdout
*stdout=fp_old; // restore stdout
The std::cout object has a fixed meaning, and that is to output to the standard out stream. The user of your program gets to control where standard out is connected to, not you. What you can do is decide whether you wish to write to a file, to standard out or to any other output stream. So in your code you switch what stream you write to.
Again, the point of writing to the standard out stream is to give the user a flexibility in choosing where the output goes to. You're not supposed to redirect standard out; this is something the user is supposed to have the freedom to do.
Another thing is that you shouldn't mix C IO and C++ IO in a C++ program. Choose which IO library you wish to work with and stick to it.
That said, you can in C++ quite elegantly switch streams for a function to take input from by templating the handler function on the template parameters of std::basic_istream<>. Then the function will read its input from the input stream independently of the real kind of stream it's working with. Here's an example:
#include<iostream>
#include<fstream>
#include<string>
template<class Ch, class Tr>
void dodge_this(std::basic_istream<Ch, Tr>& in)
{
// in is an input stream. read from it as you read from std::cin.
}
int main(int argc, char* argv[])
{
if( std::string(argv[1]) == "cin" ) {
dodge_this(std::cin);
} else if( std::string(argv[1]) == "file" ) {
std::ifstream file("input.txt");
dodge_this(file);
} else {
dodge_this(dev_null_stream); // i just made that up. you get the idea.
}
}
Another option is to place your handler class calls into the inherited streambuf class. I had a requirement to redirect cout to a Win GUI edit control in a dialog box that may be of some use. Here is the class code:
//-------------------------------- DlgStringbuf Definition -----------------------
class DlgStringbuf : public std::stringbuf
{
public:
DlgStringbuf(void) : _hwndDlg(NULL), _editControlID(0), _accum(""), _lineNum(0) {}
void SetDlg(HWND dlg, int editControlID)
{ _hwndDlg = dlg; _editControlID = editControlID; }
void Clear(void)
{ _accum.clear(); _lineNum = 0; }
protected:
virtual std::streamsize xsputn(const char* s, std::streamsize num)
{
std::mutex m;
std::lock_guard<std::mutex> lg(m);
// Prepend with the line number
std::string str(s, (const uint32_t)num);
str = std::to_string(_lineNum) + ": " + str + "\r\n";
// Accumulate the latest text to the front
_accum = str + _accum;
// Write to the Win32 dialog edit control.
if(_hwndDlg != NULL)
SetDlgItemTextW(_hwndDlg, _editControlID, (LPCWSTR)(std::wstring(_accum.begin(), _accum.end())).c_str());
_lineNum++;
return(num);
}//end xsputn.
private:
std::string _accum;
HWND _hwndDlg;
int _editControlID;
uint32_t _lineNum;
};//end DlgStringbuf.
//-------------------------------- DlgStream Definition ------------------------------
class DlgStream : public std::ostream
{
public:
DlgStream(void) : std::ostream(&_sbuff) {}
void SetDlg(HWND dlg, int editControlID)
{ _sbuff.SetDlg(dlg, editControlID); }
void Clear(void)
{ _sbuff.Clear(); }
private:
DlgStringbuf _sbuff;
};
...and in the WinMain, someplace after the dialog box and its edit control is created:
// Redirect all cout usage to the activity dlg box.
// Save output buffer of the stream - use unique pointer with deleter that ensures to restore
// the original output buffer at the end of the program.
auto del = [&](streambuf* p) { cout.rdbuf(p); };
unique_ptr<streambuf, decltype(del)> origBuffer(cout.rdbuf(), del);
// Redirect the output to the dlg stream.
_dlgStream.SetDlg(hwndActivityDlg, IDC_EDIT_ACTIVITY);
_dlgStream.copyfmt(cout);
cout.rdbuf(_dlgStream.rdbuf());
cout << "this is from cout";
You can use sprintf to write to a character array and then read the value:
char buf[1024];
sprintf(buf, "test");
MyHandler(buf);
there are also snprintf and a few others depending on platform

Display message in windows dialogue box using "cout" - C++

Can a windows message box be display using the cout syntax?
I also need the command prompt window to be suppressed / hidden.
There are ways to call the messagebox function and display text through its usage, but the main constraint here is that cout syntax must be used.
cout << "message";
I was thinking of invoking the VB msgbox command in the cout output, but couldn't find anything that worked.
Any ideas?
C++ streams work with console or file streams. Windows work on a more or less completely different paradigm, so the cout context isn't really a good one for working with this. You could probably completely mash up something that would end up more or less working, and looking more or less similar to this syntax, but it's not really worth it when you can just do:
MessageBox( NULL, message, "", MB_OK );
See the full docs on MessageBox for more info.
First thing you should take into account is that MessageBox stops the thread until you close the window. If that is the behavior you desire, go ahead.
You can create a custom streambuf and set it to std::cout:
#include <windows.h>
#include <sstream>
#include <iostream>
namespace {
class mb_streambuf : public std::stringbuf {
virtual ~mb_streambuf() { if (str().size() > 0) sync(); }
virtual int sync() {
MessageBoxA(0, str().c_str(), "", MB_OK);
str("");
return 0;
}
} mb_buf;
struct static_initializer {
static_initializer() {
std::cout.rdbuf(&mb_buf);
}
} cout_buffer_switch;
}
int main()
{
std::cout << "Hello \nworld!"; // Will show a popup
}
A popup will be shown whenever std::cout stream is flushed.
By including sstream, you can use std::ostringstream and build a message using the iostream library. You can then call .str().c_str() and get a char * to pass to MessageBox.
When confronted with this in the past, I've used a stringstream along with a manipulator that displays the current contents of the stringstream using MessageBox:
#include <windows.h>
#include <sstream>
#include <ostream>
std::ostream &MessageBox(std::ostream &s) {
std::ostringstream *st = dynamic_cast<std::ostringstream *>(&s);
if (NULL != st)
::MessageBox(NULL, st->str().c_str(), "", MB_OK);
return s;
}
To use this, the syntax looks a fair amount like using cout, but with MessageBox replacing std::endl. For example:
std::ostringstream stm;
stm << " blah blah blah. Value: " << 1213.1231 << MessageBox;
Edit: mostly for fnieto. In this case, the downcast really is necessary. The reason is fairly simple: a typical inserter receives and returns a reference to an ostream:
std::ostream &operator<<(std::ostream &os, T const &t) {
// code here to insert t into os, then return os;
}
This takes the original stringstream object and silently (and safely) casts it up to a simple ostream. That's fine in itself, and works fine for most inserters and manipulators, because they only interact with the ostream interface themselves.
This manipulator, however, is a bit different -- it uses the str() member, which ostream doesn't define at all. For our call to str() to resolve and compile, we have to convert the ostream & to an ostringstream &, so the compiler is aware that the object we're working with really will have a str() member.
To eliminate the downcast, we'd really only have one choice: make its parameter an ostringstream &. That would work as long as we never chained operators:
my_stream << x;
my_stream << MessageBox;
but trying to chain those would fail:
// should be equivalent:
my_stream << x << MessageBox;
Worse, the compiler's error message will probably try to tell the user something about std::basic_ostream<char>::str(), which isn't mentioned in the user's code at all. Worse still, most people are sufficiently accustomed to chaining or not giving identical results that it would probably take them a while to even figure out why the code sometimes worked fine, and other times failed to compile, with a completely indecipherable error message.
No simple way anyway.
The c in cout stands for console, so you're probably out of luck.
If it's just the syntax you're looking to copy, then you could write your own stream class that creates a message box under the hood and displays it.
You may want to check this out:
How can I redirect stdout to some visible display in a Windows Application?
Can a windows message box be display using the cout syntax?
You can't do it with std::cout. std::cout doesn't even promise to handle Unicode/wide characters (see std::wcout), although Windows's cout has no trouble with wide characters.
You could easily do it with the same syntax; that is, you could easily write a library that overloads operator<< to display dialog boxes. Trying to pass all the information to the dialog box that way would be very difficult, though (how would you you say which buttons to show, what those buttons should do when pressed, where those buttons should be, and the size and position of the window itself?).
You may want to look at something like ncurses. The syntax is different, but I have a
feeling it's what your coworker is looking for.