/* * ReactOS ATL * * Copyright 2009 Andrew Hill * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #pragma once #include "atlcore.h" #ifdef _MSC_VER // It is common to use this in ATL constructors. They only store this for later use, so the usage is safe. #pragma warning(disable:4355) #endif #ifndef _ATL_PACKING #define _ATL_PACKING 8 #endif #ifndef _ATL_FREE_THREADED #ifndef _ATL_APARTMENT_THREADED #ifndef _ATL_SINGLE_THREADED #define _ATL_FREE_THREADED #endif #endif #endif #ifndef ATLTRY #define ATLTRY(x) x; #endif #ifdef _ATL_DISABLE_NO_VTABLE #define ATL_NO_VTABLE #else #define ATL_NO_VTABLE __declspec(novtable) #endif namespace ATL { inline HRESULT AtlHresultFromLastError() throw() { DWORD dwError = ::GetLastError(); return HRESULT_FROM_WIN32(dwError); } template class _NoAddRefReleaseOnCComPtr : public T { private: virtual ULONG STDMETHODCALLTYPE AddRef() = 0; virtual ULONG STDMETHODCALLTYPE Release() = 0; }; // Begin code borrowed from Microsoft //CComPtrBase provides the basis for all other smart pointers //The other smartpointers add their own constructors and operators template class CComPtrBase { protected: CComPtrBase() throw() { p = NULL; } CComPtrBase(_Inout_opt_ T* lp) throw() { p = lp; if (p != NULL) p->AddRef(); } void Swap(CComPtrBase& other) { T* pTemp = p; p = other.p; other.p = pTemp; } public: typedef T _PtrClass; ~CComPtrBase() throw() { if (p) p->Release(); } operator T*() const throw() { return p; } T& operator*() const { ATLENSURE(p!=NULL); return *p; } //The assert on operator& usually indicates a bug. If this is really //what is needed, however, take the address of the p member explicitly. T** operator&() throw() { ATLASSERT(p==NULL); return &p; } _NoAddRefReleaseOnCComPtr* operator->() const throw() { ATLASSERT(p!=NULL); return (_NoAddRefReleaseOnCComPtr*)p; } bool operator!() const throw() { return (p == NULL); } bool operator<(_In_opt_ T* pT) const throw() { return p < pT; } bool operator!=(_In_opt_ T* pT) const { return !operator==(pT); } bool operator==(_In_opt_ T* pT) const throw() { return p == pT; } // Release the interface and set to NULL void Release() throw() { T* pTemp = p; if (pTemp) { p = NULL; pTemp->Release(); } } // Compare two objects for equivalence inline bool IsEqualObject(_Inout_opt_ IUnknown* pOther) throw(); // Attach to an existing interface (does not AddRef) void Attach(_In_opt_ T* p2) throw() { if (p) { ULONG ref = p->Release(); (ref); // Attaching to the same object only works if duplicate references are being coalesced. Otherwise // re-attaching will cause the pointer to be released and may cause a crash on a subsequent dereference. ATLASSERT(ref != 0 || p2 != p); } p = p2; } // Detach the interface (does not Release) T* Detach() throw() { T* pt = p; p = NULL; return pt; } _Check_return_ HRESULT CopyTo(_COM_Outptr_result_maybenull_ T** ppT) throw() { ATLASSERT(ppT != NULL); if (ppT == NULL) return E_POINTER; *ppT = p; if (p) p->AddRef(); return S_OK; } _Check_return_ HRESULT SetSite(_Inout_opt_ IUnknown* punkParent) throw() { return AtlSetChildSite(p, punkParent); } _Check_return_ HRESULT Advise( _Inout_ IUnknown* pUnk, _In_ const IID& iid, _Out_ LPDWORD pdw) throw() { return AtlAdvise(p, pUnk, iid, pdw); } _Check_return_ HRESULT CoCreateInstance( _In_ REFCLSID rclsid, _Inout_opt_ LPUNKNOWN pUnkOuter = NULL, _In_ DWORD dwClsContext = CLSCTX_ALL) throw() { ATLASSERT(p == NULL); return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&p); } #ifdef _ATL_USE_WINAPI_FAMILY_DESKTOP_APP _Check_return_ HRESULT CoCreateInstance( _In_z_ LPCOLESTR szProgID, _Inout_opt_ LPUNKNOWN pUnkOuter = NULL, _In_ DWORD dwClsContext = CLSCTX_ALL) throw() { CLSID clsid; HRESULT hr = CLSIDFromProgID(szProgID, &clsid); ATLASSERT(p == NULL); if (SUCCEEDED(hr)) hr = ::CoCreateInstance(clsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&p); return hr; } #endif // _ATL_USE_WINAPI_FAMILY_DESKTOP_APP template _Check_return_ HRESULT QueryInterface(_Outptr_ Q** pp) const throw() { ATLASSERT(pp != NULL); return p->QueryInterface(__uuidof(Q), (void**)pp); } T* p; }; // End code borrowed from Microsoft template class CComPtr : public CComPtrBase { public: T *p; public: CComPtr() { p = NULL; } CComPtr(T *lp) { p = lp; if (p != NULL) p->AddRef(); } CComPtr(const CComPtr &lp) { p = lp.p; if (p != NULL) p->AddRef(); } ~CComPtr() { if (p != NULL) p->Release(); } T *operator = (T *lp) { T* pOld = p; p = lp; if (p != NULL) p->AddRef(); if (pOld != NULL) pOld->Release(); return *this; } T *operator = (const CComPtr &lp) { T* pOld = p; p = lp.p; if (p != NULL) p->AddRef(); if (pOld != NULL) pOld->Release(); return *this; } // We cannot enable this until gcc starts supporting __uuidof // See CORE-12710 #if 0 template T* operator=(const CComPtr& lp) { T* pOld = p; if (!lp.p || FAILED(lp.p->QueryInterface(__uuidof(T), (void**)(IUnknown**)&p))) p = NULL; if (pOld != NULL) pOld->Release(); return *this; } #endif void Release() { if (p != NULL) { p->Release(); p = NULL; } } void Attach(T *lp) { if (p != NULL) p->Release(); p = lp; } T *Detach() { T *saveP; saveP = p; p = NULL; return saveP; } T **operator & () { ATLASSERT(p == NULL); return &p; } operator T * () { return p; } _NoAddRefReleaseOnCComPtr *operator -> () const { ATLASSERT(p != NULL); return (_NoAddRefReleaseOnCComPtr *)p; } }; // Begin code borrowed from Microsoft //specialization for IDispatch template <> class CComPtr : public CComPtrBase { public: CComPtr() throw() { } CComPtr(_Inout_opt_ IDispatch* lp) throw() : CComPtrBase(lp) { } CComPtr(_Inout_ const CComPtr& lp) throw() : CComPtrBase(lp.p) { } IDispatch* operator=(_Inout_opt_ IDispatch* lp) throw() { if(*this!=lp) { CComPtr(lp).Swap(*this); } return *this; } IDispatch* operator=(_Inout_ const CComPtr& lp) throw() { if(*this!=lp) { CComPtr(lp).Swap(*this); } return *this; } CComPtr(_Inout_ CComPtr&& lp) throw() : CComPtrBase() { this->p = lp.p; lp.p = NULL; } IDispatch* operator=(_Inout_ CComPtr&& lp) throw() { CComPtr(static_cast(lp)).Swap(*this); return *this; } _Check_return_ HRESULT GetPropertyByName( _In_z_ LPCOLESTR lpsz, _Out_ VARIANT* pVar) throw() { ATLASSERT(this->p); ATLASSERT(pVar); DISPID dwDispID; HRESULT hr = GetIDOfName(lpsz, &dwDispID); if (SUCCEEDED(hr)) hr = GetProperty(dwDispID, pVar); return hr; } _Check_return_ HRESULT GetProperty( _In_ DISPID dwDispID, _Out_ VARIANT* pVar) throw() { return GetProperty(this->p, dwDispID, pVar); } _Check_return_ HRESULT PutPropertyByName( _In_z_ LPCOLESTR lpsz, _In_ VARIANT* pVar) throw() { ATLASSERT(this->p); ATLASSERT(pVar); DISPID dwDispID; HRESULT hr = GetIDOfName(lpsz, &dwDispID); if (SUCCEEDED(hr)) hr = PutProperty(dwDispID, pVar); return hr; } _Check_return_ HRESULT PutProperty( _In_ DISPID dwDispID, _In_ VARIANT* pVar) throw() { return PutProperty(this->p, dwDispID, pVar); } _Check_return_ HRESULT GetIDOfName( _In_z_ LPCOLESTR lpsz, _Out_ DISPID* pdispid) throw() { return this->p->GetIDsOfNames(IID_NULL, const_cast(&lpsz), 1, LOCALE_USER_DEFAULT, pdispid); } // Invoke a method by DISPID with no parameters _Check_return_ HRESULT Invoke0( _In_ DISPID dispid, _Out_opt_ VARIANT* pvarRet = NULL) throw() { DISPPARAMS dispparams = { NULL, NULL, 0, 0}; return this->p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL); } // Invoke a method by name with no parameters _Check_return_ HRESULT Invoke0( _In_z_ LPCOLESTR lpszName, _Out_opt_ VARIANT* pvarRet = NULL) throw() { HRESULT hr; DISPID dispid; hr = GetIDOfName(lpszName, &dispid); if (SUCCEEDED(hr)) hr = Invoke0(dispid, pvarRet); return hr; } // Invoke a method by DISPID with a single parameter _Check_return_ HRESULT Invoke1( _In_ DISPID dispid, _In_ VARIANT* pvarParam1, _Out_opt_ VARIANT* pvarRet = NULL) throw() { DISPPARAMS dispparams = { pvarParam1, NULL, 1, 0}; return this->p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL); } // Invoke a method by name with a single parameter _Check_return_ HRESULT Invoke1( _In_z_ LPCOLESTR lpszName, _In_ VARIANT* pvarParam1, _Out_opt_ VARIANT* pvarRet = NULL) throw() { DISPID dispid; HRESULT hr = GetIDOfName(lpszName, &dispid); if (SUCCEEDED(hr)) hr = Invoke1(dispid, pvarParam1, pvarRet); return hr; } // Invoke a method by DISPID with two parameters _Check_return_ HRESULT Invoke2( _In_ DISPID dispid, _In_ VARIANT* pvarParam1, _In_ VARIANT* pvarParam2, _Out_opt_ VARIANT* pvarRet = NULL) throw(); // Invoke a method by name with two parameters _Check_return_ HRESULT Invoke2( _In_z_ LPCOLESTR lpszName, _In_ VARIANT* pvarParam1, _In_ VARIANT* pvarParam2, _Out_opt_ VARIANT* pvarRet = NULL) throw() { DISPID dispid; HRESULT hr = GetIDOfName(lpszName, &dispid); if (SUCCEEDED(hr)) hr = Invoke2(dispid, pvarParam1, pvarParam2, pvarRet); return hr; } // Invoke a method by DISPID with N parameters _Check_return_ HRESULT InvokeN( _In_ DISPID dispid, _In_ VARIANT* pvarParams, _In_ int nParams, _Out_opt_ VARIANT* pvarRet = NULL) throw() { DISPPARAMS dispparams = {pvarParams, NULL, (unsigned int)nParams, 0}; return this->p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL); } // Invoke a method by name with Nparameters _Check_return_ HRESULT InvokeN( _In_z_ LPCOLESTR lpszName, _In_ VARIANT* pvarParams, _In_ int nParams, _Out_opt_ VARIANT* pvarRet = NULL) throw() { HRESULT hr; DISPID dispid; hr = GetIDOfName(lpszName, &dispid); if (SUCCEEDED(hr)) hr = InvokeN(dispid, pvarParams, nParams, pvarRet); return hr; } _Check_return_ static HRESULT PutProperty( _In_ IDispatch* pDispatch, _In_ DISPID dwDispID, _In_ VARIANT* pVar) throw() { ATLASSERT(pDispatch); ATLASSERT(pVar != NULL); if (pVar == NULL) return E_POINTER; if (pDispatch == NULL) return E_INVALIDARG; DISPPARAMS dispparams = {NULL, NULL, 1, 1}; dispparams.rgvarg = pVar; DISPID dispidPut = DISPID_PROPERTYPUT; dispparams.rgdispidNamedArgs = &dispidPut; if (pVar->vt == VT_UNKNOWN || pVar->vt == VT_DISPATCH || (pVar->vt & VT_ARRAY) || (pVar->vt & VT_BYREF)) { HRESULT hr = pDispatch->Invoke(dwDispID, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUTREF, &dispparams, NULL, NULL, NULL); if (SUCCEEDED(hr)) return hr; } return pDispatch->Invoke(dwDispID, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL); } _Check_return_ static HRESULT GetProperty( _In_ IDispatch* pDispatch, _In_ DISPID dwDispID, _Out_ VARIANT* pVar) throw() { ATLASSERT(pDispatch); ATLASSERT(pVar != NULL); if (pVar == NULL) return E_POINTER; if (pDispatch == NULL) return E_INVALIDARG; DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0}; return pDispatch->Invoke(dwDispID, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispparamsNoArgs, pVar, NULL, NULL); } }; // End code borrowed from Microsoft //CComQIIDPtr is the gcc compatible version of CComQIPtr #define I_ID(Itype) Itype,&IID_##Itype template class CComQIIDPtr : public CComPtr { public: // Let's tell GCC how to find a symbol. using CComPtr::p; CComQIIDPtr() { } CComQIIDPtr(_Inout_opt_ T* lp) : CComPtr(lp) { } CComQIIDPtr(_Inout_ const CComQIIDPtr& lp): CComPtr(lp.p) { } CComQIIDPtr(_Inout_opt_ IUnknown* lp) { if (lp != NULL) { if (FAILED(lp->QueryInterface(*piid, (void**)(IUnknown**)&p))) p = NULL; } } T *operator = (T *lp) { T* pOld = p; p = lp; if (p != NULL) p->AddRef(); if (pOld != NULL) pOld->Release(); return *this; } T *operator = (const CComQIIDPtr &lp) { T* pOld = p; p = lp.p; if (p != NULL) p->AddRef(); if (pOld != NULL) pOld->Release(); return *this; } T * operator=(IUnknown* lp) { T* pOld = p; if (!lp || FAILED(lp->QueryInterface(*piid, (void**)(IUnknown**)&p))) p = NULL; if (pOld != NULL) pOld->Release(); return *this; } }; class CComBSTR { public: BSTR m_str; public: CComBSTR() : m_str(NULL) { } CComBSTR(LPCOLESTR pSrc) { if (pSrc == NULL) m_str = NULL; else m_str = ::SysAllocString(pSrc); } CComBSTR(int length) { if (length == 0) m_str = NULL; else m_str = ::SysAllocStringLen(NULL, length); } CComBSTR(int length, LPCOLESTR pSrc) { if (length == 0) m_str = NULL; else m_str = ::SysAllocStringLen(pSrc, length); } CComBSTR(PCSTR pSrc) { if (pSrc) { int len = MultiByteToWideChar(CP_THREAD_ACP, 0, pSrc, -1, NULL, 0); m_str = ::SysAllocStringLen(NULL, len - 1); if (m_str) { int res = MultiByteToWideChar(CP_THREAD_ACP, 0, pSrc, -1, m_str, len); ATLASSERT(res == len); if (res != len) { ::SysFreeString(m_str); m_str = NULL; } } } else { m_str = NULL; } } CComBSTR(const CComBSTR &other) { m_str = other.Copy(); } CComBSTR(REFGUID guid) { OLECHAR szGuid[40]; ::StringFromGUID2(guid, szGuid, 40); m_str = ::SysAllocString(szGuid); } ~CComBSTR() { ::SysFreeString(m_str); m_str = NULL; } operator BSTR () const { return m_str; } BSTR *operator & () { return &m_str; } CComBSTR &operator = (const CComBSTR &other) { ::SysFreeString(m_str); m_str = other.Copy(); return *this; } void Attach(BSTR bstr) { ::SysFreeString(m_str); m_str = bstr; } BSTR Detach() { BSTR str = m_str; m_str = NULL; return str; } BSTR Copy() const { if (!m_str) return NULL; return ::SysAllocStringLen(m_str, ::SysStringLen(m_str)); } HRESULT CopyTo(BSTR *other) const { if (!other) return E_POINTER; *other = Copy(); return S_OK; } bool LoadString(HMODULE module, DWORD uID) { ::SysFreeString(m_str); m_str = NULL; const wchar_t *ptr = NULL; int len = ::LoadStringW(module, uID, (PWSTR)&ptr, 0); if (len) m_str = ::SysAllocStringLen(ptr, len); return m_str != NULL; } unsigned int Length() const { return ::SysStringLen(m_str); } unsigned int ByteLength() const { return ::SysStringByteLen(m_str); } }; class CComVariant : public tagVARIANT { public: CComVariant() { ::VariantInit(this); } CComVariant(const CComVariant& other) { V_VT(this) = VT_EMPTY; Copy(&other); } ~CComVariant() { Clear(); } CComVariant(LPCOLESTR lpStr) { V_VT(this) = VT_BSTR; V_BSTR(this) = ::SysAllocString(lpStr); } CComVariant(LPCSTR lpStr) { V_VT(this) = VT_BSTR; CComBSTR str(lpStr); V_BSTR(this) = str.Detach(); } CComVariant(bool value) { V_VT(this) = VT_BOOL; V_BOOL(this) = value ? VARIANT_TRUE : VARIANT_FALSE; } CComVariant(char value) { V_VT(this) = VT_I1; V_I1(this) = value; } CComVariant(BYTE value) { V_VT(this) = VT_UI1; V_UI1(this) = value; } CComVariant(short value) { V_VT(this) = VT_I2; V_I2(this) = value; } CComVariant(unsigned short value) { V_VT(this) = VT_UI2; V_UI2(this) = value; } CComVariant(int value, VARENUM type = VT_I4) { if (type == VT_I4 || type == VT_INT) { V_VT(this) = type; V_I4(this) = value; } else { V_VT(this) = VT_ERROR; V_ERROR(this) = E_INVALIDARG; } } CComVariant(unsigned int value, VARENUM type = VT_UI4) { if (type == VT_UI4 || type == VT_UINT) { V_VT(this) = type; V_UI4(this) = value; } else { V_VT(this) = VT_ERROR; V_ERROR(this) = E_INVALIDARG; } } CComVariant(long value, VARENUM type = VT_I4) { if (type == VT_I4 || type == VT_ERROR) { V_VT(this) = type; V_I4(this) = value; } else { V_VT(this) = VT_ERROR; V_ERROR(this) = E_INVALIDARG; } } CComVariant(unsigned long value) { V_VT(this) = VT_UI4; V_UI4(this) = value; } CComVariant(float value) { V_VT(this) = VT_R4; V_R4(this) = value; } CComVariant(double value, VARENUM type = VT_R8) { if (type == VT_R8 || type == VT_DATE) { V_VT(this) = type; V_R8(this) = value; } else { V_VT(this) = VT_ERROR; V_ERROR(this) = E_INVALIDARG; } } CComVariant(const LONGLONG& value) { V_VT(this) = VT_I8; V_I8(this) = value; } CComVariant(const ULONGLONG& value) { V_VT(this) = VT_UI8; V_UI8(this) = value; } CComVariant(const CY& value) { V_VT(this) = VT_CY; V_I8(this) = value.int64; } HRESULT Clear() { return ::VariantClear(this); } HRESULT Copy(_In_ const VARIANT* src) { return ::VariantCopy(this, const_cast(src)); } HRESULT ChangeType(_In_ VARTYPE newType, _In_opt_ const LPVARIANT src = NULL) { const LPVARIANT lpSrc = src ? src : this; return ::VariantChangeType(this, lpSrc, 0, newType); } }; }; // namespace ATL #ifndef _ATL_NO_AUTOMATIC_NAMESPACE using namespace ATL; #endif //!_ATL_NO_AUTOMATIC_NAMESPACE