You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
239 lines
7.0 KiB
239 lines
7.0 KiB
/***************************************************************************\
|
|
*
|
|
* File: MsgTable.cpp
|
|
*
|
|
* Description:
|
|
* MsgTable.cpp implements the "Message Table" object that provide a
|
|
* dynamically generated v-table for messages.
|
|
*
|
|
*
|
|
* History:
|
|
* 8/05/2000: JStall: Created
|
|
*
|
|
* Copyright (C) 2000 by Microsoft Corporation. All rights reserved.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include "Msg.h"
|
|
#include "MsgTable.h"
|
|
|
|
#include "MsgClass.h"
|
|
|
|
|
|
/***************************************************************************\
|
|
*****************************************************************************
|
|
*
|
|
* class MsgTable
|
|
*
|
|
*****************************************************************************
|
|
\***************************************************************************/
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* MsgTable::Build
|
|
*
|
|
* Build() builds and fully initializes a new MsgTable.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
HRESULT
|
|
MsgTable::Build(
|
|
IN const DUser::MessageClassGuts * pmcInfo,
|
|
// Implementation information
|
|
IN const MsgClass * pmcPeer, // "Owning" MsgClass
|
|
OUT MsgTable ** ppmtNew) // Newly built MsgTable
|
|
{
|
|
AssertMsg(pmcPeer != NULL, "Must have a valid MsgClass peer");
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Compute how much memory the MsgTable will take
|
|
// - Find the Super
|
|
// - Determine the number of messages. This is the number of messages
|
|
// defined in the super + the number of _new_ (not overridden) messages.
|
|
//
|
|
|
|
int cSuperMsgs = 0, cNewMsgs = 0;
|
|
const MsgClass * pmcSuper = pmcPeer->GetSuper();
|
|
const MsgTable * pmtSuper = NULL;
|
|
if (pmcSuper != NULL) {
|
|
pmtSuper = pmcSuper->GetMsgTable();
|
|
cSuperMsgs = pmtSuper->GetCount();
|
|
for (int idx = 0; idx < pmcInfo->cMsgs; idx++) {
|
|
if ((pmcInfo->rgMsgInfo[idx].pfn != NULL) &&
|
|
(pmtSuper->Find(FindAtomW(pmcInfo->rgMsgInfo[idx].pszMsgName)) == 0)) {
|
|
|
|
cNewMsgs++;
|
|
}
|
|
}
|
|
} else {
|
|
cNewMsgs = pmcInfo->cMsgs;
|
|
}
|
|
|
|
|
|
//
|
|
// Allocate the new MsgTable
|
|
//
|
|
|
|
int cTotalMsgs = cSuperMsgs + cNewMsgs;
|
|
int cbAlloc = sizeof(MsgTable) + cTotalMsgs * sizeof(MsgSlot);
|
|
if ((cbAlloc > GM_EVENT) || (cTotalMsgs > 1024)) {
|
|
PromptInvalid("MsgTable will contain too many methods.");
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
void * pvAlloc = ProcessAlloc(cbAlloc);
|
|
if (pvAlloc == NULL) {
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
MsgTable * pmtNew = placement_new(pvAlloc, MsgTable);
|
|
pmtNew->m_cMsgs = cTotalMsgs;
|
|
pmtNew->m_pmcPeer = pmcPeer;
|
|
pmtNew->m_pmtSuper = pmtSuper;
|
|
|
|
|
|
//
|
|
// Setup message entries
|
|
// - Copy messages from super-class
|
|
// - Override and add messages from new class
|
|
//
|
|
// NOTE: We are using GArrayS<> to store the array of this pointers. The
|
|
// data stored in here points to the beginning of the array of data.
|
|
// Before this array, we store the size, but we don't need to worry about
|
|
// that here.
|
|
//
|
|
|
|
if (cTotalMsgs > 0) {
|
|
MsgSlot * rgmsDest = pmtNew->GetSlots();
|
|
int cThisDepth = pmtSuper != NULL ? pmtSuper->GetDepth() + 1 : 0;
|
|
int cbThisOffset = cThisDepth * sizeof(void *);
|
|
int idxAdd = 0;
|
|
|
|
if (pmtSuper != NULL) {
|
|
const MsgSlot * rgmsSrc = pmtSuper->GetSlots();
|
|
for (idxAdd = 0; idxAdd < cSuperMsgs; idxAdd++) {
|
|
rgmsDest[idxAdd] = rgmsSrc[idxAdd];
|
|
}
|
|
}
|
|
Assert(idxAdd == cSuperMsgs);
|
|
|
|
for (int idx = 0; idx < pmcInfo->cMsgs; idx++) {
|
|
const DUser::MessageInfoGuts * pmi = &pmcInfo->rgMsgInfo[idx];
|
|
ATOM atomMsg = 0;
|
|
int idxMsg = -1;
|
|
|
|
if (pmi->pfn == NULL) {
|
|
continue; // Just skip this slot
|
|
}
|
|
|
|
if ((pmtSuper == NULL) || // No super
|
|
((atomMsg = FindAtomW(pmi->pszMsgName)) == 0) || // Message not yet defined
|
|
((idxMsg = pmtSuper->FindIndex(atomMsg)) < 0)) { // Message not in super
|
|
|
|
//
|
|
// Function is defined, so it should be added.
|
|
//
|
|
|
|
atomMsg = AddAtomW(pmi->pszMsgName);
|
|
idxMsg = idxAdd++;
|
|
}
|
|
|
|
MsgSlot & ms = rgmsDest[idxMsg];
|
|
ms.atomNameID = atomMsg;
|
|
ms.cbThisOffset = cbThisOffset;
|
|
ms.pfn = pmi->pfn;
|
|
}
|
|
|
|
AssertMsg(idxAdd == cTotalMsgs, "Should have added all messages");
|
|
|
|
|
|
//
|
|
// Check to see if any messages were not properly setup.
|
|
//
|
|
|
|
BOOL fMissing = FALSE;
|
|
for (idx = 0; idx < cTotalMsgs; idx++) {
|
|
if (rgmsDest[idx].pfn == NULL) {
|
|
//
|
|
// Function is not defined and is not in the super. This is
|
|
// an error because it is being declared "new" and not being
|
|
// defined.
|
|
//
|
|
|
|
WCHAR szMsgName[256];
|
|
GetAtomNameW(rgmsDest[idx].atomNameID, szMsgName, _countof(szMsgName));
|
|
|
|
Trace("ERROR: DUser: %S::%S() was not properly setup.\n",
|
|
pmcInfo->pszClassName, szMsgName);
|
|
fMissing = TRUE;
|
|
}
|
|
}
|
|
|
|
if (fMissing) {
|
|
PromptInvalid("Class registration does not have all functions properly setup.");
|
|
hr = DU_E_MESSAGENOTIMPLEMENTED;
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Done building- return out
|
|
//
|
|
|
|
*ppmtNew = pmtNew;
|
|
return S_OK;
|
|
|
|
ErrorExit:
|
|
delete pmtNew;
|
|
return hr;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* MsgTable::FindIndex
|
|
*
|
|
* FindIndex() finds the corresponding index for the specified
|
|
* method / message.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
int
|
|
MsgTable::FindIndex(
|
|
IN ATOM atomNameID // Method to find
|
|
) const
|
|
{
|
|
const MsgSlot * rgSlots = GetSlots();
|
|
for (int idx = 0; idx < m_cMsgs; idx++) {
|
|
if (rgSlots[idx].atomNameID == atomNameID) {
|
|
return idx;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* MsgTable::Find
|
|
*
|
|
* Find() finds the corresponding MsgSlot for the specified method / message.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
const MsgSlot *
|
|
MsgTable::Find(
|
|
IN ATOM atomNameID // Method to find
|
|
) const
|
|
{
|
|
int idx = FindIndex(atomNameID);
|
|
if (idx >= 0) {
|
|
return &(GetSlots()[idx]);
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|