// ************************************************************************** // * 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(); } ComPtr( ComPtr&& other) : ptr(other.ptr) { other.ptr = nullptr; } ~ComPtr() { if (ptr) ptr->Release(); } ComPtr& operator=(ComPtr other) { swap(other); return *this; } //unifying assignment: no need for r-value reference assignment! void swap(ComPtr& rhs) { std::swap(ptr, rhs.ptr); } //throw() 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() //throw() { 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); //throw() //################# implementation ############################# //we cannot 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) //throw() { ComPtr outPtr; if (other) other->QueryInterface(IID_PPV_ARGS(outPtr.init())); return outPtr; } } #endif //SMART_COM_PTR_H