|
Hm...
After a quick look into the sources of CEditView it seems that it sometimes uses a so-called "shadow buffer". This is needed on Win32s, but the code looks like it is also used on Win95 and derived systems. Maybe ths is the source for your problem.
I recommend to single step the save/print functions in your app and take a look where in the MFC sources they crash or fail.
--
Daniel Lohmann
http://www.losoft.de
(Hey, this page is worth looking! You can find some free and handy NT tools there )
|
|
|
|
|
Sooo. that's what I'm calling fast-support!
I was already afraid for this. I will start with the easy route first, which will be stepping through the 'Save' code.
The funny part of this all is... this morning my collega started with 'Murphy's Laws' jokes, and now I'm subject to it
I will keep you in touch )!
EiSl
|
|
|
|
|
Really great class ! I give it a 5.
I've added small helper class, CStreamRedirector , that handles stream attaching / detaching.
The typical use would be: create a CEditLog instance and a CStreamRedirector instance attached to the CEditLog . When redirection has to be turned on, call CStreamRedirector::Redirect(). To turn it off, UnRedirect(). The stream pointer mess cleaning is handled by CStreamRedirector
Here it is, if anybody interested
#include "EditLog.h"
#include "editlog_stream.h"
class CStreamRedirector
{
public:
CStreamRedirector(CEditLog& log);
virtual ~CStreamRedirector();
void Redirect();
void UnRedirect();
protected:
CEditLog& m_log;
bool m_bRedirect;
std::editstreambuf m_EditCout;
std::weditstreambuf m_EditWCout;
std::editstreambuf m_EditCerr;
std::weditstreambuf m_EditWCerr;
std::basic_streambuf< char >* m_pCout;
std::basic_streambuf< wchar_t >* m_pWCout;
std::basic_streambuf< char >* m_pCerr;
std::basic_streambuf< wchar_t >* m_pWCerr;
};
And here's the implementation
CStreamRedirector::CStreamRedirector(CEditLog& log)
: m_log(log), m_bRedirect(false),
m_EditCout(log), m_EditWCout(log), m_EditCerr(log), m_EditWCerr(log)
{
}
CStreamRedirector::~CStreamRedirector()
{
UnRedirect();
}
void CStreamRedirector::Redirect()
{
if (m_bRedirect)
return;
m_bRedirect=true;
m_pCout= std::cout.rdbuf( &m_EditCout);
m_pWCout= std::wcout.rdbuf( &m_EditWCout);
m_pCerr= std::cerr.rdbuf( &m_EditCerr);
m_pWCerr= std::wcerr.rdbuf( &m_EditWCerr);
};
void CStreamRedirector::UnRedirect()
{
if (!m_bRedirect)
return;
m_bRedirect=false;
std::cout.rdbuf( m_pCout);
std::wcout.rdbuf( m_pWCout);
std::cerr.rdbuf( m_pCerr);
std::wcerr.rdbuf( m_pWCerr);
};
Jonathan de Halleux.
|
|
|
|
|
Thanks Jonathan
This looks like a useful utility class.
BTW: Your rating of the article seems to have bombed the rating system, it now always shows "0 users have rated this article". Maybe an overflow...
--
Daniel Lohmann
http://www.losoft.de
(Hey, this page is worth looking! You can find some free and handy NT tools there )
|
|
|
|
|
Thanks for the quick response on my previous problem. You were right !
My other problem is that although any cout from the application do redirects to the edit control, other cout's, which are located inside dll functions that link with the application, don't.
I have tried to change the cout within the dll to use std::cout, and use
#include <iostream>
using namespace std
but nothing helped.
Can you help me?
|
|
|
|
|
Oh, oh, this way it is getting really difficult. It may be that the DLL links statically with the CRT and therefore use an own instance of cout. Or it is simply not using cout, but printf(), Win32 WriteFile() and so on.
I can think of only one way out here, but it is a rather hard and difficult one: All output to stdout is passed at one moment (deep inside the CRT) to WriteFile(). If you patch WriteFile() and redirect it to your own function, you could check for the file handle beeing the stdout handle (using GetStdHandle()) and in this case redirect it to the EditLog. However, patching API functions is not trivial, especially under Win9x/Me. There are articles about this here at Codeproject:
[1] HookImportetFunctionByName
[2] API hooking revealed
--
Daniel Lohmann
http://www.losoft.de
|
|
|
|
|
I tried to imlpement the code in my project and i get this 4 error messages which are all the same problem :
error C2065: 'cout' : undeclared identifier
error C2228: left of '.rdbuf' must have class/struct/union type
error C2065: 'wcout' : undeclared identifier
error C2228: left of '.rdbuf' must have class/struct/union type
Those error concern this lines :
m_pOldBuf = cout.rdbuf(&m_EditStrBuf);
m_pOldBufW = wcout.rdbuf(&m_EditStrBufW);
Can any one help me figure out why?
|
|
|
|
|
I suppose the reason is that you missed to put
std:: in front of the cout/wcout identifiers or forget to write a
using std directive in the CPP file.
Take a look at the demo project how it is handled there.
--
Daniel Lohmann
http://www.losoft.de
|
|
|
|
|
Daniel,
This code was exactly what I was looking for. It took me hours to integrate it into my current project, but it was worth it. So thanks from Munich!
|
|
|
|
|
I love the control, particularly the fact that you can connect it to std::cout. However, I'd also like to be able to clear the text from the edit control while it is connected to std::cout. Is this a natively supported option? I've tried ::SendMessage(hwnd, WM_SETTEXT, 0,0) from within a CEditLog method that I added, but this doesn't seem to do the trick. Do you know if this is possible? Thanks & keep up the great work. Cheers.
|
|
|
|
|
The usual way to clear an edit control is to select the whole content and then send it a WM_CLEAR. However, This seems not to work for read-only controls, so we have to remove the read-only flag first:
BOOL bReadOnly = ::GetWindowLong( hEdit, GWL_STYLE ) & ES_READONLY;
if( bReadOnly )
::SendMessage( hEdit, EM_SETREADONLY, FALSE, 0 );
::SendMessage( hEdit, EM_SETSEL, 0, -1 );
::SendMessage( hEdit, WM_CLEAR, 0, 0 );
if( bReadOnly )
::SendMessage( hEdit, EM_SETREADONLY, TRUE, 0 );
I personally prefer to put things like that not into CEditLog, because clearing it's content is a concern belonging to the underlaying edit control and CEditLog is designed to work with any edit control. However, one can also argue that clearing the log is a fundamental feature of CEditLog
--
Daniel Lohmann
http://www.losoft.de
|
|
|
|
|
How about:
<br />
::SetWindowText(hEdit, "");<br />
-Gernot Frisch
Dream Design
reverse Tonreg to reply...
|
|
|
|
|
Oh....
Thanks, Gernot
--
Daniel Lohmann
http://www.losoft.de
(Hey, this page is worth looking! You can find some free and handy NT tools there )
|
|
|
|
|
I have a dialog box with an edit control on it in my SDI application. My dialog class is derived from cdialog. I've done as the example says but I am getting the following errors:
EditLogDlg.cpp
F:\Src\EditLogDlg.cpp(21) : error C2512: 'basic_editstreambuf<char,struct std::char_traits<char="">,512>' : no appropriate default constructor available
F:\Src\EditLogDlg.cpp(21) : error C2512: 'basic_editstreambuf<unsigned short,struct="" std::char_traits<unsigned="" short="">,512>' : no appropriate default constructor available
what does that mean and how do i get rid of it? the example compiles fine so my assumption is I'm doing something wrong. can someone please help?
|
|
|
|
|
Do you include the necessary STL headers in your stdafx.h?
I do not include them "by hand" in EditLog.h/EditLog.cpp 'cause I think never changed C++ std-headers should be located in stdafx.h.
Just add the following to your projects stdafx.h
// Include core STL header
#include <string>
#include <streambuf>
#include <iostream>
Daniel
|
|
|
|
|
I had the same problem and it took me quite a while to figure it out, but in the end it's easy: if you declare something like..
class MyClass {
private:
CEditLog m_EditLogger;
std::editstreambuf m_EditStrBuf;
...
};
...the compiler needs a default constructor for editstreambuf (because you didn't give any parameters), unless you use the initialiser list of the constructor of MyClass:
MyClass::MyClass(params...) : m_EditStrBuf( m_EditLogger ) {
...
}
Doing it this way no default constructor is needed, because m_EditStrBuf is initialised with a parameter. Btw, that's how it's done in the example application
|
|
|
|
|
1. Missing ; on line 245 of EditLog.cpp
2. Dragging the scrollbar middle section while in fast mode can get it lost and it never logs to bottom of window again.
3. 64K size limitation of Windows 9.x can be removed by using a CRichEditCtrl instead of a CEdit control. Remember to call AfxInitRichEdit() in InitInstance()
This would be a good enhancement for adding color coding etc to the log. I tried a quick demo and it works but the scrolling gets hosed, however everything else works as is.
If I get time I may try enhancing it.
Great logging class though !!!!
Colin
|
|
|
|
|
Hi Colin,
Thanks for your comments.
The really nasty thing is, as you have also found out, the scrolling. I found no solution which works really reliable in all cases.
However, if you lost the bottom position, you can get it back by pressing CTRL+END.
The scrolling is also the thing that took me away from RichEdit so far. But I'm always open for suggestions and improvements
Danie
|
|
|
|
|
I too have written a similar CTranscriptCtrl based on CEdit for managing logging information. Yours is more sophisticated : }, mine was just a simple little convenience thing.
However, the 64K limit of CEdit is getting nasty, and I need a way to increase that, and RichEdit looks like it would provide that and open up some other interesting possibilities, but for the scrolling issue!$#!@
Do you or anyone know of how to figgure out whether a given line is on screen, or better, what the total display height (in pixels, twips, anything) is? That would be an adequate piece of info to do the scrolling, since one can determine the rect height, the margins, and the first line index to be visible.
Steve Wolf
|
|
|
|
|
It works great! My question is:
Can stdout and stderr be redirected too?
Thanks.
Q
|
|
|
|
|
That would be really nice. However, I haven't found how to do this. Okay, the idea is to write your own implementation of a FILE datatype and put it's output to the edit control - but I never understood the MS implementations of FILE...
Danie
|
|
|
|
|
I've been fooling with similar ideas myself, but I haven't found many resources on iostream programing.
|
|
|
|