home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1998 May
/
Pcwk5b98.iso
/
Borland
/
Cplus45
/
BC45
/
OWL1.PAK
/
WINDOBJ.CPP
< prev
next >
Wrap
Text File
|
1995-08-29
|
32KB
|
1,008 lines
// ObjectWindows - (C) Copyright 1992 by Borland International
/* --------------------------------------------------------
WINDOBJ.CPP
Defines type TWindowsObject. This defines the basic behavior
of all Windows objects.
-------------------------------------------------------- */
#include <string.h>
#include <alloc.h>
#include "applicat.h"
#include "windobj.h"
#include "appdict.h"
extern WNDPROC MakeObjectInstance(PTWindowsObject);
extern void FreeObjectInstance(WNDPROC);
extern PTWindowsObject GetObjectPtr(HWND);
/* Constructor for a TWindowsObject. If a parent window is passed, adds
the TWindowsObject to its parent's list of children. Makes an
instance thunk to be used in associating an MS-Windows interface
element to the TWindowsObject. */
TWindowsObject::TWindowsObject(PTWindowsObject AParent, PTModule AModule)
{
Status = 0;
// If this is a "DLL alias", a derived class's constructor must set HWindow
HWindow = 0;
Title = NULL;
CreateOrder = 0;
ChildList = NULL;
Flags = 0x0;
TransferBuffer = NULL;
EnableAutoCreate();
Instance = MakeObjectInstance(this);
DefaultProc = NULL;
Parent = AParent;
if ( Parent )
Parent->AddChild(this);
else
SiblingList = NULL;
Application = GetApplicationObject();
if ( AModule )
Module = AModule;
else
/* by default Module = Application for all applications and for DLLs
dynamically linked with the OWL DLL. */
if ( Application )
Module = (PTModule)Application;
else // In a DLL statically linked with OWL and AModule == 0
Status = EM_INVALIDMODULE;
}
static void FreeChild(void *P, void *)
{
((PTWindowsObject)P)->ShutDownWindow();
}
/* Destructor for a TWindowsObject. Disposes of each window in its
ChildList and removes itself from a non-NULL parent's list of
children. Destroys a still-associated MS-Windows interface element and
frees the instance thunk used for association of an MS-Windows element
to the TWindowsObject. */
TWindowsObject::~TWindowsObject()
{
if ( !IsFlagSet(WB_ALIAS) ) //if alias only delete, don't destroy.
Destroy();
ForEach(FreeChild, 0);
if (Parent)
Parent->RemoveChild(this);
if ( GetApplication() && this == GetApplication()->MainWindow )
GetApplication()->MainWindow = NULL;
if ( HIWORD(Title) )
farfree(Title);
FreeObjectInstance(Instance);
}
void TWindowsObject::AssignCreateOrder()
{
HWND CurWindow;
PTWindowsObject Wnd;
int I;
Wnd = (PTWindowsObject)GetClient();
if ( !Wnd )
CurWindow = HWindow;
else
CurWindow = Wnd->HWindow;
if ( CurWindow )
{
CurWindow = GetWindow(CurWindow, GW_CHILD);
if ( CurWindow )
{
CurWindow = GetWindow(CurWindow, GW_HWNDLAST);
I = 1;
while ( CurWindow )
{
Wnd = (PTWindowsObject)GetObjectPtr(CurWindow);
if ( Wnd )
Wnd->CreateOrder = I++;
CurWindow = GetWindow(CurWindow, GW_HWNDPREV);
}
}
}
}
/* The private field CreateOrder is used to ensure the create order is
consistent through read and write of the object. If the object is
written, write will fill in this value. CreateOrder ranges in value
from 1 to N where N is the number of objects with values. All other
objects will have a CreateOrder of Zero, which implies the object
will be created after the last object with a create order
*/
BOOL TWindowsObject::OrderIsI(void *P, void *I)
{
return ((PTWindowsObject)P)->CreateOrder == *(WORD *)I;
}
/* Returns TRUE if the child was supposed to be created but couldn't be. */
static BOOL CantCreateChild(PTWindowsObject P)
{
BOOL Success;
Success = (!P->IsFlagSet(WB_AUTOCREATE)) || P->Create();
if ( P->HWindow && IsIconic(P->HWindow) )
{
int TextLen = GetWindowTextLength(P->HWindow);
Pchar Text = new char[TextLen + 1];
GetWindowText(P->HWindow, Text, TextLen + 1);
SetWindowText(P->HWindow, Text);
delete Text;
}
return !Success;
}
BOOL TWindowsObject::CreateZeroChild(void *P, void *)
{
return ((PTWindowsObject)P)->CreateOrder == 0 &&
CantCreateChild((PTWindowsObject)P);
}
/* Create the children of the object. Returns true if all the windows
were successfully created. */
BOOL TWindowsObject::CreateChildren()
{
int I = 1;
PTWindowsObject P;
BOOL Failure = FALSE;
do {
P = FirstThat(&TWindowsObject::OrderIsI, &I);
if ( P )
Failure = CantCreateChild(P);
++I;
} while( !Failure && P != (PTWindowsObject)NULL );
return !Failure && (FirstThat(&TWindowsObject::CreateZeroChild, NULL) == NULL);
}
/* Transfer window 'data' to/from the passed data buffer. Used to
initialize dialogs and get data out of them. The TransferFlag passed
specifies whether data is to be read from or written to the passed
buffer, or whether the data element size is simply to be returned. The
return value is the size (in bytes) of the transfer data. This method
simply returns zero and is redefined in TControl descendant classes. */
WORD TWindowsObject::Transfer(Pvoid, WORD)
{
return 0;
}
/* Sets flag which indicates that the TWindowsObject has requested
"keyboard handling" (translation of keyboard input into control
selections). */
void TWindowsObject::EnableKBHandler()
{
SetFlags(WB_KBHANDLER, TRUE);
}
/* Sets flag which indicates that the TWindowsObject should be
created if a create is sent while in the parent's child list. */
void TWindowsObject::EnableAutoCreate()
{
SetFlags(WB_AUTOCREATE, TRUE);
}
/* Sets flag which indicates that the TWindowsObject can/will
tranfer data via the transfer mechanism. */
void TWindowsObject::EnableTransfer()
{
SetFlags(WB_TRANSFER, TRUE);
}
/* Sets flag which indicates that the TWindowsObject should not be
created if a create is sent while in the parent's child list. */
void TWindowsObject::DisableAutoCreate()
{
SetFlags(WB_AUTOCREATE, FALSE);
}
/* Sets flag which indicates that the TWindowsObject cannot/
will not tranfer data via the transfer mechanism. */
void TWindowsObject::DisableTransfer()
{
SetFlags(WB_TRANSFER, FALSE);
}
/* Sets flag(s) for the TWindowsObject, which are stored in its Flags
data field. The mask of the flag(s) to be set
(WB_KBHANDLER, etc.), and an OnOff "flag" are passed --
On = True, Off = False. */
void TWindowsObject::SetFlags(WORD Mask, BOOL OnOff)
{
if ( OnOff )
Flags |= Mask;
else
Flags &= ~Mask;
}
/* Adds the passed pointer to a child window to the linked list
of sibling windows which ChildList points to. */
void TWindowsObject::AddChild(PTWindowsObject AChild)
{
if ( AChild )
if ( !ChildList )
{
ChildList = AChild;
AChild->SiblingList = AChild;
}
else
{
AChild->SiblingList = ChildList->SiblingList;
ChildList->SiblingList = AChild;
ChildList = AChild;
}
}
/* Returns a pointer to the TWindowsObject's previous sibling (the
window previous to the TWindowsObject in its parent's child window
list). Returns the sibling which points to the TWindowsObject. If
the TWindowsObject was the first child added to the list, returns
a pointer to the last child added.*/
PTWindowsObject TWindowsObject::Previous()
{
PTWindowsObject CurrentIndex;
if ( !SiblingList )
return NULL;
else
{
CurrentIndex = this;
while ( CurrentIndex->Next() != this)
CurrentIndex = CurrentIndex->Next();
return CurrentIndex;
}
}
/* Removes the passed pointer to a child window from the linked list of
sibling windows which the TWindowsObject's ChildList points to. */
void TWindowsObject::RemoveChild(PTWindowsObject AChild)
{
PTWindowsObject LastChild , NextChild;
if ( ChildList )
{
LastChild = ChildList;
NextChild = LastChild;
while ( (NextChild->SiblingList != LastChild) &&
(NextChild->SiblingList != AChild) )
NextChild = NextChild->SiblingList;
if ( NextChild->SiblingList == AChild )
if ( NextChild->SiblingList == NextChild )
ChildList = NULL;
else
{
if ( NextChild->SiblingList == ChildList )
ChildList = NextChild;
NextChild->SiblingList = NextChild->SiblingList->SiblingList;
}
}
}
/* Reparents "this" to a new parent */
void TWindowsObject::SetParent(PTWindowsObject NewParent)
{
if ( Parent )
Parent->RemoveChild(this);
SiblingList = (PTWindowsObject)NULL;
::SetParent(HWindow, NewParent->HWindow); // tell windows about it
Parent = NewParent;
if ( Parent )
Parent->AddChild(this);
}
/* Returns a pointer to the first TWindowsObject in the
ChildList that meets some specified criteria.If no child in the
list meets the criteria, NULL is returned. The Test
parameter which defines the criteria, is a pointer to a function
that takes two pointers to void. The first void* will be used as
the pointer to the child window and the second as a pointer to
the Test function's additional parameters. The Test function must
return a Boolean value indicating whether the child passed meets
the criteria. */
PTWindowsObject TWindowsObject::FirstThat(TCondFunc Test,
void *PParamList)
{
PTWindowsObject NextChild;
PTWindowsObject CurChild;
BOOL Found = FALSE;
if ( ChildList )
{
NextChild = ChildList->Next();
do {
CurChild = NextChild;
NextChild = NextChild->Next();
/* Test CurChild for ok */
if ( (*Test)( CurChild, PParamList) )
Found = TRUE;
}
while ( !Found && (CurChild != ChildList) && ChildList);
if ( Found )
return CurChild;
}
return NULL;
}
/* Iterates over each child window in the TWindowsObject's ChildList,
calling the procedure whose pointer is passed as the Action to be
performed for each child. A pointer to a child is passed as the
first parameter to the iteration procedure. */
void TWindowsObject::ForEach(TActionFunc Action, void *PParamList)
{
PTWindowsObject CurChild;
PTWindowsObject NextChild; // allows ForEach to delete children
if ( ChildList )
{
NextChild = ChildList->Next();
do
{
CurChild = NextChild;
NextChild = NextChild->Next();
( *Action )( CurChild, PParamList );
}
while ( (CurChild != ChildList) && (ChildList) );
}
}
/* Returns a pointer to the first TWindowsObject in the
ChildList that meets some specified criteria.If no child in the
list meets the criteria, NULL is returned. The Test
parameter which defines the criteria, is a pointer to a member
function (this is how it's different from FirstThat above).
that takes two pointers to void. The first void* will be used as
the pointer to the child window and the second as a pointer to
the Test function's additional parameters. The Test function must
return a Boolean value indicating whether the child passed meets
the criteria. */
PTWindowsObject TWindowsObject::FirstThat(TCondMemFunc Test,
void *PParamList)
{
PTWindowsObject NextChild;
PTWindowsObject CurChild;
BOOL Found = FALSE;
if ( ChildList )
{
NextChild = ChildList->Next();
do {
CurChild = NextChild;
NextChild = NextChild->Next();
/* Test CurChild for ok */
if ( (this->*Test)( CurChild, PParamList) )
Found = TRUE;
}
while ( !Found && (CurChild != ChildList) && ChildList);
if ( Found )
return CurChild;
}
return NULL;
}
/* Iterates over each child window in the TWindowsObject's ChildList,
calling the member function (unlike ForEach above which takes pointer
to non-member function) whose pointer is passed as the Action to
be performed for each child. A pointer to a child is passed as the
first parameter to the iteration procedure. */
void TWindowsObject::ForEach(TActionMemFunc Action, void *PParamList)
{
PTWindowsObject CurChild;
PTWindowsObject NextChild; // allows ForEach to delete children
if ( ChildList )
{
NextChild = ChildList->Next();
do
{
CurChild = NextChild;
NextChild = NextChild->Next();
( this->*Action )( CurChild, PParamList );
}
while ( (CurChild != ChildList) && (ChildList) );
}
}
static int Position;
static BOOL IsItThisChild1(void *P, void *AChild)
{
++Position;
return ((PTWindowsObject)P == (PTWindowsObject)AChild);
}
/* Returns the position at which the passed child window appears
in the TWindowsObject's ChildList. If the child does not appear in
the list, -1 is returned. Zero'th position is ChildList->Next */
int TWindowsObject::IndexOf(PTWindowsObject AChild)
{
Position = -1;
if ( FirstThat(IsItThisChild1, AChild) )
return Position;
else
return -1;
}
/* Returns the child at the passed position in the TWindowsObject's
ChildList. The ChildList is circularly-referent so that passing a
position larger than the number of children will cause the traversal
of the list to wrap. Zero'th position is ChildList->Next */
PTWindowsObject TWindowsObject::At(int APosition)
{
PTWindowsObject CurrentChild;
if ( APosition == -1 )
return NULL;
CurrentChild = ChildList;
if ( CurrentChild )
{
CurrentChild = ChildList->Next();
while (APosition > 0)
{
CurrentChild = CurrentChild->Next();
--APosition;
}
}
return CurrentChild;
}
static BOOL IsItThisChild2(void *P, void *Id)
{
return ( ((PTWindowsObject)P)->GetId() == *(int *)Id);
}
/* Returns a pointer to the window in the ChildList with the passed Id.
If no child in the list has the passed Id, NULL is returned.*/
PTWindowsObject TWindowsObject::ChildWithId(int Id)
{
return FirstThat(IsItThisChild2, &Id);
}
/* Specifies default processing for an incoming message. Invokes default
processing, defined by MS-Windows. Calls the default window procedure
if this is a window; sets Msg.Result to 0 if it's a dialog. Both cases
must be handled here instead of in TWindow or TDialog because DefWndProc
can be called while an object is being destructed, making it effectively
non-virtual */
void TWindowsObject::DefWndProc(TMessage& Msg)
{
if ( IsFlagSet(WB_MDIFRAME) )
{
HWND ClientHWnd;
if ( GetClient() )
ClientHWnd = GetClient()->HWindow;
else
ClientHWnd = 0;
Msg.Result = DefFrameProc(HWindow, ClientHWnd, Msg.Message ,
Msg.WParam, Msg.LParam);
}
else
if ( DefaultProc ) // this is a Window
Msg.Result =
#ifdef STRICT
CallWindowProc(DefaultProc, HWindow, Msg.Message,
Msg.WParam, Msg.LParam);
#else
CallWindowProc((FARPROC)DefaultProc, HWindow, Msg.Message,
Msg.WParam, Msg.LParam);
#endif
else // this is a dialog
Msg.Result = 0;
}
// --------------------------------------------------------
// DispatchAMessage gets called by StdWndProc and
// Dispatches the Windows messages to the proper WM routine
// Calls _DDVTdispatch to return a pointer to the virtual function
// to call. If a virtual function is not defined calls the
// DefProc argument instead.
// ---------------------------------------------------------
typedef void (TWindowsObject::* MRMFP)(TMessage&);
typedef void (* MRFP)(TMessage&);
#if defined(_CLASSDLL) || defined(__DLL__)
#define getVptr(thisPtr) (*(void far **)(thisPtr))
#else
#define getVptr(thisPtr) (*(void near **)(thisPtr))
#endif
MRFP far * _DDVTdispatchNULL(void near *, int);
MRFP far * _DDVTdispatchNULL(void far *, int);
typedef void FAR PASCAL (* DISPATCHHOOK)(HANDLE hWnd, WORD wMessage,
WORD wParam, LONG lParam,
void far *Handler,
void far *ObjectPtr);
DISPATCHHOOK __OWL_DISPATCH_HOOK__ = NULL;
void TWindowsObject::DispatchAMessage(WORD AMsg, TMessage& Msg,
MRMFP DefProc)
{
MRFP FFP;
MRMFP MFP;
union
{
MRMFP mfp;
MRFP fp;
} Temp;
Temp.mfp = NULL;
HWND TheHWindow = HWindow;
BeforeDispatchHandler();
FFP = *_DDVTdispatchNULL(getVptr(this), (int)AMsg);
if (FFP) // found a DDVT function
{
Temp.fp = FFP; // convert DDVT function pointer
MFP = Temp.mfp; // to member function pointer
}
else // no DDVT function, use DefProc
MFP = DefProc;
if (__OWL_DISPATCH_HOOK__)
{
if (!FFP) // if don't have normal function ptr
{ // convert from member function ptr
Temp.mfp = MFP; // to normal function pointer
FFP = Temp.fp;
}
(*__OWL_DISPATCH_HOOK__)(TheHWindow, Msg.Message, Msg.WParam,
Msg.LParam, (void far *)FFP, this);
}
(this->*MFP)(Msg); // invoke handler
if ( this == GetObjectPtr(TheHWindow) ) // this hasn't been deleted
AfterDispatchHandler();
}
/* Responds to an incoming WM_COMMAND message. If a child window had
the focus when the message was sent, the message is sent to the child
window. If the message cannot be given to a child window, it is
given to "this" */
void TWindowsObject::WMCommand(TMessage& Msg)
{
HWND CurrentWindow, Control;
PTWindowsObject Child;
if ( IsFlagSet(WB_KBHANDLER) && (Msg.LParam == 0L) )
{
Control = GetDlgItem(HWindow, Msg.WParam);
if ( Control && ( SendMessage(Control, WM_GETDLGCODE, 0, 0) &
(DLGC_DEFPUSHBUTTON | DLGC_UNDEFPUSHBUTTON) ) )
{
Msg.LP.Lo = (WORD)Control;
Msg.LP.Hi = BN_CLICKED;
}
}
if ( !IsFlagSet(WB_ALIAS) &&
(LOWORD(Msg.LParam) == 0) ) // it's a command message and...
{
if ( Msg.WParam < CM_COUNT ) // ... we can route it
{
// Find the object closest to the focus window
CurrentWindow = GetFocus(); // window with focus when command was sent
Child = (PTWindowsObject)GetObjectPtr(CurrentWindow);
while ( !Child && CurrentWindow && CurrentWindow != HWindow )
{
CurrentWindow = GetParent(CurrentWindow);
Child = (PTWindowsObject)GetObjectPtr(CurrentWindow);
}
// If the object is found, route to the object, else handle it yourself
if ( !Child )
Child = this;
Child->DispatchAMessage(CM_FIRST + Msg.WParam, Msg, &TWindowsObject::DefCommandProc);
}
else
DefWndProc(Msg);
}
else
{
// Find the child that generated the notification
Child = (PTWindowsObject)GetObjectPtr(GetDlgItem(HWindow, Msg.WParam));
/* If the child is found, give the notification to the child,
else give it to "this" as an "id" notification. */
if ( Child && HIWORD(Msg.LParam) < NF_COUNT )
Child->DispatchAMessage(NF_FIRST + HIWORD(Msg.LParam),
Msg, &TWindowsObject::DefNotificationProc);
else
if ( !IsFlagSet(WB_ALIAS) )
{
if ( Msg.WParam < ID_COUNT )
DispatchAMessage(ID_FIRST + Msg.WParam,
Msg, &TWindowsObject::DefChildProc);
else
DefChildProc(Msg);
}
else // if I'm an alias don't route ID messages to me
DefWndProc(Msg);
}
}
/* Function called when a window must redraw one of its "owner-draw"
controls. Having the control redraw itself is usually preferable.
Also called when the window's "owner draw" menu must be redrawn */
void TWindowsObject::DrawItem(DRAWITEMSTRUCT far &)
{
}
/* Dispatches WM_DRAWITEM messages (for owner draw controls) to the
appropriate control's appropriate member function */
void TWindowsObject::WMDrawItem(TMessage& Msg)
{
PTWindowsObject Child = (PTWindowsObject)GetObjectPtr(
((LPDRAWITEMSTRUCT)(Msg.LParam))->hwndItem);
if ( Child )
Child->DispatchAMessage(WM_FIRST + WM_DRAWITEM, Msg,
&TWindowsObject::DefWndProc);
else // no child object (includes case where item is a menu)
{
if ( IsFlagSet(WB_ALIAS) )
DefWndProc(Msg);
else
DrawItem(*((LPDRAWITEMSTRUCT)(Msg.LParam)));
}
}
/* Dispatches scroll messages as if they where WMCommand messages,
that is by routing them to the scroll bar control as a notification
and to "this" as an "id" notification. */
void TWindowsObject::DispatchScroll(TMessage& Msg)
{
PTWindowsObject Child;
WORD ChildId;
if ( HIWORD(Msg.LParam) )
{
Child = (PTWindowsObject)GetObjectPtr((HWND)HIWORD(Msg.LParam));
if ( Child )
Child->DispatchAMessage(NF_FIRST + Msg.WParam, Msg, &TWindowsObject::DefNotificationProc);
else
{
ChildId = GetWindowWord((HWND)HIWORD(Msg.LParam), GWW_ID);
if ( ChildId < ID_COUNT )
DispatchAMessage(ID_FIRST + ChildId, Msg, &TWindowsObject::DefChildProc);
else
DefChildProc(Msg);
}
}
else
DefWndProc(Msg);
}
/* Responds to an incoming WM_VSCROLL message by calling DispatchScroll. If
message is not handled, calls DefWndProc. */
void TWindowsObject::WMVScroll(TMessage& Msg)
{
if ( !(GetWindowLong(HWindow, GWL_STYLE) & WS_VSCROLL) )
DispatchScroll(Msg);
else
DefWndProc(Msg);
}
/* Responds to an incoming WM_HSCROLL message by calling DispatchScroll.
If message is not handled, calls DefWndProc. */
void TWindowsObject::WMHScroll(TMessage& Msg)
{
if ( !(GetWindowLong(HWindow, GWL_STYLE) & WS_HSCROLL) )
DispatchScroll(Msg);
else
DefWndProc(Msg);
}
/* Performs default processing for a command message (menu selection or
accelerator). If the original message receiver was this object, give
the message to DefWndProc, else if the object has a parent, give the
message to the parent, else give the message to the original receiver. */
void TWindowsObject::DefCommandProc(TMessage& Msg)
{
PTWindowsObject Target;
if ( Msg.Receiver == HWindow )
Target = NULL;
else
if ( Parent )
Target = Parent;
else
Target = (PTWindowsObject)GetObjectPtr(Msg.Receiver);
if ( Target == NULL )
DefWndProc(Msg);
else
Target->DispatchAMessage(CM_FIRST + Msg.WParam, Msg, &TWindowsObject::DefCommandProc);
}
/* Performs default processing for an incoming notification message from
a child of the TWindowsObject. Nothing can be done by default of a
child notification (or "id" message). The user can override this
function if it is more convenient to handle "id" messages in a case
statement. */
void TWindowsObject::DefChildProc(TMessage& Msg)
{
DefWndProc(Msg);
}
/* Performs default processing for a notification message generated by
the TWindowsObject. (The TWindowsObject has the option to perform
processing in response to its own notification messages. ) It passes
the message to the parent as an "id" message. It is assumed that the
object giving this message to this object is the parent of this
object. This is done in WMCommand, WMHScroll, or WMVScroll of the
parent. Notifications are translated into "id" messages so that the
parent does not confuse child notification with its own
notifications. If its an WMHScroll or WMVScroll the ID is looked up
explicitly. */
void TWindowsObject::DefNotificationProc(TMessage& Msg)
{
if ( Parent )
{
if ( Parent->IsFlagSet(WB_ALIAS) )
DefWndProc(Msg);
else
{
if (Msg.Message == WM_COMMAND )
Parent->DispatchAMessage(ID_FIRST + Msg.WParam, Msg, &TWindowsObject::DefChildProc);
else
Parent->DispatchAMessage(
ID_FIRST + GetWindowWord(HWindow, GWW_ID), Msg, &TWindowsObject::DefChildProc);
}
}
}
static void DoEnableAutoCreate(void *P, void *)
{
if ( ((PTWindowsObject)P)->HWindow )
((PTWindowsObject)P)->EnableAutoCreate();
}
/* Destroys an MS-Windows element associated with the TWindowsObject
after setting the WB_AUTOCREATE flag to ON for each of the windows
in the TWindowsObject's ChildList. */
void TWindowsObject::Destroy()
{
if ( HWindow )
{
ForEach(DoEnableAutoCreate, 0);
if ( IsFlagSet(WB_MDICHILD) && (Parent->GetClient() != NULL) )
SendMessage(((PTWindowsObject)(Parent->GetClient()))->HWindow,
WM_MDIDESTROY, (WORD)HWindow, 0);
else
DestroyWindow(HWindow);
}
}
/* Initializes the passed parameter with the registration attributes for
the TWindowsObject. This function serves as a placeholder for
descendant classes to redefine to specify registration
attributes for the MS-Windows class of a window object. */
void TWindowsObject::GetWindowClass(WNDCLASS&)
{
}
/* Performs setup following creation of an associated MS-Windows window.
Iterates through the TWindowsObject's ChildList, attempting to create
an associated MS-Windows interface element for each child window
object in the list. (A child's Create method is not called if its
WB_AUTOCREATE flag is not set). Calls TransferData to transfer data
for its children for whom data transfer is enabled. Can be redefined
in derived classes to perform additional special initialization.
*/
void TWindowsObject::SetupWindow()
{
if ( ! CreateChildren() )
Status = EM_INVALIDCHILD;
else
TransferData(TF_SETDATA);
}
static void _FAR * DataPtr;
static void TransferDataChild(void *AChild, void *Direction)
{
if ( ((PTWindowsObject)AChild)->IsFlagSet(WB_TRANSFER) )
{
*(LPSTR _FAR *)&DataPtr += ((PTWindowsObject)AChild)->Transfer(
DataPtr, *(WORD *)Direction);
}
}
/* Transfers data between the TWindowsObject's data buffer and the child
windows in its ChildList. (Data is not transfered between any child
windows whose WB_TRANSFER flag is not set). */
void TWindowsObject::TransferData(WORD Direction)
{
if ( TransferBuffer )
{
DataPtr = TransferBuffer;
ForEach(TransferDataChild, &Direction);
}
}
/* Registers the TWindowsObject's MS-Windows, if not already registered. */
BOOL TWindowsObject::Register()
{
WNDCLASS WindowClass;
if ( !GetClassInfo( 0, GetClassName(), &WindowClass) &&
!GetClassInfo(GetModule()->hInstance, GetClassName(),
&WindowClass) )
{
GetWindowClass(WindowClass);
return RegisterClass(&WindowClass);
}
return TRUE;
}
/* Displays the TWindowsObject, after checking that it has a valid
(non-NULL) handle. */
void TWindowsObject::Show(int ShowCmd)
{
if ( HWindow )
ShowWindow(HWindow, ShowCmd);
}
/* Sets the Title and caption of the TWindowsObject. */
void TWindowsObject::SetCaption(LPSTR ATitle)
{
if (Title != ATitle)
{
if ( HIWORD(Title) )
farfree(Title);
Title = _fstrdup(ATitle ? ATitle : "");
}
if ( HWindow )
SetWindowText(HWindow, Title);
}
static BOOL CannotCloseChild(void *P, void *)
{
return ( ((PTWindowsObject)P)->HWindow && !( ((PTWindowsObject)P)->CanClose()) );
}
/* Returns a BOOL indicating whether or not it is Ok to close
the TWindowsObject. Iterates through the TWindowsObject's
ChildList, calling the CanClose method of each. Returns False if
any of the child windows return False. */
BOOL TWindowsObject::CanClose()
{
return (FirstThat(CannotCloseChild, 0) == NULL);
}
/* Destroys the associated MS-Windows interface element and frees "this"
after determining that it is Ok to do so. If the TWindowsObject is the
main window of the application, calls the CanClose method of the
application, else calls this->CanClose, before calling ShutDownWindow. */
void TWindowsObject::CloseWindow()
{
BOOL WillClose;
if ( GetApplication() && this == GetApplication()->MainWindow )
WillClose = GetApplication()->CanClose();
else
WillClose = CanClose();
if ( WillClose )
ShutDownWindow();
}
/* Destroys the associated MS-Windows interface element and frees "this"
without calling CanClose. */
void TWindowsObject::ShutDownWindow()
{
Destroy();
delete this;
}
/* The default response to a WMClose message is to send a CloseWindow
message. CloseWindow sends a CanClose to determine if the window
can be closed. */
void TWindowsObject::WMClose(TMessage& Msg)
{
if ( IsFlagSet(WB_ALIAS) )
DefWndProc(Msg);
else
CloseWindow();
}
/* Responds to an incoming WM_DESTROY message. If the TWindowsObject
is the application's main window posts a 'quit' message to end
the application. */
void TWindowsObject::WMDestroy(TMessage& Msg)
{
if ( !IsFlagSet(WB_ALIAS) )
{
PTApplication app = GetApplication();
if (app && (this == app->MainWindow))
PostQuitMessage(app->Status);
}
DefWndProc(Msg);
}
/* Responds to an incoming WM_NCDESTROY message, the last message
sent to an MS-Windows interface element. Sets the HWindow data
member of the TWindowsObject to zero to indicate that an interface
element is no longer associated with the object. */
void TWindowsObject::WMNCDestroy(TMessage& Msg)
{
DefWndProc(Msg);
HWindow = 0;
if ( GetApplication() && this == GetApplication()->KBHandlerWnd )
GetApplication()->SetKBHandler(NULL);
if ( IsFlagSet(WB_ALIAS) )
delete this;
}
/* Responds to an incoming WM_ACTIVATE message by calling
DefWndProc followed by ActivationResponse. DefWndProc must be
called first since TWindow::ActivationResponse does a SetFocus
which would otherwise be overridden when DefWindowProc does its
SetFocus. */
void TWindowsObject::WMActivate(TMessage& Msg)
{
DefWndProc(Msg);
if ( !IsFlagSet(WB_ALIAS) )
ActivationResponse(Msg.WParam, Msg.LP.Hi);
}
/* Responds to an incoming WM_ACTIVATE or WM_MDIACTIVATE message. If the
TWindowsObject is being activated and if it has requested
keyboard handling for its messages, enables the "keyboard handler"
by calling the SetKBHandler function of the application. Otherwise
disables the "keyboard handler". */
void TWindowsObject::ActivationResponse(WORD Activated, BOOL /*IsIconified*/ )
{
if ( GetApplication() )
{
if ( Activated && IsFlagSet(WB_KBHANDLER) )
GetApplication()->SetKBHandler(this);
else
GetApplication()->SetKBHandler(NULL);
}
}
/* Respond to Windows attempt to close close down. */
void TWindowsObject::WMQueryEndSession(TMessage& Msg)
{
if ( IsFlagSet(WB_ALIAS) )
DefWndProc(Msg);
else
{
if ( GetApplication() && this == GetApplication()->MainWindow )
Msg.Result = (int)GetApplication()->CanClose();
else
Msg.Result = (int)CanClose();
}
}
/* If the window receives an Exit menu choice, it will attempt
to close down the window. */
void TWindowsObject::CMExit(TMessage& Msg)
{
if ( GetApplication() && this == GetApplication()->MainWindow )
CloseWindow();
else
DefCommandProc(Msg);
}
/* Returns a NULL pointer to indicate that the TWindowsObject is not
a TMDIFrame. Is redefined for TMDIFrame to return a pointer to
their TMDIClient window. */
TMDIClient *TWindowsObject::GetClient()
{
return NULL;
}