home *** CD-ROM | disk | FTP | other *** search
- Xref: sparky comp.lang.c++:16810 comp.os.ms-windows.programmer.misc:3628
- Newsgroups: comp.lang.c++,comp.os.ms-windows.programmer.misc
- Path: sparky!uunet!think.com!cass.ma02.bull.com!catfish.az05.bull.com!news
- From: aking@trees.az05.bull.com (Andy King)
- Subject: Re:Implementing a 'message' class
- Message-ID: <1992Nov23.235954.4348@catfish.az05.bull.com>
- Sender: news@catfish.az05.bull.com (placeholder for future)
- Reply-To: aking@trees.az05.bull.com (Andy King)
- Organization: Bull HN Information Systems Inc., Phoenix Product Division
- Date: Mon, 23 Nov 92 23:59:54 GMT
- Lines: 289
-
-
- I received two responses to my original questions, from Skip Carter and
- Steve Clamage. These responses 'inspired' the code which follows at the
- end of this article.
-
- I am posting this follow-up to both the C++ group and the windows
- programming group. The code is actually more appropriate to a
- Borland newsgroup, but I don't know of one.
-
- Basically, I wanted a facility for displaying debug or trace messages
- in a GUI based environment, sending these messages to a window, instead
- of to standard or error out. Additionally, I wanted the option of
- writing the output to a file, in addition to the display window.
-
- My solution is actually for the Borland OWL (Object Windows Library)
- environment - it won't work with other GUIs. But the approach should
- adapt easily to other environments. There are two facilities
- within the include file at the end of this article: the first is a
- redefinition of the 'assert()' macro; the second is the message display
- ('owldebug') class definition.
-
- The 'assert()' macro is overridden to display a message box, and provides
- the option to continue with execution of the program, or to exit. This
- doesn't have any relationship to the original request, but I thought
- it was appropriate.
-
- There are comments in the code describing how to use the 'owldebug'
- class. I have not separated the declaration and definition sections
- (into '.cpp' and '.h' files). An additional note to these comments is
- that the output window can be updated from the keyboard while the program
- is running; I had considered disabling input, but in retrospect decided
- that it may be useful. For example, it facilitates annotation of the
- displayed values.
-
- Some questions:
-
- - is it safe to just 'exit()' a Windows program? Almost certainly
- not, since destructors will not be called. So, what should be
- done, instead of using 'exit()'?
-
- - how do I reset the stream buffer - at present, I call 'memset()'
- and 'seekp(beg)', but the 'memset()' seems unnecessary (the results
- were unreliable without this call).
-
- - how do I set the text position to the end of the 'Editor' buffer?
- At present, output will occur at the current cursor position.
-
- - are there any Borland-specific newsgroups? (We don't receive
- most of the 'alt' groups, but I could request them).
-
- If anyone finds this code interesting or useful, I'd appreciate an
- email message, with just a 'thanks!'. If you have questions, comments,
- or suggestions, I'd welcome those, too.
-
- Thanks,
-
- Andy King.
-
- email: aking@trees.az05.bull.com
-
-
- //----------------------------- owldebug.h -----------------------------------\\
-
- #ifndef __OWLDEBUG_H
- #define __OWLDEBUG_H
-
- #include <strstream.h>
- #include <filewnd.h>
-
- //----------------------------------------------------------------------------\\
-
- //
- // The following macro and function definitions provide an alternative 'assert'
- // mechanism, for use in a Windows program. When 'assert()' is used, this
- // function will display a message box, with the standard assert information.
- // An option is provided to 'exit()' the program, or to continue.
- //
-
- #ifndef NDEBUG
- # ifdef assert
- # undef assert
- # endif
- # define assert(expression) if (!(##expression)) \
- winassert(#expression, __FILE__, __LINE__)
- #endif
-
- void
- winassert(char* expression, char* filename, long line_number)
- {
- int response;
- char message_buffer[200];
- ostrstream message(message_buffer, sizeof(message_buffer));
-
- memset(message_buffer, '\0', sizeof(message_buffer));
- message.seekp(ostream::beg);
- message << "Assertion failed: " << expression << endl;
- message << "File: " << filename << " Line: " << line_number;
- if (errno != 0)
- message << " errno: " << errno;
- message << endl;
- message << "Do you want to exit the program?" << endl;
- response = MessageBox(NULL, message.str(), "Failed Assertion",
- MB_YESNO | MB_ICONHAND | MB_SYSTEMMODAL);
- if (response == IDYES)
- exit(1);
- } // end of winassert()
-
- //----------------------------------------------------------------------------\\
-
- //
- // The 'debug_window_class' provides the output window for the 'owldebug_class'.
- // It is implemented as a 'TFileWindow', which provides both the 'EditWindow'
- // facilities (e.g., automatic scrolling) and the facility for saving the
- // output to a file.
- //
-
- class debug_window_class : public TFileWindow
- {
- public:
- debug_window_class(PTWindowsObject parent);
- virtual void SetupWindow();
- virtual LPSTR GetClassName();
- virtual BOOL CanClear();
- }; // end of debug_window_class
-
- //----------------------------------------------------------------------------\\
-
- debug_window_class::debug_window_class(PTWindowsObject parent)
- : TFileWindow(parent, "Debug", "")
- {
-
- Attr.Style = WS_POPUP | WS_OVERLAPPEDWINDOW | WS_VISIBLE;
- } // end of debug_window_class::debug_window_class()
-
- //----------------------------------------------------------------------------\\
-
- void
- debug_window_class::SetupWindow()
- {
- int width, height;
- HGDIOBJ font_handle;
- HDC device_context_handle;
- HMENU menu_bar_handle;
- TEXTMETRIC text_metrics;
-
- TFileWindow::SetupWindow();
- // set the font to be used in the debug window
- font_handle = GetStockObject(ANSI_FIXED_FONT);
- SendMessage(Editor->HWindow, WM_SETFONT, (WPARAM)font_handle, 0);
- // find out the character size in the debug window
- device_context_handle = GetDC(Editor->HWindow);
- GetTextMetrics(device_context_handle, &text_metrics);
- ReleaseDC(Editor->HWindow, device_context_handle);
- // resize the debug window to about 25 rows of 30 characters
- width = text_metrics.tmAveCharWidth * 32;
- height = text_metrics.tmHeight * 27;
- MoveWindow(HWindow, 0, 0, width, height, FALSE);
- // create the 'Save...' menu entry
- menu_bar_handle = CreateMenu();
- AppendMenu(menu_bar_handle, MF_STRING, CM_FILESAVEAS, "Save...");
- SetMenu(HWindow, menu_bar_handle);
- } // end of debug_window_class::SetupWindow()
-
- //----------------------------------------------------------------------------\\
-
- LPSTR
- debug_window_class::GetClassName()
- {
-
- return("debug_window");
- } // end of debug_window_class::GetClassName()
-
- //----------------------------------------------------------------------------\\
-
- // The 'CanClear()' member function is overridden so that closing of the
- // debug window will never be prevented, even if the output has not been
- // saved to file.
-
- BOOL
- debug_window_class::CanClear()
- {
-
- return(TRUE); // always allow clearing of the edit area
- } // end of debug_window_class::CanClear()
-
- //----------------------------------------------------------------------------\\
-
- // The 'owldebug_class' provides a stream based output mechanism for debug and
- // trace messages from an OWL program. It is derived from 'ostrstream', and
- // thus provides all stream output functionality (i.e., 'operator<<()' can
- // be used for all types on which it is defined).
- //
- // When the owldebug_class 'initialize()' member function is called, a
- // window is created, in which all subsequent stream output for that object
- // is displayed. The function 'endod()' must be used to output the stream
- // to the debug window. Don't use 'endl' in the stream output; 'endod' will
- // output a carriage return and line feed.
- //
- // Recommended use:
- // - #include <filedial.dlg> in the '.rc' file for the project. Without
- // this, no 'save' of the output can occur
- // - #include <owldebug.h> in any source unit which requires debug output
- // - instantiate an 'owldebug_class' variable before any of the functions in
- // the source unit which contains 'WinMain()'; declare the variable as
- // 'extern' in other source units
- // - following the creation of the main window, in 'InitMainWindow()',
- // initialize the 'owldebug_class' variable using the 'initialize()'
- // member function. The owldebug_class 'initialize()' function
- // takes a window object pointer as its argument (e.g.,
- // owldebug_var.initialize(MainWindow))
- // - send output to the debug window using the stream output operator with
- // the 'owldebug_class' variable. For example:
- // owldebug_var << "Load succeeded" << endod;
- // owldebug_var << "Got message " << (int)message.LP.Hi << ','
- // << (int)message.LP.Lo << endod;
- //
- // If the 'owldebug_class' instance is not initialized (by calling the
- // 'initialize()' member function) there will obviously be no display of
- // messages - but this will not cause a failure in execution. Whether
- // instantiated or not, output to an 'owldebug_class' instance will cause
- // degradation in performance.
- //
- // It is feasible to create multiple instances of the 'owldebug_class', and
- // to use the different instances for distinct purposes (e.g., varying
- // levels of debugging).
- //
-
- class owldebug_class : public ostrstream
- {
- public:
- owldebug_class();
- void initialize(PTWindowsObject parent_window);
- friend ostream& endod(ostream& debug);
- private:
- debug_window_class* debug_window;
- char stream_buffer[500];
-
- void display_message();
- }; // end of owldebug_class
-
- //----------------------------------------------------------------------------\\
-
- owldebug_class::owldebug_class()
- : ostrstream(stream_buffer, sizeof(stream_buffer))
- {
-
- memset(stream_buffer, '\0', sizeof(stream_buffer));
- debug_window = NULL;
- } // end of owldebug_class::owldebug_class()
-
- //----------------------------------------------------------------------------\\
-
- void
- owldebug_class::initialize(PTWindowsObject parent_window)
- {
-
- debug_window = new debug_window_class(parent_window);
- parent_window->GetApplication()->MakeWindow((PTWindowsObject)debug_window);
- } // end of owldebug_class::initialize()
-
- //----------------------------------------------------------------------------\\
-
- void
- owldebug_class::display_message()
- {
-
- if (debug_window != NULL)
- {
- debug_window->Editor->Insert(str());
- debug_window->Editor->Insert("\r\n");
- }
- memset(stream_buffer, '\0', sizeof(stream_buffer));
- seekp(beg);
- } // end of owldebug_class::display_message()
-
- //----------------------------------------------------------------------------\\
-
- ostream&
- endod(ostream& debug)
- {
- owldebug_class* owldebug = (owldebug_class*)&debug;
-
- owldebug->display_message();
- return((owldebug_class&)debug);
- } // end of endod()
-
- //----------------------------------------------------------------------------\\
-
- #endif // ifndef __OWLDEBUG_H
-