home *** CD-ROM | disk | FTP | other *** search
/ Power GUI Programming with VisualAge C++ / powergui.iso / trialva / ibmcppw / samples / ioc / dde / ddeserv / aserver.cpp next >
Encoding:
C/C++ Source or Header  |  1996-02-22  |  26.5 KB  |  543 lines

  1. /******************************************************************************
  2. * .FILE:         aserver.cpp                                                  *
  3. *                                                                             *
  4. * .DESCRIPTION:  Dynamic Data Exchange Server Program: Class Implementation   *
  5. *                                                                             *
  6. * .CLASSES:      AServerWindow                                                *
  7. *                ATopicServer                                                 *
  8. *                                                                             *
  9. * .COPYRIGHT:                                                                 *
  10. *    Licensed Material - Program-Property of IBM                              *
  11. *    (C) Copyright IBM Corp. 1992, 1996 - All Rights Reserved                 *
  12. *                                                                             *
  13. * .DISCLAIMER:                                                                *
  14. *   The following [enclosed] code is sample code created by IBM               *
  15. *   Corporation.  This sample code is not part of any standard IBM product    *
  16. *   and is provided to you solely for the purpose of assisting you in the     *
  17. *   development of your applications.  The code is provided 'AS IS',          *
  18. *   without warranty of any kind.  IBM shall not be liable for any damages    *
  19. *   arising out of your use of the sample code, even if they have been        *
  20. *   advised of the possibility of such damages.                               *
  21. *                                                                             *
  22. * .NOTE: WE RECOMMEND USING A FIXED SPACE FONT TO LOOK AT THE SOURCE          *
  23. *                                                                             *
  24. ******************************************************************************/
  25. #ifndef _IBASE_                         //Make sure ibase.hpp is included
  26.   #include <ibase.hpp>                  //  since that is where IC_<environ>
  27. #endif                                  //  is defined.
  28. #include <imle.hpp>
  29. #include <istattxt.hpp>
  30. #include <iinfoa.hpp>
  31. #include <ilistbox.hpp>
  32. #include <isplitcv.hpp>
  33. #include <iapp.hpp>
  34. #include <ifont.hpp>
  35. #include <imsgbox.hpp>
  36. #include <istring.hpp>
  37. #include <iddeevt.hpp>
  38. #include <icoordsy.hpp>
  39. #include "aserver.h"
  40. #include "aserver.hpp"
  41.  
  42. //*************************************************************************
  43. // main  - Application entry point
  44. //*************************************************************************
  45. int main()
  46. {
  47.   ICoordinateSystem::setApplicationOrientation(
  48.           ICoordinateSystem::originLowerLeft );
  49.  
  50.   AServerWindow serverWindow(WND_SERVER);//Create main window
  51.  
  52.   IApplication::current().run();        //Start event handling
  53.  
  54.   return 0;
  55. } /* end main */
  56.  
  57. //**************************************************************************
  58. // AServerWindow :: AServerWindow - Constructor for our main window
  59. //**************************************************************************
  60. AServerWindow :: AServerWindow(unsigned long windowId)
  61.   : IFrameWindow (windowId),            //Call IFrameWindow constructor
  62.     statusLine(WND_STATUS, this, this), //Create status line
  63.     todoStatus(WND_TODOSTA, &statusLine,//Create todo status line
  64.       &statusLine),
  65.     workStatus(WND_WORKSTA, &statusLine,//Create work status line
  66.       &statusLine),
  67.     doneStatus(WND_DONESTA, &statusLine,//Create done status line
  68.       &statusLine),
  69.     cArea(WND_CAREA, this, this),       //Create Client Area
  70.     dArea(WND_DAREA, &cArea, this),     //Create Data Area Cannvas
  71.     todoList(WND_TODO, &dArea, this,    //Create todo list
  72.       IRectangle(),                     //
  73.       (IListBox::defaultStyle()         //  Use default style with
  74.       | IListBox::noAdjustPosition)),   //  Canvas controling size
  75.     workList(WND_WORK, &dArea, this,    //Create working list
  76.       IRectangle(),                     //
  77.       (IListBox::defaultStyle()         //
  78.       | IListBox::noAdjustPosition)),   //  Allow the Canvas to control size
  79.     doneList(WND_DONE, &dArea, this,    //Create done list
  80.       IRectangle(),                     //
  81.       (IListBox::defaultStyle()         //  Use default style with
  82.       | IListBox::noAdjustPosition)),   //  Canvas controling size
  83.     mle(WND_MLE, &cArea, &cArea),       //Create MLE to display DDE activities
  84.     infoArea(this),                     //Create Information Area
  85.     resLib(),                           //Resource library
  86.     server(resLib.loadString( MI_APP ), //Create DDE Server (application name,
  87.        resLib.loadString( MI_TOPIC ),   //  topic name, window)
  88.        this )
  89. {
  90.   hot=0;                                //Hot link not active
  91.   cArea.setOrientation(                 //Set the orientation
  92.     ISplitCanvas::horizontalSplit);     //  to horizontal
  93.   setIcon( id() );                      //Set the icon
  94.   setClient(&cArea);                    //Set Client to cArea
  95.  
  96.   addExtension(&statusLine,             //Add Status Line above the client
  97.     IFrameWindow::aboveClient,          //  and specify the height
  98.     IFont(&statusLine).maxCharHeight());//  and specify height
  99.   setExtensionSize(&infoArea,           //
  100.          IFont(&infoArea).maxCharHeight());//and specify height
  101.   infoArea.setInactiveText(STR_HOTNO);  //Set information area text from RC
  102.  
  103.   sizeTo(ISize(600,400));               //Set the size of main window
  104.   moreTodo();                           //Initialize the todo list
  105.   updateStatus();                       //Update status line
  106.   setFocus();                           //Set Focus to main window
  107.   show();
  108. } /* end AServerWindow :: AServerWindow(...) */
  109.  
  110. //**************************************************************************
  111. // AServerWindow :: log(..)
  112. //**************************************************************************
  113. IBase::Boolean AServerWindow::log(IResourceId resId)
  114. {
  115.   mle.addLineAsLast( resLib.loadString( resId )); //Add to mle message log
  116.  
  117.   return true;
  118. } /* end AServerWindow :: log(..) */
  119.  
  120. //**************************************************************************
  121. // AServerWindow :: log(..)
  122. //**************************************************************************
  123. IBase::Boolean AServerWindow::log(char * message)
  124. {
  125.   mle.addLineAsLast( message );                  //Add to mle message log
  126.  
  127.   return true;
  128. } /* end AServerWindow :: log(..) */
  129.  
  130. //**************************************************************************
  131. // AServerWindow :: addDone(..)
  132. //**************************************************************************
  133. IBase::Boolean AServerWindow::addDone(char * newDone)
  134. {
  135.   doneList.addAsLast(newDone);          //Add new done item
  136.   try
  137.   {
  138.     unsigned long index=                //Locate this item in the work list
  139.       workList.locateText(newDone);
  140.     workList.remove(index);             //Remove from work list
  141.   }
  142.   catch (IException& exc)               //Catch Error
  143.   {                                     //
  144.     IMessageBox mbox(this);             //Create Message Box
  145.     mbox.show(exc);                     //
  146.     return false;                       //Return error
  147.   }                                     //
  148.   updateStatus();                       //Update status
  149.   if (hot)                              //Is hot link active?
  150.   {
  151.     log( MI_HOTLINKUPDATE_HOTWORK );
  152.     server.hotLinkUpdate( resLib.loadString( MI_HOTWORK ));  //Update work hot link
  153.     log( MI_HOTLINKUPDATE_HOTDONE );
  154.     server.hotLinkUpdate( resLib.loadString( MI_HOTDONE ));  //Update done hot link
  155.   } /* endif */
  156.   return true;
  157. } /* end AServerWindow :: addDone(..) */
  158.  
  159. //**************************************************************************
  160. // AServerWindow :: addTodo(..)
  161. //**************************************************************************
  162. IBase::Boolean AServerWindow::addTodo( IResourceId resId )
  163. {
  164.   todoList.addAsLast( resId );          //Add new todo
  165.   return true;
  166. } /* end AServerWindow :: addTodo(..) */
  167.  
  168. //**************************************************************************
  169. // AServerWindow :: moreTodo()
  170. //**************************************************************************
  171. IBase::Boolean AServerWindow::moreTodo()       //Add more items to the todo list
  172. {
  173.   addTodo( MI_BUY_GIFTS );              //Add item to todo list
  174.   addTodo( MI_PAY_PHONE );              //
  175.   addTodo( MI_PAY_TAXES );              //
  176.   addTodo( MI_PAPERS );                 //
  177.   addTodo( MI_TRASH );                  //
  178.   addTodo( MI_WASH_CAR );               //
  179.   addTodo( MI_WASH_DISH );              //
  180.   todoList.select(0);                   //Set the first item selected
  181.   return true;                          //
  182. } /* end AServerWindow :: moreTodo() */
  183.  
  184. //**************************************************************************
  185. // AServerWindow :: addHot()
  186. //**************************************************************************
  187. IBase::Boolean AServerWindow::addHot()
  188. {
  189.   hot=hot+1;                            //Set new value
  190.   if (hot == 1)
  191.   {
  192.     infoArea.setInactiveText(STR_HOTYES);//Set information area text from RC
  193.   } /* endif */
  194.   return true;                          //
  195. } /* end AServerWindow :: addHot() */
  196.  
  197. //**************************************************************************
  198. // AServerWindow :: removeHot()
  199. //**************************************************************************
  200. IBase::Boolean AServerWindow::removeHot()
  201. {
  202.   hot=hot-1;                            //Set new value
  203.   if (hot == 0)
  204.   {
  205.     infoArea.setInactiveText(STR_HOTNO);//Set information area text from RC
  206.   } /* endif */
  207.   return true;                          //
  208. } /* end AServerWindow :: removeHot(..) */
  209.  
  210. //**************************************************************************
  211. // AServerWindow :: nextTodo()
  212. //**************************************************************************
  213. IString AServerWindow::nextTodo()
  214. {
  215.   IListBox::Cursor lbCursor(todoList);  //List Box Cursor
  216.   lbCursor.setToFirst();                //Set to first item selected
  217.   IString temp(                         //Set temp to text of 1st item selected
  218.     todoList.elementAt(lbCursor));      //
  219.   workList.addAsLast(temp);             //Add to work list
  220.   todoList.removeAt(lbCursor);          //Remove this item
  221.   if (todoList.count() == 0)            //If zero count then add more items
  222.     moreTodo();                         //  since the work is never done
  223.   todoList.select(0);                   //Set the selection to first
  224.   if (hot)                              //Is hot link active?
  225.   {
  226.     log( MI_HOTLINKUPDATE_HOTTODO );
  227.     server.hotLinkUpdate(resLib.loadString( MI_HOTTODO )); //Update todo hot link
  228.     log( MI_HOTLINKUPDATE_HOTWORK );
  229.     server.hotLinkUpdate(resLib.loadString( MI_HOTWORK )); //Update work hot link
  230.   } /* endif */
  231.   updateStatus();                       //Update the status line
  232.   return temp;                          //Return String
  233. } /* end AServerWindow :: nextTodo() */
  234.  
  235. //**************************************************************************
  236. // AServerWindow :: todo()
  237. //**************************************************************************
  238. IString AServerWindow::todo()
  239. {
  240.   IString temp(todoList.count());       //Get count
  241.   return temp;                          //Return String
  242. } /* end AServerWindow :: todo() */
  243.  
  244. //**************************************************************************
  245. // AServerWindow :: work()
  246. //**************************************************************************
  247. IString AServerWindow::work()
  248. {
  249.   IString temp(workList.count());       //Get count
  250.   return temp;                          //Return String
  251. } /* end AServerWindow :: work() */
  252.  
  253. //**************************************************************************
  254. // AServerWindow :: done()
  255. //**************************************************************************
  256. IString AServerWindow::done()
  257. {
  258.   IString temp(doneList.count());       //Get count
  259.   return temp;                          //Return String
  260. } /* end AServerWindow :: done() */
  261.  
  262. //**************************************************************************
  263. // AServerWindow :: updateStatus()
  264. //**************************************************************************
  265. IBase::Boolean AServerWindow::updateStatus()
  266. {
  267.   todoStatus.setText(                   //Set the status to todo count
  268.     IString(resLib.loadString( MI_TODO_COUNT ))+
  269.     IString(todoList.count()));
  270.   workStatus.setText(                   //Set the status to work count
  271.     IString(resLib.loadString( MI_WORK_COUNT ))+
  272.     IString(workList.count()));
  273.   doneStatus.setText(                   //Set the status to done count
  274.     IString(resLib.loadString( MI_DONE_COUNT ))+
  275.     IString(doneList.count()));
  276.  
  277.   return true;
  278. } /* end AServerWindow :: updateStatus() */
  279.  
  280.  
  281. //**************************************************************************
  282. // ATopicServer :: ATopicServer - Constructor for our DDE server class
  283. //**************************************************************************
  284. ATopicServer :: ATopicServer(           //Constructor for ATopicServer
  285.                  const char* app,       //Application Name
  286.                  const char* topic,     //Topic Name
  287.                  AServerWindow* mainWin)//Windower
  288.               : IDDETopicServer(        //Call IDDETopicServer constructor
  289.                  app,                   //
  290.                  topic,                 //
  291.                  mainWin, false),       //
  292.                  serverWindow(mainWin), //Set window
  293.                  resLib()               //Resource library
  294. {;} /* end ATopicServer :: ATopicServer(..) */
  295.  
  296. //**************************************************************************
  297. // ATopicServer :: requestHotLinkData(..)
  298. //**************************************************************************
  299. void ATopicServer :: requestHotLinkData(IDDERequestDataEvent& event)
  300. {
  301.   Boolean rc=true;
  302.   if(event.item()==IString(resLib.loadString( MI_HOTTODO )))  //Check the requested item
  303.   {                                     //  the request is ok
  304.     rc=false;
  305.     IString todo;                       //  Define string to return
  306.     todo=mainWindow()->todo();          //  Get todo count from window
  307.     mainWindow()->log(                  //  Log this request with
  308.       IString(resLib.loadString( MI_REQDATA ))+//   function member name
  309.       event.item()+                     //    event item (todo)
  310.       IString(resLib.loadString( MI_RETURNING ))+ // returned to client
  311.       todo);
  312.     event.setData((char*)todo);         //  Set data to return to client
  313.   }
  314.   if(event.item()==IString(resLib.loadString( MI_HOTWORK )))  //Check the requested item
  315.   {                                     //  the request is ok
  316.     rc=false;
  317.     IString work;                       //  Define string to return
  318.     work=mainWindow()->work();          //  Get work count from window
  319.     mainWindow()->log(                  //  Log this request with
  320.       IString(resLib.loadString( MI_REQDATA ))+//   function member name
  321.       event.item()+                     //    event item (work)
  322.       IString(resLib.loadString( MI_RETURNING ))+ // returned to client
  323.       work);                            //
  324.     event.setData((char*)work);         //  Set data to return to client
  325.   }
  326.   if(event.item()==IString(resLib.loadString( MI_HOTDONE )))  //Check the requested item
  327.   {                                     //  the request is ok
  328.     rc=false;
  329.     IString done;                       //  Define string to return
  330.     done=mainWindow()->done();          //  Get done count from window
  331.     mainWindow()->log(                  //  Log this request with
  332.       IString(resLib.loadString( MI_REQDATA ))+//   function member name
  333.       event.item()+                     //    event item (done)
  334.       IString(resLib.loadString( MI_RETURNING ))+ // returned to client
  335.       done);                            //
  336.     event.setData((char*)done);         //  Set data to return to client
  337.   }
  338.   if (rc)                               //Request does not match
  339.   {                                     //
  340.     mainWindow()->log(
  341.       IString(resLib.loadString( MI_REQDATA2 ))+//   function member name
  342.       IString(resLib.loadString( MI_UNABLE_PROVIDE )) +
  343.       event.item());
  344.   }
  345. } /* end ATopicServer :: requestHotLinkData(..) */
  346.  
  347. //**************************************************************************
  348. // ATopicServer :: beginHotLink(..)
  349. //**************************************************************************
  350. IBase::Boolean ATopicServer :: beginHotLink(unsigned long conversationId,
  351.                           IDDEServerHotLinkEvent& event)
  352. {
  353.   Boolean rc=false;                     //Define return code
  354.   if(event.item()==IString(resLib.loadString(MI_HOTTODO)))  //Check the requested item
  355.   {                                     //  the request is ok
  356.     rc=true;                            //
  357.     mainWindow()->log(                  //  Log this request with
  358.       IString(resLib.loadString(MI_BEGIN_HOTLINK))+ // function member name
  359.       event.item()+                     //    event item
  360.       IString(resLib.loadString(MI_FROM))+
  361.       IString(conversationId));         //    conversation ID
  362.   }
  363.   if(event.item()==IString(resLib.loadString(MI_HOTWORK)))  //Check the requested item
  364.   {                                     //  the request is ok
  365.     mainWindow()->log(                  //  Log this request with
  366.       IString(resLib.loadString(MI_BEGIN_HOTLINK))+ // function member name
  367.       event.item()+                     //    event item
  368.       IString(resLib.loadString(MI_FROM))+
  369.       IString(conversationId));         //    conversation ID
  370.     rc=true;                            //
  371.   }
  372.   if(event.item()==IString(resLib.loadString(MI_HOTDONE)))  //Check the requested item
  373.   {                                     //  the request is ok
  374.     mainWindow()->log(                  //  Log this request with
  375.       IString(resLib.loadString(MI_BEGIN_HOTLINK))+ // function member name
  376.       event.item()+                     //    event item
  377.       IString(resLib.loadString(MI_FROM))+
  378.       IString(conversationId));         //    conversation ID
  379.     rc=true;                            //
  380.   }
  381.   if (!rc)                              //Request does not match
  382.   {                                     //
  383.     mainWindow()->log(
  384.       IString(resLib.loadString( MI_BEGINDATA2 ))+ // function member name
  385.       IString(resLib.loadString( MI_UNABLE_HANDLE ))+
  386.       event.item());        //
  387.   }
  388.   else
  389.   {
  390.     mainWindow()->addHot();             //Set hot link active
  391.   }
  392.   return rc;
  393. } /* end ATopicServer :: beginHotLink(..) */
  394.  
  395. //**************************************************************************
  396. // ATopicServer :: hotLinkEnded(..)
  397. //**************************************************************************
  398. void ATopicServer :: hotLinkEnded(unsigned long conversationId,
  399.                           IDDEEvent& event)
  400. {
  401.   mainWindow()->log(                  //  Log this request with
  402.     IString(resLib.loadString( MI_END_HOTLINK ))+ // function member name
  403.     event.item()+                     //    event item
  404.     IString(resLib.loadString( MI_FROM ))+  //
  405.     IString(conversationId));         //    conversation ID
  406.   mainWindow()->removeHot();          //Set hot link inactive
  407.   mainWindow()->removeHot();          //Set hot link inactive
  408.   mainWindow()->removeHot();          //Set hot link inactive
  409. } /* end ATopicServer :: beginHotLink(..) */
  410.  
  411. //**************************************************************************
  412. // ATopicServer :: pokeData(..)
  413. //**************************************************************************
  414. IBase::Boolean ATopicServer :: pokeData(unsigned long conversationId,
  415.                           IDDEPokeEvent& event)
  416. {
  417.   int rc=1;                             //Set default return code to processed
  418.   if(event.item()==IString(resLib.loadString( MI_DONEPOKE ))) //Check the requested item
  419.   {                                     //  the request is ok
  420.     IString workItem=event.pokedData(); //Get poked Data
  421.     mainWindow()->log(                  //  Log this request with
  422.       IString(resLib.loadString( MI_POKEDATA ))+ // function member name
  423.       event.item()+                     //    event item (nextTodo)
  424.       IString(resLib.loadString( MI_DATA ))+workItem+ // work item from client
  425.       IString(resLib.loadString( MI_FROM ))+  //
  426.       IString(conversationId));         //    conversation ID
  427.     mainWindow()->addDone(workItem);    //Add this item to the done list
  428.   }
  429.   else                                  //Request does not match
  430.   {                                     //
  431.     mainWindow()->log(
  432.       IString(resLib.loadString( MI_POKEDATA2 ))+
  433.       IString(resLib.loadString( MI_UNABLE_HANDLE )) +
  434.       event.item());
  435.     rc=0;                               //Set return code to event not processed
  436.   }
  437.   return rc;
  438. } /* end ATopicServer :: pokeData(..) */
  439.  
  440. //**************************************************************************
  441. // ATopicServer :: requestData(..)
  442. //**************************************************************************
  443. IBase::Boolean ATopicServer :: requestData(unsigned long conversationId,
  444.                                IDDERequestDataEvent& event)
  445. {
  446.   int rc=false;                         //Set default return code to processed
  447.   if(event.item()==IString(resLib.loadString( MI_NEXTTODO ))) //Check the requested item
  448.   {                                     //  the request is ok
  449.     rc=true;
  450.     IString workItem;                   //  Define work item
  451.     workItem=mainWindow()->nextTodo();  //  Get work item from todo list
  452.     mainWindow()->log(                  //  Log this request with
  453.       IString(resLib.loadString( MI_REQDATA3 ))+      //    member name
  454.       event.item()+                     //    event item (nextTodo)
  455.       IString(resLib.loadString( MI_RETURNING ))+workItem+ //    work item returned to client
  456.       IString(resLib.loadString( MI_TO ))+                 //
  457.       IString(conversationId));         //    conversation ID
  458.     event.setData((char*)workItem);     //  Set data to return to client
  459.   }
  460.   if(event.item()==IString(resLib.loadString( MI_HOTTODO )))  //Check the requested item
  461.   {                                     //  the request is ok
  462.     rc=true;
  463.     IString todo;                       //  Define string to return
  464.     todo=mainWindow()->todo();          //  Get todo count from window
  465.     mainWindow()->log(                  //  Log this request with
  466.       IString(resLib.loadString( MI_REQDATA3 ))+      //    member name
  467.       event.item()+                     //    event item (todo)
  468.       IString(resLib.loadString( MI_RETURNING ))+ //    work item returned to client
  469.       todo);                            //
  470.     event.setData((char*)todo);         //  Set data to return to client
  471.   }
  472.   if(event.item()==IString(resLib.loadString( MI_HOTWORK )))  //Check the requested item
  473.   {                                     //  the request is ok
  474.     rc=true;
  475.     IString work;                       //  Define string to return
  476.     work=mainWindow()->work();          //  Get work count from window
  477.     mainWindow()->log(                  //  Log this request with
  478.       IString(resLib.loadString( MI_REQDATA3 ))+      //    member name
  479.       event.item()+                     //    event item (work)
  480.       IString(resLib.loadString( MI_RETURNING ))+ //    work item returned to client
  481.       work);                            //
  482.     event.setData((char*)work);         //  Set data to return to client
  483.   }
  484.   if(event.item()==IString(resLib.loadString( MI_HOTDONE )))  //Check the requested item
  485.   {                                     //  the request is ok
  486.     rc=true;
  487.     IString done;                       //  Define string to return
  488.     done=mainWindow()->done();          //  Get done count from window
  489.     mainWindow()->log(                  //  Log this request with
  490.       IString(resLib.loadString( MI_REQDATA3 ))+      //    member name
  491.       event.item()+                     //    event item (done)
  492.       IString(resLib.loadString( MI_RETURNING ))+ //    work item returned to client
  493.       done);                            //
  494.     event.setData((char*)done);         //  Set data to return to client
  495.   }
  496.   if (!rc)                              //Request does not match
  497.   {                                     //
  498.     mainWindow()->log(
  499.       IString(resLib.loadString( MI_REQDATA4 ))+
  500.       IString(resLib.loadString( MI_UNABLE_PROVIDE ))+
  501.       event.item());
  502.   }
  503.   return rc;
  504. } /* end ATopicServer :: requestData(..) */
  505.  
  506. //**************************************************************************
  507. // ATopicServer :: acceptConversation(..)
  508. //**************************************************************************
  509. IBase::Boolean ATopicServer :: acceptConversation(unsigned long conversationId,
  510.                                       IDDEBeginEvent& event)
  511. {
  512.   mainWindow()->log(                    //  Log this message with
  513.     IString(resLib.loadString( MI_ACCEPT ))+  //member function name
  514.     IString(conversationId));           //    conversation ID
  515.   return true;
  516. } /* end ATopicServer :: acceptConversation(..) */
  517.  
  518. //**************************************************************************
  519. // ATopicServer :: conversationEnded(..)
  520. //**************************************************************************
  521. void ATopicServer :: conversationEnded(unsigned long conversationId,
  522.                                    IDDEEndEvent& endEvt)
  523. {
  524.   if (endEvt.sourceOfEnd() == IDDEEndEvent::server)
  525.     mainWindow()->log(                  //Log this message with
  526.       IString(resLib.loadString( MI_END_CONV ))+//member function name
  527.       IString(conversationId)+          //     conversation ID
  528.       IString(resLib.loadString( MI_BY_SERVER )));     //     by the Server
  529.  
  530.   else if (endEvt.sourceOfEnd() == IDDEEndEvent::client)
  531.     mainWindow()->log(                  //Log this message
  532.       IString(resLib.loadString( MI_END_CONV ))+//member function name
  533.       IString(conversationId)+          //     conversation ID
  534.       IString(resLib.loadString( MI_BY_CLIENT )));     //     by the Client
  535.  
  536.   else
  537.     mainWindow()->log(                  //Log this message
  538.       IString(resLib.loadString( MI_END_CONV2 ))+//member function name
  539.       IString(conversationId)+          //     conversation ID
  540.       IString(resLib.loadString( MI_BY_ERROR )));   //     due to an error
  541.  
  542. } /* end ATopicServer :: conversationEnded(..) */
  543.