|
Still does not work. Even after repalcing this line, the sample project does not compile and gives internal compiler error.
|
|
|
|
|
Same here,
still not working
|
|
|
|
|
Hi all,
The updated demo project incorporates the changes I described in this thread. It now uses typename everywhere and compiles fine on VC.NET 2003.
(Boy, I hate this typename stuff. It bloats the source code a lot and nearly everything you refer from a template is a type! The standard comitee should have made types the default and introduced a no_type to destinguish template elemets that are no types...)
--
Daniel Lohmann
http://www.losoft.de
(Hey, this page is worth looking! You can find some free and handy NT tools there )
|
|
|
|
|
Is there a possibility to restrict the number of lines?
So the buffer would not grow to "infinity" and you can only scroll back the last x lines.
I want to use it to log program actions, but I also write them to a log file. So it is not necessary to have all the lines in the buffer all the time.
I'm thinking about this, because my logfile can become very big.
But also without this functionality your CEditLog seems to be the best solution for my problem! Thanx!
|
|
|
|
|
I've been trying to get this to work effectively.... seems to be OK on a win2000/NT machine, but I've been having issues with it on win98.
Quite simply... when you're adding text, just do this too
nSize = (int) ::SendMessage( hEdit, WM_GETTEXTLENGTH, 0, 0 );
if ( nSize > MAX_TEXT_LEN ) {
::SendMessage( hEdit, EM_SETSEL, (WPARAM) 0, (LPARAM) TEXT_TRUNCATE_LEN );
if ( g_bIsWinNT ) {
::SendMessageW( hEdit, EM_REPLACESEL, 0, (LPARAM) "" );
} else {
::SendMessage( hEdit, EM_REPLACESEL, 0, (LPARAM) _W2A( (LPCWSTR) "" ) );
}
nSize = (int) ::SendMessage( hEdit, WM_GETTEXTLENGTH, 0, 0 );
}
Then use EM_SETSEL message with nSize params to set selection point to end of text.
Not 100% but worth a start for discussion purposes
|
|
|
|
|
Hi,
I had problem using your wonderful CEditLog class with a CEditView in a otherwise also strange environment (SDI app, multiple Views and the latest addition CEditLog with CEditView). The problem is, that the CEditView::OnDestroy handler isn't called and therefor the EditView doesn't tell the MainFrame to deactivate the CEditView during shutdown resulting in a crash.
As far as I have understood CSubclassWnd there is no chance to send a message to the subclassed window, after you called UnsubclassWindow (). So the subclassed CEditView doesn't see the message, since you call UnsublcassWindow within the WM_DESTROY handler.
The first solution I came up with was to call the DefWindowProc myself within the CEditLog::OnDestroy before you unsubclass the CEditCtrl
void CEditLog::OnDestroy()
{
DefWindowProc ();
UnsubclassWindow();
}
The second solution would be to remove the WM_DESTROY handling in CEditLog all together, since UnsubclassWindow is called during the WM_NCDESTROY handler from within CSublcassWnd anyway, naturally after the mesage has been passed to the subclassed window
There is this OnFinalMessage handler that you can use to do custom cleanup.
I would prefer the second solution, but I'm not sure why you introduced this handling of WM_DESTROY into your CEditLog. Perhaps some artifical relict.
As a second note: even if the following case handling will do no harm, I doesn't look like good coding style
case WM_ERASEBKGND:
if( m_bNoPaint )
return TRUE;
case WM_PAINT:
if( m_bNoPaint )
return TRUE;
You better combine those two cases and introduce a break. This is the funny behavoir if you introduce a further case statement and wonder why it is called in some strange situations.
Thanks for the class
Dirk
|
|
|
|
|
Thanks Dirk!
Very good points!
I would prefer the second solution, but I'm not sure why you introduced this handling of WM_DESTROY into your CEditLog. Perhaps some artifical relict.
To be honest - I don't know exactly why I am doing this. I assume it is still there because the original V1.0 of CSubclassWnd did not handle WM_NCDESTROY.
I will remove it in the next version
As a second note: even if the following case handling will do no harm, I doesn't look like good coding style
case WM_ERASEBKGND:
if( m_bNoPaint )
return TRUE;
case WM_PAINT:
if( m_bNoPaint )
return TRUE;
--
Daniel Lohmann
http://www.losoft.de
(Hey, this page is worth looking! You can find some free and handy NT tools there )
|
|
|
|
|
I am trying to display data from an array (lets just say a CString array) in a standard CEdit control with each item in the array on its own line. Is there a way to do this in a CEdit? I have tried to read the data into one big string with "\n"s between the items but this does not work. I am using SetWindowText() to display this data in the edit control. When I do that with "\n"s in the string, it just displays a "|" character where the line breaks are and keeps writing the rest of the text on the same line. There must be an easy way to do this. Please help!!!!!!
Newby,
Anthony
|
|
|
|
|
|
Perfect piece of code, especially because I needed the 'fast' thing since my debug-tool used this to handle a lot of data from several devices in a testbed.
Its based around Doc/View MDI architecture, where CEditLog is hooked into CEditView.
Now I've run into a small problem
When trying to print it cannot 'access' the textdata (and so crashes), and if saving the data, the file will be empty.
I do not have any clue where to start. Anyone a suggestion?
Thanks in advance
EiSl
|
|
|
|
|
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
|
|
|
|
|