diff --git a/mozilla/embedding/browser/activex/src/control/ControlSite.cpp b/mozilla/embedding/browser/activex/src/control/ControlSite.cpp index b59d34345a5..443b8c81694 100644 --- a/mozilla/embedding/browser/activex/src/control/ControlSite.cpp +++ b/mozilla/embedding/browser/activex/src/control/ControlSite.cpp @@ -39,8 +39,9 @@ #include "StdAfx.h" -#include "ControlSite.h" +#include +#include "ControlSite.h" std::list CControlSite::m_cControlList; @@ -93,6 +94,34 @@ CControlSite::~CControlSite() // Helper method checks whether a class implements a particular category HRESULT CControlSite::ClassImplementsCategory(const CLSID &clsid, const CATID &catid) { + // Test if there is a CLSID entry. If there isn't then obviously + // the object doesn't exist and therefore doesn't implement any category. + // In this situation, the function returns REGDB_E_CLASSNOTREG. + + CRegKey key; + if (key.Open(HKEY_CLASSES_ROOT, _T("CLSID"), KEY_READ) != ERROR_SUCCESS) + { + // Must fail if we can't even open this! + return E_FAIL; + } + LPOLESTR szCLSID = NULL; + if (FAILED(StringFromCLSID(clsid, &szCLSID))) + { + return E_FAIL; + } + USES_CONVERSION; + CRegKey keyCLSID; + LONG lResult = keyCLSID.Open(key, W2CT(szCLSID), KEY_READ); + CoTaskMemFree(szCLSID); + if (lResult != ERROR_SUCCESS) + { + // Class doesn't exist + return REGDB_E_CLASSNOTREG; + } + keyCLSID.Close(); + + // CLSID exists, so try checking what categories it implements + CIPtr(ICatInformation) spCatInfo; HRESULT hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatInformation, (LPVOID*) &spCatInfo); if (spCatInfo == NULL) @@ -136,7 +165,8 @@ static const CATID CATID_SafeForScripting = // Create the specified control, optionally providing properties to initialise // it with and a name. -HRESULT CControlSite::Create(REFCLSID clsid, PropertyList &pl) +HRESULT CControlSite::Create(REFCLSID clsid, PropertyList &pl, + LPCWSTR szCodebase, IBindCtx *pBindContext) { NG_TRACE_METHOD(CControlSite::Create); @@ -144,20 +174,167 @@ HRESULT CControlSite::Create(REFCLSID clsid, PropertyList &pl) m_ParameterList = pl; // See if object is script safe - if (m_bSafeForScriptingObjectsOnly && - ClassImplementsCategory(clsid, CATID_SafeForScripting) != S_OK) + BOOL checkForObjectSafety = FALSE; + if (m_bSafeForScriptingObjectsOnly) { - return E_FAIL; + HRESULT hrClass = ClassImplementsCategory(clsid, CATID_SafeForScripting); + if (hrClass == REGDB_E_CLASSNOTREG && szCodebase) + { + // Class doesn't exist, so allow code below to fetch it + } + else if (FAILED(hrClass)) + { + // The class is not flagged as safe for scripting, so + // we'll have to create it to ask it if its safe. + checkForObjectSafety = TRUE; + } } // Create the object - HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IUnknown, (void **) &m_spObject); - if (FAILED(hr)) + CComPtr spObject; + HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IUnknown, (void **) &spObject); + if (SUCCEEDED(hr) && checkForObjectSafety) { - return E_FAIL; + // The control was created but it didn't check out as safe so + // it must be asked if its safe for scripting. + CComQIPtr spObjectSafety = spObject; + if (!spObjectSafety) + { + return E_FAIL; + } + DWORD dwSupported = 0; // Supported options (mask) + DWORD dwEnabled = 0; // Enabled options + + // Assume scripting via IDispatch + if (FAILED(spObjectSafety->GetInterfaceSafetyOptions( + __uuidof(IDispatch), &dwSupported, &dwEnabled))) + { + // Interface is not safe or failure. + return E_FAIL; + } + + // Test if safe for scripting + if (!(dwEnabled & dwSupported) & INTERFACESAFE_FOR_UNTRUSTED_CALLER) + { + return E_FAIL; + } + // Drop through, success! } - return S_OK; + // Do we need to download the control? + if (FAILED(hr) && szCodebase) + { + wchar_t *szURL = NULL; + + // Test if the code base ends in #version=a,b,c,d + DWORD dwFileVersionMS = 0xffffffff; + DWORD dwFileVersionLS = 0xffffffff; + wchar_t *szHash = wcsrchr(szCodebase, wchar_t('#')); + if (szHash) + { + if (wcsnicmp(szHash, L"#version=", 9) == 0) + { + int a, b, c, d; + if (swscanf(szHash + 9, L"%d,%d,%d,%d", &a, &b, &c, &d) == 4) + { + dwFileVersionMS = MAKELONG(b,a); + dwFileVersionLS = MAKELONG(d,c); + } + } + szURL = _wcsdup(szCodebase); + // Terminate at the hash mark + if (szURL) + szURL[szHash - szCodebase] = wchar_t('\0'); + } + else + { + szURL = _wcsdup(szCodebase); + } + if (!szURL) + return E_OUTOFMEMORY; + + CComPtr spBindContext; + CComPtr spBindStatusCallback; + CComPtr spOldBSC; + + // Create our own bind context or use the one provided? + BOOL useInternalBSC = FALSE; + if (!pBindContext) + { + useInternalBSC = TRUE; + hr = CreateBindCtx(0, &spBindContext); + if (FAILED(hr)) + { + free(szURL); + return hr; + } + spBindStatusCallback = dynamic_cast(this); + hr = RegisterBindStatusCallback(spBindContext, spBindStatusCallback, &spOldBSC, 0); + if (FAILED(hr)) + { + free(szURL); + return hr; + } + } + else + { + spBindContext = pBindContext; + } + + hr = CoGetClassObjectFromURL(clsid, szURL, dwFileVersionMS, dwFileVersionLS, + NULL, spBindContext, CLSCTX_ALL, NULL, IID_IUnknown, (void **) &m_spObject); + + free(szURL); + + // Handle the internal binding synchronously so the object exists + // or an error code is available when the method returns. + if (useInternalBSC) + { + if (MK_S_ASYNCHRONOUS == hr) + { + m_bBindingInProgress = TRUE; + m_hrBindResult = E_FAIL; + + // Spin around waiting for binding to complete + HANDLE hFakeEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); + while (m_bBindingInProgress) + { + MSG msg; + // Process pending messages + while (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) + { + if (!::GetMessage(&msg, NULL, 0, 0)) + { + m_bBindingInProgress = FALSE; + break; + } + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + if (!m_bBindingInProgress) + break; + // Sleep for a bit or the next msg to appear + ::MsgWaitForMultipleObjects(1, &hFakeEvent, FALSE, 500, QS_ALLEVENTS); + } + ::CloseHandle(hFakeEvent); + + // Set the result + hr = m_hrBindResult; + } + + // Destroy the bind status callback & context + if (spBindStatusCallback) + { + RevokeBindStatusCallback(spBindContext, spBindStatusCallback); + spBindContext.Release(); + } + } + } + + if (spObject) + m_spObject = spObject; + + return hr; } @@ -178,7 +355,6 @@ HRESULT CControlSite::Attach(HWND hwndParent, const RECT &rcPos, IUnknown *pInit // Object must have been created if (m_spObject == NULL) { - NG_ASSERT(0); return E_UNEXPECTED; } @@ -212,13 +388,14 @@ HRESULT CControlSite::Attach(HWND hwndParent, const RECT &rcPos, IUnknown *pInit // If there is a parameter list for the object and no init stream then // create one here. CPropertyBagInstance *pPropertyBag = NULL; - if (pInitStream == NULL && m_ParameterList.size() >= 1) + if (pInitStream == NULL && m_ParameterList.GetSize() > 0) { CPropertyBagInstance::CreateInstance(&pPropertyBag); pPropertyBag->AddRef(); - for (PropertyList::const_iterator i = m_ParameterList.begin(); i != m_ParameterList.end(); i++) + for (unsigned long i = 0; i < m_ParameterList.GetSize(); i++) { - pPropertyBag->Write((*i).szName, (VARIANT *) &(*i).vValue); + pPropertyBag->Write(m_ParameterList.GetNameOf(i), + const_cast(m_ParameterList.GetValueOf(i))); } pInitStream = (IPersistPropertyBag *) pPropertyBag; } @@ -584,7 +761,13 @@ HRESULT STDMETHODCALLTYPE CControlSite::GetMoniker(/* [in] */ DWORD dwAssign, /* HRESULT STDMETHODCALLTYPE CControlSite::GetContainer(/* [out] */ IOleContainer __RPC_FAR *__RPC_FAR *ppContainer) { - return E_NOINTERFACE; + if (!ppContainer) return E_INVALIDARG; + *ppContainer = m_spContainer; + if (*ppContainer) + { + (*ppContainer)->AddRef(); + } + return (*ppContainer) ? S_OK : E_NOINTERFACE; } @@ -1074,3 +1257,75 @@ HRESULT STDMETHODCALLTYPE CControlSite::ShowPropertyFrame(void) return E_NOTIMPL; } +/////////////////////////////////////////////////////////////////////////////// +// IBindStatusCallback implementation + +HRESULT STDMETHODCALLTYPE CControlSite::OnStartBinding(DWORD dwReserved, + IBinding __RPC_FAR *pib) +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CControlSite::GetPriority(LONG __RPC_FAR *pnPriority) +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CControlSite::OnLowResource(DWORD reserved) +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CControlSite::OnProgress(ULONG ulProgress, + ULONG ulProgressMax, + ULONG ulStatusCode, + LPCWSTR szStatusText) +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CControlSite::OnStopBinding(HRESULT hresult, LPCWSTR szError) +{ + m_bBindingInProgress = FALSE; + m_hrBindResult = hresult; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CControlSite::GetBindInfo(DWORD __RPC_FAR *pgrfBINDF, + BINDINFO __RPC_FAR *pbindInfo) +{ + *pgrfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | + BINDF_GETNEWESTVERSION | BINDF_NOWRITECACHE; + pbindInfo->cbSize = sizeof(BINDINFO); + pbindInfo->szExtraInfo = NULL; + memset(&pbindInfo->stgmedData, 0, sizeof(STGMEDIUM)); + pbindInfo->grfBindInfoF = 0; + pbindInfo->dwBindVerb = 0; + pbindInfo->szCustomVerb = NULL; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CControlSite::OnDataAvailable(DWORD grfBSCF, + DWORD dwSize, + FORMATETC __RPC_FAR *pformatetc, + STGMEDIUM __RPC_FAR *pstgmed) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CControlSite::OnObjectAvailable(REFIID riid, + IUnknown __RPC_FAR *punk) +{ + return S_OK; +} + +// IWindowForBindingUI +HRESULT STDMETHODCALLTYPE CControlSite::GetWindow( + /* [in] */ REFGUID rguidReason, + /* [out] */ HWND *phwnd) +{ + *phwnd = NULL; + return S_OK; +} + + diff --git a/mozilla/embedding/browser/activex/src/control/ControlSite.h b/mozilla/embedding/browser/activex/src/control/ControlSite.h index 2d133837040..d811dc6ad97 100644 --- a/mozilla/embedding/browser/activex/src/control/ControlSite.h +++ b/mozilla/embedding/browser/activex/src/control/ControlSite.h @@ -20,8 +20,8 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): - * Adam Lock * + * Adam Lock * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -57,7 +57,9 @@ COM_INTERFACE_ENTRY_IID(IID_IAdviseSink2, IAdviseSinkEx) \ COM_INTERFACE_ENTRY_IID(IID_IAdviseSinkEx, IAdviseSinkEx) \ COM_INTERFACE_ENTRY(IOleCommandTarget) \ - COM_INTERFACE_ENTRY(IServiceProvider) + COM_INTERFACE_ENTRY(IServiceProvider) \ + COM_INTERFACE_ENTRY(IBindStatusCallback) \ + COM_INTERFACE_ENTRY(IWindowForBindingUI) // // Class for hosting an ActiveX control @@ -89,7 +91,9 @@ class CControlSite : public CComObjectRootEx, public IAdviseSinkEx, public IDispatch, public IServiceProvider, - public IOleCommandTargetImpl + public IOleCommandTargetImpl, + public IBindStatusCallback, + public IWindowForBindingUI { public: // Site management values @@ -113,6 +117,10 @@ public: unsigned m_bWindowless:1; // Flag indicating if only safely scriptable controls are allowed unsigned m_bSafeForScriptingObjectsOnly:1; + // Pointer to an externally registered service provider + CComPtr m_spServiceProvider; + // Pointer to the OLE container + CComPtr m_spContainer; protected: // Pointers to object interfaces @@ -126,13 +134,17 @@ protected: CComQIPtr m_spIOleInPlaceObject; // Pointer to object's IOleInPlaceObjectWindowless interface CComQIPtr m_spIOleInPlaceObjectWindowless; - // Pointer to an externally registered service provider - CComPtr m_spServiceProvider; // CLSID of the control CLSID m_clsid; // Parameter list PropertyList m_ParameterList; +// Binding variables + // Flag indicating whether binding is in progress + unsigned m_bBindingInProgress; + // Result from the binding operation + HRESULT m_hrBindResult; + // Double buffer drawing variables used for windowless controls // Area of buffer RECT m_rcBuffer; @@ -195,7 +207,8 @@ END_OLECOMMAND_TABLE() // Object creation and management functions // Creates and initialises an object - virtual HRESULT Create(REFCLSID clsid, PropertyList &pl = PropertyList()); + virtual HRESULT Create(REFCLSID clsid, PropertyList &pl = PropertyList(), + LPCWSTR szCodebase = NULL, IBindCtx *pBindContext = NULL); // Attaches the object to the site virtual HRESULT Attach(HWND hwndParent, const RECT &rcPos, IUnknown *pInitStream = NULL); // Detaches the object from the site @@ -217,6 +230,10 @@ END_OLECOMMAND_TABLE() { m_spServiceProvider = pSP; } + virtual void SetContainer(IOleContainer *pContainer) + { + m_spContainer = pContainer; + } // Methods to set ambient properties virtual void SetAmbientUserMode(BOOL bUser); @@ -316,6 +333,19 @@ END_OLECOMMAND_TABLE() virtual HRESULT STDMETHODCALLTYPE TranslateAccelerator(/* [in] */ MSG __RPC_FAR *pMsg, /* [in] */ DWORD grfModifiers); virtual HRESULT STDMETHODCALLTYPE OnFocus(/* [in] */ BOOL fGotFocus); virtual HRESULT STDMETHODCALLTYPE ShowPropertyFrame( void); + +// IBindStatusCallback + virtual HRESULT STDMETHODCALLTYPE OnStartBinding(/* [in] */ DWORD dwReserved, /* [in] */ IBinding __RPC_FAR *pib); + virtual HRESULT STDMETHODCALLTYPE GetPriority(/* [out] */ LONG __RPC_FAR *pnPriority); + virtual HRESULT STDMETHODCALLTYPE OnLowResource(/* [in] */ DWORD reserved); + virtual HRESULT STDMETHODCALLTYPE OnProgress(/* [in] */ ULONG ulProgress, /* [in] */ ULONG ulProgressMax, /* [in] */ ULONG ulStatusCode, /* [in] */ LPCWSTR szStatusText); + virtual HRESULT STDMETHODCALLTYPE OnStopBinding(/* [in] */ HRESULT hresult, /* [unique][in] */ LPCWSTR szError); + virtual /* [local] */ HRESULT STDMETHODCALLTYPE GetBindInfo( /* [out] */ DWORD __RPC_FAR *grfBINDF, /* [unique][out][in] */ BINDINFO __RPC_FAR *pbindinfo); + virtual /* [local] */ HRESULT STDMETHODCALLTYPE OnDataAvailable(/* [in] */ DWORD grfBSCF, /* [in] */ DWORD dwSize, /* [in] */ FORMATETC __RPC_FAR *pformatetc, /* [in] */ STGMEDIUM __RPC_FAR *pstgmed); + virtual HRESULT STDMETHODCALLTYPE OnObjectAvailable(/* [in] */ REFIID riid, /* [iid_is][in] */ IUnknown __RPC_FAR *punk); + +// IWindowForBindingUI + virtual HRESULT STDMETHODCALLTYPE GetWindow(/* [in] */ REFGUID rguidReason, /* [out] */ HWND *phwnd); }; typedef CComObject CControlSiteInstance; diff --git a/mozilla/embedding/browser/activex/src/control/MozillaBrowser.cpp b/mozilla/embedding/browser/activex/src/control/MozillaBrowser.cpp index 3e6be679b24..182105900bc 100644 --- a/mozilla/embedding/browser/activex/src/control/MozillaBrowser.cpp +++ b/mozilla/embedding/browser/activex/src/control/MozillaBrowser.cpp @@ -20,6 +20,7 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): + * * Adam Lock * * Alternatively, the contents of this file may be used under the terms of @@ -2484,23 +2485,9 @@ HRESULT STDMETHODCALLTYPE CMozillaBrowser::PutProperty(BSTR szProperty, VARIANT { RETURN_E_INVALIDARG(); } - PropertyList::iterator i; - for (i = mPropertyList.begin(); i != mPropertyList.end(); i++) - { - // Is the property already in the list? - if (wcscmp((*i).szName, szProperty) == 0) - { - // Copy the new value - (*i).vValue = CComVariant(vtValue); - return S_OK; - } - } - Property p; - p.szName = CComBSTR(szProperty); - p.vValue = vtValue; + mPropertyList.AddOrReplaceNamedProperty(szProperty, vtValue); - mPropertyList.push_back(p); return S_OK; } @@ -2524,14 +2511,12 @@ HRESULT STDMETHODCALLTYPE CMozillaBrowser::GetProperty(BSTR Property, VARIANT __ } VariantInit(pvtValue); - PropertyList::iterator i; - for (i = mPropertyList.begin(); i != mPropertyList.end(); i++) + for (unsigned long i = 0; i < mPropertyList.GetSize(); i++) { - // Is the property already in the list? - if (wcscmp((*i).szName, Property) == 0) + if (wcsicmp(mPropertyList.GetNameOf(i), Property) == 0) { // Copy the new value - VariantCopy(pvtValue, &(*i).vValue); + VariantCopy(pvtValue, const_cast(mPropertyList.GetValueOf(i))); return S_OK; } } diff --git a/mozilla/embedding/browser/activex/src/control/PropertyBag.cpp b/mozilla/embedding/browser/activex/src/control/PropertyBag.cpp index 3ee2f8167a3..2f321c55a84 100644 --- a/mozilla/embedding/browser/activex/src/control/PropertyBag.cpp +++ b/mozilla/embedding/browser/activex/src/control/PropertyBag.cpp @@ -67,14 +67,12 @@ HRESULT STDMETHODCALLTYPE CPropertyBag::Read(/* [in] */ LPCOLESTR pszPropName, / } VariantInit(pVar); - PropertyList::iterator i; - for (i = m_PropertyList.begin(); i != m_PropertyList.end(); i++) + for (unsigned long i = 0; i < m_PropertyList.GetSize(); i++) { - // Is the property already in the list? - if (wcsicmp((*i).szName, pszPropName) == 0) + if (wcsicmp(m_PropertyList.GetNameOf(i), pszPropName) == 0) { // Copy the new value - VariantCopy(pVar, &(*i).vValue); + VariantCopy(pVar, const_cast(m_PropertyList.GetValueOf(i))); return S_OK; } } @@ -94,23 +92,9 @@ HRESULT STDMETHODCALLTYPE CPropertyBag::Write(/* [in] */ LPCOLESTR pszPropName, return E_INVALIDARG; } - PropertyList::iterator i; - for (i = m_PropertyList.begin(); i != m_PropertyList.end(); i++) - { - // Is the property already in the list? - if (wcsicmp((*i).szName, pszPropName) == 0) - { - // Copy the new value - (*i).vValue = CComVariant(*pVar); - return S_OK; - } - } + CComBSTR bstrName(pszPropName); + m_PropertyList.AddOrReplaceNamedProperty(bstrName, *pVar); - Property p; - p.szName = CComBSTR(pszPropName); - p.vValue = *pVar; - - m_PropertyList.push_back(p); return S_OK; } diff --git a/mozilla/embedding/browser/activex/src/control/PropertyList.h b/mozilla/embedding/browser/activex/src/control/PropertyList.h index ad350e634b1..4760d998b02 100644 --- a/mozilla/embedding/browser/activex/src/control/PropertyList.h +++ b/mozilla/embedding/browser/activex/src/control/PropertyList.h @@ -20,8 +20,8 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): - * Adam Lock * + * Adam Lock * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -39,28 +39,120 @@ #ifndef PROPERTYLIST_H #define PROPERTYLIST_H +// A simple array class for managing name/value pairs typically fed to controls +// during initialization by IPersistPropertyBag -// Property is a name,variant pair held by the browser. In IE, properties -// offer a primitive way for DHTML elements to talk back and forth with -// the host app. - -struct Property +class PropertyList { - CComBSTR szName; - CComVariant vValue; + struct Property { + BSTR bstrName; + VARIANT vValue; + } *mProperties; + unsigned long mListSize; + unsigned long mMaxListSize; + + bool EnsureMoreSpace() + { + // Ensure enough space exists to accomodate a new item + const unsigned long kGrowBy = 10; + if (!mProperties) + { + mProperties = (Property *) malloc(sizeof(Property) * kGrowBy); + if (!mProperties) + return false; + mMaxListSize = kGrowBy; + } + else if (mListSize == mMaxListSize) + { + Property *pNewProperties; + pNewProperties = (Property *) realloc(mProperties, sizeof(Property) * (mMaxListSize + kGrowBy)); + if (!pNewProperties) + return false; + mProperties = pNewProperties; + mMaxListSize += kGrowBy; + } + return true; + } + +public: + PropertyList() : + mProperties(NULL), + mListSize(0), + mMaxListSize(0) + { + } + ~PropertyList() + { + } + void Clear() + { + if (mProperties) + { + for (unsigned long i = 0; i < mListSize; i++) + { + SysFreeString(mProperties[i].bstrName); // Safe even if NULL + VariantClear(&mProperties[i].vValue); + } + free(mProperties); + mProperties = NULL; + } + mListSize = 0; + mMaxListSize = 0; + } + unsigned long GetSize() const + { + return mListSize; + } + const BSTR GetNameOf(unsigned long nIndex) const + { + if (nIndex > mListSize) + { + return NULL; + } + return mProperties[nIndex].bstrName; + } + const VARIANT *GetValueOf(unsigned long nIndex) const + { + if (nIndex > mListSize) + { + return NULL; + } + return &mProperties[nIndex].vValue; + } + bool AddOrReplaceNamedProperty(const BSTR bstrName, const VARIANT &vValue) + { + if (!bstrName) + return false; + for (unsigned long i = 0; i < GetSize(); i++) + { + // Case insensitive + if (wcsicmp(mProperties[i].bstrName, bstrName) == 0) + { + return SUCCEEDED( + VariantCopy(&mProperties[i].vValue, const_cast(&vValue))); + } + } + return AddNamedProperty(bstrName, vValue); + } + bool AddNamedProperty(const BSTR bstrName, const VARIANT &vValue) + { + if (!bstrName || !EnsureMoreSpace()) + return false; + Property *pProp = &mProperties[mListSize]; + pProp->bstrName = ::SysAllocString(bstrName); + if (!pProp->bstrName) + { + return false; + } + VariantInit(&pProp->vValue); + if (FAILED(VariantCopy(&pProp->vValue, const_cast(&vValue)))) + { + SysFreeString(pProp->bstrName); + return false; + } + mListSize++; + return true; + } }; -// A list of properties -typedef std::vector PropertyList; - - -// DEVNOTE: These operators are required since the unpatched VC++ 5.0 -// generates code even for unreferenced template methods in -// the file and will give compiler errors without -// them. Service Pack 1 and above fixes this problem - -int operator <(const Property&, const Property&); -int operator ==(const Property&, const Property&); - - #endif \ No newline at end of file