NT4/private/ole32/com/inc/psctbl2.cxx
2020-09-30 17:12:29 +02:00

1798 lines
58 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1995.
//
// File: psctbl2.cxx
//
// Contents: Trie-based IID to CLSID map
//
// Classes: CMapGuidToGuidBase
// CPSClsidTbl (DLL)
// CScmPSClsidTbl (SCM/EXE)
//
// Functions: bmemcmp
// bmemcpy
// CMapGuidToGuidBase::Initialize
// CMapGuidToGuidBase::CGUIDBlock -> internal functions
// CMapGuidToGuidBase::TrieNode -> internal functions
// CPSClsidTbl::Initialize
// CPSClsidTbl::Find
// CScmPSClsidTbl::Initialize
// CScmPSClsidTbl::InitTbl
// CScmPSClsidTbl::AddLocal
// CScmPSClsidTbl::CopyToSharedMem
//
// History: 06-Jun-95 t-stevan Created
//
//--------------------------------------------------------------------------
#include <ole2int.h>
#pragma hdrstop
#include <psctbl2.hxx>
// *** Defines and Constants ***
// The number of bits used to store the number of key bytes in a TrieNode
const int KEYBYTE_BITS = 5;
// # of bits used to store # of links
const int LINKS_BITS = 9;
// The mask for number of key bytes stored in a TrieNode
const WORD KEYBYTE_MASK = 0x1f;
// The mask for the number of links stored in a TrieNode
const WORD LINKS_MASK = (0x1ff<<KEYBYTE_BITS);
// Mask for leaf bit in TrieNode
const WORD ISLEAF_MASK = 0x4000;
// Mask for deleted flag bit in TrieNode
const WORD DELETED_MASK = 0x8000;
// *** These definitions control the amount of memory that the cache uses/can use ***
// The default number of links per TrieNode
const int NODE_LINKS = 4;
// The initial amount to grow by
const int NODE_INIT_GROWBY =4;
// The amount to growby afterwards
// Note: must be a factor of 256, so therefore must be power of 2
// also, NODE_LINKS+NODE_INIT_GROWBY = multiple of NODE_GROWBY
const int NODE_GROWBY = 8;
// Mod mask for NODE_GROWBY so we can just and it instead of using %
const int NODE_GROWBY_MOD_MASK = NODE_GROWBY-1;
// Constants for our initial/maximum map size
const ULONG MAP_INITIAL_SIZE = 4096; // initial size of map = 4K
const ULONG MAP_MAX_SIZE = 65536; // maximum size of map = 64K
// Key text of registry
TCHAR tszInterface[] = TEXT("Interface");
// the following string is used in compapi.cxx
WCHAR wszProxyStubClsid[] = L"\\ProxyStubClsid32";
WCHAR wszProxyStubClsid16[] = L"\\ProxyStubClsid";
// macros for setting up a pointer to base off of in member funcs
#ifdef SETUP_BASE_POINTER
#undef SETUP_BASE_POINTER
#endif
#define SETUP_BASE_POINTER() void *pBase = m_pMemBase
#ifdef SYNC_BASE_POINTER
#undef SYNC_BASE_POINTER
#endif
#define SYNC_BASE_POINTER() pBase = m_pMemBase
// a based pointer for TrieNode, using passed bases
#define PASSBASED __based(pBase)
#define OLDBASED __based(pOldBase)
#define NEWBASED __based(pNewBase)
//+-------------------------------------------------------------------------
//
// Function: bmemcmp
//
// Synopsis: compares two memory strings, the first of which runs forward in memory
// the second of which runs backwards in memory
//
// Arguments: [pFBuf] - the forward-running string in memory
// [pBBuf] - the backward-running string in memory
// [count] - the number of bytes to compare
//
// Returns: 0 if the two memory strings are equal. Example: pFBuf = "abcd", pBBuf-3 = "dcba" would be equal
// else it returns the number of bytes left to compare.
//
//--------------------------------------------------------------------------
inline int bmemcmp(const BYTE *pFBuf, const BYTE *pBBuf, size_t count)
{
// pFBuf goes forward, pBBuf goes backward
while((count > 0) && (*pFBuf++ == *pBBuf--))
{
count--;
}
return count;
}
//+-------------------------------------------------------------------------
//
// Function: bmemcpy
//
// Synopsis: copies a backward-running memory string into a forward running one,
//
// Arguments: [pFDest] - the forward-running destination
// [pBSrc] - the backward-running string in memory
// [count] - the number of bytes to copy
//
// Returns: nothing
//
//--------------------------------------------------------------------------
inline void bmemcpy(BYTE *pFDest, const BYTE *pBSrc, size_t count)
{
while(count-- > 0)
{
*pFDest++ = *pBSrc--;
}
}
// *** CMapGuidToGuidBase ***
//+-------------------------------------------------------------------------
//
// Function: CMapGuidToGuidBase::Initialize
//
// Synopsis: Initializes base (client or server) guid -> guid map
//
// Arguments: [pBase] - the base address of our shared memory region
//
// Returns: appropriate status code
//
//--------------------------------------------------------------------------
HRESULT CMapGuidToGuidBase::Initialize(void *pBase)
{
CairoleDebugOut((DEB_ITRACE, "CMapGuidToGuidBase::Initialize(pBase = %p)\n", pBase));
m_pMemBase = pBase;
return S_OK;
}
// *** CMapGuidToGuidBase::CGUIDBlock ***
//+-------------------------------------------------------------------------
//
// Function: CMapGuidToGuidBase::CGUIDBlock::Initialize, public
//
// Synopsis: Initializes the GUID list, we store the mapped-to GUIDs in this
// list because there aren't that many different ones, so storing one per
// leaf would be wasteful
//
// Arguments: none
//
// Returns: nothing
//
//--------------------------------------------------------------------------
inline void CMapGuidToGuidBase::CGUIDBlock::Initialize()
{
m_nGuids = 0;
m_bpNext = NULL;
}
//+-------------------------------------------------------------------------
//
// Function: CMapGuidToGuidBase::CGUIDBlock::GetGuid, public
//
// Synopsis: Returns a GUID associated with a given GUIDIndex
//
// Arguments: [pBase] - the base address of the memory region
// [guidIndex] - the index of the GUID to retreive
// [guidOut] - a reference to a GUID to store the retreive guid in
//
// Returns: TRUE if found, FALSE if didn't
//
//--------------------------------------------------------------------------
inline BOOL CMapGuidToGuidBase::CGUIDBlock::GetGuid(void *pBase, GUIDIndex guidIndex, GUID &guidOut) const
{
const CGUIDBlock * pBlock = this;
if(guidIndex == INVALID_GUID_INDEX)
{
return FALSE;
}
while(guidIndex > cGuids)
{
guidIndex -= cGuids;
pBlock = BP_TO_P(CGUIDBlock *, (CGUIDBlock PASSBASED *) pBlock->m_bpNext);
if(pBlock == NULL)
{
return FALSE;
}
}
guidOut = pBlock->m_guidArray[guidIndex];
return TRUE;
}
//+-------------------------------------------------------------------------
//
// Function: CMapGuidToGuidBase::CGUIDBlock::AddGuid, public
//
// Synopsis: Adds a GUID to the list, or if the GUID is already there, just returns the proper
// reference to it.
//
// Arguments: [pBase] - base address of memory region (NULL if using local memory)
// [guid] - the guid to insert into the list
// [alloc] - the functor to use to allocate memory
//
// Returns: a based pointer to the GUID in the table
//
//--------------------------------------------------------------------------
GUIDIndex CMapGuidToGuidBase::CGUIDBlock::AddGuid(void *pBase, REFGUID guid, CAllocFunctor &alloc)
{
CGUIDBlock *pBlock;
int iRetVal; // use an int so we can detect if our table of GUIDs is full
// First check to see if this GUID is already in the table
iRetVal = GuidInTable(pBase, this, guid);
if(iRetVal == INVALID_GUID_INDEX)
{
// Nope, add it
// avoid recursion
pBlock = this;
iRetVal = 0;
while(pBlock != NULL && (iRetVal < INVALID_GUID_INDEX))
{
Win4Assert(pBlock->m_nGuids <= cGuids && "More than cGuids in CGUIDBlock");
if(pBlock->m_nGuids == cGuids)
{
// we've outgrown this table, add a new block to the end
if(BP_TO_P(CGUIDBlock *, (CGUIDBlock PASSBASED *) pBlock->m_bpNext) == NULL)
{
CGUIDBlock *pNewBlock;
// allocate a new one
pNewBlock = (CGUIDBlock *) alloc.Alloc(sizeof(CGUIDBlock));
if(pNewBlock == NULL)
{
// we're out of memory
return INVALID_GUID_INDEX;
}
// initialize it
pNewBlock->Initialize();
// add the guid to it
pNewBlock->m_guidArray[0] = guid;
pNewBlock->m_nGuids++;
// chain it on the list
pBlock->m_bpNext = (CGUIDBlockBasedPtr) P_TO_BP(CGUIDBlock PASSBASED *, pNewBlock);
// set the return value
iRetVal += cGuids; // we're the first guid on this link in the chain
break;
}
else
{
// keep on looking for empty space
pBlock = BP_TO_P(CGUIDBlock *, (CGUIDBlock PASSBASED *) pBlock->m_bpNext);
iRetVal += cGuids;
}
}
else
{
// insert this GUID (in no particular order) into the block's array
pBlock->m_guidArray[pBlock->m_nGuids] = guid;
iRetVal += pBlock->m_nGuids;
pBlock->m_nGuids++;
break;
}
}
}
if(iRetVal >= INVALID_GUID_INDEX)
{
iRetVal = INVALID_GUID_INDEX;
}
return (GUIDIndex) iRetVal;
}
//+-------------------------------------------------------------------------
//
// Function: CMapGuidToGuidBase::CGUIDBlock::GuidInTable, private (implementation)
//
// Synopsis: Looks down the chained block list for a particular GUID, if it finds it return a
// reference to it.
//
// Arguments: [pBase] - pointer to the base of the shared memory region
// [pBlock] - the block to start at
// [guid] - the guid to find
//
// Returns: a based pointer to the GUID in the table, NULL if it was not found
//
//--------------------------------------------------------------------------
GUIDIndex CMapGuidToGuidBase::CGUIDBlock::GuidInTable(void *pBase, CGUIDBlock *pBlock, REFGUID guid)
{
GUIDIndex iRet = 0;
GUID *pIndex;
BOOL fFound = FALSE;
int i;
// avoid recursion!
while(pBlock != NULL)
{
// Check this block
for(i =0, pIndex = &(pBlock->m_guidArray[0]); i < pBlock->m_nGuids; i++, pIndex++)
{
if(*pIndex == guid)
{
// found it, break outta here
iRet += i;
fFound = TRUE;
break;
}
}
if(!fFound)
{
// not in this block ,try next one
pBlock = BP_TO_P(CGUIDBlock *, (CGUIDBlock PASSBASED *) pBlock->m_bpNext);
iRet += cGuids;
}
else
{
// we found it, break outta here
break;
}
}
if(!fFound)
{
return INVALID_GUID_INDEX;
}
return iRet;
}
//+-------------------------------------------------------------------------
//
// Function: CMapGuidToGuidBase::CGUIDBlock::CopyToSharedMem
//
// Synopsis: Copies an entire list of CGUIDBlocks allocated in local memory
// to shared memory, making sure the original blocks now have
// based pointers to where the new (copied) data lies
//
// Arguments: [pNewBase] - the base pointer of the destination shared memory block
// [pOldBase] - the base pointer of the source memory block (usually NULL)
// [pCopyBlock] - the block to copy the first CGUIDBlock to
// [alloc] - the allocator to use to allocate shared memory
//
// Returns: appropriate status code
//
//--------------------------------------------------------------------------
HRESULT CMapGuidToGuidBase::CGUIDBlock::CopyToSharedMem(void *pNewBase, void *pOldBase, CGUIDBlock *pCopyBlock, CAllocFunctor &alloc)
{
CGUIDBlock *pBlock = this;
int i;
while(pBlock != NULL)
{
pCopyBlock->m_nGuids = pBlock->m_nGuids;
for(i = 0; i < m_nGuids; i++)
{
pCopyBlock->m_guidArray[i] = pBlock->m_guidArray[i];
}
pBlock = BP_TO_P(CGUIDBlock *, (CGUIDBlock OLDBASED *) pBlock->m_bpNext);
if(pBlock != NULL)
{
CGUIDBlock *pNewBlock;
pNewBlock = (CGUIDBlock *) alloc.Alloc(sizeof(CGUIDBlock));
if(pNewBlock == NULL)
{
return E_OUTOFMEMORY;
}
pCopyBlock->m_bpNext = (CGUIDBlockBasedPtr) P_TO_BP(CGUIDBlock NEWBASED *, pNewBlock);
pCopyBlock = pNewBlock;
}
else
{
pCopyBlock->m_bpNext = (CGUIDBlockBasedPtr) P_TO_BP(CGUIDBlock NEWBASED *, NULL);
}
}
return S_OK;
}
// *** CMapGuidToGuidBase::TrieNode ***
//+-------------------------------------------------------------------------
//
// Member: CMapGuidToGuidBase::TrieNode::NumLinks
//
// Synopsis: Return the number of links used in a node
//
// Arguments: (none)
//
// Returns: see synopsis
//
//--------------------------------------------------------------------------
inline int CMapGuidToGuidBase::TrieNode::NumLinks() const
{
return (m_wInfo & LINKS_MASK)>>KEYBYTE_BITS;
}
//+-------------------------------------------------------------------------
//
// Member: CMapGuidToGuidBase::TrieNode::NumKeyBytes
//
// Synopsis: Return the number of bytes of the key stored in this node
//
// Arguments: (none)
//
// Returns: see synopsis
//
//--------------------------------------------------------------------------
inline int CMapGuidToGuidBase::TrieNode::NumKeyBytes() const
{
return (m_wInfo & KEYBYTE_MASK);
}
//+-------------------------------------------------------------------------
//
// Member: CPSClsidTbl::TrieNode::IsLeaf
//
// Synopsis: Return whether a node is a Node or a Leaf
//
// Arguments: (none)
//
// Returns: TRUE if the node is a Leaf (is has no links)
// FALSE if it is a Node (it has links)
//--------------------------------------------------------------------------
inline BOOL CMapGuidToGuidBase::TrieNode::IsLeaf() const
{
if(m_wInfo & ISLEAF_MASK)
{
return TRUE;
}
return FALSE;
}
//+-------------------------------------------------------------------------
//
// Member: CPSClsidTbl::TrieNode::IsDeleted
//
// Synopsis: Return whether a given node is deleted
//
// Arguments: (none)
//
// Returns: TRUE if the node is marked as deleted
// FALSE otherwise
//
//--------------------------------------------------------------------------
inline BOOL CMapGuidToGuidBase::TrieNode::IsDeleted() const
{
if(m_wInfo & DELETED_MASK)
{
return TRUE;
}
return FALSE;
}
//+-------------------------------------------------------------------------
//
// Member: CMapGuidToGuidBase::TrieNode::SetLeaf
//
// Synopsis: sets the leaf bit of a node
//
// Arguments: [fLeaf] - should be TRUE to set this node to a Leaf
// FALSE if this node should be a Node
// Returns: nothing
//
//--------------------------------------------------------------------------
inline void CMapGuidToGuidBase::TrieNode::SetLeaf(BOOL fLeaf)
{
if(fLeaf)
{
m_wInfo = m_wInfo | ISLEAF_MASK;
}
else
{
m_wInfo = m_wInfo & (~ISLEAF_MASK);
}
}
//+-------------------------------------------------------------------------
//
// Member: CMapGuidToGuidBase::TrieNode::SetDeleted
//
// Synopsis: sets the deleted bit of a node
//
// Arguments: [fDeleted] - should be TRUE to mark this node as deleted
// FALSE to not mark it (equivalent to un-marking it)
//
// Returns: nothing
//
//--------------------------------------------------------------------------
inline void CMapGuidToGuidBase::TrieNode::SetDeleted(BOOL fDeleted)
{
Win4Assert(IsLeaf() && "Tried to delete a non-Leaf TrieNode!");
if (fDeleted)
{
m_wInfo = m_wInfo | DELETED_MASK;
}
else
{
m_wInfo = m_wInfo & (~DELETED_MASK);
}
}
//+-------------------------------------------------------------------------
//
// Member: CMapGuidToGuidBase::TrieNode::SetKeyBytes
//
// Synopsis: Sets the number of bytes of a key stored in this node
//
// Arguments: [nKeyBytes] - the number of bytes
//
// Returns: nothing
//
//--------------------------------------------------------------------------
inline void CMapGuidToGuidBase::TrieNode::SetKeyBytes(int nKeyBytes)
{
Win4Assert(nKeyBytes <= GUID_BYTES && "Tried to add more than GUID_BYTES to a TrieNode!");
m_wInfo = (m_wInfo & (~KEYBYTE_MASK)) |
(nKeyBytes&KEYBYTE_MASK);
}
//+-------------------------------------------------------------------------
//
// Member: CMapGuidToGuidBase::TrieNode::SetLinks
//
// Synopsis: Sets the number of links used in a node
//
// Arguments: [nLinks] - the number of links used
//
// Returns: nothing
//
//--------------------------------------------------------------------------
inline void CMapGuidToGuidBase::TrieNode::SetLinks(int nLinks)
{
Win4Assert(nLinks <= 256 && "Tried to have more than 256 links in a node");
m_wInfo = (m_wInfo & (~LINKS_MASK)) |
((nLinks<<KEYBYTE_BITS)&LINKS_MASK);
}
//+-------------------------------------------------------------------------
//
// Member: CPSClsidTbl::TrieNode::IncrementLinks
//
// Synopsis: Increments the number of links used in a node by 1
//
// Arguments: (none)
//
// Returns: (nothing)
//
//--------------------------------------------------------------------------
inline void CMapGuidToGuidBase::TrieNode::IncrementLinks()
{
Win4Assert(((m_wInfo & LINKS_MASK)>>KEYBYTE_BITS) <= 255
&& "Tried to insert past 256 links in a node");
m_wInfo += (1<<KEYBYTE_BITS);
}
//+-------------------------------------------------------------------------
//
// Member: CMapGuidToGuidBase::TrieNode::GetKey
//
// Synopsis: Return a pointer to a node's key data
//
// Arguments: (none)
//
// Returns: see synopsis
//
//--------------------------------------------------------------------------
inline BYTE *CMapGuidToGuidBase::TrieNode::GetKey()
{
#if !defined(_M_IX86)
// we need to worry about alignment
// so we put the 2-byte GUIDIndex before the n-byte key
if(IsLeaf())
{
return m_bData + sizeof(GUIDIndex);
}
else
{
return m_bData;
}
#else
// On the x86, we don't need to worry about alignment
return m_bData; // remember, this pointer not based!!
#endif // !defined(_M_IX86)
}
//+-------------------------------------------------------------------------
//
// Member: CMapGuidToGuidBase::TrieNode::GetData
//
// Synopsis: Return a pointer to a Leaf's data (the data mapped to the key)
//
// Arguments: (none)
//
// Returns: pointer to a Leaf's data
//
//--------------------------------------------------------------------------
inline GUIDIndex *CMapGuidToGuidBase::TrieNode::GetData()
{
Win4Assert(IsLeaf() && "Tried to get data from a non-Leaf node!");
#if !defined(_M_IX86)
// we need to worry about alignment
// so we put the 2-byte GUIDIndex before the n-byte key
return (GUIDIndex *) m_bData;
#else
// On the x86, we don't need to worry about alignment
return (GUIDIndex *) &m_bData[NumKeyBytes()];
#endif // !defined(_M_IX86)
}
//+-------------------------------------------------------------------------
//
// Member: CMapGuidToGuidBase::TrieNode::GetNodeSize
//
// Synopsis: Calculates the amount of bytes a node will take with the given parameters
//
// Arguments: [bKeyBytes] - the number of bytes of the key stored in this node
// [fLeaf] - TRUE = Leaf node, FALSE = Node node
// [bLinks] - the number of links to *allocate* (not the number of links used!!!!!)
//
// Returns: the computed size of the node
//
//--------------------------------------------------------------------------
inline DWORD CMapGuidToGuidBase::TrieNode::GetNodeSize(BYTE bKeyBytes, BOOL fLeaf, int bLinks)
{
return sizeof(WORD)+bKeyBytes+sizeof(GUIDIndex)*(fLeaf?1:0)+bLinks*sizeof(TrieNodeBasedPtr);
}
//+-------------------------------------------------------------------------
//
// Member: CMapGuidToGuidBase::TrieNode::GetLinkStart
//
// Synopsis: Return the beginning of the link array of a node
//
// Arguments: (none)
//
// Returns: a pointer to the beginning of the link array
//
//--------------------------------------------------------------------------
inline TrieNodeBasedPtr UNALIGNED *CMapGuidToGuidBase::TrieNode::GetLinkStart() const
{
return (TrieNodeBasedPtr UNALIGNED *) &m_bData[NumKeyBytes()];
}
//+-------------------------------------------------------------------------
//
// Function: TrieNode::InsertIntoLinkArray (static)
//
// Synopsis: insert a based pointer into the array of links to other nodes
//
// Arguments: [pArray] - pointer to the place in the array we wish to insert
// [pInsert] - based pointer to insert
// [nAfter] - number of nodes we need to "tumble" down the rest of the array
//
// Returns: void
//
//--------------------------------------------------------------------------
inline void CMapGuidToGuidBase::TrieNode::InsertIntoLinkArray(TrieNodeBasedPtr UNALIGNED *pbpArray, TrieNodeBasedPtr bpInsert,int nAfter)
{
Win4Assert(pbpArray != NULL && "Tried to insert into a NULL link array");
Win4Assert(bpInsert != 0 && "Tried to insert a NULL based pointer into link array");
// must use memmove, because memory regions overlap
memmove((pbpArray+1), pbpArray, nAfter*sizeof(TrieNodeBasedPtr));
*pbpArray = bpInsert;
}
//+-------------------------------------------------------------------------
//
// Function: CMapGuidToGuidBase::TrieNode::FindLinkSize, static
//
// Synopsis: Finds the number of allocated links to hold a given number of used links
//
// Arguments: [num] number of used links
//
// Returns: number of allocated links
//
//--------------------------------------------------------------------------
inline int CMapGuidToGuidBase::TrieNode::FindLinkSize(int nLinks)
{
if(nLinks <= NODE_LINKS)
{
return NODE_LINKS;
}
if(nLinks <= (NODE_LINKS+NODE_INIT_GROWBY))
{
return NODE_LINKS+NODE_INIT_GROWBY;
}
return NODE_GROWBY*((nLinks+(NODE_GROWBY-1))/NODE_GROWBY);
}
//+-------------------------------------------------------------------------
//
// Function: TrieNode::GetLink
//
// Synopsis: Given the next byte of a key, return the link to the next node in the trie
//
// Arguments: [pBase] - pointer to base of shared memory
// [bComp] - the next byte of the key to look for a link on
// [pbpLink]- a reference to a TrieNodeBasedPtr *, which on exit will hold
// the address of the link pointer so it can be changed
// in the future.
// Returns: the pointer to the node correspoding to bComp, or NULL if no such
// node exists
//
//--------------------------------------------------------------------------
CMapGuidToGuidBase::TrieNode *CMapGuidToGuidBase::TrieNode::GetLink(void *pBase, BYTE bComp, TrieNodeBasedPtr UNALIGNED *&pbpLink)
{
TrieNodeBasedPtr UNALIGNED *pbpLower;
TrieNodeBasedPtr UNALIGNED *pbpUpper;
TrieNodeBasedPtr UNALIGNED *pbpIndex;
BYTE bIndex;
Win4Assert(!IsLeaf() && "Tried to get a link from a leaf!\n");
pbpLower = GetLinkStart();
pbpUpper = pbpLower+(NumLinks() - 1);
// Use binary search
while(pbpLower < pbpUpper)
{
pbpIndex = pbpLower + ((pbpUpper - pbpLower)>>1);
bIndex = *(((TrieNode PASSBASED *) (*pbpIndex))->GetKey());
if(bComp < bIndex)
{
pbpUpper = pbpIndex - 1;
}
else
if(bComp > bIndex)
{
pbpLower = pbpIndex + 1;
}
else
{
// found it
pbpLink = pbpIndex;
return BP_TO_P(TrieNode *, (TrieNode PASSBASED *)(*pbpIndex));
}
}
if((pbpLower != pbpUpper) ||
(bComp != *(((TrieNode PASSBASED *) (*pbpLower))->GetKey())))
{
return NULL; // didn't find anything
}
pbpLink = pbpLower;
return BP_TO_P(TrieNode *, (TrieNode PASSBASED *) (*pbpLower));
}
//+-------------------------------------------------------------------------
//
// Function: TrieNode::AddLink (static)
//
// Synopsis: Adds a link to a node to the link array
//
// Arguments: [pBase] - pointer to the base of the block of memory the trie is in
// [pRoot] - pointer of node to add to
// pretty much an explicit "this" pointer so we can
// avoid a recursive step if we need to allocated more
// links (and therefore a new node)
// [pNode] - pointer of node to add
// [pbpNewNode]- handle to stick a new node in if we need to increase
// the number of links allocated to this node. If this is
// done, the original node will be deleted, so we need to
// change references to it.
// [alloc] - The allocator to use to allocate new memory
//
// Returns: S_OK if link was added without allocating more links,
// S_FALSE if more links were allocated, and there for *pbpNewNode is the
// pointer of the node that should be used to replace this one.
// Otherwise appropriate status code
//
//--------------------------------------------------------------------------
HRESULT CMapGuidToGuidBase::TrieNode::AddLink(void *pBase, TrieNode *pRoot, TrieNode *pNode,
TrieNodeBasedPtr UNALIGNED*pbpNewNode, CAllocFunctor &alloc)
{
Win4Assert(pNode != NULL && "Tried to add link to NULL TrieNode");
Win4Assert(!pRoot->IsLeaf() && "Tried to add link to leaf TrieNode"); // can't add links to leafs!
HRESULT retVal = S_OK;
int newLinks = NODE_LINKS;
if(pRoot->NumLinks() == NODE_LINKS) // Check to see if we need more links
{
newLinks += NODE_INIT_GROWBY; // we need to grow by NODE_INIT_GROWBY
}
else if (((pRoot->NumLinks()&NODE_GROWBY_MOD_MASK) == 0) && (pRoot->NumLinks() != 0))
{
// we need to grow by NODE_GROWBY
// this computes the size of the node
newLinks = pRoot->NumLinks()+NODE_GROWBY;
}
else
{
newLinks = 0; // we don't need to grow
}
if((newLinks != 0) && (newLinks <= 256)) // we don't grow over 256
{
TrieNode *pTemp;
// we have to allocate another TrieNode, we've used all our links
Win4Assert(pRoot->NumLinks() <= 255);
// Create new trienode with more links
pTemp = (TrieNode *) alloc.Alloc(GetNodeSize(pRoot->NumKeyBytes(), FALSE, newLinks));
if(pTemp == NULL)
{
return E_OUTOFMEMORY;
}
*pbpNewNode = (TrieNodeBasedPtr) P_TO_BP(TrieNode PASSBASED *, pTemp);
// Copy over current data
memcpy(pTemp, pRoot, GetNodeSize(pRoot->NumKeyBytes(), FALSE, pRoot->NumLinks()));
// we don't delete the current node
alloc.Free(pRoot, GetNodeSize(pRoot->NumKeyBytes(), FALSE, pRoot->NumLinks()));
pRoot = pTemp;
retVal = S_FALSE;
}
if(pRoot->NumLinks() == 0) // Now that that's taken care of, let's add the link
{
// just pluck it right in the beginning
*(pRoot->GetLinkStart()) = (TrieNodeBasedPtr) P_TO_BP(TrieNode PASSBASED *, pNode);
}
else
{
// Insert using binary insertion
// This gives us an array in sorted order
TrieNodeBasedPtr UNALIGNED *pbpLower;
TrieNodeBasedPtr UNALIGNED *pbpUpper;
TrieNodeBasedPtr UNALIGNED *pbpIndex;
BYTE bIndex;
pbpLower = pRoot->GetLinkStart();
pbpUpper = pbpLower + (pRoot->NumLinks() - 1);
while(pbpLower < pbpUpper)
{
pbpIndex = pbpLower + (pbpUpper - pbpLower)/2;
bIndex = *(((TrieNode PASSBASED *) (*pbpIndex))->GetKey());
if(*(pNode->GetKey()) < bIndex)
{
pbpUpper = pbpIndex - 1;
}
else
if(*(pNode->GetKey()) > bIndex)
{
pbpLower = pbpIndex + 1;
}
else
{
// we shouldn't have duplicates in the table
Win4Assert(0 && "Duplicate Entries in IID->CLSID table!\n");
}
}
TrieNodeBasedPtr UNALIGNED *pStart = pRoot->GetLinkStart();
int iNumLinks = pRoot->NumLinks();
if(*(((TrieNode PASSBASED *) (*pbpLower))->GetKey()) > *(pNode->GetKey()))
{
// insert before
InsertIntoLinkArray(pbpLower,
(TrieNodeBasedPtr) P_TO_BP(TrieNode PASSBASED *, pNode),
iNumLinks - (pbpLower - pStart));
}
else
{
// insert after
InsertIntoLinkArray(pbpLower+1,
(TrieNodeBasedPtr) P_TO_BP(TrieNode PASSBASED *, pNode),
iNumLinks - (pbpLower+ 1 - pStart));
}
}
// Keep track of how many links
pRoot->IncrementLinks();
return retVal;
}
//+-------------------------------------------------------------------------
//
// Function: TrieNode::CreateSuffixNode
//
// Synopsis: Creates a suffix node from the current node. A suffix node is
// the same node except with the bytes that are the same chopped off the beginning
// of the key
//
// Arguments: [bBytesDifferent] - the number of bytes which make up the suffix
// [alloc] - a memory allocator to use
//
// Returns: pointer to a TrieNode, which is the suffix node
//
//--------------------------------------------------------------------------
CMapGuidToGuidBase::TrieNode *CMapGuidToGuidBase::TrieNode::CreateSuffixNode(BYTE bBytesDifferent,
CAllocFunctor &alloc)
{
TrieNode *pNewNode;
if(IsLeaf())
{
// Create a Suffix leaf
pNewNode = (TrieNode *) alloc.Alloc(GetNodeSize(bBytesDifferent, TRUE, 0));
if(pNewNode == NULL)
{
return NULL;
}
pNewNode->SetLeaf(TRUE);
pNewNode->SetKeyBytes(bBytesDifferent);
pNewNode->SetLinks(0);
memcpy(pNewNode->GetKey(), GetKey()+(NumKeyBytes() - bBytesDifferent), bBytesDifferent);
*(pNewNode->GetData()) = *(GetData());
}
else
{
// Create a Suffix Node
pNewNode = (TrieNode *) alloc.Alloc(GetNodeSize(bBytesDifferent, FALSE, FindLinkSize(NumLinks())));
if(pNewNode == NULL)
{
return NULL;
}
pNewNode->SetKeyBytes(bBytesDifferent);
pNewNode->SetLeaf(FALSE);
pNewNode->SetLinks(NumLinks());
memcpy(pNewNode->GetKey(), GetKey()+(NumKeyBytes() - bBytesDifferent), bBytesDifferent);
memcpy(pNewNode->GetLinkStart(), GetLinkStart(), NumLinks()*sizeof(TrieNodeBasedPtr));
}
return pNewNode;
}
//+-------------------------------------------------------------------------
//
// Function: TrieNode::CreateTrieNode (static)
//
// Synopsis: creates a trie Node with the passed data
//
// Arguments: [pbKey] - a pointer to key data (goes forward)
// [bKeyBytes] - how many bytes are in the key
// [bLinks] - how many links to allocated (must be power of 2)
// [alloc] - a memory allocator to use
//
// Returns: a pointer to a TrieNode filled with the above data
//
//--------------------------------------------------------------------------
CMapGuidToGuidBase::TrieNode *CMapGuidToGuidBase::TrieNode::CreateTrieNode(const BYTE *pbKey,
BYTE bKeyBytes,
BYTE bLinks,
CAllocFunctor &alloc)
{
TrieNode *pNode;
// if pbKey == NULL, bKeyBytes must = 0
Win4Assert(pbKey != NULL || (bKeyBytes == 0));
Win4Assert(bKeyBytes >= 0);
pNode = (TrieNode *) alloc.Alloc(GetNodeSize(bKeyBytes, FALSE, bLinks));
if(pNode == NULL)
{
return NULL;
}
pNode->SetLeaf(FALSE);
pNode->SetKeyBytes(bKeyBytes);
pNode->SetLinks(0);
memcpy(pNode->GetKey(), pbKey, bKeyBytes);
return pNode;
}
//+-------------------------------------------------------------------------
//
// Function: TrieNode::CreateTrieLeaf (static)
//
// Synopsis: creates a Leaf node with the passed data
//
// Arguments: [pbKey] - a pointer to the key data (goes backwards)
// [bKeyBytes] - how many bytes are in the key
// [data] - a GUIDIndex this key maps to.
// [alloc] - a memory allocator to use
//
// Returns: a pointer to a TrieNode structure filled with above data
//
//--------------------------------------------------------------------------
CMapGuidToGuidBase::TrieNode *CMapGuidToGuidBase::TrieNode::CreateTrieLeaf(const BYTE *pbKey,
BYTE bKeyBytes,
GUIDIndex data,
CAllocFunctor &alloc)
{
Win4Assert(pbKey != NULL);
Win4Assert(bKeyBytes > 0);
TrieNode *pNode;
pNode = (TrieNode *) alloc.Alloc(GetNodeSize(bKeyBytes, TRUE, 0));
if(pNode == NULL)
{
return NULL;
}
pNode->SetLeaf(TRUE);
pNode->SetKeyBytes(bKeyBytes);
pNode->SetLinks(0);
bmemcpy(pNode->GetKey(), pbKey, bKeyBytes);
*(pNode->GetData()) = data;
return pNode;
}
//+-------------------------------------------------------------------------
//
// Function: TrieNode::AddKey (static)
//
// Synopsis: This function adds a key/GUIDBasedPtr pair to the passed trie.
//
// Arguments: [pBase] - the base of our shared memory block
// [pRoot] - the root node of the trie (explicit "this" pointer)
// [pbpPrev] - a handle to the previous reference to the root node,
// so that if AddLink requires us to update it, we can.
// [pbKey] - a pointer to the END of the key data, we add the key reversed!!!
// [data] - the GUIDIndex to map this key to
// [fReplace] - whether or not we should replace an existing entry
// [alloc] - a memory allocator to use
//
// Returns: S_OK if successful, S_FALSE if the key was already in the trie and fReplace == FALSE,
// appropriate error code otherwise
//
//--------------------------------------------------------------------------
HRESULT CMapGuidToGuidBase::TrieNode::AddKey(void *pBase, TrieNode *pRoot, TrieNodeBasedPtr UNALIGNED *pbpPrev,
const BYTE *pbKey, GUIDIndex data, BOOL fReplace,
CAllocFunctor &alloc)
{
Win4Assert(pRoot != NULL && "Tried to add key to NULL trie");
Win4Assert(pbpPrev != NULL && "Backlink to Trie NULL");
Win4Assert(pbKey != NULL && "Pointer to key data NULL");
int numDifferent, nNodeKeyBytes, nKeyBytes;
BYTE *pbNodeKey;
TrieNode *pNextLevel, *pNewNode, *pPrefixNode, *pSuffixNode;
TrieNodeBasedPtr UNALIGNED *pbpLinkPointer;
TrieNodeBasedPtr bpDummy;
nKeyBytes = GUID_BYTES; // Every Key is a full GUID
pbNodeKey = pRoot->GetKey();
nNodeKeyBytes = pRoot->NumKeyBytes();
// while both keys are the same, traverse the trie
while((numDifferent = bmemcmp(pbNodeKey, pbKey, nNodeKeyBytes)) == 0)
{
Win4Assert(nKeyBytes >= nNodeKeyBytes);
// Key prefix is the same
if(nKeyBytes == nNodeKeyBytes) // that means these keys are *exactly* the same!!!
{ // so we might have to replace the key/data mapping
if(pRoot->IsDeleted() || fReplace)
{
Win4Assert(pRoot->IsLeaf());
// the leaf node is deleted, or the replace flag is set, we can write over the data map
*(pRoot->GetData()) = data;
pRoot->SetDeleted(FALSE); // this doesn't hurt if the node wasn't deleted in the first place
return S_OK;
}
return S_FALSE; // else we don't do anything
}
pbKey-= nNodeKeyBytes; // Chop off this part of the key, continue down the trie
nKeyBytes -= nNodeKeyBytes;
pNextLevel = BP_TO_P(TrieNode *, (TrieNode PASSBASED *) pRoot->GetLink(pBase, *pbKey, pbpLinkPointer));
if(pNextLevel == NULL) // no next level, create new leaf here
{
HRESULT hr;
pNewNode = CreateTrieLeaf(pbKey, nKeyBytes, data, alloc);
if(pNewNode == NULL)
{
return E_OUTOFMEMORY;
}
hr = AddLink(pBase, pRoot, pNewNode, &bpDummy, alloc);
if(FAILED(hr))
{
return hr;
}
if(hr == S_FALSE)
{
// had to allocate a new node (ran out of links), reattatch to previous link
*pbpPrev = bpDummy;
}
return S_OK;
}
pRoot = pNextLevel;
pbpPrev = pbpLinkPointer;
pbNodeKey = pRoot->GetKey();
nNodeKeyBytes = pRoot->NumKeyBytes();
}
// we have to split the tree up
Win4Assert(*pbNodeKey == *pbKey && "Took wrong path in Trie"); // if this isn't true, something's really screwed up
// We create three nodes : a prefix node, containing the part of the key similar both to the existing
// GUIDs in the trie and the new GUID we are adding
// a new node, containing the part of the new GUID that's DIFFERENT from the rest
// a suffix node, containg the part of the old GUID subtrie that's different from the new GUID
pSuffixNode = pRoot->CreateSuffixNode(numDifferent, alloc);
if(pSuffixNode == NULL)
{
return E_OUTOFMEMORY;
}
pNewNode = CreateTrieLeaf(pbKey-(nNodeKeyBytes - numDifferent), nKeyBytes - (nNodeKeyBytes - numDifferent),
data, alloc);
if(pNewNode == NULL)
{
return E_OUTOFMEMORY;
}
pPrefixNode = CreateTrieNode(pbNodeKey, (nNodeKeyBytes - numDifferent), NODE_LINKS, alloc);
if(pPrefixNode == NULL)
{
return E_OUTOFMEMORY;
}
// Delete original node
alloc.Free(pRoot, GetNodeSize(pRoot->NumKeyBytes(), pRoot->IsLeaf(), FindLinkSize(pRoot->NumLinks())));
*pbpPrev = (TrieNodeBasedPtr) P_TO_BP(TrieNode PASSBASED *, pPrefixNode);
// This is the assumption we make, that each new node has at least 2 links pre-allocated
Win4Assert(NODE_LINKS >= 2);
// We add the link here without calling AddLink because we know that our newly created node
// has no existing links, and we can just stick the two in order
if(*(pSuffixNode->GetKey()) < *(pNewNode->GetKey()))
{
// suffix node goes before new node
*(pPrefixNode->GetLinkStart()) = (TrieNodeBasedPtr) P_TO_BP(TrieNode PASSBASED *, pSuffixNode);
pPrefixNode->IncrementLinks();
*(pPrefixNode->GetLinkStart()+1) = (TrieNodeBasedPtr) P_TO_BP(TrieNode PASSBASED *, pNewNode);
pPrefixNode->IncrementLinks();
}
else
{
// new node goes before suffix node
*(pPrefixNode->GetLinkStart()+1) = (TrieNodeBasedPtr) P_TO_BP(TrieNode PASSBASED *, pNewNode);
pPrefixNode->IncrementLinks();
*(pPrefixNode->GetLinkStart()) = (TrieNodeBasedPtr) P_TO_BP(TrieNode PASSBASED *, pSuffixNode);
pPrefixNode->IncrementLinks();
}
return TRUE;
}
//+-------------------------------------------------------------------------
//
// Function: TrieNode::RemoveKey (static)
//
// Synopsis: Given a key and a trie, removes the key from the trie
//
//
// Arguments: [pRoot] - the trie (explicit "this" pointer)
// [ppPrev] - a handle to the previous reference to the root node,
// so that if we need to update it, we can.
// [pbKey] - the key
//
// Returns: TRUE if we succeeded
// FALSE if we failed to find the key
//--------------------------------------------------------------------------
/*BOOL CMapGuidToGuidBase::TrieNode::RemoveKey(void *pBase, TrieNode *pRoot, const BYTE *pbKey)
{
int nKeyBytes = GUID_BYTES;
TrieNodeBasedPtr *ppDummy;
Win4Assert(pRoot != NULL);
Win4Assert(pbKey != NULL);
while(pRoot != NULL)
{
if(bmemcmp(pRoot->GetKey(), pbKey, pRoot->NumKeyBytes()))
{
return FALSE; // if the prefix of this node ain't the same as the prefix of the key
// then the key is not in the table
}
pbKey -= pRoot->NumKeyBytes();
nKeyBytes -= pRoot->NumKeyBytes();
Win4Assert(nKeyBytes >= 0);
if(nKeyBytes == 0) // then this should be a leaf node
{
Win4Assert(pRoot->IsLeaf());
if(!pRoot->IsDeleted())
{
pRoot->SetDeleted(TRUE); // set the flag on the node to deleted
return TRUE;
}
return FALSE; // node is already deleted
}
pRoot = pRoot->GetLink(pBase, *pbKey, ppDummy);
}
return FALSE;
}
*/
//+-------------------------------------------------------------------------
//
// Function: TrieNode::TraverseKey (static)
//
// Synopsis: Given a key, a trie, and a place to store data, find the data mapped to the key
//
// Arguments: [pBase] - the base pointer of our memory block
// [pRoot] - the trie to traverse (explicit "this" pointer)
// [pbKey] - a pointer to the key data
// [data] - a GUIDIndex ref to stick the data in if we succeed
//
// Returns: TRUE if we succeeded, then dwData has the GUIDIndex mapped to the passed key
// FALSE if we failed to find the key
//--------------------------------------------------------------------------
BOOL CMapGuidToGuidBase::TrieNode::TraverseKey(void *pBase, TrieNode *pRoot, const BYTE *pbKey,
GUIDIndex &data)
{
Win4Assert(pRoot != NULL && "Tried to traverse a NULL Trie");
Win4Assert(pbKey != NULL && "Pointer to key data is NULL");
int bKeyBytes = GUID_BYTES;
TrieNodeBasedPtr UNALIGNED *pbpDummy;
while(pRoot != NULL)
{
if(bmemcmp(pRoot->GetKey(), pbKey, pRoot->NumKeyBytes()))
{
return FALSE; // if the prefix of this node ain't the same as the prefix of the key
// then the key is not in the table
}
pbKey -= pRoot->NumKeyBytes();
bKeyBytes -= pRoot->NumKeyBytes();
Win4Assert(bKeyBytes >= 0 && "Too many key bytes in this Trie path");
if(bKeyBytes == 0) // then this should be a leaf node
{
Win4Assert(pRoot->IsLeaf() && "Ran out of key bytes before got to leaf");
if(pRoot->IsDeleted()) // is this node deleted
{
return FALSE; // if so, this map is not valid
}
data = *(pRoot->GetData());
return TRUE;
}
pRoot = pRoot->GetLink(pBase, *pbKey, pbpDummy);
}
return FALSE;
}
//+-------------------------------------------------------------------------
//
// Function: TrieNode::CopyToSharedMem
//
// Synopsis: Copy a given trie from one memory block to another
//
// Arguments: [pNewBase] - the base of the destination memory block
// [pOldBase] - the base of the source memory block
// [pRoot] - the trie to copy
// [alloc] - the allocation functor to use to allocate memory
//
// Returns: a based pointer (off of pNewBase) to the newly copied trie
// NULL if we failed to copy the trie
//--------------------------------------------------------------------------
TrieNodeBasedPtr CMapGuidToGuidBase::TrieNode::CopyToSharedMem(void *pNewBase, void *pOldBase, TrieNode *pRoot,
CAllocFunctor &alloc)
{
// we use recursion here because it is more complex than simple tail recursion
// and a non-recursive implementation would be very confusing
// considering that there is a recursive depth of at most 16, this means this function
// could take a maximum of 7*4*16=448 bytes on the stack
TrieNode *pCopy;
Win4Assert(pRoot != NULL && "Tried to copy a NULL Trie to shared memory");
if(pRoot->IsLeaf())
{
// allocate shared memory
pCopy = (TrieNode *) alloc.Alloc(GetNodeSize(pRoot->NumKeyBytes(), TRUE, 0));
if(pCopy == NULL)
{
return (TrieNodeBasedPtr) BP_TO_P(TrieNode NEWBASED *, NULL);
}
// copy over data
memcpy(pCopy, pRoot, GetNodeSize(pRoot->NumKeyBytes(), TRUE, 0));
return (TrieNodeBasedPtr) P_TO_BP(TrieNode NEWBASED *, pCopy);
}
else
{
// allocate shared memory
pCopy = (TrieNode *) alloc.Alloc(GetNodeSize(pRoot->NumKeyBytes(), FALSE,
FindLinkSize(pRoot->NumLinks())));
if(pCopy == NULL)
{
return (TrieNodeBasedPtr) BP_TO_P(TrieNode NEWBASED *, NULL);
}
// copy over data
memcpy(pCopy, pRoot, sizeof(WORD)+pRoot->NumKeyBytes());
// recursively set links
for(int i = 0; i < pRoot->NumLinks(); i++)
{
(pCopy->GetLinkStart())[i] = CopyToSharedMem(pNewBase, pOldBase, BP_TO_P(TrieNode *,
(TrieNode OLDBASED *)(pRoot->GetLinkStart()[i])),
alloc);
if(BP_TO_P(TrieNode *, (TrieNode NEWBASED *) (pCopy->GetLinkStart())[i]) == NULL)
{
return (TrieNodeBasedPtr) BP_TO_P(TrieNode NEWBASED *, NULL);
}
}
return (TrieNodeBasedPtr) P_TO_BP(TrieNode NEWBASED *, pCopy);
}
}
// *** CPSClsidTbl *** (DLL)
//+-------------------------------------------------------------------------
//
// Function: CPSClsidTbl::Initialize
//
// Synopsis: Initializes the client side of the guid->guid map
//
// Arguments: [pscMapName] - name of this stack, used to create a shared stack
//
// Returns: appropriate status code
//
//--------------------------------------------------------------------------
HRESULT CPSClsidTbl::Initialize(void *pBase)
{
HRESULT hr;
CairoleDebugOut((DEB_ITRACE, "CPSClsidTbl::Initialize(pBase = %p)\n", pBase));
hr = CMapGuidToGuidBase::Initialize(pBase);
if(SUCCEEDED(hr))
{
// Get a pointer to our shared memory header
m_pHeader = (SharedMemHeader *) m_pMemBase;
}
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: CPSClsidTbl::Find
//
// Synopsis: Given a GUID key, looks for the data mapped to it
//
// Arguments: [refguid] - a C++ reference to a GUID structure
// [pGuidOut] - a GUID * to store the data in
//
// Returns: a pointer to the data (really pGuidOut)
// NULL if guid was not found
//
//--------------------------------------------------------------------------
HRESULT CPSClsidTbl::Find(REFGUID srcguid, GUID *pGuidOut) const
{
GUIDIndex iGuid;
HRESULT hr;
SETUP_BASE_POINTER();
if(IsFull()) // initialize hr to error value
{
hr = E_OUTOFMEMORY;
}
else
{
hr = REGDB_E_IIDNOTREG;
}
if(TrieNode::TraverseKey(m_pMemBase, BP_TO_P(TrieNode *, (TrieNode PASSBASED *)m_pHeader->m_bpTrie),
((const BYTE *)&srcguid)+GUID_BYTES-1, iGuid))
{
if(m_pHeader->m_GUIDs.GetGuid(m_pMemBase, iGuid, *pGuidOut))
{
hr = S_OK; // set hr to OK
}
else
{
CairoleDebugOut((DEB_IWARN, "CPSClsidTbl: Found GUID %I in table, but couldn't find CLSID at %d\n",
srcguid, iGuid));
}
}
else
{
CairoleDebugOut((DEB_IWARN, "CPSClsidTbl: Couldn't find GUID - %I\n", &srcguid));
}
return hr;
}
// *** CScmPSClsidTbl *** (SCM)
//+-------------------------------------------------------------------------
//
// Function: CScmPSClsidTbl::Initialize
//
// Synopsis: Initializes the server side of the guid->guid map
//
// Arguments: [pscMapName] - name of this stack, used to create a shared stack
//
// Returns: appropriate status code
//
//--------------------------------------------------------------------------
HRESULT CScmPSClsidTbl::Initialize()
{
HRESULT hr;
CairoleDebugOut((DEB_ITRACE, "CScmPSClsidTbl::Initialize()\n"));
hr = CMapGuidToGuidBase::Initialize(NULL);
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: CScmPSClsidTbl::AddLocal
//
// Synopsis: Adds a key/data (GUID/GUIDBasedPtr) pair to internal dictionary
//
// Arguments: [guid] - a C++ reference to a GUID structure
// [dataGuid] - a GUID to map the GUID to
// [fReplace] - if TRUE, if the guid is already a key
// replace what it is mapped to with dataGuid
//
// Returns: TRUE if key/data pair was added to the dictionary
// FALSE if key was already in dictionary
//
//--------------------------------------------------------------------------
HRESULT CScmPSClsidTbl::AddLocal(REFGUID keyGuid, REFGUID dataGuid, BOOL fReplace)
{
GUIDIndex iGuid;
CHeapAlloc heap(m_hHeap); // create allocation functor
void *pBase = NULL; // the base of our locally-created table
// we use this so we can support adding GUIDs to the table later, when it is in shared memory
CairoleDebugOut((DEB_ITRACE, "CScmPSClsidTbl::AddLocal called with keyGuid = %I, dataGuid = %I, fReplace =%d.\n"
, &keyGuid, &dataGuid, (DWORD) fReplace));
// Add guid to array of GUIDs
iGuid = m_pLocalHeader->m_GUIDs.AddGuid(pBase, dataGuid, heap);
if(iGuid == INVALID_GUID_INDEX)
{
m_pLocalHeader->m_fFull = TRUE; // we are out of memory
return E_OUTOFMEMORY;
}
return TrieNode::AddKey(pBase, BP_TO_P(TrieNode *, (TrieNode PASSBASED *) m_pLocalHeader->m_bpTrie),
&m_pLocalHeader->m_bpTrie, ((const BYTE *)&keyGuid)+GUID_BYTES - 1,
iGuid, fReplace, heap);
}
//+-------------------------------------------------------------------------
//
// Function: CScmPSClsidTbl::Delete
//
// Synopsis: Given a GUID key, removes it from the trie
//
// Arguments: [guid] - a C++ reference to a GUID structure
//
// Returns: TRUE if key/data pair was found and deleted
// FALSE if key was not found
//
//--------------------------------------------------------------------------
/*BOOL CScmPSClsidTbl::Delete(REFGUID srcguid)
{
TrieNode *pRoot;
BYTE index;
SETUP_BASE_POINTER();
index = *(((const BYTE *)&srcguid)+GUID_BYTES - 1);
pRoot = BP_TO_P(TrieNode *, (TrieNode PASSBASED *) m_pHeader->m_pTries[index]);
if(pRoot == NULL)
{
return FALSE;
}
return TrieNode::RemoveKey(m_pMemBase, pRoot, ((const BYTE *)&srcguid)+GUID_BYTES-1);
}
*/
//+-------------------------------------------------------------------------
//
// Member: CScmPSClsidTbl::CopytoSharedMem
//
// Synopsis: Copies a locally created GUID->GUID map into shared memory
//
// Arguments: [pBase] - base pointer of shared memory
// [alloc] - stack-based allocator of shared memory
//
// Returns: appropriate status code
//
//--------------------------------------------------------------------------
HRESULT CScmPSClsidTbl::CopyToSharedMem(void *pBase, CSmStackAllocator &alloc)
{
HRESULT hr = S_OK;
Win4Assert(m_hHeap != NULL);
CStackAlloc stack(alloc);
void *pOldBase = NULL;
// Allocate our shared memory header
m_pHeader = (SharedMemHeader *) alloc.Alloc(sizeof(SharedMemHeader));
if(m_pHeader == NULL)
{
return E_OUTOFMEMORY;
}
m_pMemBase = pBase;
m_pHeader->m_fFull = m_pLocalHeader->m_fFull;
// first copy over guids
hr = m_pLocalHeader->m_GUIDs.CopyToSharedMem(m_pMemBase, pOldBase, &(m_pHeader->m_GUIDs), stack);
if(SUCCEEDED(hr))
{
// now copy over our trie
if( BP_TO_P(TrieNode *, (TrieNode OLDBASED *) m_pLocalHeader->m_bpTrie) != NULL)
{
m_pHeader->m_bpTrie = TrieNode::CopyToSharedMem(m_pMemBase, pOldBase,
BP_TO_P(TrieNode *, (TrieNode OLDBASED *) m_pLocalHeader->m_bpTrie), stack);
if(BP_TO_P(TrieNode *, (TrieNode PASSBASED *) m_pHeader->m_bpTrie) == NULL)
{
m_pHeader->m_fFull = TRUE;
hr = E_OUTOFMEMORY;
}
}
else
{
m_pHeader->m_fFull = TRUE;
hr = E_OUTOFMEMORY;
}
}
// we are done
return hr;
}
//+-------------------------------------------------------------------------
//
// Member: CScmPSClsidTbl::InitTbl
//
// Synopsis: intializes the table
//
// Arguments: none
//
// Returns : appropriate status code
//
//--------------------------------------------------------------------------
HRESULT CScmPSClsidTbl::InitTbl()
{
HKEY hKey;
FILETIME ftLastWrite;
WCHAR awName[MAX_PATH], awcsPSClsid[80];
WCHAR *pwcEndOfName;
GUID guidIID, guidCLSID;
DWORD cName = sizeof(awName);
DWORD iSubKey = 0;
LONG cbPSClsid = sizeof(awcsPSClsid);
void *pOldBase = NULL;
// Create a local heap to build the trie in
m_hHeap = HeapCreate(0, MAP_INITIAL_SIZE, MAP_MAX_SIZE);
if(m_hHeap == NULL)
{
return E_OUTOFMEMORY;
}
// allocate our local header
m_pLocalHeader = (LocalMemHeader *) HeapAlloc(m_hHeap, 0, sizeof(LocalMemHeader));
if(m_pLocalHeader == NULL)
{
return E_OUTOFMEMORY;
}
m_pLocalHeader->m_fFull = FALSE;
m_pLocalHeader->m_GUIDs.Initialize();
TrieNode *pNode = TrieNode::CreateTrieNode(NULL, 0, NODE_LINKS, CHeapAlloc(m_hHeap));
m_pLocalHeader->m_bpTrie = (TrieNodeBasedPtr) P_TO_BP(TrieNode OLDBASED *, pNode);
if(BP_TO_P(TrieNode *, (TrieNode OLDBASED *) m_pLocalHeader->m_bpTrie) == NULL)
{
return E_OUTOFMEMORY;
}
// enumerate the interface keys in the registry and create a table
// entry for each interface that has a ProxyStubClsid32 entry.
#ifdef _CHICAGO_
if (RegOpenKeyExA(HKEY_CLASSES_ROOT, tszInterface, NULL, KEY_READ, &hKey)
== ERROR_SUCCESS)
#else //_CHICAGO_
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, tszInterface, NULL, KEY_READ, &hKey)
== ERROR_SUCCESS)
#endif //_CHICAGO_
{
while (RegEnumKeyEx(hKey, iSubKey, awName, &cName,
NULL, NULL, NULL, &ftLastWrite) == ERROR_SUCCESS)
{
// Get data from registry for this interface
// This variable is used below to overwrite the ProxyStubClsid32
pwcEndOfName = awName + lstrlenW(awName);
lstrcatW(awName, wszProxyStubClsid);
if (RegQueryValue(hKey, awName, awcsPSClsid, &cbPSClsid)
== ERROR_SUCCESS)
{
// Convert registry string formats to GUID formats
*pwcEndOfName = 0;
if (GUIDFromString(awName, &guidIID))
{
if (GUIDFromString(awcsPSClsid, &guidCLSID))
{
if (FAILED(AddLocal(guidIID, guidCLSID, TRUE)))
{
// we ran out of space in the cache table, exit
// now to avoid doing anymore work
break;
}
}
}
}
else
{
//
// There wasn't a ProxyStubClsid32 for this interface.
// Because many applications install with interfaces
// that are variations on IDispatch, we are going to check
// to see if there is a ProxyStubClsid. If there is, and its
// class is that of IDispatch, then the OLE Automation DLL is
// the correct one to use. In that particular case, we will
// pretend that ProxyStubClsid32 existed, and that it is
// for IDispatch.
//
// Copy over ProxyStubClsid
lstrcpyW(pwcEndOfName,wszProxyStubClsid16);
if (RegQueryValue(hKey, awName, awcsPSClsid, &cbPSClsid)
== ERROR_SUCCESS)
{
// Convert registry string formats to GUID formats
if (GUIDFromString(awcsPSClsid, &guidCLSID))
{
//
// If the clsid for the proxy stub is that of
// IDispatch, then register it.
//
*pwcEndOfName = 0;
if (!memcmp(&guidCLSID,&CLSID_PSDispatch, sizeof(GUID)) &&
GUIDFromString(awName, &guidIID))
{
if (FAILED(AddLocal(guidIID, guidCLSID, TRUE)))
{
// we ran out of space in the cache table, exit
// now to avoid doing anymore work
break;
}
}
}
}
}
iSubKey++;
cName = sizeof(awName);
}
RegCloseKey(hKey);
}
return S_OK;
}