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

374 lines
10 KiB
C++

//+---------------------------------------------------------------------------//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1993 - 1993.
//
// File: guidmap.hxx
//
// Contents: IID to proxy/stub CLSID mapping cache
//
// Classes: CScmGuidMap - shared memory guid map
//
// Functions: none
//
// History: 07-Apr-94 Rickhi Created
//
// Notes: this class maintains an IID to CLSID mapping table
// in shared memory.
//
//----------------------------------------------------------------------------
// function prototypes
extern HANDLE CreateSharedFileMapping(TCHAR *pszName, ULONG ulSize, void *pvBase,
PSECURITY_DESCRIPTOR lpSecDes, void **ppv, BOOL *pfCreated);
extern HANDLE OpenSharedFileMapping(TCHAR *pszName, ULONG ulSize, void **ppv);
void CloseSharedFileMapping(HANDLE hMem, void *pv);
// name and size of shared memory region
#define IIDMAP_NAME L"PSClsidMapName"
#define IIDMAP_SIZE 4096
typedef struct tagDWORDPAIR
{
DWORD dw1; // IID
DWORD dw2; // CLSID
} DWORDPAIR;
typedef struct tagGUIDPAIR
{
GUID guid1; // IID
GUID guid2; // CLSID
} GUIDPAIR;
typedef struct tagGUIDMAP
{
ULONG ulCntShort; // number of entries in the short list
ULONG ulCntLong; // number of entries in the long list
ULONG ulCntShortOverFlow; // number of entries in short overflow
ULONG ulCntLongOverFlow; // number of entries in long overflow
DWORDPAIR DwordStart; // first entry in the list
} GUIDMAP;
// template for OLE201 style guids
const GUID guidOleTemplate =
{0x00000000,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
//+---------------------------------------------------------------------------
//
// class: CScmGuidMap
//
// synopsis: shared memory cache of IID to PSCLSID mappings
//
// Classes: CScmGuidMap
//
// History: 06-Apr-94 Rickhi Created
//
// Notes: this maintains a list of IID to CLSID mappings in shared mem.
// this list is used by ole32.dll when loading interface proxies
// and stubs, and we want to avoid random registry hits.
//
// the SCM creates the list and is the only one who can modify
// the shared memory. the clients are simply read only. the
// SCM updates it when the registry changes.
//
// for OLE20 style guids that change only in the first DWORD,
// we store only the first DWORD instead of the whole GUID,
// giving us 4-1 compression for the (currently) common case.
//
// the DWORD cache starts at the beginning of the shared mem
// and grows up, the GUID cache starts at the end of the shared
// mem and grows down, giving us the maximum capacity.
//
//----------------------------------------------------------------------------
class CScmGuidMap
{
public:
CScmGuidMap(BOOL fCreate);
~CScmGuidMap();
void Add(REFGUID rguid1, REFGUID rguid2, BOOL fReload);
GUID * Find(REFGUID rguid, GUID *pGuidOut);
BOOL IsFull();
private:
BOOL IsOleStyleGuid(REFGUID rguid1);
ULONG FreeSpace();
DWORDPAIR * SearchShortList(DWORD dwFind);
GUIDPAIR * SearchLongList(REFGUID rguid);
HANDLE _hMem;
GUIDMAP * _pGuidMap;
DWORDPAIR * _pShortList; // list of OLE style guids
GUIDPAIR * _pLongList; // list of non OLE style guids
};
//+-------------------------------------------------------------------------
//
// Member: CScmGuidMap::CScmGuidMap
//
// Synopsis: Creates or gets access to memory mapped file.
//
// Arguments: [fCreate] - TRUE = create file mapping, FALSE = open
//
// Algorithm: if fCreate it creates and intializes the shared file mapping,
// otherwise it opens it.
//
//--------------------------------------------------------------------------
inline CScmGuidMap::CScmGuidMap(BOOL fCreate) :
_pGuidMap(NULL),
_hMem(NULL)
{
if (!fCreate)
{
// ole32 client. just open the shared memory
_hMem = OpenSharedFileMapping(IIDMAP_NAME, IIDMAP_SIZE, (void **)&_pGuidMap);
}
else
{
// scm. create the file mapping
_hMem = CreateSharedFileMapping(IIDMAP_NAME, IIDMAP_SIZE, NULL, NULL,
(void **)&_pGuidMap, NULL);
if (_pGuidMap)
{
_pGuidMap->ulCntShort = 0;
_pGuidMap->ulCntLong = 0;
_pGuidMap->ulCntShortOverFlow = 0;
_pGuidMap->ulCntLongOverFlow = 0;
}
}
if (_pGuidMap)
{
_pShortList = &_pGuidMap->DwordStart;
_pLongList = (GUIDPAIR *) (((BYTE *)_pGuidMap) +
IIDMAP_SIZE - sizeof(GUIDPAIR));
}
}
//+-------------------------------------------------------------------------
//
// Member: CScmGuidMap::~CScmGuidMap
//
// Synopsis: unmaps file mapping and closes the handle
//
// Algorithm: calls CloseSharedFileMapping to unmap the view and close the
// file handle.
//
//--------------------------------------------------------------------------
inline CScmGuidMap::~CScmGuidMap()
{
CloseSharedFileMapping(_hMem, _pGuidMap);
}
//+-------------------------------------------------------------------------
//
// Member: CScmGuidMap::IsOleStyleGuid
//
// Synopsis: determines if the GUID is one of the OLE201 style guids
//
// Arguments: [rguid] - guid to check
//
// Returns: TRUE if OLE20 style guid, FALSE otherwise.
//
// Algorithm: If the last 3 dwords of the GUID match the ones uses by all
// OLE20 guids, then this returns TRUE, otherwise FALSE
//
//--------------------------------------------------------------------------
inline BOOL CScmGuidMap::IsOleStyleGuid(REFGUID rguid)
{
const DWORD *ptr = &rguid.Data1;
return (*(ptr+1) == 0x00000000 && // all ole sytle guids's have
*(ptr+2) == 0x000000C0 && // these common values
*(ptr+3) == 0x46000000);
}
//+-------------------------------------------------------------------------
//
// Member: CScmGuidMap::IsFull
//
// Synopsis: returns TRUE if there is no room in the table
//
// Algorithm: compares FreeSpace with the size of the largest entry we
// might need to make.
//
//--------------------------------------------------------------------------
inline BOOL CScmGuidMap::IsFull()
{
return ((FreeSpace() - sizeof(GUIDPAIR)) < 0);
}
//+-------------------------------------------------------------------------
//
// Member: CScmGuidMap::Add
//
// Synopsis: Adds a new entry to the table.
//
// Arguments: [rguid1] - the IID to add
// [rguid2] - the CLSID to map the IID to
// [fReload] - TRUE if reloading the cache due to registry
// changes.
//
// Algorithm: This is called only be the SCM, no one else has write access
// to the memory.
//
// If fReload is set, we scan the list to ensure there are no
// duplicates before adding the new one. Note that we NEVER
// REPLACE any existing guid, as doing so while the system is
// running will have unpredicatable results.
//
// If boths guids are OLE201 style guids, we only store the
// first DWORD of each guid in the short table.
//
// If either one is not an OLE201 style guid, we store the
// whole guids in the long table.
//
// Note: This function is inline because it is used in only one place
// (in SCM.EXE LoadIIDMap).
//
//--------------------------------------------------------------------------
inline void CScmGuidMap::Add(REFGUID rguid1, REFGUID rguid2, BOOL fReload)
{
Win4Assert(_pGuidMap &&
"CScmGuidMap should have already created shared memory!");
if (_pGuidMap)
{
if (fReload)
{
// if reloading, we must check for duplicates before
// placing this entry in the tables.
GUID guidDummy;
if (Find(rguid1, &guidDummy))
return;
}
if (IsOleStyleGuid(rguid1) && IsOleStyleGuid(rguid2))
{
// start by placing it at the end of the short table
if (FreeSpace() < sizeof(DWORDPAIR))
{
CairoleDebugOut((DEB_WARN,
"CScmGuidMap table is FULL. For efficiency, table size should be increased.\n"));
return;
}
DWORDPAIR *pInsertSlot = _pShortList + _pGuidMap->ulCntShort +
_pGuidMap->ulCntShortOverFlow;
#if DBG==1
WCHAR wszBuf[80];
StringFromIID2(rguid1, wszBuf, sizeof(wszBuf));
CairoleDebugOut((DEB_USER2, "PSClsidMap adding key: %ws\n", wszBuf));
#endif
if (!fReload)
{
// must ensure the initial list remains sorted, so go find
// the insertion slot.
DWORDPAIR *pPrev = pInsertSlot - 1;
while (pPrev >= _pShortList && pPrev->dw1 > rguid1.Data1)
{
// move the data from the previous slot to the current
// insert slot, and make the previous slot the current
// insert slot.
pInsertSlot->dw1 = pPrev->dw1;
pInsertSlot->dw2 = pPrev->dw2;
pInsertSlot--;
pPrev--;
}
}
// found the insertion slot, copy in the data
pInsertSlot->dw1 = rguid1.Data1;
pInsertSlot->dw2 = rguid2.Data1;
// only after we've copied the data do we inc the count.
// this is important to avoid races in the Reload case.
if (fReload)
_pGuidMap->ulCntShortOverFlow++;
else
_pGuidMap->ulCntShort++;
}
else
{
// put it in the long table
if (FreeSpace() < sizeof(GUIDPAIR))
{
CairoleDebugOut((DEB_WARN,
"CScmGuidMap table is FULL. For efficiency, table size should be increased.\n"));
return;
}
#if DBG==1
WCHAR wszBuf[80];
StringFromIID2(rguid1, wszBuf, sizeof(wszBuf));
CairoleDebugOut((DEB_USER2, "PSClsidMap adding key: %ws\n", wszBuf));
#endif
GUIDPAIR *pInsertSlot = _pLongList - _pGuidMap->ulCntLong;
if (!fReload)
{
// must ensure initial list remains sorted, so go find the
// insertion spot.
GUIDPAIR *pPrev = pInsertSlot + 1;
while (pPrev <= _pLongList &&
(memcmp(&pPrev->guid1, &rguid1, sizeof(GUID)) > 0))
{
// move both guids up in the table, and make the previous
// slot the current insert slot.
memcpy(&pInsertSlot->guid1, &pPrev->guid1, 2*sizeof(GUID));
pInsertSlot++;
pPrev++;
}
}
// found the insertion slot, so copy in the data
memcpy(&pInsertSlot->guid1, &rguid1, sizeof(GUID));
memcpy(&pInsertSlot->guid2, &rguid2, sizeof(GUID));
// only after we've copied the data do we inc the count.
// this is important to avoid races in the Reload case.
if (fReload)
_pGuidMap->ulCntLongOverFlow++;
else
_pGuidMap->ulCntLong++;
}
}
}
// global pointer to this map
extern CScmGuidMap *g_pPSClsidMap;