home *** CD-ROM | disk | FTP | other *** search
/ C Programming Starter Kit 2.0 / SamsPublishing-CProgrammingStarterKit-v2.0-Win31.iso / bc45 / docview.pak / XCPTVIEW.CPP < prev    next >
C/C++ Source or Header  |  1997-07-23  |  12KB  |  486 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows - (C) Copyright 1993 by Borland International
  3. //   Implements class TExceptionView
  4. //----------------------------------------------------------------------------
  5. #include <owl\owlpch.h>
  6. #include <owl\docmanag.h>
  7. #include "xcptview.rc"
  8. #include <owl\docview.rc>
  9. #include <owl\inputdia.h>
  10. #include <owl\compat.h>
  11. #include <owl\listbox.h>
  12. #include <owl\filedoc.h>
  13. #include "xcptview.rc"
  14.  
  15. class XVLink;
  16.  
  17. class _DOCVIEWCLASS TExceptionView : public TListBox, public TView {
  18.   public:
  19.     TExceptionView(TDocument& doc, TWindow* parent = 0);
  20.    ~TExceptionView();
  21.     static LPCSTR StaticName() {return "Exception Log";}  // put in resource
  22.     BOOL DirtyFlag;
  23.     int CurIndex;
  24.     void LogThrow(char* str);
  25.     void Annotate(int index, char chr, BOOL cache = FALSE);
  26.  
  27.     //
  28.     // overridden virtuals from TView
  29.     //
  30.     const char far*   GetViewName(){return StaticName();}
  31. //    LPCSTR   GetViewName(){return StaticName();}
  32.     TWindow* GetWindow()  {return (TWindow*)this;}
  33.     BOOL     SetDocTitle(const char far* docname, int index)
  34. //    BOOL     SetDocTitle(LPCSTR docname, int index)
  35.                           {return TListBox::SetDocTitle(docname, index); }
  36.     //
  37.     // overridden virtuals from TWindow
  38.     //
  39.     BOOL CanClose()   {return TListBox::CanClose() && Doc->CanClose();}
  40.     BOOL Create();
  41.  
  42.   protected:
  43.     long Origin;
  44.     int  MaxWidth;    // maximum horizontal extent
  45.     XVLink* Link;
  46.     char Cache;
  47.     unexpected_function OldUnexpectedHandler;
  48.     void Init();
  49.     void SetExtent(LPSTR str);
  50.     BOOL LoadData(int top, int sel);
  51.     //
  52.     // message response functions
  53.     //
  54.     BOOL VnDocClosed(int omode);
  55.     BOOL VnCommit(BOOL force);
  56.     BOOL VnRevert(BOOL clear);
  57.     BOOL VnIsWindow(HWND hWnd) {return HWindow == hWnd;}
  58.     BOOL VnIsDirty()       {return DirtyFlag;}
  59.     void CmSelChange(){} // to prevent interpreting as unprocessed accelerator
  60.     void CmTXOwl();
  61.     void CmTXTest();
  62.     void CmTXComp();
  63.     void CmTXMem();
  64.     void CmXalloc();
  65.     void CmXmsg();
  66.     void CmForeign();
  67.     void CmUnexpected() throw (xalloc);
  68.     void CmBadCast();
  69.     void CmBadTypeid();
  70.     void CmOwlSend();
  71.     void CmClear();
  72.     void EvTimeChange();
  73.   DECLARE_RESPONSE_TABLE(TExceptionView);
  74.   DECLARE_STREAMABLE(,TExceptionView,1);
  75. };
  76.  
  77. class XVLink{  // access class to prevent calling deleted view
  78.   public:
  79.     XVLink(TExceptionView* view) : View(view), RefCnt(1), Suspended(FALSE) {}
  80.     TExceptionView* View;
  81.     int RefCnt;
  82.     BOOL Suspended;
  83.     void Annotate(int index, char chr)
  84.       {if (View) View->Annotate(index, chr, Suspended);}
  85.     void AddRef() {RefCnt++;}
  86.     void SubRef() {if (--RefCnt == 0) delete this;}
  87. };
  88.  
  89. class TXTest : public TXOwl {
  90.   public:
  91.     TXTest(UINT resId, XVLink* view, int index);
  92.     TXTest(const TXTest&);
  93.     const TXTest& operator = (const TXTest&);
  94.    ~TXTest();
  95.     TXOwl* Clone();
  96.     void Throw();
  97.     int Unhandled(TModule* app, unsigned promptResId);
  98.     XVLink* View;
  99.     int Index;
  100. };
  101.  
  102. DEFINE_RESPONSE_TABLE1(TExceptionView, TListBox)
  103.   EV_COMMAND(CM_TXOWL,      CmTXOwl),
  104.   EV_COMMAND(CM_TXTEST,     CmTXTest),
  105.   EV_COMMAND(CM_TXCOMP,     CmTXComp),
  106.   EV_COMMAND(CM_TXMEM,      CmTXMem),
  107.   EV_COMMAND(CM_XALLOC,     CmXalloc),
  108.   EV_COMMAND(CM_XMSG,       CmXmsg),
  109.   EV_COMMAND(CM_FOREIGN,    CmForeign),
  110.   EV_COMMAND(CM_UNEXPECTED, CmUnexpected),
  111.   EV_COMMAND(CM_BADCAST,    CmBadCast),
  112.   EV_COMMAND(CM_BADTYPEID,  CmBadTypeid),
  113.   EV_COMMAND(CM_OWLSEND,    CmOwlSend),
  114.   EV_COMMAND(CM_XCLEAR,     CmClear),
  115.   EV_NOTIFY_AT_CHILD(LBN_SELCHANGE, CmSelChange),
  116.   EV_VN_DOCCLOSED,
  117.   EV_VN_ISWINDOW,
  118.   EV_VN_ISDIRTY,
  119.   EV_VN_COMMIT,
  120.   EV_VN_REVERT,
  121.   EV_WM_TIMECHANGE,
  122. END_RESPONSE_TABLE;
  123.  
  124. void XUnexpectedHandler()
  125. {
  126.   throw xmsg(string(*::Module,XM_UNEXPECTED));
  127. }
  128.  
  129. TExceptionView::TExceptionView(TDocument& doc, TWindow* parent)
  130.    : TView(doc), TListBox(parent, GetNextViewId(), 0,0,0,0),
  131.      Origin(0), MaxWidth(0)
  132. {
  133.   Attr.Style &= ~(WS_BORDER | LBS_SORT);
  134.   Attr.Style |= (WS_HSCROLL | LBS_NOINTEGRALHEIGHT);
  135.   Attr.AccelTable = IDA_XCPTVIEW;
  136.   SetViewMenu(new TMenuDescr(IDM_XCPTVIEW,0,2,0,0,0,1));
  137.   Init();
  138. }
  139.  
  140. void TExceptionView::Init()
  141. {
  142.   Link = new XVLink(this);
  143.   OldUnexpectedHandler = set_unexpected(XUnexpectedHandler);
  144.   DirtyFlag = FALSE;
  145.   Cache = 0;
  146. }
  147.  
  148. TExceptionView::~TExceptionView()
  149. {
  150.   Link->View = 0;  // prevent calling into destructed view
  151.   Link->SubRef();  // will destruct when no outstanding exceptions
  152.   set_unexpected(OldUnexpectedHandler);
  153. }
  154.  
  155. struct XTest {  // class with destructor for testing TPointer
  156.   char* P;
  157.   XTest() {P = new char[4];}
  158.   virtual ~XTest();     // non inline to allow breakpoint set
  159. };
  160. XTest::~XTest(){delete P;}
  161.  
  162. struct XTestD : public XTest {  // class derived from XTest
  163.   XTestD() : XTest(), Q(0) {}
  164.   char* Q;
  165.  ~XTestD() {delete Q;}
  166. };
  167.  
  168. static ThrowTXOwl()  // extra call level to allow TPointer testing
  169. {
  170.   throw TXOwl(XM_TXOWL);
  171. }
  172.  
  173. void TExceptionView::CmTXOwl()
  174. {
  175.   TPointer<char> ptr = new char[20];
  176.   ptr[0] = 0;
  177.   TPointer<XTest> x;
  178.   x = new XTest();
  179.   LogThrow("TXOwl thrown");
  180.   XTest* xt = new XTestD();
  181.   delete xt;
  182.   ThrowTXOwl();
  183. }
  184.  
  185. void TExceptionView::CmTXTest()
  186. {
  187.   LogThrow("TXTest thrown");
  188.   throw TXTest(XM_TXTEST, Link, CurIndex);
  189. }
  190.  
  191. void TExceptionView::CmTXComp()
  192. {
  193.   LogThrow("TXCompatibility throw by setting Status");
  194.   Status = EM_INVALIDWINDOW;
  195. }
  196.  
  197. void TExceptionView::CmTXMem()
  198. {
  199.   LogThrow("TXOutOfMemory thrown");
  200.   throw TXOutOfMemory();
  201. }
  202.  
  203. void TExceptionView::CmXalloc()
  204. {
  205.   LogThrow("xalloc thrown");
  206.   throw xalloc(string(*::Module,XM_XALLOC),1234);
  207. }
  208.  
  209. void TExceptionView::CmXmsg()
  210. {
  211.   LogThrow("xmsg thrown");
  212.   throw xmsg(string(*::Module,XM_XMSG));
  213. }
  214.  
  215. void TExceptionView::CmForeign()
  216. {
  217.   LogThrow("int thrown");
  218.   throw (int)35;
  219. }
  220.  
  221. void TExceptionView::CmUnexpected() throw (xalloc)
  222. {
  223.   LogThrow("Unexpected xmsg thrown");
  224.   throw xmsg(string(*::Module,XM_UNEXPECTED));
  225. }
  226.  
  227. static xmsg* XVRef(xmsg&) {return 0;}
  228.  
  229. void TExceptionView::CmBadCast()
  230. {
  231.   LogThrow("Failed dynamic_cast<>");
  232.   XVRef(dynamic_cast<xmsg&>(*this));
  233. }
  234.  
  235. void TExceptionView::CmBadTypeid()
  236. {
  237.   LogThrow("type_id() called on invalid object");
  238.   class __rtti C {int i; virtual ~C(){}};
  239.   C* o = 0;
  240.   static const char* n;
  241.   n = typeid(*o).name();
  242. }
  243.  
  244. void TExceptionView::CmOwlSend()
  245. {
  246.   ::SendMessage(HWindow, WM_TIMECHANGE,0,0); // any strange message will do
  247.   GetApplication()->ResumeThrow();
  248. }
  249.  
  250. void TExceptionView::EvTimeChange()
  251. {
  252.   LogThrow("TXTest thrown from event handler");
  253.   throw TXTest(XM_OWLSEND, Link, CurIndex);
  254. }
  255.  
  256. void TExceptionView::CmClear()
  257. {
  258.   ClearList();
  259.   DirtyFlag = FALSE;
  260.   SetHorizontalExtent(MaxWidth = 0);
  261. }
  262.  
  263. void TExceptionView::LogThrow(char* str)
  264. {
  265.   SetSelIndex(CurIndex = AddString(str));
  266.   SetExtent(str);
  267.   DirtyFlag = TRUE;
  268. }
  269.  
  270. void TExceptionView::Annotate(int index, char chr, BOOL cache)
  271. {
  272.   if (Cache) {  // check if character logged during exception processing
  273.     char chr = Cache;
  274.     Cache = 0;
  275.     Annotate(index, chr);  // we assume here we're still at the same index
  276.   }
  277.   if (cache && chr == '~') {  // check if in destructor with cloned exception
  278.     Cache = chr;
  279.     return;
  280.   }
  281.   char buf[100];
  282.   int len = GetStringLen(index);
  283.   GetString(buf, index);
  284.   buf[len]   = ' ';
  285.   buf[len+1] = chr;
  286.   buf[len+2] = 0;
  287.   DeleteString(index);
  288.   InsertString(buf, index);
  289.   SetSelIndex(index);
  290. }
  291.  
  292. void TExceptionView::SetExtent(LPSTR str)
  293. {
  294.   HDC hdc;
  295.   int len;
  296.   TSize extent;
  297.   if ((len = strlen(str)) == 0)
  298.     return;
  299.   hdc = ::GetDC(HWindow);
  300.   ::GetTextExtentPoint(hdc, str, len, &extent);
  301.   extent.cx += 2; // room for focus rectangle
  302.  
  303.   if (extent.cx > MaxWidth){
  304.     SetHorizontalExtent(MaxWidth = extent.cx);
  305.   }
  306.   ::ReleaseDC(HWindow, hdc);
  307. }
  308.  
  309. BOOL TExceptionView::VnDocClosed(int omode)
  310. {
  311.   int top;
  312.   int sel;
  313.   if (DirtyFlag == 2 || !(omode & ofWrite))  // make sure someone else's write
  314.     return FALSE;
  315.   top = GetTopIndex();
  316.   sel = GetSelIndex();
  317.   LoadData(top, sel);
  318.   return TRUE;
  319. }
  320.  
  321. BOOL TExceptionView::LoadData(int top, int sel)
  322. {
  323.   char buf[100+1];
  324.   istream* inStream;
  325.   BOOL status = TRUE;
  326.  
  327.   CmClear();
  328.   DirtyFlag = FALSE;
  329.   if ((inStream = Doc->InStream(ios::in)) == 0) {
  330.     Doc->PostError(IDS_UNABLEOPEN, MB_OK);
  331.     return FALSE;
  332.   }
  333.   for (;;) {
  334.     inStream->getline(buf, sizeof(buf)-1);
  335.     if (!inStream->gcount() && !inStream->good()) {
  336.       status = inStream->eof();
  337.       break;
  338.     }
  339.     AddString(buf);
  340.     SetExtent(buf);
  341.   }
  342.   SetTopIndex(top);
  343.   SetSelIndex(sel);
  344.   delete inStream;   // close file in case process switch
  345.   if (!status)
  346.     Doc->PostError(IDS_READERROR, MB_OK);
  347.   return status;
  348. }
  349.  
  350. BOOL TExceptionView::Create()
  351. {
  352.   try {
  353.     TListBox::Create();   // throws exception TWindow::TXWindow
  354.   }
  355.   catch (TXOwl& x) {
  356.     Doc->PostError(IDS_NOMEMORYFORVIEW, MB_OK);
  357.     return TRUE;   // cannot return FALSE - throws another exception
  358.   }
  359.   if (Doc->GetDocPath() == 0) {
  360.     return TRUE;           // new file, no data to display
  361.   }
  362.   if (!LoadData(0, 0))
  363.     NotOK();
  364.   return TRUE;
  365. }
  366.  
  367. BOOL TExceptionView::VnCommit(BOOL force)
  368. {
  369.   int count;
  370.   int index;
  371.   int len;
  372.   char* buf;
  373.   ostream* outStream;
  374.   BOOL status;
  375.  
  376.   if (!force && !DirtyFlag)
  377.     return TRUE;
  378.   if ((outStream = Doc->OutStream(ios::out)) == 0) {
  379.     Doc->PostError(IDS_UNABLEOPEN, MB_OK);
  380.     return FALSE;
  381.   }
  382.   outStream->seekp(Origin);
  383.   count = GetCount();
  384.   for (index = 0; index < count; index++) {
  385.     len = GetStringLen(index);
  386.     buf = new char[len+1];
  387.     GetString(buf, index);
  388.     *outStream << buf << '\n';
  389.     delete buf;
  390.   }
  391.   DirtyFlag = 2;           // to detect our own close notification
  392.   status = outStream->good();
  393.   delete outStream;
  394.   DirtyFlag = FALSE;
  395.   if (!status)
  396.     Doc->PostError(IDS_WRITEERROR, MB_OK);
  397.   return status;
  398. }
  399.  
  400. BOOL TExceptionView::VnRevert(BOOL clear)
  401. {
  402.   if (!clear && Doc->GetDocPath() != 0)
  403.     return LoadData(0,0);
  404.   CmClear();
  405.   return TRUE;
  406. }
  407.  
  408. // Exception class for monitoring exception progress
  409.  
  410. TXTest::TXTest(UINT resId, XVLink* view, int index)
  411.        : TXOwl(resId), View(view), Index(index)
  412. {
  413.   View->AddRef();
  414.   View->Annotate(Index, '#');
  415. }
  416.  
  417. TXTest::TXTest(const TXTest& s) : TXOwl(s), View(s.View),Index(s.Index)
  418. {
  419.   View->AddRef();
  420.   View->Annotate(Index, '+');
  421. }
  422.  
  423. TXTest::~TXTest()
  424. {
  425. // We cannot do any action here that would cause an exeption to be thrown
  426. // since this object may have just been caught and cloned, a call involving
  427. // messaging through windows would cause the cloned exception to be rethrown
  428.   View->Annotate(Index, '~');
  429.   View->SubRef();
  430. }
  431.  
  432. const TXTest& TXTest::operator = (const TXTest& src)
  433. {
  434.   *(TXOwl*)this = src;
  435.   View = src.View;
  436.   Index = src.Index;
  437.   View->AddRef();
  438.   View->Annotate(Index, '=');
  439.   return *this;
  440. }
  441.  
  442. TXOwl* TXTest::Clone()
  443. {
  444.   View->Suspended = TRUE;  // prevent rethrow during logging Windows call
  445.   View->Annotate(Index, '&');
  446.   return new TXTest(*this);  // will do the AddRef
  447. }
  448.  
  449. void TXTest::Throw()
  450. {
  451.   View->Suspended = FALSE;
  452.   View->Annotate(Index, '!');
  453.   throw *this;
  454. }
  455.  
  456. int TXTest::Unhandled(TModule* app, unsigned promptResId)
  457. {
  458.   View->Annotate(Index, '?');
  459.   return TXOwl::Unhandled(app, promptResId);
  460. }
  461.  
  462. IMPLEMENT_STREAMABLE2(TExceptionView, TListBox, TView);
  463.  
  464. void* TExceptionView::Streamer::Read(ipstream& is, uint32 /*version*/) const
  465. {
  466.   TExceptionView* o = GetObject();
  467.   ReadBaseObject((TListBox*)o, is);
  468.   ReadBaseObject((TView*)o, is);
  469.   o->Init();
  470.   is >> o->Origin;
  471.   is >> o->MaxWidth;
  472.   return o;
  473. }
  474.  
  475. void TExceptionView::Streamer::Write(opstream &os) const
  476. {
  477.   WriteBaseObject((TListBox*)GetObject(), os);
  478.   WriteBaseObject((TView*)GetObject(), os);
  479.   os << GetObject()->Origin;
  480.   os << GetObject()->MaxWidth;
  481. }
  482.  
  483. DEFINE_DOC_TEMPLATE_CLASS(TFileDocument, TExceptionView, XcptTemplate);
  484. XcptTemplate xcptTpl("Exception Log File","*.xlg", 0, "XLG",dtAutoDelete|dtUpdateDir);
  485.  
  486.