| OLD | NEW |
| (Empty) |
| 1 // Copyright 2009 Google Inc. | |
| 2 // | |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
| 4 // you may not use this file except in compliance with the License. | |
| 5 // You may obtain a copy of the License at | |
| 6 // | |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 // | |
| 9 // Unless required by applicable law or agreed to in writing, software | |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 // See the License for the specific language governing permissions and | |
| 13 // limitations under the License. | |
| 14 // ======================================================================== | |
| 15 // | |
| 16 // TODO(omaha): use NPN_SetException to return useful error information. | |
| 17 | |
| 18 #include "omaha/plugins/update/npapi/dispatch_host.h" | |
| 19 | |
| 20 #include "base/logging.h" | |
| 21 #include "base/scope_guard.h" | |
| 22 #include "base/scoped_ptr.h" | |
| 23 #include "omaha/base/string.h" | |
| 24 #include "omaha/plugins/update/npapi/variant_utils.h" | |
| 25 | |
| 26 namespace omaha { | |
| 27 | |
| 28 namespace { | |
| 29 | |
| 30 void SetExceptionIfFailed(NPObject* object, HRESULT result) { | |
| 31 if (FAILED(result)) { | |
| 32 CStringA message; | |
| 33 message.Format("0x%08x", result); | |
| 34 NPN_SetException(object, message); | |
| 35 } | |
| 36 } | |
| 37 | |
| 38 } // namespace | |
| 39 | |
| 40 DispatchHost* DispatchHost::CreateInstance(NPP npp, IDispatch* dispatch) { | |
| 41 ASSERT1(dispatch); | |
| 42 DispatchHost* host = static_cast<DispatchHost*>( | |
| 43 NPN_CreateObject(npp, &kNPClass_)); | |
| 44 host->dispatch_ = dispatch; | |
| 45 CORE_LOG(L3, (L"[DispatchHost::DispatchHost][this=0x%p][dispatch=0x%p]", | |
| 46 host, dispatch)); | |
| 47 return host; | |
| 48 } | |
| 49 | |
| 50 DispatchHost::DispatchHost(NPP npp) : npp_(npp) { | |
| 51 } | |
| 52 | |
| 53 DispatchHost::~DispatchHost() { | |
| 54 CORE_LOG(L3, (L"[DispatchHost::~DispatchHost][this=0x%p][dispatch=0x%p]", | |
| 55 this, dispatch_)); | |
| 56 } | |
| 57 | |
| 58 DISPID DispatchHost::GetDispatchId(NPIdentifier name) { | |
| 59 NPUTF8* utf8_name = NPN_UTF8FromIdentifier(name); | |
| 60 CString wide_name = Utf8ToWideChar(utf8_name, lstrlenA(utf8_name)); | |
| 61 NPN_MemFree(utf8_name); | |
| 62 DISPID dispatch_id = DISPID_UNKNOWN; | |
| 63 HRESULT hr = dispatch_.GetIDOfName(wide_name, &dispatch_id); | |
| 64 if (FAILED(hr)) { | |
| 65 return DISPID_UNKNOWN; | |
| 66 } | |
| 67 return dispatch_id; | |
| 68 } | |
| 69 | |
| 70 // Whether or not a member should be treated as a property by NPAPI. A member is | |
| 71 // considered a property for NPAPI if either of the following are true: | |
| 72 // - The property is a getter with exactly one [out, retval] argument. | |
| 73 // - The property is a putter with exactly one [in] argument. | |
| 74 // The reason for this limitation is NPAPI does not support passing additional | |
| 75 // arguments when getting/setting properties. Properties that take additional | |
| 76 // arguments are handled as methods by NPAPI instead. | |
| 77 bool DispatchHost::IsProperty(DISPID dispatch_id) { | |
| 78 CComPtr<ITypeInfo> type_info; | |
| 79 HRESULT hr = dispatch_->GetTypeInfo(0, LOCALE_SYSTEM_DEFAULT, &type_info); | |
| 80 if (FAILED(hr)) { | |
| 81 ASSERT(false, (L"[IsProperty][failed=0x%08x]", hr)); | |
| 82 return false; | |
| 83 } | |
| 84 TYPEATTR* type_attr; | |
| 85 hr = type_info->GetTypeAttr(&type_attr); | |
| 86 if (FAILED(hr)) { | |
| 87 ASSERT(false, (L"[IsProperty][failed=0x%08x]", hr)); | |
| 88 return false; | |
| 89 } | |
| 90 ON_SCOPE_EXIT_OBJ(*type_info.p, &ITypeInfo::ReleaseTypeAttr, type_attr); | |
| 91 | |
| 92 for (int i = 0; i < type_attr->cFuncs; ++i) { | |
| 93 FUNCDESC* func_desc = NULL; | |
| 94 hr = type_info->GetFuncDesc(i, &func_desc); | |
| 95 if (FAILED(hr)) { | |
| 96 ASSERT(false, (L"[IsProperty][failed=0x%08x]", hr)); | |
| 97 return false; | |
| 98 } | |
| 99 ON_SCOPE_EXIT_OBJ(*type_info.p, &ITypeInfo::ReleaseFuncDesc, func_desc); | |
| 100 if (dispatch_id == func_desc->memid) { | |
| 101 if (((func_desc->invkind & DISPATCH_PROPERTYGET) && | |
| 102 func_desc->cParams == 0) || | |
| 103 ((func_desc->invkind & DISPATCH_PROPERTYPUT) && | |
| 104 func_desc->cParams == 1 && | |
| 105 (func_desc->lprgelemdescParam[0].paramdesc.wParamFlags & | |
| 106 PARAMFLAG_FIN))) { | |
| 107 return true; | |
| 108 } | |
| 109 } | |
| 110 } | |
| 111 return false; | |
| 112 } | |
| 113 | |
| 114 // Simple helper to adapt NPAPI method/property invocations to IDispatch::Invoke | |
| 115 // by wrapping/unwrapping NPVariants into VARIANTs. | |
| 116 HRESULT DispatchHost::InvokeHelper(DISPID dispatch_id, WORD flags, | |
| 117 const NPVariant* args, uint32_t arg_count, | |
| 118 NPP npp, NPVariant* result) { | |
| 119 ASSERT1(args || arg_count == 0); | |
| 120 ASSERT1(result); | |
| 121 CORE_LOG(L3, (L"[InvokeHelper][this=0x%p][dispatch=0x%p][flags=0x%x]" | |
| 122 L"[arg_count=%d]", this, dispatch_, flags, arg_count)); | |
| 123 | |
| 124 // Just in case a rogue browser decides to use the return value on failure. | |
| 125 VOID_TO_NPVARIANT(*result); | |
| 126 scoped_array<CComVariant> dispatch_args(new CComVariant[arg_count]); | |
| 127 | |
| 128 // IDispatch::Invoke expects arguments in "reverse" order | |
| 129 for (uint32_t i = 0 ; i < arg_count; ++i) { | |
| 130 NPVariantToVariant(npp, args[i], &dispatch_args[arg_count - i - 1]); | |
| 131 } | |
| 132 DISPPARAMS dispatch_params = {}; | |
| 133 dispatch_params.rgvarg = dispatch_args.get(); | |
| 134 dispatch_params.cArgs = arg_count; | |
| 135 CComVariant dispatch_result; | |
| 136 HRESULT hr = dispatch_->Invoke(dispatch_id, IID_NULL, LOCALE_USER_DEFAULT, | |
| 137 flags, &dispatch_params, &dispatch_result, | |
| 138 NULL, NULL); | |
| 139 if (FAILED(hr)) { | |
| 140 CORE_LOG(L3, (L"[InvokeHelper][failed_hr=0x%p]", hr)); | |
| 141 return hr; | |
| 142 } | |
| 143 VariantToNPVariant(npp, dispatch_result, result); | |
| 144 return hr; | |
| 145 } | |
| 146 | |
| 147 NPObject* DispatchHost::Allocate(NPP npp, NPClass* class_functions) { | |
| 148 UNREFERENCED_PARAMETER(class_functions); | |
| 149 return new DispatchHost(npp); | |
| 150 } | |
| 151 | |
| 152 void DispatchHost::Deallocate(NPObject* object) { | |
| 153 delete static_cast<DispatchHost*>(object); | |
| 154 } | |
| 155 | |
| 156 bool DispatchHost::HasMethod(NPObject* object, NPIdentifier name) { | |
| 157 DispatchHost* host = static_cast<DispatchHost*>(object); | |
| 158 DISPID dispatch_id = host->GetDispatchId(name); | |
| 159 return dispatch_id != DISPID_UNKNOWN && !host->IsProperty(dispatch_id); | |
| 160 } | |
| 161 | |
| 162 bool DispatchHost::Invoke(NPObject* object, NPIdentifier name, | |
| 163 const NPVariant* args, uint32_t arg_count, | |
| 164 NPVariant* result) { | |
| 165 DispatchHost* host = static_cast<DispatchHost*>(object); | |
| 166 CORE_LOG(L3, (L"[DispatchHost::Invoke][this=0x%p][dispatch=0x%p]", | |
| 167 host, host->dispatch_)); | |
| 168 HRESULT hr = host->InvokeHelper(host->GetDispatchId(name), | |
| 169 DISPATCH_METHOD | DISPATCH_PROPERTYGET, | |
| 170 args, | |
| 171 arg_count, | |
| 172 host->npp_, | |
| 173 result); | |
| 174 SetExceptionIfFailed(object, hr); | |
| 175 return SUCCEEDED(hr); | |
| 176 } | |
| 177 | |
| 178 bool DispatchHost::InvokeDefault(NPObject* object, const NPVariant* args, | |
| 179 uint32_t arg_count, NPVariant* result) { | |
| 180 DispatchHost* host = static_cast<DispatchHost*>(object); | |
| 181 CORE_LOG(L3, (L"[DispatchHost::InvokeDefault][this=0x%p][dispatch=0x%p]", | |
| 182 host, host->dispatch_)); | |
| 183 HRESULT hr = host->InvokeHelper(DISPID_VALUE, | |
| 184 DISPATCH_METHOD | DISPATCH_PROPERTYGET, | |
| 185 args, | |
| 186 arg_count, | |
| 187 host->npp_, | |
| 188 result); | |
| 189 SetExceptionIfFailed(object, hr); | |
| 190 return SUCCEEDED(hr); | |
| 191 } | |
| 192 | |
| 193 bool DispatchHost::HasProperty(NPObject* object, NPIdentifier name) { | |
| 194 DispatchHost* host = static_cast<DispatchHost*>(object); | |
| 195 DISPID dispatch_id = host->GetDispatchId(name); | |
| 196 return dispatch_id != DISPID_UNKNOWN && host->IsProperty(dispatch_id); | |
| 197 } | |
| 198 | |
| 199 bool DispatchHost::GetProperty(NPObject* object, NPIdentifier name, | |
| 200 NPVariant* result) { | |
| 201 DispatchHost* host = static_cast<DispatchHost*>(object); | |
| 202 CORE_LOG(L3, (L"[DispatchHost::GetProperty][this=0x%p][dispatch=0x%p]", | |
| 203 host, host->dispatch_)); | |
| 204 HRESULT hr = host->InvokeHelper(host->GetDispatchId(name), | |
| 205 DISPATCH_PROPERTYGET, | |
| 206 NULL, | |
| 207 0, | |
| 208 host->npp_, | |
| 209 result); | |
| 210 SetExceptionIfFailed(object, hr); | |
| 211 return SUCCEEDED(hr); | |
| 212 } | |
| 213 | |
| 214 bool DispatchHost::SetProperty(NPObject* object, NPIdentifier name, | |
| 215 const NPVariant* value) { | |
| 216 DispatchHost* host = static_cast<DispatchHost*>(object); | |
| 217 CORE_LOG(L3, (L"[DispatchHost::SetProperty][this=0x%p][dispatch=0x%p]", | |
| 218 host, host->dispatch_)); | |
| 219 DISPID dispatch_id = host->GetDispatchId(name); | |
| 220 CComVariant dispatch_arg; | |
| 221 NPVariantToVariant(host->npp_, *value, &dispatch_arg); | |
| 222 HRESULT hr = host->dispatch_.PutProperty(dispatch_id, &dispatch_arg); | |
| 223 SetExceptionIfFailed(object, hr); | |
| 224 return SUCCEEDED(hr); | |
| 225 } | |
| 226 | |
| 227 bool DispatchHost::RemoveProperty(NPObject* object, NPIdentifier name) { | |
| 228 UNREFERENCED_PARAMETER(object); | |
| 229 UNREFERENCED_PARAMETER(name); | |
| 230 return false; | |
| 231 } | |
| 232 | |
| 233 bool DispatchHost::Enumerate(NPObject* object, NPIdentifier** names, | |
| 234 uint32_t* count) { | |
| 235 UNREFERENCED_PARAMETER(object); | |
| 236 UNREFERENCED_PARAMETER(names); | |
| 237 UNREFERENCED_PARAMETER(count); | |
| 238 return false; | |
| 239 } | |
| 240 | |
| 241 bool DispatchHost::Construct(NPObject* object, const NPVariant* args, | |
| 242 uint32_t arg_count, NPVariant* result) { | |
| 243 UNREFERENCED_PARAMETER(object); | |
| 244 UNREFERENCED_PARAMETER(args); | |
| 245 UNREFERENCED_PARAMETER(arg_count); | |
| 246 UNREFERENCED_PARAMETER(result); | |
| 247 return false; | |
| 248 } | |
| 249 | |
| 250 NPClass DispatchHost::kNPClass_ = { | |
| 251 NP_CLASS_STRUCT_VERSION, | |
| 252 Allocate, | |
| 253 Deallocate, | |
| 254 NULL, | |
| 255 HasMethod, | |
| 256 Invoke, | |
| 257 InvokeDefault, | |
| 258 HasProperty, | |
| 259 GetProperty, | |
| 260 SetProperty, | |
| 261 RemoveProperty, | |
| 262 Enumerate, | |
| 263 Construct, | |
| 264 }; | |
| 265 | |
| 266 } // namespace omaha | |
| OLD | NEW |