1 // Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights 2 // reserved. Use of this source code is governed by a BSD-style license that 3 // can be found in the LICENSE file. 4 5 #ifndef CEF_LIBCEF_DLL_CPPTOC_CPPTOC_SCOPED_H_ 6 #define CEF_LIBCEF_DLL_CPPTOC_CPPTOC_SCOPED_H_ 7 #pragma once 8 9 #include "include/base/cef_logging.h" 10 #include "include/base/cef_macros.h" 11 #include "include/capi/cef_base_capi.h" 12 #include "include/cef_base.h" 13 #include "libcef_dll/ptr_util.h" 14 #include "libcef_dll/wrapper_types.h" 15 16 // Wrap a C++ class with a C structure. This is used when the class 17 // implementation exists on this side of the DLL boundary but will have methods 18 // called from the other side of the DLL boundary. 19 template <class ClassName, class BaseName, class StructName> 20 class CefCppToCScoped : public CefBaseScoped { 21 public: 22 // Create a new wrapper instance and associated structure reference for 23 // passing an object instance the other side. The wrapper object will be 24 // deleted when |del| is called on the associated structure. The wrapped 25 // object will be deleted when the wrapper object is deleted. For example: 26 // 27 // void MyMethod(CefOwnPtr<MyType> obj) { 28 // my_method(MyTypeCppToC::WrapOwn(obj)); 29 // } 30 // 31 // void my_method(my_type_t* struct) { 32 // // Delete the MyTypeCppToC wrapper and the owned MyType object. 33 // struct->del(struct); 34 // } WrapOwn(CefOwnPtr<BaseName> c)35 static StructName* WrapOwn(CefOwnPtr<BaseName> c) { 36 if (!c) 37 return nullptr; 38 39 // Wrap our object with the CefCppToC class. 40 ClassName* wrapper = new ClassName(); 41 wrapper->Initialize(c.release(), true); 42 43 // Return the structure pointer that can now be passed to the other side. 44 return wrapper->GetStruct(); 45 } 46 47 // Create a new wrapper instance and associated structure reference for 48 // passing an object instance to the other side. The wrapper object is owned 49 // by the caller. The wrapped object is unowned and must outlive the wrapper. 50 // For example: 51 // 52 // void MyMethod(MyType* obj) { 53 // CefOwnPtr<MyTypeCppToC> MyTypeWrapper = MyTypeCppToC::WrapRaw(obj); 54 // my_method(MyTypeWrapper->GetStruct()); 55 // // MyTypeWrapper is deleted when MyMethod() goes out of scope. 56 // } 57 // 58 // void my_method(my_type_t* struct) { 59 // // Access |struct| here but you can't delete it. 60 // } WrapRaw(CefRawPtr<BaseName> c)61 static CefOwnPtr<ClassName> WrapRaw(CefRawPtr<BaseName> c) { 62 if (!c) 63 return CefOwnPtr<ClassName>(); 64 65 // Wrap our object with the CefCppToC class. 66 ClassName* wrapper = new ClassName(); 67 wrapper->Initialize(c, false); 68 69 // Return the owned wrapper object. 70 return CefOwnPtr<ClassName>(wrapper); 71 } 72 73 // Retrieve the underlying object instance for a structure reference passed 74 // back from the other side. The caller takes ownership of the object. For 75 // example: 76 // 77 // void my_method(my_type_t* struct) { 78 // CefOwnPtr<MyType> MyTypePtr = MyTypeCppToC::UnwrapOwn(struct); 79 // // |struct| has been deleted and should no longer be accessed. 80 // } UnwrapOwn(StructName * s)81 static CefOwnPtr<BaseName> UnwrapOwn(StructName* s) { 82 if (!s) 83 return CefOwnPtr<BaseName>(); 84 85 // Cast our structure to the wrapper structure type. 86 WrapperStruct* wrapperStruct = GetWrapperStruct(s); 87 88 // If the type does not match this object then we need to unwrap as the 89 // derived type. 90 if (wrapperStruct->type_ != kWrapperType) 91 return UnwrapDerivedOwn(wrapperStruct->type_, s); 92 93 // We should own the underlying object currently. 94 DCHECK(wrapperStruct->wrapper_->owned_); 95 DCHECK(wrapperStruct->object_); 96 97 // We're giving up ownership of the underlying object. Clear the pointer so 98 // it doesn't get deleted. 99 BaseName* object = wrapperStruct->object_; 100 wrapperStruct->object_ = nullptr; 101 102 delete wrapperStruct->wrapper_; 103 104 // Return the underlying object instance. 105 return CefOwnPtr<BaseName>(object); 106 } 107 108 // Retrieve the underlying object instance for a structure reference passed 109 // back from the other side. Ownership does not change. For example: 110 // 111 // void my_method(my_type_t* struct) { 112 // CefRawPtr<MyType> MyTypePtr = MyTypeCppToC::UnwrapRaw(struct); 113 // // |struct| is still valid. 114 // } UnwrapRaw(StructName * s)115 static CefRawPtr<BaseName> UnwrapRaw(StructName* s) { 116 if (!s) 117 return nullptr; 118 119 // Cast our structure to the wrapper structure type. 120 WrapperStruct* wrapperStruct = GetWrapperStruct(s); 121 122 // If the type does not match this object then we need to unwrap as the 123 // derived type. 124 if (wrapperStruct->type_ != kWrapperType) 125 return UnwrapDerivedRaw(wrapperStruct->type_, s); 126 127 // Return the underlying object instance. 128 return wrapperStruct->object_; 129 } 130 131 // Retrieve the same side wrapper associated with the structure. Ownership 132 // does not change. GetWrapper(StructName * s)133 static ClassName* GetWrapper(StructName* s) { 134 DCHECK(s); 135 WrapperStruct* wrapperStruct = GetWrapperStruct(s); 136 // Verify that the wrapper offset was calculated correctly. 137 DCHECK_EQ(kWrapperType, wrapperStruct->type_); 138 return static_cast<ClassName*>(wrapperStruct->wrapper_); 139 } 140 141 // Retrieve the underlying object instance from our own structure reference 142 // when the reference is passed as the required first parameter of a C API 143 // function call. Ownership of the object does not change. Get(StructName * s)144 static BaseName* Get(StructName* s) { 145 DCHECK(s); 146 WrapperStruct* wrapperStruct = GetWrapperStruct(s); 147 // Verify that the wrapper offset was calculated correctly. 148 DCHECK_EQ(kWrapperType, wrapperStruct->type_); 149 return wrapperStruct->object_; 150 } 151 152 // If returning the structure across the DLL boundary you should call 153 // AddRef() on this CefCppToC object. On the other side of the DLL boundary, 154 // call UnderlyingRelease() on the wrapping CefCToCpp object. GetStruct()155 StructName* GetStruct() { return &wrapper_struct_.struct_; } 156 157 protected: CefCppToCScoped()158 CefCppToCScoped() { 159 wrapper_struct_.type_ = kWrapperType; 160 wrapper_struct_.wrapper_ = this; 161 memset(GetStruct(), 0, sizeof(StructName)); 162 } 163 ~CefCppToCScoped()164 virtual ~CefCppToCScoped() { 165 // Only delete the underlying object if we own it. 166 if (owned_ && wrapper_struct_.object_) 167 delete wrapper_struct_.object_; 168 } 169 170 private: 171 // Used to associate this wrapper object, the underlying object instance and 172 // the structure that will be passed to the other side. 173 struct WrapperStruct { 174 CefWrapperType type_; 175 BaseName* object_; 176 CefCppToCScoped<ClassName, BaseName, StructName>* wrapper_; 177 StructName struct_; 178 }; 179 Initialize(BaseName * obj,bool owned)180 void Initialize(BaseName* obj, bool owned) { 181 wrapper_struct_.object_ = obj; 182 owned_ = owned; 183 184 cef_base_scoped_t* base = reinterpret_cast<cef_base_scoped_t*>(GetStruct()); 185 base->size = sizeof(StructName); 186 if (owned) 187 base->del = struct_del; 188 } 189 GetWrapperStruct(StructName * s)190 static WrapperStruct* GetWrapperStruct(StructName* s) { 191 // Offset using the WrapperStruct size instead of individual member sizes 192 // to avoid problems due to platform/compiler differences in structure 193 // padding. 194 return reinterpret_cast<WrapperStruct*>( 195 reinterpret_cast<char*>(s) - 196 (sizeof(WrapperStruct) - sizeof(StructName))); 197 } 198 199 // Unwrap as the derived type. 200 static CefOwnPtr<BaseName> UnwrapDerivedOwn(CefWrapperType type, 201 StructName* s); 202 static CefRawPtr<BaseName> UnwrapDerivedRaw(CefWrapperType type, 203 StructName* s); 204 struct_del(cef_base_scoped_t * base)205 static void CEF_CALLBACK struct_del(cef_base_scoped_t* base) { 206 DCHECK(base); 207 if (!base) 208 return; 209 210 WrapperStruct* wrapperStruct = 211 GetWrapperStruct(reinterpret_cast<StructName*>(base)); 212 // Verify that the wrapper offset was calculated correctly. 213 DCHECK_EQ(kWrapperType, wrapperStruct->type_); 214 215 // Should only be deleting wrappers that own the underlying object. 216 DCHECK(wrapperStruct->wrapper_->owned_); 217 delete wrapperStruct->wrapper_; 218 } 219 220 WrapperStruct wrapper_struct_; 221 bool owned_; 222 223 static CefWrapperType kWrapperType; 224 225 DISALLOW_COPY_AND_ASSIGN(CefCppToCScoped); 226 }; 227 228 #endif // CEF_LIBCEF_DLL_CPPTOC_CPPTOC_SCOPED_H_ 229