home *** CD-ROM | disk | FTP | other *** search
- ////
- //
- // CExpandoObject
- //
- // Notes:
- // 1) If the LCID passed to this object changes from call to call we are screwed. This is hard to
- // create an ASSERT for because it would require memoizing the LCID at some point.
- // 2) There is a maximum on the number of slots allowed (this is currently 2048)
- // 3) This is not a thread safe structure.
- // 4) I'm currently using malloc -- this is probably wrong for IE.
- //
-
- // for ASSERT and FAIL
- //
-
- #include "IPServer.H"
- #include "LocalSrv.H"
- #include "Globals.H"
- #include "extobj.h"
- #include "Util.H"
- #define GTR_MALLOC(size) CoTaskMemAlloc(size)
- #define GTR_FREE(pv) CoTaskMemFree(pv)
-
- SZTHISFILE
- ////
- //
- // Private Utility Functions
- //
- ////
-
- ////
- //
- // Get the ID of a Name
- //
-
- HRESULT CExpandoObject::GetIDOfName(LPOLESTR name, LCID lcid, BOOL caseSensitive, DISPID* id)
- {
- HRESULT hr = NOERROR;
- ULONG hash = LHashValOfName(lcid, name);
- UINT hashIndex = hash % kSlotHashTableSize;
- CExpandoObjectSlot* slot;
-
- for (slot=GetHashTableHead(hashIndex); slot!=NULL; slot=slot->Next(m_slots))
- {
- if (slot->CompareName(name, hash, caseSensitive))
- {
- *id = slot->DispId();
- goto Exit;
- }
- }
-
- // not found
- hr = DISP_E_UNKNOWNNAME;
- *id = DISPID_UNKNOWN;
-
- Exit:
- return hr;
- }
-
- ////
- //
- // Add a new slot to the object
- //
-
- HRESULT CExpandoObject::AddSlot(LPOLESTR name, LCID lcid, BOOL caseSensitive, VARIANT* initialValue, DISPID* id)
- {
- HRESULT hr = NOERROR;
- ULONG hash = LHashValOfName(lcid, name);
- UINT hashIndex = hash % kSlotHashTableSize;
- CExpandoObjectSlot* slot;
- DISPID dispId;
-
- // first check if the slot exists
- for (slot=GetHashTableHead(hashIndex); slot!=NULL; slot=slot->Next(m_slots))
- {
- // bail if the name matches
- if (slot->CompareName(name, hash, caseSensitive))
- {
- hr = E_INVALIDARG;
- goto Exit;
- }
- }
-
- // allocate a slot
- dispId = (DISPID) m_totalSlots;
- slot = AllocSlot();
- if (slot == NULL)
- {
- hr = E_OUTOFMEMORY;
- goto Exit;
- }
-
- // Initialize it
- // BUGBUG robwell 8May96 If this fails and the initialValue is not VT_EMTPY or VT_NULL
- // there in no cleanup code.
- hr = slot->Init(name, lcid, dispId + m_dispIdBase, initialValue);
- if (FAILED(hr))
- {
- // free the slot and dispId
- m_totalSlots -= 1;
- goto Exit;
- }
-
- // intern the slot into the proper hash table
- slot->Insert(m_slots, m_hashTable[hashIndex]);
-
- // set the DISPID return value
- *id = slot->DispId();
-
- Exit:
- return hr;
- }
-
- ////
- //
- // Slot allocation
- //
- // Because slots are never freed there is no free method
- //
-
- CExpandoObjectSlot* CExpandoObject::AllocSlot()
- {
- // limit on the number of slots
- if (m_totalSlots >= kMaxTotalSlots)
- return NULL;
-
- // do we need to realloc the array?
- if (m_totalSlots == m_slotTableSize)
- {
- UINT i;
- UINT newSize;
- CExpandoObjectSlot* newSlots;
-
- // allocate twice as many slots unless first time around
- if (m_slotTableSize == 0)
- newSize = kInitialSlotTableSize;
- else
- newSize = m_slotTableSize * 2;
-
- // allocate the space for the slots
- newSlots = (CExpandoObjectSlot*) GTR_MALLOC(sizeof(CExpandoObjectSlot)*newSize);
- if (newSlots == NULL)
- return NULL;
-
- // copy the old values if the old m_slots is not NULL
- if (m_slots)
- {
- // copy the slots
- memcpy(newSlots, m_slots, sizeof(CExpandoObjectSlot)*m_totalSlots);
- // free the old values
- GTR_FREE(m_slots);
- }
-
- // construct all of the unused slots
- for (i=m_totalSlots; i<newSize; ++i)
- newSlots[i].Construct();
-
- // make the new array the new table and fix the total size
- m_slots = newSlots;
- m_slotTableSize = newSize;
- }
-
- // return a pointer to the slot and bump the totalSlots count
- return &m_slots[m_totalSlots++];
- }
-
- ////
- //
- // Free all of the slots
- //
-
- void CExpandoObject::FreeAllSlots()
- {
- UINT i;
- UINT initedSlotCount;
- CExpandoObjectSlot* slots;
-
- // first clear the hash table
- ClearHashTable();
-
- // detach the slots
- slots = m_slots;
- initedSlotCount = m_totalSlots;
-
- // clear the object info
- m_totalSlots = 0;
- m_slotTableSize = 0;
- m_slots = NULL;
-
- // only need to destruct those slots in use
- for (i=0; i<initedSlotCount; ++i)
- slots[i].Destruct();
-
- // free the storage
- if (slots)
- GTR_FREE(slots);
- }
-
-
-
- ////
- //
- // IDispatch Methods
- //
- ////
-
- HRESULT CExpandoObject::GetTypeInfoCount(UINT *pctinfo)
- {
- *pctinfo = 0;
- return NOERROR;
- }
-
- HRESULT CExpandoObject::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo)
- {
- *pptinfo = NULL;
- return E_NOTIMPL;
- }
-
- HRESULT CExpandoObject::GetIDsOfNames(
- REFIID riid,
- LPOLESTR *prgpsz,
- UINT cpsz,
- LCID lcid,
- DISPID *prgdispid
- )
- {
- HRESULT hr;
-
- if (IID_NULL != riid)
- return DISP_E_UNKNOWNINTERFACE;
-
- // First see if the outer object knows about the name
- if (m_pdisp)
- {
- hr = m_pdisp->GetIDsOfNames(
- riid,
- prgpsz,
- cpsz,
- lcid,
- prgdispid);
-
- // if so, just return
- if (SUCCEEDED(hr))
- return hr;
- }
-
- // Otherwise look on our expanded properties
-
- if (cpsz == 0)
- return NOERROR;
-
- // get the ids for the name
- hr = GetIDOfName(prgpsz[0], lcid, FALSE, &prgdispid[0]);
-
- // clear the rest of the array
- for (unsigned int i = 1; i < cpsz; i++)
- {
- if (SUCCEEDED(hr))
- hr = DISP_E_UNKNOWNNAME;
- prgdispid[i] = DISPID_UNKNOWN;
- }
-
- return hr;
- }
-
- HRESULT CExpandoObject::Invoke(
- DISPID dispID,
- REFIID riid,
- LCID lcid,
- WORD wFlags,
- DISPPARAMS *pdispparams,
- VARIANT *pvarRes,
- EXCEPINFO *pexcepinfo,
- UINT *puArgErr
- )
- {
- if (IID_NULL != riid)
- return DISP_E_UNKNOWNINTERFACE;
-
- HRESULT hr;
-
- // First try the outer object's invoke
- if (m_pdisp)
- {
- hr = m_pdisp->Invoke(
- dispID,
- riid,
- lcid,
- wFlags,
- pdispparams,
- pvarRes,
- pexcepinfo,
- puArgErr
- );
-
- // If that succeeded, we're done
- if (SUCCEEDED(hr))
- return hr;
- }
-
- // Otherwise, try the expando object's invoke
- if (NULL != puArgErr)
- *puArgErr = 0;
-
- if (wFlags & DISPATCH_PROPERTYGET)
- {
- if (NULL == pvarRes)
- return NOERROR;
-
- if (NULL != pdispparams && 0 != pdispparams->cArgs)
- return E_INVALIDARG;
-
- // clear the result slot
- pvarRes->vt = VT_EMPTY;
- return GetSlot(dispID, pvarRes);
- }
-
- if (wFlags & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF))
- {
- if (NULL == pdispparams
- || 1 != pdispparams->cArgs
- || 1 != pdispparams->cNamedArgs
- || DISPID_PROPERTYPUT != pdispparams->rgdispidNamedArgs[0]
- )
- return DISP_E_PARAMNOTOPTIONAL;
-
- return SetSlot(dispID, &pdispparams->rgvarg[0]);
- }
-
- return DISP_E_MEMBERNOTFOUND;
- }
-
- ////
- //
- // IDispatchEx methods
- //
- ////
-
- // Get dispID for names, with options
- HRESULT STDMETHODCALLTYPE CExpandoObject::GetIDsOfNamesEx(
- REFIID riid,
- LPOLESTR *prgpsz,
- UINT cpsz,
- LCID lcid,
- DISPID *prgid,
- DWORD grfdex
- )
- {
- HRESULT hr;
- BOOL caseSensitive = ((grfdex & fdexCaseSensitive) != 0);
-
-
- // First see if the outer object knows about the name
- if (m_pdisp)
- {
- hr = m_pdisp->GetIDsOfNames(
- riid,
- prgpsz,
- cpsz,
- lcid,
- prgid);
-
- // if so, just return
- if (SUCCEEDED(hr))
- return hr;
- }
-
-
- if (IID_NULL != riid)
- return DISP_E_UNKNOWNINTERFACE;
-
- if (cpsz == 0)
- return NOERROR;
-
- // check the array arguments
- if (prgpsz == NULL || prgid == NULL)
- return E_INVALIDARG;
-
- // get the id from the name
- hr = GetIDOfName(prgpsz[0], lcid, caseSensitive, &prgid[0]);
-
- // create the slot?
- if (hr == DISP_E_UNKNOWNNAME && (grfdex & fdexDontCreate) == 0)
- {
- VARIANT initialValue;
-
- if (grfdex & fdexInitNull)
- initialValue.vt = VT_NULL;
- else
- initialValue.vt = VT_EMPTY;
-
- hr = AddSlot(prgpsz[0], lcid, caseSensitive, &initialValue, &prgid[0]);
- }
-
- // clear the rest of the array
- for (unsigned int i = 1; i < cpsz; i++)
- {
- hr = DISP_E_UNKNOWNNAME;
- prgid[i] = DISPID_UNKNOWN;
- }
-
- return hr;
- }
-
- // Enumerate dispIDs and their associated "names".
- // Returns S_FALSE if the enumeration is done, NOERROR if it's not, an
- // error code if the call fails.
- HRESULT STDMETHODCALLTYPE CExpandoObject::GetNextDispID(
- DISPID id,
- DISPID *pid,
- BSTR *pbstrName
- )
- {
- HRESULT hr;
- CExpandoObjectSlot* slot;
-
- // check the outgoing parameters
- if (pid == NULL || pbstrName == NULL)
- return E_INVALIDARG;
-
- // set to the default failure case
- *pid = DISPID_UNKNOWN;
- *pbstrName = NULL;
-
- // get the next slot
- hr = Next(id, slot);
- if (hr == NOERROR)
- {
- BSTR name;
-
- // allocate the result string
- name = SysAllocString(slot->Name());
- if (name == NULL)
- return E_OUTOFMEMORY;
-
- // fill in the outgoing parameters
- *pid = slot->DispId();
- *pbstrName = name;
- }
-
- return hr;
- }
-
- // Copy all of the expando-object properties from obj
- CExpandoObject::CloneProperties(CExpandoObject& obj)
- {
- // BUGBUG PhilBo
- // The initialization code below is copied from the default constructor.
- // This should be factored out into a shared method.
-
- // Copy each of the properties from the original object
- HRESULT hr = S_OK;
- DISPID dispid = 0;
- BSTR bstrName = NULL;
-
- while (obj.GetNextDispID(dispid, &dispid, &bstrName) == S_OK)
- {
- // Get the value of the property from the original object
- VARIANT varResult;
- DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
- VariantInit(&varResult);
-
- hr = obj.Invoke(
- dispid,
- IID_NULL,
- LOCALE_SYSTEM_DEFAULT,
- DISPATCH_PROPERTYGET,
- &dispparamsNoArgs, &varResult, NULL, NULL);
-
- ASSERT(SUCCEEDED(hr), "");
- if (FAILED(hr))
- continue;
-
- // Set the property on the new object
- DISPID dispidNew = 0;
- hr = GetIDsOfNamesEx(IID_NULL, &bstrName, 1, LOCALE_SYSTEM_DEFAULT,
- &dispidNew, 0);
-
- ASSERT(SUCCEEDED(hr), "");
- if (FAILED(hr))
- continue;
-
- DISPPARAMS dispparams;
- dispparams.rgvarg[0] = varResult;
-
- DISPID rgdispid[] = {DISPID_PROPERTYPUT};
- dispparams.rgdispidNamedArgs = rgdispid;
- dispparams.cArgs = 1;
- dispparams.cNamedArgs = 1;
-
- hr = Invoke(
- dispidNew,
- IID_NULL,
- LOCALE_SYSTEM_DEFAULT,
- DISPATCH_PROPERTYPUT,
- &dispparams, NULL, NULL, NULL);
- }
-
- return hr;
- }
-