Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef BASE_SCOPED_COMPTR_WIN_H_
      6 #define BASE_SCOPED_COMPTR_WIN_H_
      7 
      8 #include <unknwn.h>
      9 
     10 #include "base/logging.h"
     11 #include "base/ref_counted.h"
     12 
     13 // Utility template to prevent users of ScopedComPtr from calling AddRef and/or
     14 // Release() without going through the ScopedComPtr class.
     15 template <class Interface>
     16 class BlockIUnknownMethods : public Interface {
     17  private:
     18   STDMETHOD(QueryInterface)(REFIID iid, void** object) = 0;
     19   STDMETHOD_(ULONG, AddRef)() = 0;
     20   STDMETHOD_(ULONG, Release)() = 0;
     21 };
     22 
     23 // A fairly minimalistic smart class for COM interface pointers.
     24 // Uses scoped_refptr for the basic smart pointer functionality
     25 // and adds a few IUnknown specific services.
     26 template <class Interface, const IID* interface_id = &__uuidof(Interface)>
     27 class ScopedComPtr : public scoped_refptr<Interface> {
     28  public:
     29   typedef scoped_refptr<Interface> ParentClass;
     30 
     31   ScopedComPtr() {
     32   }
     33 
     34   explicit ScopedComPtr(Interface* p) : ParentClass(p) {
     35   }
     36 
     37   ScopedComPtr(const ScopedComPtr<Interface, interface_id>& p)
     38       : ParentClass(p) {
     39   }
     40 
     41   ~ScopedComPtr() {
     42     // We don't want the smart pointer class to be bigger than the pointer
     43     // it wraps.
     44     COMPILE_ASSERT(sizeof(ScopedComPtr<Interface, interface_id>) ==
     45                    sizeof(Interface*), ScopedComPtrSize);
     46   }
     47 
     48   // Explicit Release() of the held object.  Useful for reuse of the
     49   // ScopedComPtr instance.
     50   // Note that this function equates to IUnknown::Release and should not
     51   // be confused with e.g. scoped_ptr::release().
     52   void Release() {
     53     if (ptr_ != NULL) {
     54       ptr_->Release();
     55       ptr_ = NULL;
     56     }
     57   }
     58 
     59   // Sets the internal pointer to NULL and returns the held object without
     60   // releasing the reference.
     61   Interface* Detach() {
     62     Interface* p = ptr_;
     63     ptr_ = NULL;
     64     return p;
     65   }
     66 
     67   // Accepts an interface pointer that has already been addref-ed.
     68   void Attach(Interface* p) {
     69     DCHECK(ptr_ == NULL);
     70     ptr_ = p;
     71   }
     72 
     73   // Retrieves the pointer address.
     74   // Used to receive object pointers as out arguments (and take ownership).
     75   // The function DCHECKs on the current value being NULL.
     76   // Usage: Foo(p.Receive());
     77   Interface** Receive() {
     78     DCHECK(ptr_ == NULL) << "Object leak. Pointer must be NULL";
     79     return &ptr_;
     80   }
     81 
     82   template <class Query>
     83   HRESULT QueryInterface(Query** p) {
     84     DCHECK(p != NULL);
     85     DCHECK(ptr_ != NULL);
     86     // IUnknown already has a template version of QueryInterface
     87     // so the iid parameter is implicit here. The only thing this
     88     // function adds are the DCHECKs.
     89     return ptr_->QueryInterface(p);
     90   }
     91 
     92   // QI for times when the IID is not associated with the type.
     93   HRESULT QueryInterface(const IID& iid, void** obj) {
     94     DCHECK(obj != NULL);
     95     DCHECK(ptr_ != NULL);
     96     return ptr_->QueryInterface(iid, obj);
     97   }
     98 
     99   // Queries |other| for the interface this object wraps and returns the
    100   // error code from the other->QueryInterface operation.
    101   HRESULT QueryFrom(IUnknown* object) {
    102     DCHECK(object != NULL);
    103     return object->QueryInterface(Receive());
    104   }
    105 
    106   // Convenience wrapper around CoCreateInstance
    107   HRESULT CreateInstance(const CLSID& clsid, IUnknown* outer = NULL,
    108                          DWORD context = CLSCTX_ALL) {
    109     DCHECK(ptr_ == NULL);
    110     HRESULT hr = ::CoCreateInstance(clsid, outer, context, *interface_id,
    111                                     reinterpret_cast<void**>(&ptr_));
    112     return hr;
    113   }
    114 
    115   // Checks if the identity of |other| and this object is the same.
    116   bool IsSameObject(IUnknown* other) {
    117     if (!other && !ptr_)
    118       return true;
    119 
    120     if (!other || !ptr_)
    121       return false;
    122 
    123     ScopedComPtr<IUnknown> my_identity;
    124     QueryInterface(my_identity.Receive());
    125 
    126     ScopedComPtr<IUnknown> other_identity;
    127     other->QueryInterface(other_identity.Receive());
    128 
    129     return static_cast<IUnknown*>(my_identity) ==
    130            static_cast<IUnknown*>(other_identity);
    131   }
    132 
    133   // Provides direct access to the interface.
    134   // Here we use a well known trick to make sure we block access to
    135   // IUknown methods so that something bad like this doesn't happen:
    136   //    ScopedComPtr<IUnknown> p(Foo());
    137   //    p->Release();
    138   //    ... later the destructor runs, which will Release() again.
    139   // and to get the benefit of the DCHECKs we add to QueryInterface.
    140   // There's still a way to call these methods if you absolutely must
    141   // by statically casting the ScopedComPtr instance to the wrapped interface
    142   // and then making the call... but generally that shouldn't be necessary.
    143   BlockIUnknownMethods<Interface>* operator->() const {
    144     DCHECK(ptr_ != NULL);
    145     return reinterpret_cast<BlockIUnknownMethods<Interface>*>(ptr_);
    146   }
    147 
    148   // Pull in operator=() from the parent class.
    149   using scoped_refptr<Interface>::operator=;
    150 
    151   // static methods
    152 
    153   static const IID& iid() {
    154     return *interface_id;
    155   }
    156 };
    157 
    158 #endif  // BASE_SCOPED_COMPTR_WIN_H_
    159