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 |