253 lines
7.4 KiB
C++
253 lines
7.4 KiB
C++
/***************************************************************************\
|
|
*
|
|
* File: MsgObject.cpp
|
|
*
|
|
* Description:
|
|
* MsgObject.cpp implements the "Message Object" class that is used to receive
|
|
* messages in DirectUser. This object is created for each instance of a
|
|
* class that is instantiated.
|
|
*
|
|
*
|
|
* History:
|
|
* 8/05/2000: JStall: Created
|
|
*
|
|
* Copyright (C) 2000 by Microsoft Corporation. All rights reserved.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include "Msg.h"
|
|
#include "MsgObject.h"
|
|
|
|
#include "MsgTable.h"
|
|
#include "MsgClass.h"
|
|
|
|
|
|
/***************************************************************************\
|
|
*****************************************************************************
|
|
*
|
|
* class MsgObject
|
|
*
|
|
*****************************************************************************
|
|
\***************************************************************************/
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* MsgObject::xwDestroy
|
|
*
|
|
* xwDestroy() is called when the object reaches the final xwUnlock(), giving
|
|
* the MsgObject a chance to hook into properly tear-down the external object.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
void
|
|
MsgObject::xwDestroy()
|
|
{
|
|
xwEndDestroy();
|
|
|
|
BaseObject::xwDestroy();
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* MsgObject::xwEndDestroy
|
|
*
|
|
* xwEndDestroy() ends the destruction process for a given MsgObject to free
|
|
* its associated resources. This includes destroying all child Gadgets in
|
|
* the subtree before this Gadget is destroyed.
|
|
*
|
|
* Any class that derives from MsgObject and overrides xwDestroy() without
|
|
* calling MsgObject::xwDestroy() MUST call xwEndDestroy(). This allows
|
|
* derived classes to use special pool allocators, but still properly
|
|
* tear down the "attached" objects.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
void
|
|
MsgObject::xwEndDestroy()
|
|
{
|
|
if (m_emo.m_pmt != NULL) {
|
|
//
|
|
// Need to "demote" the object all of the way down.
|
|
//
|
|
|
|
m_emo.m_pmt->GetClass()->xwTearDownObject(this);
|
|
AssertMsg(m_emo.m_arpThis.GetSize() == 0,
|
|
"After TearDown, should not have any remaining 'this' pointers");
|
|
|
|
#if DBG
|
|
// DEBUG: Stuff pMT with a bogus value to help identify destroyed object
|
|
m_emo.m_pmt = (const MsgTable *) ULongToPtr(0xA0E2A0E2);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* MsgObject::PromoteInternal
|
|
*
|
|
* PromoteInternal() provides an empty promotion function that can be used
|
|
* to build internal objects. This promotion function WILL NOT actually
|
|
* allocate the object and can only be used to prevent the creation of a
|
|
* base class that can not be directly created.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
HRESULT CALLBACK
|
|
MsgObject::PromoteInternal(
|
|
IN DUser::ConstructProc pfnCS, // Creation callback function
|
|
IN HCLASS hclCur, // Class to promote to
|
|
IN DUser::Gadget * pgad, // Object being promoted
|
|
IN DUser::Gadget::ConstructInfo * pciData) // Construction parameters
|
|
{
|
|
UNREFERENCED_PARAMETER(pfnCS);
|
|
UNREFERENCED_PARAMETER(hclCur);
|
|
UNREFERENCED_PARAMETER(pgad);
|
|
UNREFERENCED_PARAMETER(pciData);
|
|
|
|
|
|
//
|
|
// Not allowed to directly create this object. Derived classes must provide
|
|
// their own Promotion function.
|
|
//
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* MsgObject::DemoteInternal
|
|
*
|
|
* DemoteInternal() provides an empty demotion function that can be used
|
|
* to tear-down internal objects. Since there is rarely anything to do for
|
|
* demotion of internal objects, this demotion function may be safely used
|
|
* for internal objects.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
HCLASS CALLBACK
|
|
MsgObject::DemoteInternal(
|
|
IN HCLASS hclCur, // Class of Gadget being destroyed
|
|
IN DUser::Gadget * pgad, // Gadget being destroyed
|
|
IN void * pvData) // Implementation data on object
|
|
{
|
|
UNREFERENCED_PARAMETER(hclCur);
|
|
UNREFERENCED_PARAMETER(pgad);
|
|
UNREFERENCED_PARAMETER(pvData);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
#if 1
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* MsgObject::SetupInternal
|
|
*
|
|
* SetupInternal() sets up an internal object that is being created as a
|
|
* handle (legacy object). This function should not be called on objects
|
|
* that are being created as "Gadget's".
|
|
*
|
|
* TODO: Try to remove this function
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL
|
|
MsgObject::SetupInternal(
|
|
IN HCLASS hcl) // Internal class being setup
|
|
{
|
|
MsgClass * pmcThis = ValidateMsgClass(hcl);
|
|
AssertMsg((pmcThis != NULL) && pmcThis->IsInternal(), "Must be a valid internal class");
|
|
|
|
int cLevels = 0;
|
|
const MsgClass * pmcCur = pmcThis;
|
|
while (pmcCur != NULL) {
|
|
cLevels++;
|
|
pmcCur = pmcCur->GetSuper();
|
|
}
|
|
|
|
VerifyMsg(m_emo.m_arpThis.GetSize() == 0, "Must not already be initialized");
|
|
if (!m_emo.m_arpThis.SetSize(cLevels)) {
|
|
return FALSE;
|
|
}
|
|
|
|
for (int idx = 0; idx < cLevels; idx++) {
|
|
m_emo.m_arpThis[idx] = this;
|
|
}
|
|
|
|
m_emo.m_pmt = pmcThis->GetMsgTable();
|
|
AssertMsg(m_emo.m_pmt != NULL, "Must now have a valid MT");
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* MsgObject::InstanceOf
|
|
*
|
|
* InstanceOf() checks if the MsgObject is an "instance of" a specified class
|
|
* by traversing the inheritance heirarchy.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL
|
|
MsgObject::InstanceOf(
|
|
IN const MsgClass * pmcTest // Class checking for instance
|
|
) const
|
|
{
|
|
AssertMsg(pmcTest != NULL, "Must have a valid MsgClass");
|
|
|
|
const MsgClass * pmcCur = m_emo.m_pmt->GetClass();
|
|
while (pmcCur != NULL) {
|
|
if (pmcCur == pmcTest) {
|
|
return TRUE;
|
|
}
|
|
|
|
pmcCur = pmcCur->GetSuper();
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* MsgObject::GetGutsData
|
|
*
|
|
* GetGutsData() retreives the implementation-specific data for the specified
|
|
* class on the given object.
|
|
*
|
|
* NOTE: This operation has been highly optimized for speed and will not
|
|
* validate that the object is of the specified class type. If the caller is
|
|
* uncertain, they must call InstanceOf() or CastClass() to properly
|
|
* determine the object's type.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
void *
|
|
MsgObject::GetGutsData(
|
|
IN const MsgClass * pmcData // Class of guts data
|
|
) const
|
|
{
|
|
#if DBG
|
|
if (!InstanceOf(pmcData)) {
|
|
PromptInvalid("The Gadget is not the specified class");
|
|
}
|
|
#endif
|
|
|
|
int cDepth = pmcData->GetMsgTable()->GetDepth();
|
|
#if DBG
|
|
if ((cDepth < 0) || (cDepth >= m_emo.m_arpThis.GetSize())) {
|
|
PromptInvalid("The Gadget does not have data for the specified class");
|
|
}
|
|
#endif
|
|
|
|
return m_emo.m_arpThis[cDepth];
|
|
}
|