home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 May / Pcwk5b98.iso / Borland / Cplus45 / BC45 / OWL1.PAK / WINDOBJ.CPP < prev    next >
Text File  |  1995-08-29  |  32KB  |  1,008 lines

  1. // ObjectWindows - (C) Copyright 1992 by Borland International
  2.  
  3. /* --------------------------------------------------------
  4.   WINDOBJ.CPP
  5.   Defines type TWindowsObject.  This defines the basic behavior
  6.   of all Windows objects.
  7.   -------------------------------------------------------- */
  8.  
  9. #include <string.h>
  10. #include <alloc.h>
  11. #include "applicat.h"
  12. #include "windobj.h"
  13. #include "appdict.h"
  14.  
  15. extern WNDPROC MakeObjectInstance(PTWindowsObject);
  16. extern void FreeObjectInstance(WNDPROC);
  17. extern PTWindowsObject GetObjectPtr(HWND);
  18.  
  19. /* Constructor for a TWindowsObject.  If a parent window is passed, adds
  20.   the TWindowsObject to its parent's list of children.  Makes an
  21.   instance thunk to be used in associating an MS-Windows interface
  22.   element to the TWindowsObject. */
  23. TWindowsObject::TWindowsObject(PTWindowsObject AParent, PTModule AModule)
  24. {
  25.   Status = 0;
  26. // If this is a "DLL alias", a derived class's constructor must set HWindow
  27.   HWindow = 0;
  28.   Title = NULL;
  29.   CreateOrder = 0;
  30.   ChildList = NULL;
  31.   Flags = 0x0;
  32.   TransferBuffer = NULL;
  33.   EnableAutoCreate();
  34.   Instance = MakeObjectInstance(this);
  35.   DefaultProc = NULL;
  36.  
  37.   Parent = AParent;
  38.   if ( Parent )
  39.     Parent->AddChild(this);
  40.   else
  41.     SiblingList = NULL;
  42.  
  43.   Application = GetApplicationObject();
  44.   if ( AModule )
  45.     Module = AModule;
  46.   else
  47.   /* by default Module = Application for all applications and for DLLs
  48.      dynamically linked with the OWL DLL. */
  49.     if ( Application )
  50.       Module = (PTModule)Application;
  51.     else  // In a DLL statically linked with OWL and AModule == 0
  52.       Status = EM_INVALIDMODULE;
  53. }
  54.  
  55. static void FreeChild(void *P, void *)
  56. {
  57.   ((PTWindowsObject)P)->ShutDownWindow();
  58. }
  59.  
  60. /* Destructor for a TWindowsObject.  Disposes of each window in its
  61.   ChildList and removes itself from a non-NULL parent's list of
  62.   children. Destroys a still-associated MS-Windows interface element and
  63.   frees the instance thunk used for association of an MS-Windows element
  64.   to the TWindowsObject. */
  65. TWindowsObject::~TWindowsObject()
  66. {
  67.   if ( !IsFlagSet(WB_ALIAS) ) //if alias only delete, don't destroy.
  68.     Destroy();
  69.   ForEach(FreeChild, 0);
  70.   if (Parent)
  71.     Parent->RemoveChild(this);
  72.   if ( GetApplication() && this == GetApplication()->MainWindow )
  73.     GetApplication()->MainWindow = NULL;
  74.   if ( HIWORD(Title) )
  75.     farfree(Title);
  76.   FreeObjectInstance(Instance);
  77. }
  78.  
  79. void TWindowsObject::AssignCreateOrder()
  80. {
  81.   HWND CurWindow;
  82.   PTWindowsObject Wnd;
  83.   int I;
  84.  
  85.   Wnd = (PTWindowsObject)GetClient();
  86.   if ( !Wnd )
  87.     CurWindow = HWindow;
  88.   else
  89.     CurWindow = Wnd->HWindow;
  90.   if ( CurWindow )
  91.   {
  92.     CurWindow = GetWindow(CurWindow, GW_CHILD);
  93.     if ( CurWindow )
  94.     {
  95.       CurWindow = GetWindow(CurWindow, GW_HWNDLAST);
  96.       I = 1;
  97.       while ( CurWindow )
  98.       {
  99.         Wnd = (PTWindowsObject)GetObjectPtr(CurWindow);
  100.         if ( Wnd )
  101.           Wnd->CreateOrder = I++;
  102.         CurWindow = GetWindow(CurWindow, GW_HWNDPREV);
  103.       }
  104.     }
  105.   }
  106. }
  107.  
  108. /* The private field CreateOrder is used to ensure the create order is
  109.   consistent through read and write of the object.  If the object is
  110.   written, write will fill in this value.  CreateOrder ranges in value
  111.   from 1 to N where N is the number of objects with values.  All other
  112.   objects will have a CreateOrder of Zero, which implies the object
  113.   will be created after the last object with a create order
  114. */
  115. BOOL TWindowsObject::OrderIsI(void *P, void *I)
  116. {
  117.   return ((PTWindowsObject)P)->CreateOrder == *(WORD *)I;
  118. }
  119.  
  120. /*  Returns TRUE if the child was supposed to be created but couldn't be. */
  121. static BOOL CantCreateChild(PTWindowsObject P)
  122. {
  123.   BOOL Success;
  124.  
  125.   Success = (!P->IsFlagSet(WB_AUTOCREATE)) || P->Create();
  126.   if ( P->HWindow && IsIconic(P->HWindow) )
  127.   {
  128.     int TextLen = GetWindowTextLength(P->HWindow);
  129.     Pchar Text = new char[TextLen + 1];
  130.     GetWindowText(P->HWindow, Text, TextLen + 1);
  131.     SetWindowText(P->HWindow, Text);
  132.     delete Text;
  133.   }
  134.   return !Success;
  135. }
  136.  
  137. BOOL TWindowsObject::CreateZeroChild(void *P, void *)
  138. {
  139.   return ((PTWindowsObject)P)->CreateOrder == 0 &&
  140.          CantCreateChild((PTWindowsObject)P);
  141. }
  142.  
  143. /* Create the children of the object.  Returns true if all the windows
  144.    were successfully created. */
  145. BOOL TWindowsObject::CreateChildren()
  146. {
  147.   int I = 1;
  148.   PTWindowsObject P;
  149.   BOOL Failure = FALSE;
  150.  
  151.   do {
  152.     P = FirstThat(&TWindowsObject::OrderIsI, &I);
  153.     if ( P )
  154.       Failure = CantCreateChild(P);
  155.     ++I;
  156.   } while( !Failure && P != (PTWindowsObject)NULL );
  157.   return !Failure && (FirstThat(&TWindowsObject::CreateZeroChild, NULL) == NULL);
  158. }
  159.  
  160. /* Transfer window 'data' to/from the passed data buffer.  Used to
  161.   initialize dialogs and get data out of them.  The TransferFlag passed
  162.   specifies whether data is to be read from or written to the passed
  163.   buffer, or whether the data element size is simply to be returned. The
  164.   return value is the size (in bytes) of the transfer data.  This method
  165.   simply returns zero and is redefined in TControl descendant classes. */
  166. WORD TWindowsObject::Transfer(Pvoid, WORD)
  167. {
  168.     return 0;
  169. }
  170.  
  171. /* Sets flag which indicates that the TWindowsObject has requested
  172.   "keyboard handling" (translation of keyboard input into control
  173.   selections). */
  174. void TWindowsObject::EnableKBHandler()
  175. {
  176.   SetFlags(WB_KBHANDLER, TRUE);
  177. }
  178.  
  179. /* Sets flag which indicates that the TWindowsObject should be
  180.   created if a create is sent while in the parent's child list. */
  181. void TWindowsObject::EnableAutoCreate()
  182. {
  183.   SetFlags(WB_AUTOCREATE, TRUE);
  184. }
  185.  
  186. /* Sets flag which indicates that the TWindowsObject can/will
  187.   tranfer data via the transfer mechanism. */
  188. void TWindowsObject::EnableTransfer()
  189. {
  190.   SetFlags(WB_TRANSFER, TRUE);
  191. }
  192.  
  193. /* Sets flag which indicates that the TWindowsObject should not be
  194.   created if a create is sent while in the parent's child list. */
  195. void TWindowsObject::DisableAutoCreate()
  196. {
  197.   SetFlags(WB_AUTOCREATE, FALSE);
  198. }
  199.  
  200. /* Sets flag which indicates that the TWindowsObject cannot/
  201.   will not tranfer data via the transfer mechanism. */
  202. void TWindowsObject::DisableTransfer()
  203. {
  204.   SetFlags(WB_TRANSFER, FALSE);
  205. }
  206.  
  207. /* Sets flag(s) for the TWindowsObject, which are stored in its Flags
  208.    data field.  The mask of the flag(s) to be set
  209.   (WB_KBHANDLER, etc.), and an OnOff "flag" are passed --
  210.   On = True, Off = False. */
  211. void TWindowsObject::SetFlags(WORD Mask, BOOL OnOff)
  212. {
  213.   if ( OnOff )
  214.     Flags |= Mask;
  215.   else
  216.     Flags &= ~Mask;
  217. }
  218.  
  219. /* Adds the passed pointer to a child window to the linked list
  220.   of sibling windows which ChildList points to. */
  221. void TWindowsObject::AddChild(PTWindowsObject AChild)
  222. {
  223.   if ( AChild )
  224.     if ( !ChildList )
  225.     {
  226.       ChildList = AChild;
  227.       AChild->SiblingList = AChild;
  228.     }
  229.     else
  230.     {
  231.       AChild->SiblingList = ChildList->SiblingList;
  232.       ChildList->SiblingList = AChild;
  233.       ChildList = AChild;
  234.     }
  235. }
  236.  
  237. /* Returns a pointer to the TWindowsObject's previous sibling (the
  238.    window previous to the TWindowsObject in its parent's child window
  239.    list). Returns the sibling which points to the TWindowsObject. If
  240.    the TWindowsObject was the first child added to the list, returns
  241.    a pointer to the last child added.*/
  242. PTWindowsObject TWindowsObject::Previous()
  243. {
  244.   PTWindowsObject CurrentIndex;
  245.  
  246.   if ( !SiblingList )
  247.    return NULL;
  248.   else
  249.   {
  250.     CurrentIndex = this;
  251.     while ( CurrentIndex->Next() != this)
  252.       CurrentIndex = CurrentIndex->Next();
  253.     return CurrentIndex;
  254.   }
  255. }
  256.  
  257. /* Removes the passed pointer to a child window from the linked list of
  258.   sibling windows which the TWindowsObject's ChildList points to. */
  259. void TWindowsObject::RemoveChild(PTWindowsObject AChild)
  260. {
  261.   PTWindowsObject LastChild , NextChild;
  262.  
  263.   if ( ChildList )
  264.   {
  265.     LastChild = ChildList;
  266.     NextChild = LastChild;
  267.     while ( (NextChild->SiblingList != LastChild) &&
  268.             (NextChild->SiblingList != AChild) )
  269.       NextChild = NextChild->SiblingList;
  270.     if ( NextChild->SiblingList == AChild )
  271.       if ( NextChild->SiblingList == NextChild )
  272.         ChildList = NULL;
  273.       else
  274.       {
  275.         if ( NextChild->SiblingList == ChildList )
  276.           ChildList = NextChild;
  277.         NextChild->SiblingList = NextChild->SiblingList->SiblingList;
  278.       }
  279.   }
  280. }
  281.  
  282. /* Reparents "this" to a new parent */
  283. void TWindowsObject::SetParent(PTWindowsObject NewParent)
  284. {
  285.   if ( Parent )
  286.     Parent->RemoveChild(this);
  287.   SiblingList = (PTWindowsObject)NULL;
  288.   ::SetParent(HWindow, NewParent->HWindow);  // tell windows about it
  289.   Parent = NewParent;
  290.   if ( Parent )
  291.     Parent->AddChild(this);
  292. }
  293.  
  294. /* Returns a pointer to the first TWindowsObject in the
  295.    ChildList that meets some specified criteria.If no child in the
  296.    list meets the criteria, NULL is returned. The Test
  297.    parameter which defines the criteria, is a pointer to a function
  298.    that takes two pointers to void. The first void* will be used as
  299.    the pointer to the child window and the second as a pointer to
  300.    the Test function's additional parameters.  The Test function must
  301.    return a Boolean value indicating whether the child passed meets
  302.    the criteria.  */
  303. PTWindowsObject TWindowsObject::FirstThat(TCondFunc Test,
  304.                                           void *PParamList)
  305. {
  306.   PTWindowsObject NextChild;
  307.   PTWindowsObject CurChild;
  308.   BOOL Found = FALSE;
  309.  
  310.   if ( ChildList )
  311.   {
  312.     NextChild = ChildList->Next();
  313.     do {
  314.       CurChild = NextChild;
  315.       NextChild = NextChild->Next();
  316.       /* Test CurChild for ok */
  317.       if ( (*Test)( CurChild, PParamList) )
  318.         Found = TRUE;
  319.     }
  320.     while ( !Found && (CurChild != ChildList) && ChildList);
  321.  
  322.     if ( Found )
  323.       return CurChild;
  324.   }
  325.   return NULL;
  326.  
  327. }
  328.  
  329. /* Iterates over each child window in the TWindowsObject's ChildList,
  330.    calling the procedure whose pointer is passed as the Action to be
  331.    performed for each child.  A pointer to a child is passed as the
  332.    first parameter to the iteration procedure. */
  333. void TWindowsObject::ForEach(TActionFunc Action, void *PParamList)
  334. {
  335.   PTWindowsObject CurChild;
  336.   PTWindowsObject NextChild; // allows ForEach to delete children
  337.  
  338.   if ( ChildList )
  339.   {
  340.     NextChild = ChildList->Next();
  341.     do
  342.     {
  343.       CurChild = NextChild;
  344.       NextChild = NextChild->Next();
  345.       ( *Action )( CurChild, PParamList );
  346.     }
  347.     while ( (CurChild != ChildList) && (ChildList) );
  348.   }
  349. }
  350.  
  351. /* Returns a pointer to the first TWindowsObject in the
  352.    ChildList that meets some specified criteria.If no child in the
  353.    list meets the criteria, NULL is returned. The Test
  354.    parameter which defines the criteria, is a pointer to a member
  355.    function (this is how it's different from FirstThat above).
  356.    that takes two pointers to void. The first void* will be used as
  357.    the pointer to the child window and the second as a pointer to
  358.    the Test function's additional parameters.  The Test function must
  359.    return a Boolean value indicating whether the child passed meets
  360.    the criteria.  */
  361. PTWindowsObject TWindowsObject::FirstThat(TCondMemFunc Test,
  362.                                           void *PParamList)
  363. {
  364.   PTWindowsObject NextChild;
  365.   PTWindowsObject CurChild;
  366.   BOOL Found = FALSE;
  367.  
  368.   if ( ChildList )
  369.   {
  370.     NextChild = ChildList->Next();
  371.     do {
  372.       CurChild = NextChild;
  373.       NextChild = NextChild->Next();
  374.       /* Test CurChild for ok */
  375.       if ( (this->*Test)( CurChild, PParamList) )
  376.         Found = TRUE;
  377.     }
  378.     while ( !Found && (CurChild != ChildList) && ChildList);
  379.  
  380.     if ( Found )
  381.       return CurChild;
  382.   }
  383.   return NULL;
  384.  
  385. }
  386.  
  387. /* Iterates over each child window in the TWindowsObject's ChildList,
  388.    calling the member function (unlike ForEach above which takes pointer
  389.    to non-member function) whose pointer is passed as the Action to
  390.    be performed for each child.  A pointer to a child is passed as the
  391.    first parameter to the iteration procedure. */
  392. void TWindowsObject::ForEach(TActionMemFunc Action, void *PParamList)
  393. {
  394.   PTWindowsObject CurChild;
  395.   PTWindowsObject NextChild; // allows ForEach to delete children
  396.  
  397.   if ( ChildList )
  398.   {
  399.     NextChild = ChildList->Next();
  400.     do
  401.     {
  402.       CurChild = NextChild;
  403.       NextChild = NextChild->Next();
  404.       ( this->*Action )( CurChild, PParamList );
  405.     }
  406.     while ( (CurChild != ChildList) && (ChildList) );
  407.   }
  408. }
  409.  
  410. static int Position;
  411.  
  412. static BOOL IsItThisChild1(void *P, void *AChild)
  413. {
  414.   ++Position;
  415.   return ((PTWindowsObject)P == (PTWindowsObject)AChild);
  416. }
  417.  
  418. /* Returns the position at which the passed child window appears
  419.    in the TWindowsObject's ChildList. If the child does not appear in
  420.    the list, -1 is returned. Zero'th position is ChildList->Next */
  421. int TWindowsObject::IndexOf(PTWindowsObject AChild)
  422. {
  423.   Position = -1;
  424.   if ( FirstThat(IsItThisChild1, AChild) )
  425.     return Position;
  426.   else
  427.     return -1;
  428. }
  429.  
  430. /* Returns the child at the passed position in the TWindowsObject's
  431.    ChildList.  The ChildList is circularly-referent so that passing a
  432.    position larger than the number of children will cause the traversal
  433.    of the list to wrap. Zero'th position is ChildList->Next */
  434. PTWindowsObject TWindowsObject::At(int APosition)
  435. {
  436.   PTWindowsObject CurrentChild;
  437.  
  438.   if ( APosition == -1 )
  439.     return NULL;
  440.   CurrentChild = ChildList;
  441.   if ( CurrentChild )
  442.   {
  443.     CurrentChild = ChildList->Next();
  444.     while (APosition > 0)
  445.     {
  446.       CurrentChild = CurrentChild->Next();
  447.       --APosition;
  448.     }
  449.   }
  450.   return CurrentChild;
  451. }
  452.  
  453. static BOOL IsItThisChild2(void *P, void *Id)
  454. {
  455.   return ( ((PTWindowsObject)P)->GetId() == *(int *)Id);
  456. }
  457.  
  458. /* Returns a pointer to the window in the ChildList with the passed Id.
  459.    If no child in the list has the passed Id, NULL is returned.*/
  460. PTWindowsObject TWindowsObject::ChildWithId(int Id)
  461. {
  462.   return FirstThat(IsItThisChild2, &Id);
  463. }
  464.  
  465. /* Specifies default processing for an incoming message. Invokes default
  466.    processing, defined by MS-Windows. Calls the default window procedure
  467.    if this is a window; sets Msg.Result to 0 if it's a dialog. Both cases
  468.    must be handled here instead of in TWindow or TDialog because DefWndProc
  469.    can be called while an object is being destructed, making it effectively
  470.    non-virtual */
  471. void TWindowsObject::DefWndProc(TMessage& Msg)
  472. {
  473.   if ( IsFlagSet(WB_MDIFRAME) )
  474.   {
  475.     HWND ClientHWnd;
  476.  
  477.     if ( GetClient() )
  478.       ClientHWnd = GetClient()->HWindow;
  479.     else
  480.       ClientHWnd = 0;
  481.     Msg.Result = DefFrameProc(HWindow, ClientHWnd, Msg.Message ,
  482.                               Msg.WParam, Msg.LParam);
  483.   }
  484.   else
  485.     if ( DefaultProc ) // this is a Window
  486.       Msg.Result =
  487. #ifdef STRICT
  488.       CallWindowProc(DefaultProc, HWindow, Msg.Message,
  489.                   Msg.WParam, Msg.LParam);
  490. #else
  491.       CallWindowProc((FARPROC)DefaultProc, HWindow, Msg.Message,
  492.                   Msg.WParam, Msg.LParam);
  493. #endif
  494.     else // this is a dialog
  495.       Msg.Result = 0;
  496. }
  497.  
  498. // --------------------------------------------------------
  499. // DispatchAMessage gets called by StdWndProc and
  500. // Dispatches the Windows messages to the proper WM routine
  501. // Calls _DDVTdispatch to return a pointer to the virtual function
  502. // to call. If a virtual function is not defined calls the
  503. // DefProc argument instead.
  504. // ---------------------------------------------------------
  505.  
  506. typedef void (TWindowsObject::* MRMFP)(TMessage&);
  507. typedef void (* MRFP)(TMessage&);
  508.  
  509. #if defined(_CLASSDLL) || defined(__DLL__)
  510. #define getVptr(thisPtr)    (*(void far **)(thisPtr))
  511. #else
  512. #define getVptr(thisPtr)    (*(void near **)(thisPtr))
  513. #endif
  514.  
  515. MRFP far * _DDVTdispatchNULL(void near *, int);
  516. MRFP far * _DDVTdispatchNULL(void far  *, int);
  517.  
  518. typedef void FAR PASCAL (* DISPATCHHOOK)(HANDLE hWnd, WORD wMessage,
  519.                                              WORD wParam, LONG lParam,
  520.                                              void far *Handler,
  521.                                              void far *ObjectPtr);
  522. DISPATCHHOOK __OWL_DISPATCH_HOOK__ = NULL;
  523.  
  524. void TWindowsObject::DispatchAMessage(WORD AMsg, TMessage& Msg,
  525.                                       MRMFP DefProc)
  526. {
  527.     MRFP FFP;
  528.     MRMFP MFP;
  529.  
  530.     union
  531.     {
  532.         MRMFP mfp;
  533.         MRFP fp;
  534.     }   Temp;
  535.  
  536.     Temp.mfp = NULL;
  537.  
  538.     HWND TheHWindow = HWindow;
  539.  
  540.     BeforeDispatchHandler();
  541.  
  542.     FFP = *_DDVTdispatchNULL(getVptr(this), (int)AMsg);
  543.  
  544.     if (FFP)                        // found a DDVT function
  545.     {
  546.         Temp.fp = FFP;              // convert DDVT function pointer
  547.         MFP = Temp.mfp;             //   to member function pointer
  548.     }
  549.     else                            // no DDVT function, use DefProc
  550.         MFP = DefProc;
  551.  
  552.     if (__OWL_DISPATCH_HOOK__)
  553.     {
  554.         if (!FFP)                   // if don't have normal function ptr
  555.         {                           //   convert from member function ptr
  556.             Temp.mfp = MFP;         //   to normal function pointer
  557.             FFP = Temp.fp;
  558.         }
  559.  
  560.         (*__OWL_DISPATCH_HOOK__)(TheHWindow, Msg.Message, Msg.WParam,
  561.                     Msg.LParam, (void far *)FFP, this);
  562.     }
  563.  
  564.     (this->*MFP)(Msg);           // invoke handler
  565.  
  566.     if ( this == GetObjectPtr(TheHWindow) ) // this hasn't been deleted
  567.       AfterDispatchHandler();
  568. }
  569.  
  570. /* Responds to an incoming WM_COMMAND message.  If a child window had
  571.   the focus when the message was sent, the message is sent to the child
  572.   window.  If the message cannot be given to a child window, it is
  573.   given to "this"  */
  574. void TWindowsObject::WMCommand(TMessage& Msg)
  575. {
  576.   HWND CurrentWindow, Control;
  577.   PTWindowsObject Child;
  578.  
  579.   if ( IsFlagSet(WB_KBHANDLER) && (Msg.LParam == 0L) )
  580.   {
  581.     Control = GetDlgItem(HWindow, Msg.WParam);
  582.     if ( Control && ( SendMessage(Control, WM_GETDLGCODE, 0, 0) &
  583.          (DLGC_DEFPUSHBUTTON | DLGC_UNDEFPUSHBUTTON) ) )
  584.     {
  585.       Msg.LP.Lo = (WORD)Control;
  586.       Msg.LP.Hi = BN_CLICKED;
  587.     }
  588.   }
  589.   if ( !IsFlagSet(WB_ALIAS) &&
  590.      (LOWORD(Msg.LParam) == 0) )        // it's a command message and...
  591.   {
  592.     if ( Msg.WParam < CM_COUNT )        // ... we can route it
  593.     {
  594.       // Find the object closest to the focus window
  595.       CurrentWindow = GetFocus(); // window with focus when command was sent
  596.       Child = (PTWindowsObject)GetObjectPtr(CurrentWindow);
  597.       while ( !Child && CurrentWindow && CurrentWindow != HWindow )
  598.       {
  599.         CurrentWindow = GetParent(CurrentWindow);
  600.         Child = (PTWindowsObject)GetObjectPtr(CurrentWindow);
  601.       }
  602.  
  603.  // If the object is found, route to the object, else handle it yourself
  604.       if ( !Child )
  605.         Child = this;
  606.       Child->DispatchAMessage(CM_FIRST + Msg.WParam, Msg, &TWindowsObject::DefCommandProc);
  607.     }
  608.     else
  609.       DefWndProc(Msg);
  610.   }
  611.   else
  612.   {
  613.     // Find the child that generated the notification
  614.     Child = (PTWindowsObject)GetObjectPtr(GetDlgItem(HWindow, Msg.WParam));
  615.  
  616.     /* If the child is found, give the notification to the child,
  617.       else give it to "this" as an "id" notification. */
  618.     if ( Child && HIWORD(Msg.LParam) < NF_COUNT )
  619.       Child->DispatchAMessage(NF_FIRST + HIWORD(Msg.LParam),
  620.                Msg, &TWindowsObject::DefNotificationProc);
  621.     else
  622.       if ( !IsFlagSet(WB_ALIAS) )
  623.       {
  624.         if ( Msg.WParam < ID_COUNT )
  625.           DispatchAMessage(ID_FIRST + Msg.WParam,
  626.                  Msg, &TWindowsObject::DefChildProc);
  627.         else
  628.           DefChildProc(Msg);
  629.       }
  630.       else  // if I'm an alias don't route ID messages to me
  631.         DefWndProc(Msg);
  632.   }
  633. }
  634.  
  635. /* Function called when a window must redraw one of its "owner-draw"
  636.    controls. Having the control redraw itself is usually preferable.
  637.    Also called when the window's "owner draw" menu must be redrawn */
  638. void TWindowsObject::DrawItem(DRAWITEMSTRUCT far &)
  639. {
  640. }
  641.  
  642. /* Dispatches WM_DRAWITEM messages (for owner draw controls) to the
  643.    appropriate control's appropriate member function */
  644. void TWindowsObject::WMDrawItem(TMessage& Msg)
  645. {
  646.   PTWindowsObject Child = (PTWindowsObject)GetObjectPtr(
  647.                           ((LPDRAWITEMSTRUCT)(Msg.LParam))->hwndItem);
  648.   if ( Child )
  649.     Child->DispatchAMessage(WM_FIRST + WM_DRAWITEM, Msg,
  650.                                     &TWindowsObject::DefWndProc);
  651.   else  // no child object (includes case where item is a menu)
  652.   {
  653.     if ( IsFlagSet(WB_ALIAS) )
  654.       DefWndProc(Msg);
  655.     else
  656.       DrawItem(*((LPDRAWITEMSTRUCT)(Msg.LParam)));
  657.   }
  658. }
  659.  
  660. /* Dispatches scroll messages as if they where WMCommand messages,
  661.    that is by routing them to the scroll bar control as a notification
  662.    and to "this" as an "id" notification.  */
  663. void TWindowsObject::DispatchScroll(TMessage& Msg)
  664. {
  665.     PTWindowsObject Child;
  666.     WORD ChildId;
  667.  
  668.   if ( HIWORD(Msg.LParam) )
  669.   {
  670.     Child = (PTWindowsObject)GetObjectPtr((HWND)HIWORD(Msg.LParam));
  671.     if ( Child )
  672.       Child->DispatchAMessage(NF_FIRST + Msg.WParam, Msg, &TWindowsObject::DefNotificationProc);
  673.     else
  674.     {
  675.       ChildId = GetWindowWord((HWND)HIWORD(Msg.LParam), GWW_ID);
  676.       if ( ChildId < ID_COUNT )
  677.         DispatchAMessage(ID_FIRST + ChildId, Msg, &TWindowsObject::DefChildProc);
  678.       else
  679.         DefChildProc(Msg);
  680.     }
  681.   }
  682.   else
  683.     DefWndProc(Msg);
  684. }
  685.  
  686. /* Responds to an incoming WM_VSCROLL message by calling DispatchScroll. If
  687.    message is not handled, calls DefWndProc. */
  688. void TWindowsObject::WMVScroll(TMessage& Msg)
  689. {
  690.   if ( !(GetWindowLong(HWindow, GWL_STYLE) & WS_VSCROLL) )
  691.     DispatchScroll(Msg);
  692.   else
  693.     DefWndProc(Msg);
  694. }
  695.  
  696. /* Responds to an incoming WM_HSCROLL message by calling DispatchScroll.
  697.    If message is not handled, calls DefWndProc. */
  698. void TWindowsObject::WMHScroll(TMessage& Msg)
  699. {
  700.   if ( !(GetWindowLong(HWindow, GWL_STYLE) & WS_HSCROLL) )
  701.     DispatchScroll(Msg);
  702.   else
  703.     DefWndProc(Msg);
  704. }
  705.  
  706. /* Performs default processing for a command message (menu selection or
  707.   accelerator). If the original message receiver was this object, give
  708.   the message to DefWndProc, else if the object has a parent, give the
  709.   message to the parent, else give the message to the original receiver. */
  710. void TWindowsObject::DefCommandProc(TMessage& Msg)
  711. {
  712.   PTWindowsObject Target;
  713.  
  714.   if ( Msg.Receiver == HWindow )
  715.     Target = NULL;
  716.   else
  717.     if ( Parent )
  718.       Target = Parent;
  719.     else
  720.       Target = (PTWindowsObject)GetObjectPtr(Msg.Receiver);
  721.   if ( Target == NULL )
  722.     DefWndProc(Msg);
  723.   else
  724.     Target->DispatchAMessage(CM_FIRST + Msg.WParam, Msg, &TWindowsObject::DefCommandProc);
  725. }
  726.  
  727. /* Performs default processing for an incoming notification message from
  728.   a child of the TWindowsObject. Nothing can be done by default of a
  729.   child notification (or "id" message). The user can override this
  730.   function if it is more convenient to handle "id" messages in a case
  731.   statement. */
  732. void TWindowsObject::DefChildProc(TMessage& Msg)
  733. {
  734.   DefWndProc(Msg);
  735. }
  736.  
  737. /* Performs default processing for a notification message generated by
  738.    the TWindowsObject. (The TWindowsObject has the option to perform
  739.    processing in response to its own notification messages. )  It passes
  740.    the message to the parent as an "id" message.  It is assumed that the
  741.    object giving this message to this object is the parent of this
  742.    object.  This is done in WMCommand, WMHScroll, or WMVScroll of the
  743.    parent. Notifications are translated into "id" messages so that the
  744.    parent does not confuse child notification with its own
  745.    notifications. If its an WMHScroll or WMVScroll the ID is looked up
  746.    explicitly. */
  747. void TWindowsObject::DefNotificationProc(TMessage& Msg)
  748. {
  749.   if ( Parent )
  750.   {
  751.     if ( Parent->IsFlagSet(WB_ALIAS) )
  752.       DefWndProc(Msg);
  753.     else
  754.     {
  755.       if (Msg.Message == WM_COMMAND )
  756.         Parent->DispatchAMessage(ID_FIRST + Msg.WParam, Msg, &TWindowsObject::DefChildProc);
  757.       else
  758.         Parent->DispatchAMessage(
  759.              ID_FIRST + GetWindowWord(HWindow, GWW_ID), Msg, &TWindowsObject::DefChildProc);
  760.     }
  761.   }
  762. }
  763.  
  764.  
  765. static void DoEnableAutoCreate(void *P, void *)
  766. {
  767.   if ( ((PTWindowsObject)P)->HWindow )
  768.     ((PTWindowsObject)P)->EnableAutoCreate();
  769. }
  770.  
  771. /* Destroys an MS-Windows element associated with the TWindowsObject
  772.    after setting the WB_AUTOCREATE flag to ON for each of the windows
  773.    in the TWindowsObject's ChildList. */
  774. void TWindowsObject::Destroy()
  775. {
  776.   if ( HWindow )
  777.   {
  778.     ForEach(DoEnableAutoCreate, 0);
  779.     if ( IsFlagSet(WB_MDICHILD) && (Parent->GetClient() != NULL) )
  780.       SendMessage(((PTWindowsObject)(Parent->GetClient()))->HWindow,
  781.         WM_MDIDESTROY, (WORD)HWindow, 0);
  782.     else
  783.       DestroyWindow(HWindow);
  784.   }
  785. }
  786.  
  787. /* Initializes the passed parameter with the registration attributes for
  788.   the TWindowsObject. This function serves as a placeholder for
  789.   descendant classes to redefine to specify registration
  790.   attributes for the MS-Windows class of a window object. */
  791. void TWindowsObject::GetWindowClass(WNDCLASS&)
  792. {
  793. }
  794.  
  795. /* Performs setup following creation of an associated MS-Windows window.
  796.   Iterates through the TWindowsObject's ChildList, attempting to create
  797.   an associated MS-Windows interface element for each child window
  798.   object in the list. (A child's Create method is not called if its
  799.   WB_AUTOCREATE flag is not set). Calls TransferData to transfer data
  800.   for its children for whom data transfer is enabled.  Can be redefined
  801.   in derived classes to perform additional special initialization.
  802. */
  803. void TWindowsObject::SetupWindow()
  804. {
  805.   if ( ! CreateChildren() )
  806.     Status = EM_INVALIDCHILD;
  807.   else
  808.     TransferData(TF_SETDATA);
  809. }
  810.  
  811. static void _FAR * DataPtr;
  812.  
  813. static void TransferDataChild(void *AChild, void *Direction)
  814. {
  815.     if ( ((PTWindowsObject)AChild)->IsFlagSet(WB_TRANSFER) )
  816.     {
  817.       *(LPSTR _FAR *)&DataPtr += ((PTWindowsObject)AChild)->Transfer(
  818.                      DataPtr, *(WORD *)Direction);
  819.     }
  820. }
  821.  
  822. /* Transfers data between the TWindowsObject's data buffer and the child
  823.    windows in its ChildList. (Data is not transfered between any child
  824.    windows whose WB_TRANSFER flag is not set). */
  825. void TWindowsObject::TransferData(WORD Direction)
  826. {
  827.   if ( TransferBuffer )
  828.   {
  829.     DataPtr = TransferBuffer;
  830.     ForEach(TransferDataChild, &Direction);
  831.   }
  832. }
  833.  
  834. /* Registers the TWindowsObject's MS-Windows, if not already registered. */
  835. BOOL TWindowsObject::Register()
  836. {
  837.   WNDCLASS WindowClass;
  838.  
  839.   if ( !GetClassInfo( 0, GetClassName(), &WindowClass) &&
  840.        !GetClassInfo(GetModule()->hInstance, GetClassName(),
  841.         &WindowClass) )
  842.   {
  843.     GetWindowClass(WindowClass);
  844.     return RegisterClass(&WindowClass);
  845.   }
  846.     return TRUE;
  847. }
  848.  
  849. /* Displays the TWindowsObject, after checking that it has a valid
  850.    (non-NULL) handle. */
  851. void TWindowsObject::Show(int ShowCmd)
  852. {
  853.   if ( HWindow )
  854.     ShowWindow(HWindow, ShowCmd);
  855. }
  856.  
  857. /* Sets the Title and caption of the TWindowsObject. */
  858. void TWindowsObject::SetCaption(LPSTR ATitle)
  859. {
  860.     if (Title != ATitle)
  861.     {
  862.         if ( HIWORD(Title) )
  863.             farfree(Title);
  864.  
  865.         Title = _fstrdup(ATitle ? ATitle : "");
  866.     }
  867.     if ( HWindow )
  868.         SetWindowText(HWindow, Title);
  869. }
  870.  
  871. static BOOL CannotCloseChild(void *P, void *)
  872. {
  873.   return ( ((PTWindowsObject)P)->HWindow && !( ((PTWindowsObject)P)->CanClose()) );
  874. }
  875.  
  876.  
  877. /* Returns a BOOL indicating whether or not it is Ok to close
  878.   the TWindowsObject.  Iterates through the TWindowsObject's
  879.   ChildList, calling the CanClose method of each.  Returns False if
  880.   any of the child windows return False. */
  881. BOOL TWindowsObject::CanClose()
  882. {
  883.   return (FirstThat(CannotCloseChild, 0) == NULL);
  884. }
  885.  
  886. /* Destroys the associated MS-Windows interface element and frees "this"
  887.   after determining that it is Ok to do so. If the TWindowsObject is the
  888.   main window of the application, calls the CanClose method of the
  889.   application, else calls this->CanClose, before calling ShutDownWindow. */
  890. void TWindowsObject::CloseWindow()
  891. {
  892.   BOOL WillClose;
  893.  
  894.   if ( GetApplication() && this == GetApplication()->MainWindow )
  895.     WillClose = GetApplication()->CanClose();
  896.   else
  897.     WillClose = CanClose();
  898.   if ( WillClose )
  899.     ShutDownWindow();
  900. }
  901.  
  902. /* Destroys the associated MS-Windows interface element and frees "this"
  903.    without calling CanClose. */
  904. void TWindowsObject::ShutDownWindow()
  905. {
  906.   Destroy();
  907.   delete this;
  908. }
  909.  
  910. /* The default response to a WMClose message is to send a CloseWindow
  911.   message.  CloseWindow sends a CanClose to determine if the window
  912.   can be closed. */
  913. void TWindowsObject::WMClose(TMessage& Msg)
  914. {
  915.   if ( IsFlagSet(WB_ALIAS) )
  916.     DefWndProc(Msg);
  917.   else
  918.     CloseWindow();
  919. }
  920.  
  921. /* Responds to an incoming WM_DESTROY message.  If the TWindowsObject
  922.    is the application's main window posts a 'quit' message to end
  923.    the application. */
  924. void TWindowsObject::WMDestroy(TMessage& Msg)
  925. {
  926.   if ( !IsFlagSet(WB_ALIAS) )
  927.   {
  928.       PTApplication app = GetApplication();
  929.       if (app && (this == app->MainWindow))
  930.           PostQuitMessage(app->Status);
  931.   }
  932.   DefWndProc(Msg);
  933. }
  934.  
  935. /* Responds to an incoming WM_NCDESTROY message, the last message
  936.    sent to an MS-Windows interface element.  Sets the HWindow data
  937.    member of the TWindowsObject to zero to indicate that an interface
  938.    element is no longer associated with the object.  */
  939. void TWindowsObject::WMNCDestroy(TMessage& Msg)
  940. {
  941.   DefWndProc(Msg);
  942.   HWindow = 0;
  943.   if ( GetApplication() && this == GetApplication()->KBHandlerWnd )
  944.     GetApplication()->SetKBHandler(NULL);
  945.   if ( IsFlagSet(WB_ALIAS) )
  946.     delete this;
  947. }
  948.  
  949. /* Responds to an incoming WM_ACTIVATE message by calling
  950.    DefWndProc followed by ActivationResponse. DefWndProc must be
  951.    called first since TWindow::ActivationResponse does a SetFocus
  952.    which would otherwise be overridden when DefWindowProc does its
  953.    SetFocus. */
  954. void TWindowsObject::WMActivate(TMessage& Msg)
  955. {
  956.   DefWndProc(Msg);
  957.   if ( !IsFlagSet(WB_ALIAS) )
  958.     ActivationResponse(Msg.WParam, Msg.LP.Hi);
  959. }
  960.  
  961. /* Responds to an incoming WM_ACTIVATE or WM_MDIACTIVATE message. If the
  962.    TWindowsObject is being activated and if it has requested
  963.    keyboard handling for its messages, enables the "keyboard handler"
  964.    by calling the SetKBHandler function of the application. Otherwise
  965.    disables the "keyboard handler". */
  966. void TWindowsObject::ActivationResponse(WORD Activated, BOOL /*IsIconified*/ )
  967. {
  968.   if ( GetApplication() )
  969.   {
  970.     if ( Activated && IsFlagSet(WB_KBHANDLER) )
  971.       GetApplication()->SetKBHandler(this);
  972.     else
  973.       GetApplication()->SetKBHandler(NULL);
  974.   }
  975. }
  976.  
  977. /* Respond to Windows attempt to close close down. */
  978. void TWindowsObject::WMQueryEndSession(TMessage& Msg)
  979. {
  980.   if ( IsFlagSet(WB_ALIAS) )
  981.     DefWndProc(Msg);
  982.   else
  983.   {
  984.     if ( GetApplication() && this == GetApplication()->MainWindow )
  985.       Msg.Result = (int)GetApplication()->CanClose();
  986.     else
  987.       Msg.Result = (int)CanClose();
  988.   }
  989. }
  990.  
  991. /* If the window receives an Exit menu choice, it will attempt
  992.   to close down the window. */
  993. void TWindowsObject::CMExit(TMessage& Msg)
  994. {
  995.   if ( GetApplication() && this == GetApplication()->MainWindow )
  996.     CloseWindow();
  997.   else
  998.     DefCommandProc(Msg);
  999. }
  1000.  
  1001. /* Returns a NULL pointer to indicate that the TWindowsObject is not
  1002.    a TMDIFrame.  Is redefined for TMDIFrame to return a pointer to
  1003.    their TMDIClient window. */
  1004. TMDIClient *TWindowsObject::GetClient()
  1005. {
  1006.   return NULL;
  1007. }
  1008.