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