summaryrefslogtreecommitdiffstats
path: root/chrome_frame/scoped_ns_ptr_win.h
blob: 91780fd61bf0d69f775144487ae6ceaa2b5335ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_FRAME_SCOPED_NS_PTR_WIN_H_
#define CHROME_FRAME_SCOPED_NS_PTR_WIN_H_

#include "base/logging.h"
#include "base/ref_counted.h"

#include "third_party/xulrunner-sdk/win/include/xpcom/nsISupports.h"


// Utility template to prevent users of ScopedNsPtr from calling AddRef and/or
// Release() without going through the ScopedNsPtr class.
template <class nsInterface>
class BlocknsISupportsMethods : public nsInterface {
 private:
  NS_IMETHOD QueryInterface(REFNSIID iid, void** object) = 0;
  NS_IMETHOD_(nsrefcnt) AddRef() = 0;
  NS_IMETHOD_(nsrefcnt) Release() = 0;
};

// A smart pointer class for nsISupports.
// Based on ScopedComPtr.
// We have our own class instead of nsCOMPtr.  nsCOMPtr has parts of its
// implementation in the xpcomglue lib which we can't use since that lib
// is built with incompatible build flags to ours.
template <class nsInterface,
          const nsIID* interface_id =
              reinterpret_cast<const nsIID*>(&__uuidof(nsInterface))>
class ScopedNsPtr : public scoped_refptr<nsInterface> {
 public:
  typedef scoped_refptr<nsInterface> ParentClass;

  ScopedNsPtr() {
  }

  explicit ScopedNsPtr(nsInterface* p) : ParentClass(p) {
  }

  explicit ScopedNsPtr(const ScopedNsPtr<nsInterface, interface_id>& p)
      : ParentClass(p) {
  }

  ~ScopedNsPtr() {
    // We don't want the smart pointer class to be bigger than the pointer
    // it wraps.
    COMPILE_ASSERT(sizeof(ScopedNsPtr<nsInterface, interface_id>) ==
                   sizeof(nsInterface*), ScopedNsPtrSize);
  }

  // Explicit Release() of the held object.  Useful for reuse of the
  // ScopedNsPtr instance.
  // Note that this function equates to nsISupports::Release and should not
  // be confused with e.g. scoped_ptr::release().
  void Release() {
    if (ptr_ != NULL) {
      ptr_->Release();
      ptr_ = NULL;
    }
  }

  // Sets the internal pointer to NULL and returns the held object without
  // releasing the reference.
  nsInterface* Detach() {
    nsInterface* p = ptr_;
    ptr_ = NULL;
    return p;
  }

  // Accepts an interface pointer that has already been addref-ed.
  void Attach(nsInterface* p) {
    DCHECK(ptr_ == NULL);
    ptr_ = p;
  }

  // Retrieves the pointer address.
  // Used to receive object pointers as out arguments (and take ownership).
  // The function DCHECKs on the current value being NULL.
  // Usage: Foo(p.Receive());
  nsInterface** Receive() {
    DCHECK(ptr_ == NULL) << "Object leak. Pointer must be NULL";
    return &ptr_;
  }

  template <class Query>
  nsresult QueryInterface(Query** p) {
    DCHECK(p != NULL);
    DCHECK(ptr_ != NULL);
    return ptr_->QueryInterface(Query::GetIID(), reinterpret_cast<void**>(p));
  }

  template <class Query>
  nsresult QueryInterface(const nsIID& iid, Query** p) {
    DCHECK(p != NULL);
    DCHECK(ptr_ != NULL);
    return ptr_->QueryInterface(iid, reinterpret_cast<void**>(p));
  }

  // Queries |other| for the interface this object wraps and returns the
  // error code from the other->QueryInterface operation.
  nsresult QueryFrom(nsISupports* other) {
    DCHECK(other != NULL);
    return other->QueryInterface(iid(), reinterpret_cast<void**>(Receive()));
  }

  // Checks if the identity of |other| and this object is the same.
  bool IsSameObject(nsISupports* other) {
    if (!other && !ptr_)
      return true;

    if (!other || !ptr_)
      return false;

    nsIID iid = NS_ISUPPORTS_IID;
    ScopedNsPtr<nsISupports, iid> my_identity;
    QueryInterface(my_identity.Receive());

    ScopedNsPtr<nsISupports, iid> other_identity;
    other->QueryInterface(other_identity.Receive());

    return static_cast<nsISupports*>(my_identity) ==
           static_cast<nsISupports*>(other_identity);
  }

  // Provides direct access to the interface.
  // Here we use a well known trick to make sure we block access to
  // IUknown methods so that something bad like this doesn't happen:
  //    ScopedNsPtr<nsISupports> p(Foo());
  //    p->Release();
  //    ... later the destructor runs, which will Release() again.
  // and to get the benefit of the DCHECKs we add to QueryInterface.
  // There's still a way to call these methods if you absolutely must
  // by statically casting the ScopedNsPtr instance to the wrapped interface
  // and then making the call... but generally that shouldn't be necessary.
  BlocknsISupportsMethods<nsInterface>* operator->() const {
    DCHECK(ptr_ != NULL);
    return reinterpret_cast<BlocknsISupportsMethods<nsInterface>*>(ptr_);
  }

  // static methods

  static const nsIID& iid() {
    return *interface_id;
  }
};

#endif  // CHROME_FRAME_SCOPED_NS_PTR_WIN_H_