// ************************************************************************** // * This file is part of the FreeFileSync project. It is distributed under * // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef SMART_COM_PTR_H #define SMART_COM_PTR_H #include #include "win.h" //includes "windows.h" -> always include before other headers that also might include "windows.h"! #include namespace zen { /* ComPtr: RAII class handling COM objects Example: -------- ComPtr devFinder; if (FAILED(::CoCreateInstance(CLSID_UPnPDeviceFinder, nullptr, CLSCTX_ALL, IID_PPV_ARGS(devFinder.init())))) return -1; ComPtr devEnum = com_dynamic_cast(devColl); if (!devEnum) return -1; */ template class ComPtr { public: ComPtr() : ptr(nullptr) {} // ComPtr(const ComPtr& other) : ptr(other.ptr) { if (ptr) ptr->AddRef(); } //noexcept in C++11 ComPtr( ComPtr&& tmp ) : ptr(tmp.release()) {} // ~ComPtr() { if (ptr) ptr->Release(); } //has exception spec of compiler-generated destructor by default ComPtr& operator=(const ComPtr& other) { ComPtr(other).swap(*this); return *this; } //noexcept in C++11 ComPtr& operator=(ComPtr&& tmp) { swap(tmp); return *this; } // //don't use unifying assignment but save one move-construction in the r-value case instead! void swap(ComPtr& rhs) { std::swap(ptr, rhs.ptr); } //noexcept in C++11 T** init() //get pointer for use with ::CoCreateInstance() { ComPtr().swap(*this); return &ptr; } T* get() const { return ptr; } T* operator->() const { return ptr; } T& operator* () const { return *ptr; } T* release() //noexcept in C++11 { T* tmp = ptr; ptr = nullptr; return tmp; } private: T* ptr; struct ConversionToBool { int dummy; }; public: //use member pointer as implicit conversion to bool (C++ Templates - Vandevoorde/Josuttis; chapter 20) operator int ConversionToBool::* () const { return ptr != nullptr ? &ConversionToBool::dummy : nullptr; } }; template ComPtr com_dynamic_cast(const ComPtr& other); //noexcept in C++11 //################# implementation ############################# //we cannot partially specialize std::swap() for a class template and are not allowed to overload it => offer swap in own namespace template inline void swap(zen::ComPtr& lhs, zen::ComPtr& rhs) { lhs.swap(rhs); } template inline ComPtr com_dynamic_cast(const ComPtr& other) //noexcept in C++11 { ComPtr outPtr; if (other) other->QueryInterface(IID_PPV_ARGS(outPtr.init())); return outPtr; } } #endif //SMART_COM_PTR_H