xref: /reactos/dll/win32/mshtml/pluginhost.c (revision 50cf16b3)
1 /*
2  * Copyright 2010 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #include "mshtml_private.h"
20 
21 static BOOL check_load_safety(PluginHost *host)
22 {
23     DWORD policy_size, policy;
24     struct CONFIRMSAFETY cs;
25     BYTE *ppolicy;
26     HRESULT hres;
27 
28     cs.clsid = host->clsid;
29     cs.pUnk = host->plugin_unk;
30     cs.dwFlags = CONFIRMSAFETYACTION_LOADOBJECT;
31 
32     hres = IInternetHostSecurityManager_QueryCustomPolicy(&host->doc->IInternetHostSecurityManager_iface,
33             &GUID_CUSTOM_CONFIRMOBJECTSAFETY, &ppolicy, &policy_size, (BYTE*)&cs, sizeof(cs), 0);
34     if(FAILED(hres))
35         return FALSE;
36 
37     policy = *(DWORD*)ppolicy;
38     CoTaskMemFree(ppolicy);
39     return policy == URLPOLICY_ALLOW;
40 }
41 
42 static BOOL check_script_safety(PluginHost *host)
43 {
44     DISPPARAMS params = {NULL,NULL,0,0};
45     DWORD policy_size, policy;
46     struct CONFIRMSAFETY cs;
47     BYTE *ppolicy;
48     ULONG err = 0;
49     VARIANT v;
50     HRESULT hres;
51 
52     cs.clsid = host->clsid;
53     cs.pUnk = host->plugin_unk;
54     cs.dwFlags = 0;
55 
56     hres = IInternetHostSecurityManager_QueryCustomPolicy(&host->doc->IInternetHostSecurityManager_iface,
57             &GUID_CUSTOM_CONFIRMOBJECTSAFETY, &ppolicy, &policy_size, (BYTE*)&cs, sizeof(cs), 0);
58     if(FAILED(hres))
59         return FALSE;
60 
61     policy = *(DWORD*)ppolicy;
62     CoTaskMemFree(ppolicy);
63 
64     if(policy != URLPOLICY_ALLOW)
65         return FALSE;
66 
67     V_VT(&v) = VT_EMPTY;
68     hres = IDispatch_Invoke(host->disp, DISPID_SECURITYCTX, &IID_NULL, 0, DISPATCH_PROPERTYGET, &params, &v, NULL, &err);
69     if(SUCCEEDED(hres)) {
70         FIXME("Handle security ctx %s\n", debugstr_variant(&v));
71         return FALSE;
72     }
73 
74     return TRUE;
75 }
76 
77 static void update_readystate(PluginHost *host)
78 {
79     DISPPARAMS params = {NULL,NULL,0,0};
80     IDispatchEx *dispex;
81     IDispatch *disp;
82     ULONG err = 0;
83     VARIANT v;
84     HRESULT hres;
85 
86     hres = IUnknown_QueryInterface(host->plugin_unk, &IID_IDispatchEx, (void**)&dispex);
87     if(SUCCEEDED(hres)) {
88         FIXME("Use IDispatchEx\n");
89         IDispatchEx_Release(dispex);
90     }
91 
92     hres = IUnknown_QueryInterface(host->plugin_unk, &IID_IDispatch, (void**)&disp);
93     if(FAILED(hres))
94         return;
95 
96     hres = IDispatch_Invoke(disp, DISPID_READYSTATE, &IID_NULL, 0, DISPATCH_PROPERTYGET, &params, &v, NULL, &err);
97     IDispatch_Release(disp);
98     if(SUCCEEDED(hres)) {
99         /* FIXME: make plugin readystate affect document readystate */
100         TRACE("readystate = %s\n", debugstr_variant(&v));
101         VariantClear(&v);
102     }
103 }
104 
105 /* FIXME: We shouldn't need this function and we should embed plugin directly in the main document */
106 static void get_pos_rect(PluginHost *host, RECT *ret)
107 {
108     ret->top = 0;
109     ret->left = 0;
110     ret->bottom = host->rect.bottom - host->rect.top;
111     ret->right = host->rect.right - host->rect.left;
112 }
113 
114 static void load_prop_bag(PluginHost *host, IPersistPropertyBag *persist_prop_bag)
115 {
116     IPropertyBag *prop_bag;
117     HRESULT hres;
118 
119     hres = create_param_prop_bag(host->element->element.nselem, &prop_bag);
120     if(FAILED(hres))
121         return;
122 
123     if(prop_bag && !check_load_safety(host)) {
124         IPropertyBag_Release(prop_bag);
125         prop_bag = NULL;
126     }
127 
128     if(prop_bag) {
129         hres = IPersistPropertyBag_Load(persist_prop_bag, prop_bag, NULL);
130         IPropertyBag_Release(prop_bag);
131         if(FAILED(hres))
132             WARN("Load failed: %08x\n", hres);
133     }else {
134         hres = IPersistPropertyBag_InitNew(persist_prop_bag);
135         if(FAILED(hres))
136             WARN("InitNew failed: %08x\n", hres);
137     }
138 }
139 
140 static void load_plugin(PluginHost *host)
141 {
142     IPersistPropertyBag2 *persist_prop_bag2;
143     IPersistPropertyBag *persist_prop_bag;
144     HRESULT hres;
145 
146     hres = IUnknown_QueryInterface(host->plugin_unk, &IID_IPersistPropertyBag2, (void**)&persist_prop_bag2);
147     if(SUCCEEDED(hres)) {
148         FIXME("Use IPersistPropertyBag2 iface\n");
149         IPersistPropertyBag2_Release(persist_prop_bag2);
150         return;
151     }
152 
153     hres = IUnknown_QueryInterface(host->plugin_unk, &IID_IPersistPropertyBag, (void**)&persist_prop_bag);
154     if(SUCCEEDED(hres)) {
155         load_prop_bag(host, persist_prop_bag);
156         IPersistPropertyBag_Release(persist_prop_bag);
157         return;
158     }
159 
160     FIXME("No IPersistPropertyBag iface\n");
161 }
162 
163 static void initialize_plugin_object(PluginHost *host)
164 {
165     IClientSecurity *client_security;
166     IQuickActivate *quick_activate;
167     IOleObject *ole_obj = NULL;
168     IOleCommandTarget *cmdtrg;
169     IViewObjectEx *view_obj;
170     IDispatchEx *dispex;
171     IDispatch *disp;
172     HRESULT hres;
173 
174     /* Note native calls QI on plugin for an undocumented IID and CLSID_HTMLDocument */
175 
176     /* FIXME: call FreezeEvents(TRUE) */
177 
178     hres = IUnknown_QueryInterface(host->plugin_unk, &IID_IClientSecurity, (void**)&client_security);
179     if(SUCCEEDED(hres)) {
180         FIXME("Handle IClientSecurity\n");
181         IClientSecurity_Release(client_security);
182         return;
183     }
184 
185     hres = IUnknown_QueryInterface(host->plugin_unk, &IID_IQuickActivate, (void**)&quick_activate);
186     if(SUCCEEDED(hres)) {
187         QACONTAINER container = {sizeof(container)};
188         QACONTROL control = {sizeof(control)};
189 
190         TRACE("Using IQuickActivate\n");
191 
192         container.pClientSite = &host->IOleClientSite_iface;
193         container.dwAmbientFlags = QACONTAINER_SUPPORTSMNEMONICS|QACONTAINER_MESSAGEREFLECT|QACONTAINER_USERMODE;
194         container.pAdviseSink = &host->IAdviseSinkEx_iface;
195         container.pPropertyNotifySink = &host->IPropertyNotifySink_iface;
196 
197         hres = IQuickActivate_QuickActivate(quick_activate, &container, &control);
198         IQuickActivate_Release(quick_activate);
199         if(FAILED(hres))
200             FIXME("QuickActivate failed: %08x\n", hres);
201     }else {
202         DWORD status = 0;
203 
204         hres = IUnknown_QueryInterface(host->plugin_unk, &IID_IOleObject, (void**)&ole_obj);
205         if(SUCCEEDED(hres)) {
206             hres = IOleObject_GetMiscStatus(ole_obj, DVASPECT_CONTENT, &status);
207             TRACE("GetMiscStatus returned %08x %x\n", hres, status);
208 
209             hres = IOleObject_SetClientSite(ole_obj, &host->IOleClientSite_iface);
210             IOleObject_Release(ole_obj);
211             if(FAILED(hres)) {
212                 FIXME("SetClientSite failed: %08x\n", hres);
213                 return;
214             }
215         }else {
216             TRACE("Plugin does not support IOleObject\n");
217         }
218     }
219 
220     load_plugin(host);
221 
222     if(ole_obj) {
223         hres = IUnknown_QueryInterface(host->plugin_unk, &IID_IViewObjectEx, (void**)&view_obj);
224         if(SUCCEEDED(hres)) {
225             DWORD view_status = 0;
226 
227             hres = IViewObjectEx_SetAdvise(view_obj, DVASPECT_CONTENT, 0, (IAdviseSink*)&host->IAdviseSinkEx_iface);
228             if(FAILED(hres))
229                 WARN("SetAdvise failed: %08x\n", hres);
230 
231             hres = IViewObjectEx_GetViewStatus(view_obj, &view_status);
232             IViewObjectEx_Release(view_obj);
233             TRACE("GetViewStatus returned %08x %x\n", hres, view_status);
234         }
235     }
236 
237     update_readystate(host);
238 
239     /* NOTE: Native QIs for IActiveScript, an undocumented IID, IOleControl and IRunnableObject */
240 
241     hres = IUnknown_QueryInterface(host->plugin_unk, &IID_IDispatchEx, (void**)&dispex);
242     if(SUCCEEDED(hres)) {
243         FIXME("Use IDispatchEx\n");
244         host->disp = (IDispatch*)dispex;
245     }else {
246         hres = IUnknown_QueryInterface(host->plugin_unk, &IID_IDispatch, (void**)&disp);
247         if(SUCCEEDED(hres))
248             host->disp = disp;
249         else
250             TRACE("no IDispatch iface\n");
251     }
252 
253     hres = IUnknown_QueryInterface(host->plugin_unk, &IID_IOleCommandTarget, (void**)&cmdtrg);
254     if(SUCCEEDED(hres)) {
255         FIXME("Use IOleCommandTarget\n");
256         IOleCommandTarget_Release(cmdtrg);
257     }
258 }
259 
260 static void embed_plugin_object(PluginHost *host)
261 {
262     IOleObject *ole_obj;
263     RECT rect;
264     HRESULT hres;
265 
266     hres = IUnknown_QueryInterface(host->plugin_unk, &IID_IOleObject, (void**)&ole_obj);
267     if(FAILED(hres)) {
268         FIXME("Plugin does not support IOleObject\n");
269         return;
270     }
271 
272     get_pos_rect(host, &rect);
273     hres = IOleObject_DoVerb(ole_obj, OLEIVERB_INPLACEACTIVATE, NULL, &host->IOleClientSite_iface, 0, host->hwnd, &rect);
274     IOleObject_Release(ole_obj);
275     if(FAILED(hres))
276         WARN("DoVerb failed: %08x\n", hres);
277 
278     if(host->ip_object) {
279         HWND hwnd;
280 
281         hres = IOleInPlaceObject_GetWindow(host->ip_object, &hwnd);
282         if(SUCCEEDED(hres))
283             TRACE("hwnd %p\n", hwnd);
284     }
285 }
286 
287 void update_plugin_window(PluginHost *host, HWND hwnd, const RECT *rect)
288 {
289     BOOL rect_changed = FALSE;
290 
291     if(!hwnd || (host->hwnd && host->hwnd != hwnd)) {
292         FIXME("unhandled hwnd\n");
293         return;
294     }
295 
296     TRACE("%p %s\n", hwnd, wine_dbgstr_rect(rect));
297 
298     if(memcmp(rect, &host->rect, sizeof(RECT))) {
299         host->rect = *rect;
300         rect_changed = TRUE;
301     }
302 
303     if(!host->hwnd) {
304         host->hwnd = hwnd;
305         embed_plugin_object(host);
306     }
307 
308     if(rect_changed && host->ip_object)
309         IOleInPlaceObject_SetObjectRects(host->ip_object, &host->rect, &host->rect);
310 }
311 
312 static void notif_enabled(PluginHost *plugin_host)
313 {
314     DISPPARAMS args = {NULL, NULL, 0, 0};
315     IDispatch *disp;
316     ULONG err = 0;
317     VARIANT res;
318     HRESULT hres;
319 
320     hres = IUnknown_QueryInterface(plugin_host->plugin_unk, &IID_IDispatch, (void**)&disp);
321     if(FAILED(hres)) {
322         FIXME("Could not get IDispatch iface: %08x\n", hres);
323         return;
324     }
325 
326     V_VT(&res) = VT_EMPTY;
327     hres = IDispatch_Invoke(disp, DISPID_ENABLED, &IID_NULL, 0/*FIXME*/, DISPATCH_PROPERTYGET, &args, &res, NULL, &err);
328     IDispatch_Release(disp);
329     if(SUCCEEDED(hres)) {
330         FIXME("Got enabled %s\n", debugstr_variant(&res));
331         VariantClear(&res);
332     }
333 }
334 
335 void notif_container_change(HTMLPluginContainer *plugin_container, DISPID dispid)
336 {
337     IOleControl *ole_control;
338     HRESULT hres;
339 
340     if(!plugin_container->plugin_host || !plugin_container->plugin_host->plugin_unk)
341         return;
342 
343     notif_enabled(plugin_container->plugin_host);
344 
345     hres = IUnknown_QueryInterface(plugin_container->plugin_host->plugin_unk, &IID_IOleControl, (void**)&ole_control);
346     if(SUCCEEDED(hres)) {
347         IOleControl_OnAmbientPropertyChange(ole_control, dispid);
348         IOleControl_Release(ole_control);
349     }
350 }
351 
352 HRESULT get_plugin_disp(HTMLPluginContainer *plugin_container, IDispatch **ret)
353 {
354     PluginHost *host;
355 
356     host = plugin_container->plugin_host;
357     if(!host) {
358         ERR("No plugin host\n");
359         return E_UNEXPECTED;
360     }
361 
362     if(!host->disp) {
363         *ret = NULL;
364         return S_OK;
365     }
366 
367     if(!check_script_safety(host)) {
368         FIXME("Insecure object\n");
369         return E_FAIL;
370     }
371 
372     IDispatch_AddRef(host->disp);
373     *ret = host->disp;
374     return S_OK;
375 }
376 
377 HRESULT get_plugin_dispid(HTMLPluginContainer *plugin_container, WCHAR *name, DISPID *ret)
378 {
379     IDispatch *disp;
380     DISPID id;
381     DWORD i;
382     HRESULT hres;
383 
384     if(!plugin_container->plugin_host) {
385         WARN("no plugin host\n");
386         return DISP_E_UNKNOWNNAME;
387     }
388 
389     disp = plugin_container->plugin_host->disp;
390     if(!disp)
391         return DISP_E_UNKNOWNNAME;
392 
393     hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &name, 1, 0, &id);
394     if(FAILED(hres)) {
395         TRACE("no prop %s\n", debugstr_w(name));
396         return DISP_E_UNKNOWNNAME;
397     }
398 
399     for(i=0; i < plugin_container->props_len; i++) {
400         if(id == plugin_container->props[i]) {
401             *ret = MSHTML_DISPID_CUSTOM_MIN+i;
402             return S_OK;
403         }
404     }
405 
406     if(!plugin_container->props) {
407         plugin_container->props = heap_alloc(8*sizeof(DISPID));
408         if(!plugin_container->props)
409             return E_OUTOFMEMORY;
410         plugin_container->props_size = 8;
411     }else if(plugin_container->props_len == plugin_container->props_size) {
412         DISPID *new_props;
413 
414         new_props = heap_realloc(plugin_container->props, plugin_container->props_size*2*sizeof(DISPID));
415         if(!new_props)
416             return E_OUTOFMEMORY;
417 
418         plugin_container->props = new_props;
419         plugin_container->props_size *= 2;
420     }
421 
422     plugin_container->props[plugin_container->props_len] = id;
423     *ret = MSHTML_DISPID_CUSTOM_MIN+plugin_container->props_len;
424     plugin_container->props_len++;
425     return S_OK;
426 }
427 
428 HRESULT invoke_plugin_prop(HTMLPluginContainer *plugin_container, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
429         VARIANT *res, EXCEPINFO *ei)
430 {
431     PluginHost *host;
432 
433     host = plugin_container->plugin_host;
434     if(!host || !host->disp) {
435         FIXME("Called with no disp\n");
436         return E_UNEXPECTED;
437     }
438 
439     if(!check_script_safety(host)) {
440         FIXME("Insecure object\n");
441         return E_FAIL;
442     }
443 
444     if(id < MSHTML_DISPID_CUSTOM_MIN || id > MSHTML_DISPID_CUSTOM_MIN + plugin_container->props_len) {
445         ERR("Invalid id\n");
446         return E_FAIL;
447     }
448 
449     return IDispatch_Invoke(host->disp, plugin_container->props[id-MSHTML_DISPID_CUSTOM_MIN], &IID_NULL,
450             lcid, flags, params, res, ei, NULL);
451 }
452 
453 typedef struct {
454     DISPID id;
455     IDispatch *disp;
456 } sink_entry_t;
457 
458 struct PHEventSink {
459     IDispatch IDispatch_iface;
460 
461     LONG ref;
462 
463     PluginHost *host;
464     ITypeInfo *typeinfo;
465     GUID iid;
466     DWORD cookie;
467     BOOL is_dispiface;
468 
469     sink_entry_t *handlers;
470     DWORD handlers_cnt;
471     DWORD handlers_size;
472 };
473 
474 static sink_entry_t *find_sink_entry(PHEventSink *sink, DISPID id)
475 {
476     sink_entry_t *iter;
477 
478     for(iter = sink->handlers; iter < sink->handlers+sink->handlers_cnt; iter++) {
479         if(iter->id == id)
480             return iter;
481     }
482 
483     return NULL;
484 }
485 
486 static void add_sink_handler(PHEventSink *sink, DISPID id, IDispatch *disp)
487 {
488     sink_entry_t *entry = find_sink_entry(sink, id);
489 
490     if(entry) {
491         if(entry->disp)
492             IDispatch_Release(entry->disp);
493     }else {
494         if(!sink->handlers_size) {
495             sink->handlers = heap_alloc(4*sizeof(*sink->handlers));
496             if(!sink->handlers)
497                 return;
498             sink->handlers_size = 4;
499         }else if(sink->handlers_cnt == sink->handlers_size) {
500             sink_entry_t *new_handlers;
501 
502             new_handlers = heap_realloc(sink->handlers, 2*sink->handlers_size*sizeof(*sink->handlers));
503             if(!new_handlers)
504                 return;
505             sink->handlers = new_handlers;
506             sink->handlers_size *= 2;
507         }
508         entry = sink->handlers + sink->handlers_cnt++;
509         entry->id = id;
510     }
511 
512     IDispatch_AddRef(disp);
513     entry->disp = disp;
514 }
515 
516 static inline PHEventSink *PHEventSink_from_IDispatch(IDispatch *iface)
517 {
518     return CONTAINING_RECORD(iface, PHEventSink, IDispatch_iface);
519 }
520 
521 static HRESULT WINAPI PHEventSink_QueryInterface(IDispatch *iface, REFIID riid, void **ppv)
522 {
523     PHEventSink *This = PHEventSink_from_IDispatch(iface);
524 
525     if(IsEqualGUID(riid, &IID_IUnknown)) {
526         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
527         *ppv = &This->IDispatch_iface;
528     }else if(IsEqualGUID(riid, &IID_IDispatch)) {
529         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
530         *ppv = &This->IDispatch_iface;
531     }else if(This->is_dispiface && IsEqualGUID(riid, &This->iid)) {
532         TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
533         *ppv = &This->IDispatch_iface;
534     }else {
535         WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
536         *ppv = NULL;
537         return E_NOINTERFACE;
538     }
539 
540     IUnknown_AddRef((IUnknown*)*ppv);
541     return S_OK;
542 }
543 
544 static ULONG WINAPI PHEventSink_AddRef(IDispatch *iface)
545 {
546     PHEventSink *This = PHEventSink_from_IDispatch(iface);
547     LONG ref = InterlockedIncrement(&This->ref);
548 
549     TRACE("(%p)\n", This);
550 
551     return ref;
552 }
553 
554 static ULONG WINAPI PHEventSink_Release(IDispatch *iface)
555 {
556     PHEventSink *This = PHEventSink_from_IDispatch(iface);
557     LONG ref = InterlockedDecrement(&This->ref);
558 
559     TRACE("(%p)\n", This);
560 
561     if(!ref) {
562         unsigned i;
563 
564         assert(!This->host);
565 
566         for(i=0; i < This->handlers_cnt; i++) {
567             if(This->handlers[i].disp)
568                 IDispatch_Release(This->handlers[i].disp);
569         }
570         heap_free(This->handlers);
571         heap_free(This);
572     }
573 
574     return ref;
575 }
576 
577 static HRESULT WINAPI PHEventSink_GetTypeInfoCount(IDispatch *iface, UINT *pctinfo)
578 {
579     PHEventSink *This = PHEventSink_from_IDispatch(iface);
580     FIXME("(%p)->(%p)\n", This, pctinfo);
581     return E_NOTIMPL;
582 }
583 
584 static HRESULT WINAPI PHEventSink_GetTypeInfo(IDispatch *iface, UINT iTInfo,
585         LCID lcid, ITypeInfo **ppTInfo)
586 {
587     PHEventSink *This = PHEventSink_from_IDispatch(iface);
588     FIXME("(%p)->(%d %d %p)\n", This, iTInfo, lcid, ppTInfo);
589     return E_NOTIMPL;
590 }
591 
592 static HRESULT WINAPI PHEventSink_GetIDsOfNames(IDispatch *iface, REFIID riid, LPOLESTR *rgszNames,
593         UINT cNames, LCID lcid, DISPID *rgDispId)
594 {
595     PHEventSink *This = PHEventSink_from_IDispatch(iface);
596     FIXME("(%p)->(%s %p %u %d %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
597     return E_NOTIMPL;
598 }
599 
600 static HRESULT WINAPI PHEventSink_Invoke(IDispatch *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
601         WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
602 {
603     PHEventSink *This = PHEventSink_from_IDispatch(iface);
604     IDispatchEx *dispex;
605     sink_entry_t *entry;
606     HRESULT hres;
607 
608     TRACE("(%p)->(%d %s %d %x %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), lcid, wFlags,
609           pDispParams, pVarResult, pExcepInfo, puArgErr);
610 
611     if(!This->host) {
612         WARN("No host\n");
613         return E_UNEXPECTED;
614     }
615 
616     entry = find_sink_entry(This, dispIdMember);
617     if(!entry || !entry->disp) {
618         WARN("No handler %d\n", dispIdMember);
619         if(pVarResult)
620             V_VT(pVarResult) = VT_EMPTY;
621         return S_OK;
622     }
623 
624     hres = IDispatch_QueryInterface(entry->disp, &IID_IDispatchEx, (void**)&dispex);
625 
626     TRACE("(%p) %d >>>\n", This, entry->id);
627     if(SUCCEEDED(hres)) {
628         hres = IDispatchEx_InvokeEx(dispex, DISPID_VALUE, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, NULL);
629         IDispatchEx_Release(dispex);
630     }else {
631         hres = IDispatch_Invoke(entry->disp, DISPID_VALUE, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
632     }
633     if(SUCCEEDED(hres))
634         TRACE("(%p) %d <<<\n", This, entry->id);
635     else
636         WARN("(%p) %d <<< %08x\n", This, entry->id, hres);
637     return hres;
638 }
639 
640 static const IDispatchVtbl PHCPDispatchVtbl = {
641     PHEventSink_QueryInterface,
642     PHEventSink_AddRef,
643     PHEventSink_Release,
644     PHEventSink_GetTypeInfoCount,
645     PHEventSink_GetTypeInfo,
646     PHEventSink_GetIDsOfNames,
647     PHEventSink_Invoke
648 };
649 
650 static PHEventSink *create_event_sink(PluginHost *plugin_host, ITypeInfo *typeinfo)
651 {
652     IConnectionPointContainer *cp_container;
653     PHEventSink *ret;
654     IConnectionPoint *cp;
655     TYPEATTR *typeattr;
656     TYPEKIND typekind;
657     GUID guid;
658     HRESULT hres;
659 
660     hres = ITypeInfo_GetTypeAttr(typeinfo, &typeattr);
661     if(FAILED(hres))
662         return NULL;
663 
664     typekind = typeattr->typekind;
665     guid = typeattr->guid;
666     ITypeInfo_ReleaseTypeAttr(typeinfo, typeattr);
667 
668     TRACE("guid %s typekind %d\n", debugstr_guid(&guid), typekind);
669 
670     if(typekind != TKIND_INTERFACE && typekind != TKIND_DISPATCH) {
671         WARN("invalid typekind %d\n", typekind);
672         return NULL;
673     }
674 
675     hres = IUnknown_QueryInterface(plugin_host->plugin_unk, &IID_IConnectionPointContainer, (void**)&cp_container);
676     if(FAILED(hres)) {
677         WARN("Could not get IConnectionPointContainer iface: %08x\n", hres);
678         return NULL;
679     }
680 
681     hres = IConnectionPointContainer_FindConnectionPoint(cp_container, &guid, &cp);
682     IConnectionPointContainer_Release(cp_container);
683     if(FAILED(hres)) {
684         WARN("Could not find %s connection point\n", debugstr_guid(&guid));
685         return NULL;
686     }
687 
688     ret = heap_alloc_zero(sizeof(*ret));
689     if(ret) {
690         ret->IDispatch_iface.lpVtbl = &PHCPDispatchVtbl;
691         ret->ref = 1;
692         ret->host = plugin_host;
693         ret->iid = guid;
694         ret->is_dispiface = typekind == TKIND_DISPATCH;
695 
696         ITypeInfo_AddRef(typeinfo);
697         ret->typeinfo = typeinfo;
698 
699         hres = IConnectionPoint_Advise(cp, (IUnknown*)&ret->IDispatch_iface, &ret->cookie);
700     }else {
701         hres = E_OUTOFMEMORY;
702     }
703 
704     IConnectionPoint_Release(cp);
705     if(FAILED(hres)) {
706         WARN("Advise failed: %08x\n", hres);
707         return NULL;
708     }
709 
710     return ret;
711 }
712 
713 static ITypeInfo *get_eventiface_info(HTMLPluginContainer *plugin_container, ITypeInfo *class_info)
714 {
715     int impl_types, i, impl_flags;
716     ITypeInfo *ret = NULL;
717     TYPEATTR *typeattr;
718     HREFTYPE ref;
719     HRESULT hres;
720 
721     hres = ITypeInfo_GetTypeAttr(class_info, &typeattr);
722     if(FAILED(hres))
723         return NULL;
724 
725     if(typeattr->typekind != TKIND_COCLASS) {
726         WARN("not coclass\n");
727         ITypeInfo_ReleaseTypeAttr(class_info, typeattr);
728         return NULL;
729     }
730 
731     impl_types = typeattr->cImplTypes;
732     ITypeInfo_ReleaseTypeAttr(class_info, typeattr);
733 
734     for(i=0; i<impl_types; i++) {
735         hres = ITypeInfo_GetImplTypeFlags(class_info, i, &impl_flags);
736         if(FAILED(hres))
737             continue;
738 
739         if((impl_flags & IMPLTYPEFLAG_FSOURCE)) {
740             if(!(impl_flags & IMPLTYPEFLAG_FDEFAULT)) {
741                 FIXME("Handle non-default source iface\n");
742                 continue;
743             }
744 
745             hres = ITypeInfo_GetRefTypeOfImplType(class_info, i, &ref);
746             if(FAILED(hres))
747                 continue;
748 
749             hres = ITypeInfo_GetRefTypeInfo(class_info, ref, &ret);
750             if(FAILED(hres))
751                 ret = NULL;
752         }
753     }
754 
755     return ret;
756 }
757 
758 void bind_activex_event(HTMLDocumentNode *doc, HTMLPluginContainer *plugin_container, WCHAR *event, IDispatch *disp)
759 {
760     PluginHost *plugin_host = plugin_container->plugin_host;
761     ITypeInfo *class_info, *source_info;
762     DISPID id;
763     HRESULT hres;
764 
765     TRACE("(%p %p %s %p)\n", doc, plugin_host, debugstr_w(event), disp);
766 
767     if(!plugin_host || !plugin_host->plugin_unk) {
768         WARN("detached element %p\n", plugin_host);
769         return;
770     }
771 
772     if(plugin_host->sink) {
773         source_info = plugin_host->sink->typeinfo;
774         ITypeInfo_AddRef(source_info);
775     }else {
776         IProvideClassInfo *provide_ci;
777 
778         hres = IUnknown_QueryInterface(plugin_host->plugin_unk, &IID_IProvideClassInfo, (void**)&provide_ci);
779         if(FAILED(hres)) {
780             FIXME("No IProvideClassInfo, try GetTypeInfo?\n");
781             return;
782         }
783 
784         hres = IProvideClassInfo_GetClassInfo(provide_ci, &class_info);
785         IProvideClassInfo_Release(provide_ci);
786         if(FAILED(hres) || !class_info) {
787             WARN("GetClassInfo failed: %08x\n", hres);
788             return;
789         }
790 
791         source_info = get_eventiface_info(plugin_container, class_info);
792         ITypeInfo_Release(class_info);
793         if(!source_info)
794             return;
795     }
796 
797     hres = ITypeInfo_GetIDsOfNames(source_info, &event, 1, &id);
798     if(FAILED(hres))
799         WARN("Could not get disp id: %08x\n", hres);
800     else if(!plugin_host->sink)
801         plugin_host->sink = create_event_sink(plugin_host, source_info);
802 
803     ITypeInfo_Release(source_info);
804     if(FAILED(hres) || !plugin_host->sink)
805         return;
806 
807     add_sink_handler(plugin_host->sink, id, disp);
808 }
809 
810 static inline PluginHost *impl_from_IOleClientSite(IOleClientSite *iface)
811 {
812     return CONTAINING_RECORD(iface, PluginHost, IOleClientSite_iface);
813 }
814 
815 static HRESULT WINAPI PHClientSite_QueryInterface(IOleClientSite *iface, REFIID riid, void **ppv)
816 {
817     PluginHost *This = impl_from_IOleClientSite(iface);
818 
819     if(IsEqualGUID(&IID_IUnknown, riid)) {
820         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
821         *ppv = &This->IOleClientSite_iface;
822     }else if(IsEqualGUID(&IID_IOleClientSite, riid)) {
823         TRACE("(%p)->(IID_IOleClientSite %p)\n", This, ppv);
824         *ppv = &This->IOleClientSite_iface;
825     }else if(IsEqualGUID(&IID_IAdviseSink, riid)) {
826         TRACE("(%p)->(IID_IAdviseSink %p)\n", This, ppv);
827         *ppv = &This->IAdviseSinkEx_iface;
828     }else if(IsEqualGUID(&IID_IAdviseSinkEx, riid)) {
829         TRACE("(%p)->(IID_IAdviseSinkEx %p)\n", This, ppv);
830         *ppv = &This->IAdviseSinkEx_iface;
831     }else if(IsEqualGUID(&IID_IPropertyNotifySink, riid)) {
832         TRACE("(%p)->(IID_IPropertyNotifySink %p)\n", This, ppv);
833         *ppv = &This->IPropertyNotifySink_iface;
834     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
835         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
836         *ppv = &This->IDispatch_iface;
837     }else if(IsEqualGUID(&IID_IOleWindow, riid)) {
838         TRACE("(%p)->(IID_IOleWindow %p)\n", This, ppv);
839         *ppv = &This->IOleInPlaceSiteEx_iface;
840     }else if(IsEqualGUID(&IID_IOleInPlaceSite, riid)) {
841         TRACE("(%p)->(IID_IOleInPlaceSite %p)\n", This, ppv);
842         *ppv = &This->IOleInPlaceSiteEx_iface;
843     }else if(IsEqualGUID(&IID_IOleInPlaceSiteEx, riid)) {
844         TRACE("(%p)->(IID_IOleInPlaceSiteEx %p)\n", This, ppv);
845         *ppv = &This->IOleInPlaceSiteEx_iface;
846     }else if(IsEqualGUID(&IID_IOleControlSite, riid)) {
847         TRACE("(%p)->(IID_IOleControlSite %p)\n", This, ppv);
848         *ppv = &This->IOleControlSite_iface;
849     }else if(IsEqualGUID(&IID_IBindHost, riid)) {
850         TRACE("(%p)->(IID_IBindHost %p)\n", This, ppv);
851         *ppv = &This->IBindHost_iface;
852     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
853         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
854         *ppv = &This->IServiceProvider_iface;
855     }else {
856         WARN("Unsupported interface %s\n", debugstr_guid(riid));
857         *ppv = NULL;
858         return E_NOINTERFACE;
859     }
860 
861     IUnknown_AddRef((IUnknown*)*ppv);
862     return S_OK;
863 }
864 
865 static ULONG WINAPI PHClientSite_AddRef(IOleClientSite *iface)
866 {
867     PluginHost *This = impl_from_IOleClientSite(iface);
868     LONG ref = InterlockedIncrement(&This->ref);
869 
870     TRACE("(%p) ref=%d\n", This, ref);
871 
872     return ref;
873 }
874 
875 static void release_plugin_ifaces(PluginHost *This)
876 {
877     if(This->disp) {
878         IDispatch_Release(This->disp);
879         This->disp = NULL;
880     }
881 
882     if(This->ip_object) {
883         IOleInPlaceObject_Release(This->ip_object);
884         This->ip_object = NULL;
885     }
886 
887     if(This->plugin_unk) {
888         IUnknown *unk = This->plugin_unk;
889         LONG ref;
890 
891         This->plugin_unk = NULL;
892         ref = IUnknown_Release(unk);
893 
894         TRACE("plugin ref = %d\n", ref);
895     }
896 }
897 
898 static ULONG WINAPI PHClientSite_Release(IOleClientSite *iface)
899 {
900     PluginHost *This = impl_from_IOleClientSite(iface);
901     LONG ref = InterlockedDecrement(&This->ref);
902 
903     TRACE("(%p) ref=%d\n", This, ref);
904 
905     if(!ref) {
906         release_plugin_ifaces(This);
907         if(This->sink) {
908             This->sink->host = NULL;
909             IDispatch_Release(&This->sink->IDispatch_iface);
910             This->sink = NULL;
911         }
912         list_remove(&This->entry);
913         if(This->element)
914             This->element->plugin_host = NULL;
915         heap_free(This);
916     }
917 
918     return ref;
919 }
920 
921 static HRESULT WINAPI PHClientSite_SaveObject(IOleClientSite *iface)
922 {
923     PluginHost *This = impl_from_IOleClientSite(iface);
924     FIXME("(%p)\n", This);
925     return E_NOTIMPL;
926 }
927 
928 static HRESULT WINAPI PHClientSite_GetMoniker(IOleClientSite *iface, DWORD dwAssign,
929         DWORD dwWhichMoniker, IMoniker **ppmk)
930 {
931     PluginHost *This = impl_from_IOleClientSite(iface);
932 
933     TRACE("(%p)->(%d %d %p)\n", This, dwAssign, dwWhichMoniker, ppmk);
934 
935     switch(dwWhichMoniker) {
936     case OLEWHICHMK_CONTAINER:
937         if(!This->doc || !This->doc->window || !This->doc->window->mon) {
938             FIXME("no moniker\n");
939             return E_UNEXPECTED;
940         }
941 
942         *ppmk = This->doc->window->mon;
943         IMoniker_AddRef(*ppmk);
944         break;
945     default:
946         FIXME("which %d\n", dwWhichMoniker);
947         return E_NOTIMPL;
948     }
949 
950     return S_OK;
951 }
952 
953 static HRESULT WINAPI PHClientSite_GetContainer(IOleClientSite *iface, IOleContainer **ppContainer)
954 {
955     PluginHost *This = impl_from_IOleClientSite(iface);
956 
957     TRACE("(%p)->(%p)\n", This, ppContainer);
958 
959     if(!This->doc) {
960         ERR("Called on detached object\n");
961         return E_UNEXPECTED;
962     }
963 
964     *ppContainer = &This->doc->basedoc.IOleContainer_iface;
965     IOleContainer_AddRef(*ppContainer);
966     return S_OK;
967 }
968 
969 static HRESULT WINAPI PHClientSite_ShowObject(IOleClientSite *iface)
970 {
971     PluginHost *This = impl_from_IOleClientSite(iface);
972 
973     TRACE("(%p)\n", This);
974 
975     return S_OK;
976 }
977 
978 static HRESULT WINAPI PHClientSite_OnShowWindow(IOleClientSite *iface, BOOL fShow)
979 {
980     PluginHost *This = impl_from_IOleClientSite(iface);
981     FIXME("(%p)->(%x)\n", This, fShow);
982     return E_NOTIMPL;
983 }
984 
985 static HRESULT WINAPI PHClientSite_RequestNewObjectLayout(IOleClientSite *iface)
986 {
987     PluginHost *This = impl_from_IOleClientSite(iface);
988     FIXME("(%p)\n", This);
989     return E_NOTIMPL;
990 }
991 
992 static const IOleClientSiteVtbl OleClientSiteVtbl = {
993     PHClientSite_QueryInterface,
994     PHClientSite_AddRef,
995     PHClientSite_Release,
996     PHClientSite_SaveObject,
997     PHClientSite_GetMoniker,
998     PHClientSite_GetContainer,
999     PHClientSite_ShowObject,
1000     PHClientSite_OnShowWindow,
1001     PHClientSite_RequestNewObjectLayout
1002 };
1003 
1004 static inline PluginHost *impl_from_IAdviseSinkEx(IAdviseSinkEx *iface)
1005 {
1006     return CONTAINING_RECORD(iface, PluginHost, IAdviseSinkEx_iface);
1007 }
1008 
1009 static HRESULT WINAPI PHAdviseSinkEx_QueryInterface(IAdviseSinkEx *iface, REFIID riid, void **ppv)
1010 {
1011     PluginHost *This = impl_from_IAdviseSinkEx(iface);
1012     return IOleClientSite_QueryInterface(&This->IOleClientSite_iface, riid, ppv);
1013 }
1014 
1015 static ULONG WINAPI PHAdviseSinkEx_AddRef(IAdviseSinkEx *iface)
1016 {
1017     PluginHost *This = impl_from_IAdviseSinkEx(iface);
1018     return IOleClientSite_AddRef(&This->IOleClientSite_iface);
1019 }
1020 
1021 static ULONG WINAPI PHAdviseSinkEx_Release(IAdviseSinkEx *iface)
1022 {
1023     PluginHost *This = impl_from_IAdviseSinkEx(iface);
1024     return IOleClientSite_Release(&This->IOleClientSite_iface);
1025 }
1026 
1027 static void WINAPI PHAdviseSinkEx_OnDataChange(IAdviseSinkEx *iface, FORMATETC *pFormatetc, STGMEDIUM *pStgMedium)
1028 {
1029     PluginHost *This = impl_from_IAdviseSinkEx(iface);
1030     FIXME("(%p)->(%p %p)\n", This, pFormatetc, pStgMedium);
1031 }
1032 
1033 static void WINAPI PHAdviseSinkEx_OnViewChange(IAdviseSinkEx *iface, DWORD dwAspect, LONG lindex)
1034 {
1035     PluginHost *This = impl_from_IAdviseSinkEx(iface);
1036     FIXME("(%p)->(%d %d)\n", This, dwAspect, lindex);
1037 }
1038 
1039 static void WINAPI PHAdviseSinkEx_OnRename(IAdviseSinkEx *iface, IMoniker *pmk)
1040 {
1041     PluginHost *This = impl_from_IAdviseSinkEx(iface);
1042     FIXME("(%p)->(%p)\n", This, pmk);
1043 }
1044 
1045 static void WINAPI PHAdviseSinkEx_OnSave(IAdviseSinkEx *iface)
1046 {
1047     PluginHost *This = impl_from_IAdviseSinkEx(iface);
1048     FIXME("(%p)\n", This);
1049 }
1050 
1051 static void WINAPI PHAdviseSinkEx_OnClose(IAdviseSinkEx *iface)
1052 {
1053     PluginHost *This = impl_from_IAdviseSinkEx(iface);
1054     FIXME("(%p)\n", This);
1055 }
1056 
1057 static void WINAPI PHAdviseSinkEx_OnViewStatusChange(IAdviseSinkEx *iface, DWORD dwViewStatus)
1058 {
1059     PluginHost *This = impl_from_IAdviseSinkEx(iface);
1060     FIXME("(%p)->(%d)\n", This, dwViewStatus);
1061 }
1062 
1063 static const IAdviseSinkExVtbl AdviseSinkExVtbl = {
1064     PHAdviseSinkEx_QueryInterface,
1065     PHAdviseSinkEx_AddRef,
1066     PHAdviseSinkEx_Release,
1067     PHAdviseSinkEx_OnDataChange,
1068     PHAdviseSinkEx_OnViewChange,
1069     PHAdviseSinkEx_OnRename,
1070     PHAdviseSinkEx_OnSave,
1071     PHAdviseSinkEx_OnClose,
1072     PHAdviseSinkEx_OnViewStatusChange
1073 };
1074 
1075 static inline PluginHost *impl_from_IPropertyNotifySink(IPropertyNotifySink *iface)
1076 {
1077     return CONTAINING_RECORD(iface, PluginHost, IPropertyNotifySink_iface);
1078 }
1079 
1080 static HRESULT WINAPI PHPropertyNotifySink_QueryInterface(IPropertyNotifySink *iface, REFIID riid, void **ppv)
1081 {
1082     PluginHost *This = impl_from_IPropertyNotifySink(iface);
1083     return IOleClientSite_QueryInterface(&This->IOleClientSite_iface, riid, ppv);
1084 }
1085 
1086 static ULONG WINAPI PHPropertyNotifySink_AddRef(IPropertyNotifySink *iface)
1087 {
1088     PluginHost *This = impl_from_IPropertyNotifySink(iface);
1089     return IOleClientSite_AddRef(&This->IOleClientSite_iface);
1090 }
1091 
1092 static ULONG WINAPI PHPropertyNotifySink_Release(IPropertyNotifySink *iface)
1093 {
1094     PluginHost *This = impl_from_IPropertyNotifySink(iface);
1095     return IOleClientSite_Release(&This->IOleClientSite_iface);
1096 }
1097 
1098 static HRESULT WINAPI PHPropertyNotifySink_OnChanged(IPropertyNotifySink *iface, DISPID dispID)
1099 {
1100     PluginHost *This = impl_from_IPropertyNotifySink(iface);
1101 
1102     TRACE("(%p)->(%d)\n", This, dispID);
1103 
1104     switch(dispID) {
1105     case DISPID_READYSTATE:
1106         update_readystate(This);
1107         break;
1108     default :
1109         FIXME("Unimplemented dispID %d\n", dispID);
1110         return E_NOTIMPL;
1111     }
1112 
1113     return S_OK;
1114 }
1115 
1116 static HRESULT WINAPI PHPropertyNotifySink_OnRequestEdit(IPropertyNotifySink *iface, DISPID dispID)
1117 {
1118     PluginHost *This = impl_from_IPropertyNotifySink(iface);
1119     FIXME("(%p)->(%d)\n", This, dispID);
1120     return E_NOTIMPL;
1121 }
1122 
1123 static const IPropertyNotifySinkVtbl PropertyNotifySinkVtbl = {
1124     PHPropertyNotifySink_QueryInterface,
1125     PHPropertyNotifySink_AddRef,
1126     PHPropertyNotifySink_Release,
1127     PHPropertyNotifySink_OnChanged,
1128     PHPropertyNotifySink_OnRequestEdit
1129 };
1130 
1131 static inline PluginHost *impl_from_IDispatch(IDispatch *iface)
1132 {
1133     return CONTAINING_RECORD(iface, PluginHost, IDispatch_iface);
1134 }
1135 
1136 static HRESULT WINAPI PHDispatch_QueryInterface(IDispatch *iface, REFIID riid, void **ppv)
1137 {
1138     PluginHost *This = impl_from_IDispatch(iface);
1139     return IOleClientSite_QueryInterface(&This->IOleClientSite_iface, riid, ppv);
1140 }
1141 
1142 static ULONG WINAPI PHDispatch_AddRef(IDispatch *iface)
1143 {
1144     PluginHost *This = impl_from_IDispatch(iface);
1145     return IOleClientSite_AddRef(&This->IOleClientSite_iface);
1146 }
1147 
1148 static ULONG WINAPI PHDispatch_Release(IDispatch *iface)
1149 {
1150     PluginHost *This = impl_from_IDispatch(iface);
1151     return IOleClientSite_Release(&This->IOleClientSite_iface);
1152 }
1153 
1154 static HRESULT WINAPI PHDispatch_GetTypeInfoCount(IDispatch *iface, UINT *pctinfo)
1155 {
1156     PluginHost *This = impl_from_IDispatch(iface);
1157     FIXME("(%p)->(%p)\n", This, pctinfo);
1158     return E_NOTIMPL;
1159 }
1160 
1161 static HRESULT WINAPI PHDispatch_GetTypeInfo(IDispatch *iface, UINT iTInfo,
1162         LCID lcid, ITypeInfo **ppTInfo)
1163 {
1164     PluginHost *This = impl_from_IDispatch(iface);
1165     FIXME("(%p)->(%d %d %p)\n", This, iTInfo, lcid, ppTInfo);
1166     return E_NOTIMPL;
1167 }
1168 
1169 static HRESULT WINAPI PHDispatch_GetIDsOfNames(IDispatch *iface, REFIID riid,
1170         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
1171 {
1172     PluginHost *This = impl_from_IDispatch(iface);
1173     FIXME("(%p)->(%s %p %d %d %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1174     return E_NOTIMPL;
1175 }
1176 
1177 static HRESULT WINAPI PHDispatch_Invoke(IDispatch *iface, DISPID dispid,  REFIID riid, LCID lcid,
1178         WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1179 {
1180     PluginHost *This = impl_from_IDispatch(iface);
1181     FIXME("(%p)->(%d %x %p %p)\n", This, dispid, wFlags, pDispParams, pVarResult);
1182     return E_NOTIMPL;
1183 }
1184 
1185 static const IDispatchVtbl DispatchVtbl = {
1186     PHDispatch_QueryInterface,
1187     PHDispatch_AddRef,
1188     PHDispatch_Release,
1189     PHDispatch_GetTypeInfoCount,
1190     PHDispatch_GetTypeInfo,
1191     PHDispatch_GetIDsOfNames,
1192     PHDispatch_Invoke
1193 };
1194 
1195 static inline PluginHost *impl_from_IOleInPlaceSiteEx(IOleInPlaceSiteEx *iface)
1196 {
1197     return CONTAINING_RECORD(iface, PluginHost, IOleInPlaceSiteEx_iface);
1198 }
1199 
1200 static HRESULT WINAPI PHInPlaceSite_QueryInterface(IOleInPlaceSiteEx *iface, REFIID riid, void **ppv)
1201 {
1202     PluginHost *This = impl_from_IOleInPlaceSiteEx(iface);
1203     return IOleClientSite_QueryInterface(&This->IOleClientSite_iface, riid, ppv);
1204 }
1205 
1206 static ULONG WINAPI PHInPlaceSite_AddRef(IOleInPlaceSiteEx *iface)
1207 {
1208     PluginHost *This = impl_from_IOleInPlaceSiteEx(iface);
1209     return IOleClientSite_AddRef(&This->IOleClientSite_iface);
1210 }
1211 
1212 static ULONG WINAPI PHInPlaceSite_Release(IOleInPlaceSiteEx *iface)
1213 {
1214     PluginHost *This = impl_from_IOleInPlaceSiteEx(iface);
1215     return IOleClientSite_Release(&This->IOleClientSite_iface);
1216 }
1217 
1218 static HRESULT WINAPI PHInPlaceSite_GetWindow(IOleInPlaceSiteEx *iface, HWND *phwnd)
1219 {
1220     PluginHost *This = impl_from_IOleInPlaceSiteEx(iface);
1221 
1222     TRACE("(%p)->(%p)\n", This, phwnd);
1223 
1224     *phwnd = This->hwnd;
1225     return S_OK;
1226 }
1227 
1228 static HRESULT WINAPI PHInPlaceSite_ContextSensitiveHelp(IOleInPlaceSiteEx *iface, BOOL fEnterMode)
1229 {
1230     PluginHost *This = impl_from_IOleInPlaceSiteEx(iface);
1231     FIXME("(%p)->(%x)\n", This, fEnterMode);
1232     return E_NOTIMPL;
1233 }
1234 
1235 static HRESULT WINAPI PHInPlaceSite_CanInPlaceActivate(IOleInPlaceSiteEx *iface)
1236 {
1237     PluginHost *This = impl_from_IOleInPlaceSiteEx(iface);
1238 
1239     TRACE("(%p)\n", This);
1240 
1241     return S_OK;
1242 }
1243 
1244 static HRESULT WINAPI PHInPlaceSite_OnInPlaceActivate(IOleInPlaceSiteEx *iface)
1245 {
1246     PluginHost *This = impl_from_IOleInPlaceSiteEx(iface);
1247     FIXME("(%p)\n", This);
1248     return E_NOTIMPL;
1249 }
1250 
1251 static HRESULT WINAPI PHInPlaceSite_OnUIActivate(IOleInPlaceSiteEx *iface)
1252 {
1253     PluginHost *This = impl_from_IOleInPlaceSiteEx(iface);
1254 
1255     TRACE("(%p)\n", This);
1256 
1257     if(!This->plugin_unk) {
1258         ERR("No plugin object\n");
1259         return E_UNEXPECTED;
1260     }
1261 
1262     This->ui_active = TRUE;
1263 
1264     notif_enabled(This);
1265     return S_OK;
1266 }
1267 
1268 static HRESULT WINAPI PHInPlaceSite_GetWindowContext(IOleInPlaceSiteEx *iface,
1269         IOleInPlaceFrame **ppFrame, IOleInPlaceUIWindow **ppDoc, RECT *lprcPosRect,
1270         RECT *lprcClipRect, OLEINPLACEFRAMEINFO *frame_info)
1271 {
1272     PluginHost *This = impl_from_IOleInPlaceSiteEx(iface);
1273     IOleInPlaceUIWindow *ip_window;
1274     IOleInPlaceFrame *ip_frame;
1275     RECT pr, cr;
1276     HRESULT hres;
1277 
1278     TRACE("(%p)->(%p %p %p %p %p)\n", This, ppFrame, ppDoc, lprcPosRect, lprcClipRect, frame_info);
1279 
1280     if(!This->doc || !This->doc->basedoc.doc_obj || !This->doc->basedoc.doc_obj->ipsite) {
1281         FIXME("No ipsite\n");
1282         return E_UNEXPECTED;
1283     }
1284 
1285     hres = IOleInPlaceSite_GetWindowContext(This->doc->basedoc.doc_obj->ipsite, &ip_frame, &ip_window, &pr, &cr, frame_info);
1286     if(FAILED(hres)) {
1287         WARN("GetWindowContext failed: %08x\n", hres);
1288         return hres;
1289     }
1290 
1291     if(ip_window)
1292         IOleInPlaceUIWindow_Release(ip_window);
1293     if(ip_frame)
1294         IOleInPlaceFrame_Release(ip_frame);
1295 
1296     hres = create_ip_frame(&ip_frame);
1297     if(FAILED(hres))
1298         return hres;
1299 
1300     hres = create_ip_window(ppDoc);
1301     if(FAILED(hres)) {
1302         IOleInPlaceFrame_Release(ip_frame);
1303         return hres;
1304     }
1305 
1306     *ppFrame = ip_frame;
1307     *lprcPosRect = This->rect;
1308     *lprcClipRect = This->rect;
1309     return S_OK;
1310 }
1311 
1312 static HRESULT WINAPI PHInPlaceSite_Scroll(IOleInPlaceSiteEx *iface, SIZE scrollExtent)
1313 {
1314     PluginHost *This = impl_from_IOleInPlaceSiteEx(iface);
1315     FIXME("(%p)->({%d %d})\n", This, scrollExtent.cx, scrollExtent.cy);
1316     return E_NOTIMPL;
1317 }
1318 
1319 static HRESULT WINAPI PHInPlaceSite_OnUIDeactivate(IOleInPlaceSiteEx *iface, BOOL fUndoable)
1320 {
1321     PluginHost *This = impl_from_IOleInPlaceSiteEx(iface);
1322     FIXME("(%p)->(%x)\n", This, fUndoable);
1323     return E_NOTIMPL;
1324 }
1325 
1326 static HRESULT WINAPI PHInPlaceSite_OnInPlaceDeactivate(IOleInPlaceSiteEx *iface)
1327 {
1328     PluginHost *This = impl_from_IOleInPlaceSiteEx(iface);
1329 
1330     TRACE("(%p)\n", This);
1331 
1332     if(This->ip_object) {
1333         IOleInPlaceObject_Release(This->ip_object);
1334         This->ip_object = NULL;
1335     }
1336 
1337     return S_OK;
1338 }
1339 
1340 static HRESULT WINAPI PHInPlaceSite_DiscardUndoState(IOleInPlaceSiteEx *iface)
1341 {
1342     PluginHost *This = impl_from_IOleInPlaceSiteEx(iface);
1343     FIXME("(%p)\n", This);
1344     return E_NOTIMPL;
1345 }
1346 
1347 static HRESULT WINAPI PHInPlaceSite_DeactivateAndUndo(IOleInPlaceSiteEx *iface)
1348 {
1349     PluginHost *This = impl_from_IOleInPlaceSiteEx(iface);
1350     FIXME("(%p)\n", This);
1351     return E_NOTIMPL;
1352 }
1353 
1354 static HRESULT WINAPI PHInPlaceSite_OnPosRectChange(IOleInPlaceSiteEx *iface, LPCRECT lprcPosRect)
1355 {
1356     PluginHost *This = impl_from_IOleInPlaceSiteEx(iface);
1357     FIXME("(%p)->(%p)\n", This, lprcPosRect);
1358     return E_NOTIMPL;
1359 }
1360 
1361 static HRESULT WINAPI PHInPlaceSiteEx_OnInPlaceActivateEx(IOleInPlaceSiteEx *iface, BOOL *pfNoRedraw, DWORD dwFlags)
1362 {
1363     PluginHost *This = impl_from_IOleInPlaceSiteEx(iface);
1364     HWND hwnd;
1365     HRESULT hres;
1366 
1367     TRACE("(%p)->(%p %x)\n", This, pfNoRedraw, dwFlags);
1368 
1369     if(This->ip_object)
1370         return S_OK;
1371 
1372     hres = IUnknown_QueryInterface(This->plugin_unk, &IID_IOleInPlaceObject, (void**)&This->ip_object);
1373     if(FAILED(hres))
1374         return hres;
1375 
1376     hres = IOleInPlaceObject_GetWindow(This->ip_object, &hwnd);
1377     if(SUCCEEDED(hres))
1378         FIXME("Use hwnd %p\n", hwnd);
1379 
1380     *pfNoRedraw = FALSE;
1381     return S_OK;
1382 }
1383 
1384 static HRESULT WINAPI PHInPlaceSiteEx_OnInPlaceDeactivateEx(IOleInPlaceSiteEx *iface, BOOL fNoRedraw)
1385 {
1386     PluginHost *This = impl_from_IOleInPlaceSiteEx(iface);
1387     FIXME("(%p)->(%x)\n", This, fNoRedraw);
1388     return E_NOTIMPL;
1389 }
1390 
1391 static HRESULT WINAPI PHInPlaceSiteEx_RequestUIActivate(IOleInPlaceSiteEx *iface)
1392 {
1393     PluginHost *This = impl_from_IOleInPlaceSiteEx(iface);
1394     FIXME("(%p)\n", This);
1395     return E_NOTIMPL;
1396 }
1397 
1398 static const IOleInPlaceSiteExVtbl OleInPlaceSiteExVtbl = {
1399     PHInPlaceSite_QueryInterface,
1400     PHInPlaceSite_AddRef,
1401     PHInPlaceSite_Release,
1402     PHInPlaceSite_GetWindow,
1403     PHInPlaceSite_ContextSensitiveHelp,
1404     PHInPlaceSite_CanInPlaceActivate,
1405     PHInPlaceSite_OnInPlaceActivate,
1406     PHInPlaceSite_OnUIActivate,
1407     PHInPlaceSite_GetWindowContext,
1408     PHInPlaceSite_Scroll,
1409     PHInPlaceSite_OnUIDeactivate,
1410     PHInPlaceSite_OnInPlaceDeactivate,
1411     PHInPlaceSite_DiscardUndoState,
1412     PHInPlaceSite_DeactivateAndUndo,
1413     PHInPlaceSite_OnPosRectChange,
1414     PHInPlaceSiteEx_OnInPlaceActivateEx,
1415     PHInPlaceSiteEx_OnInPlaceDeactivateEx,
1416     PHInPlaceSiteEx_RequestUIActivate
1417 };
1418 
1419 static inline PluginHost *impl_from_IOleControlSite(IOleControlSite *iface)
1420 {
1421     return CONTAINING_RECORD(iface, PluginHost, IOleControlSite_iface);
1422 }
1423 
1424 static HRESULT WINAPI PHControlSite_QueryInterface(IOleControlSite *iface, REFIID riid, void **ppv)
1425 {
1426     PluginHost *This = impl_from_IOleControlSite(iface);
1427     return IOleClientSite_QueryInterface(&This->IOleClientSite_iface, riid, ppv);
1428 }
1429 
1430 static ULONG WINAPI PHControlSite_AddRef(IOleControlSite *iface)
1431 {
1432     PluginHost *This = impl_from_IOleControlSite(iface);
1433     return IOleClientSite_AddRef(&This->IOleClientSite_iface);
1434 }
1435 
1436 static ULONG WINAPI PHControlSite_Release(IOleControlSite *iface)
1437 {
1438     PluginHost *This = impl_from_IOleControlSite(iface);
1439     return IOleClientSite_Release(&This->IOleClientSite_iface);
1440 }
1441 
1442 static HRESULT WINAPI PHControlSite_OnControlInfoChanged(IOleControlSite *iface)
1443 {
1444     PluginHost *This = impl_from_IOleControlSite(iface);
1445     FIXME("(%p)\n", This);
1446     return E_NOTIMPL;
1447 }
1448 
1449 static HRESULT WINAPI PHControlSite_LockInPlaceActive(IOleControlSite *iface, BOOL fLock)
1450 {
1451     PluginHost *This = impl_from_IOleControlSite(iface);
1452     FIXME("(%p)->(%x)\n", This, fLock);
1453     return E_NOTIMPL;
1454 }
1455 
1456 static HRESULT WINAPI PHControlSite_GetExtendedControl(IOleControlSite *iface, IDispatch **ppDisp)
1457 {
1458     PluginHost *This = impl_from_IOleControlSite(iface);
1459     FIXME("(%p)->(%p)\n", This, ppDisp);
1460     return E_NOTIMPL;
1461 }
1462 
1463 static HRESULT WINAPI PHControlSite_TransformCoords(IOleControlSite *iface, POINTL *pPtlHimetric, POINTF *pPtfContainer, DWORD dwFlags)
1464 {
1465     PluginHost *This = impl_from_IOleControlSite(iface);
1466     FIXME("(%p)->(%p %p %x)\n", This, pPtlHimetric, pPtfContainer, dwFlags);
1467     return E_NOTIMPL;
1468 }
1469 
1470 static HRESULT WINAPI PHControlSite_TranslateAccelerator(IOleControlSite *iface, MSG *pMsg, DWORD grfModifiers)
1471 {
1472     PluginHost *This = impl_from_IOleControlSite(iface);
1473     FIXME("(%p)->(%x)\n", This, grfModifiers);
1474     return E_NOTIMPL;
1475 }
1476 
1477 static HRESULT WINAPI PHControlSite_OnFocus(IOleControlSite *iface, BOOL fGotFocus)
1478 {
1479     PluginHost *This = impl_from_IOleControlSite(iface);
1480     FIXME("(%p)->(%x)\n", This, fGotFocus);
1481     return E_NOTIMPL;
1482 }
1483 
1484 static HRESULT WINAPI PHControlSite_ShowPropertyFrame(IOleControlSite *iface)
1485 {
1486     PluginHost *This = impl_from_IOleControlSite(iface);
1487     FIXME("(%p)\n", This);
1488     return E_NOTIMPL;
1489 }
1490 
1491 static const IOleControlSiteVtbl OleControlSiteVtbl = {
1492     PHControlSite_QueryInterface,
1493     PHControlSite_AddRef,
1494     PHControlSite_Release,
1495     PHControlSite_OnControlInfoChanged,
1496     PHControlSite_LockInPlaceActive,
1497     PHControlSite_GetExtendedControl,
1498     PHControlSite_TransformCoords,
1499     PHControlSite_TranslateAccelerator,
1500     PHControlSite_OnFocus,
1501     PHControlSite_ShowPropertyFrame
1502 };
1503 
1504 static inline PluginHost *impl_from_IBindHost(IBindHost *iface)
1505 {
1506     return CONTAINING_RECORD(iface, PluginHost, IBindHost_iface);
1507 }
1508 
1509 static HRESULT WINAPI PHBindHost_QueryInterface(IBindHost *iface, REFIID riid, void **ppv)
1510 {
1511     PluginHost *This = impl_from_IBindHost(iface);
1512     return IOleClientSite_QueryInterface(&This->IOleClientSite_iface, riid, ppv);
1513 }
1514 
1515 static ULONG WINAPI PHBindHost_AddRef(IBindHost *iface)
1516 {
1517     PluginHost *This = impl_from_IBindHost(iface);
1518     return IOleClientSite_AddRef(&This->IOleClientSite_iface);
1519 }
1520 
1521 static ULONG WINAPI PHBindHost_Release(IBindHost *iface)
1522 {
1523     PluginHost *This = impl_from_IBindHost(iface);
1524     return IOleClientSite_Release(&This->IOleClientSite_iface);
1525 }
1526 
1527 static HRESULT WINAPI PHBindHost_CreateMoniker(IBindHost *iface, LPOLESTR szName, IBindCtx *pBC, IMoniker **ppmk, DWORD dwReserved)
1528 {
1529     PluginHost *This = impl_from_IBindHost(iface);
1530 
1531     TRACE("(%p)->(%s %p %p %x)\n", This, debugstr_w(szName), pBC, ppmk, dwReserved);
1532 
1533     if(!This->doc || !This->doc->window || !This->doc->window->mon) {
1534         FIXME("no moniker\n");
1535         return E_UNEXPECTED;
1536     }
1537 
1538     return CreateURLMoniker(This->doc->window->mon, szName, ppmk);
1539 }
1540 
1541 static HRESULT WINAPI PHBindHost_MonikerBindToStorage(IBindHost *iface, IMoniker *pMk, IBindCtx *pBC,
1542         IBindStatusCallback *pBSC, REFIID riid, void **ppvObj)
1543 {
1544     PluginHost *This = impl_from_IBindHost(iface);
1545     FIXME("(%p)->(%p %p %p %s %p)\n", This, pMk, pBC, pBSC, debugstr_guid(riid), ppvObj);
1546     return E_NOTIMPL;
1547 }
1548 
1549 static HRESULT WINAPI PHBindHost_MonikerBindToObject(IBindHost *iface, IMoniker *pMk, IBindCtx *pBC,
1550         IBindStatusCallback *pBSC, REFIID riid, void **ppvObj)
1551 {
1552     PluginHost *This = impl_from_IBindHost(iface);
1553     FIXME("(%p)->(%p %p %p %s %p)\n", This, pMk, pBC, pBSC, debugstr_guid(riid), ppvObj);
1554     return E_NOTIMPL;
1555 }
1556 
1557 static const IBindHostVtbl BindHostVtbl = {
1558     PHBindHost_QueryInterface,
1559     PHBindHost_AddRef,
1560     PHBindHost_Release,
1561     PHBindHost_CreateMoniker,
1562     PHBindHost_MonikerBindToStorage,
1563     PHBindHost_MonikerBindToObject
1564 };
1565 
1566 static inline PluginHost *impl_from_IServiceProvider(IServiceProvider *iface)
1567 {
1568     return CONTAINING_RECORD(iface, PluginHost, IServiceProvider_iface);
1569 }
1570 
1571 static HRESULT WINAPI PHServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
1572 {
1573     PluginHost *This = impl_from_IServiceProvider(iface);
1574     return IOleClientSite_QueryInterface(&This->IOleClientSite_iface, riid, ppv);
1575 }
1576 
1577 static ULONG WINAPI PHServiceProvider_AddRef(IServiceProvider *iface)
1578 {
1579     PluginHost *This = impl_from_IServiceProvider(iface);
1580     return IOleClientSite_AddRef(&This->IOleClientSite_iface);
1581 }
1582 
1583 static ULONG WINAPI PHServiceProvider_Release(IServiceProvider *iface)
1584 {
1585     PluginHost *This = impl_from_IServiceProvider(iface);
1586     return IOleClientSite_Release(&This->IOleClientSite_iface);
1587 }
1588 
1589 static HRESULT WINAPI PHServiceProvider_QueryService(IServiceProvider *iface, REFGUID guidService, REFIID riid, void **ppv)
1590 {
1591     PluginHost *This = impl_from_IServiceProvider(iface);
1592 
1593     if(IsEqualGUID(guidService, &SID_SBindHost)) {
1594         TRACE("SID_SBindHost service\n");
1595         return IOleClientSite_QueryInterface(&This->IOleClientSite_iface, riid, ppv);
1596     }
1597 
1598     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1599 
1600     if(!This->doc || !This->doc->basedoc.window) {
1601         *ppv = NULL;
1602         return E_NOINTERFACE;
1603     }
1604 
1605     return IServiceProvider_QueryService(&This->doc->basedoc.window->base.IServiceProvider_iface,
1606             guidService, riid, ppv);
1607 }
1608 
1609 static const IServiceProviderVtbl ServiceProviderVtbl = {
1610     PHServiceProvider_QueryInterface,
1611     PHServiceProvider_AddRef,
1612     PHServiceProvider_Release,
1613     PHServiceProvider_QueryService
1614 };
1615 
1616 static BOOL parse_classid(const PRUnichar *classid, CLSID *clsid)
1617 {
1618     const WCHAR *ptr;
1619     unsigned len;
1620     HRESULT hres;
1621 
1622     static const PRUnichar clsidW[] = {'c','l','s','i','d',':'};
1623 
1624     if(strncmpiW(classid, clsidW, sizeof(clsidW)/sizeof(WCHAR)))
1625         return FALSE;
1626 
1627     ptr = classid + sizeof(clsidW)/sizeof(WCHAR);
1628     len = strlenW(ptr);
1629 
1630     if(len == 38) {
1631         hres = CLSIDFromString(ptr, clsid);
1632     }else if(len == 36) {
1633         WCHAR buf[39];
1634 
1635         buf[0] = '{';
1636         memcpy(buf+1, ptr, len*sizeof(WCHAR));
1637         buf[37] = '}';
1638         buf[38] = 0;
1639         hres = CLSIDFromString(buf, clsid);
1640     }else {
1641         return FALSE;
1642     }
1643 
1644     return SUCCEEDED(hres);
1645 }
1646 
1647 static BOOL get_elem_clsid(nsIDOMHTMLElement *elem, CLSID *clsid)
1648 {
1649     const PRUnichar *val;
1650     nsAString val_str;
1651     nsresult nsres;
1652     BOOL ret = FALSE;
1653 
1654     static const PRUnichar classidW[] = {'c','l','a','s','s','i','d',0};
1655 
1656     nsres = get_elem_attr_value(elem, classidW, &val_str, &val);
1657     if(NS_SUCCEEDED(nsres)) {
1658         if(*val)
1659             ret = parse_classid(val, clsid);
1660         nsAString_Finish(&val_str);
1661     }
1662 
1663     return ret;
1664 }
1665 
1666 typedef struct {
1667     IBindStatusCallback IBindStatusCallback_iface;
1668     IWindowForBindingUI IWindowForBindingUI_iface;
1669     LONG ref;
1670 } InstallCallback;
1671 
1672 static inline InstallCallback *impl_from_IBindStatusCallback(IBindStatusCallback *iface)
1673 {
1674     return CONTAINING_RECORD(iface, InstallCallback, IBindStatusCallback_iface);
1675 }
1676 
1677 static HRESULT WINAPI InstallCallback_QueryInterface(IBindStatusCallback *iface,
1678         REFIID riid, void **ppv)
1679 {
1680     InstallCallback *This = impl_from_IBindStatusCallback(iface);
1681 
1682     if(IsEqualGUID(&IID_IUnknown, riid)) {
1683         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
1684         *ppv = &This->IBindStatusCallback_iface;
1685     }else if(IsEqualGUID(&IID_IBindStatusCallback, riid)) {
1686         TRACE("(%p)->(IID_IBindStatusCallback %p)\n", This, ppv);
1687         *ppv = &This->IBindStatusCallback_iface;
1688     }else if(IsEqualGUID(&IID_IWindowForBindingUI, riid)) {
1689         TRACE("(%p)->(IID_IWindowForBindingUI %p)\n", This, ppv);
1690         *ppv = &This->IWindowForBindingUI_iface;
1691     }else {
1692         TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
1693         *ppv = NULL;
1694         return E_NOINTERFACE;
1695     }
1696 
1697     IUnknown_AddRef((IUnknown*)*ppv);
1698     return S_OK;
1699 }
1700 
1701 static ULONG WINAPI InstallCallback_AddRef(IBindStatusCallback *iface)
1702 {
1703     InstallCallback *This = impl_from_IBindStatusCallback(iface);
1704     LONG ref = InterlockedIncrement(&This->ref);
1705 
1706     TRACE("(%p) ref=%d\n", This, ref);
1707 
1708     return ref;
1709 }
1710 
1711 static ULONG WINAPI InstallCallback_Release(IBindStatusCallback *iface)
1712 {
1713     InstallCallback *This = impl_from_IBindStatusCallback(iface);
1714     LONG ref = InterlockedIncrement(&This->ref);
1715 
1716     TRACE("(%p) ref=%d\n", This, ref);
1717 
1718     if(!ref)
1719         heap_free(This);
1720 
1721     return ref;
1722 }
1723 
1724 static HRESULT WINAPI InstallCallback_OnStartBinding(IBindStatusCallback *iface,
1725         DWORD dwReserved, IBinding *pib)
1726 {
1727     InstallCallback *This = impl_from_IBindStatusCallback(iface);
1728     TRACE("(%p)->(%x %p)\n", This, dwReserved, pib);
1729     return S_OK;
1730 }
1731 
1732 static HRESULT WINAPI InstallCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
1733 {
1734     InstallCallback *This = impl_from_IBindStatusCallback(iface);
1735     TRACE("(%p)->(%p)\n", This, pnPriority);
1736     return E_NOTIMPL;
1737 }
1738 
1739 static HRESULT WINAPI InstallCallback_OnLowResource(IBindStatusCallback *iface, DWORD dwReserved)
1740 {
1741     InstallCallback *This = impl_from_IBindStatusCallback(iface);
1742     TRACE("(%p)->(%x)\n", This, dwReserved);
1743     return S_OK;
1744 }
1745 
1746 static HRESULT WINAPI InstallCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
1747         ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
1748 {
1749     InstallCallback *This = impl_from_IBindStatusCallback(iface);
1750     TRACE("(%p)->(%u %u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode, debugstr_w(szStatusText));
1751     return S_OK;
1752 }
1753 
1754 static HRESULT WINAPI InstallCallback_OnStopBinding(IBindStatusCallback *iface,
1755         HRESULT hresult, LPCWSTR szError)
1756 {
1757     InstallCallback *This = impl_from_IBindStatusCallback(iface);
1758     TRACE("(%p)->(%08x %s)\n", This, hresult, debugstr_w(szError));
1759     return S_OK;
1760 }
1761 
1762 static HRESULT WINAPI InstallCallback_GetBindInfo(IBindStatusCallback *iface,
1763         DWORD* grfBINDF, BINDINFO* pbindinfo)
1764 {
1765     InstallCallback *This = impl_from_IBindStatusCallback(iface);
1766 
1767     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
1768 
1769     *grfBINDF = BINDF_ASYNCHRONOUS;
1770     return S_OK;
1771 }
1772 
1773 static HRESULT WINAPI InstallCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
1774         DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
1775 {
1776     InstallCallback *This = impl_from_IBindStatusCallback(iface);
1777     ERR("(%p)\n", This);
1778     return E_NOTIMPL;
1779 }
1780 
1781 static HRESULT WINAPI InstallCallback_OnObjectAvailable(IBindStatusCallback *iface,
1782         REFIID riid, IUnknown* punk)
1783 {
1784     InstallCallback *This = impl_from_IBindStatusCallback(iface);
1785     ERR("(%p)\n", This);
1786     return E_NOTIMPL;
1787 }
1788 
1789 static IBindStatusCallbackVtbl InstallCallbackVtbl = {
1790     InstallCallback_QueryInterface,
1791     InstallCallback_AddRef,
1792     InstallCallback_Release,
1793     InstallCallback_OnStartBinding,
1794     InstallCallback_GetPriority,
1795     InstallCallback_OnLowResource,
1796     InstallCallback_OnProgress,
1797     InstallCallback_OnStopBinding,
1798     InstallCallback_GetBindInfo,
1799     InstallCallback_OnDataAvailable,
1800     InstallCallback_OnObjectAvailable
1801 };
1802 
1803 static inline InstallCallback *impl_from_IWindowForBindingUI(IWindowForBindingUI *iface)
1804 {
1805     return CONTAINING_RECORD(iface, InstallCallback, IWindowForBindingUI_iface);
1806 }
1807 
1808 static HRESULT WINAPI WindowForBindingUI_QueryInterface(IWindowForBindingUI *iface, REFIID riid, void **ppv)
1809 {
1810     InstallCallback *This = impl_from_IWindowForBindingUI(iface);
1811     return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
1812 }
1813 
1814 static ULONG WINAPI WindowForBindingUI_AddRef(IWindowForBindingUI *iface)
1815 {
1816     InstallCallback *This = impl_from_IWindowForBindingUI(iface);
1817     return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
1818 }
1819 
1820 static ULONG WINAPI WindowForBindingUI_Release(IWindowForBindingUI *iface)
1821 {
1822     InstallCallback *This = impl_from_IWindowForBindingUI(iface);
1823     return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
1824 }
1825 
1826 static HRESULT WINAPI WindowForBindingUI_GetWindow(IWindowForBindingUI *iface, REFGUID rguidReason, HWND *phwnd)
1827 {
1828     InstallCallback *This = impl_from_IWindowForBindingUI(iface);
1829     FIXME("(%p)->(%s %p)\n", This, debugstr_guid(rguidReason), phwnd);
1830     *phwnd = NULL;
1831     return S_OK;
1832 }
1833 
1834 static const IWindowForBindingUIVtbl WindowForBindingUIVtbl = {
1835     WindowForBindingUI_QueryInterface,
1836     WindowForBindingUI_AddRef,
1837     WindowForBindingUI_Release,
1838     WindowForBindingUI_GetWindow
1839 };
1840 
1841 typedef struct {
1842     struct list entry;
1843     IUri *uri;
1844 } install_entry_t;
1845 
1846 static struct list install_list = LIST_INIT(install_list);
1847 
1848 static CRITICAL_SECTION cs_install_list;
1849 static CRITICAL_SECTION_DEBUG cs_install_list_dbg =
1850 {
1851     0, 0, &cs_install_list,
1852     { &cs_install_list_dbg.ProcessLocksList, &cs_install_list_dbg.ProcessLocksList },
1853       0, 0, { (DWORD_PTR)(__FILE__ ": install_list") }
1854 };
1855 static CRITICAL_SECTION cs_install_list = { &cs_install_list_dbg, -1, 0, 0, 0, 0 };
1856 
1857 static void install_codebase(const WCHAR *url)
1858 {
1859     InstallCallback *callback;
1860     IBindCtx *bctx;
1861     HRESULT hres;
1862 
1863     callback = heap_alloc(sizeof(*callback));
1864     if(!callback)
1865         return;
1866 
1867     callback->IBindStatusCallback_iface.lpVtbl = &InstallCallbackVtbl;
1868     callback->IWindowForBindingUI_iface.lpVtbl = &WindowForBindingUIVtbl;
1869     callback->ref = 1;
1870 
1871     hres = CreateAsyncBindCtx(0, &callback->IBindStatusCallback_iface, NULL, &bctx);
1872     IBindStatusCallback_Release(&callback->IBindStatusCallback_iface);
1873     if(FAILED(hres))
1874         return;
1875 
1876     hres = AsyncInstallDistributionUnit(NULL, NULL, NULL, 0, 0, url, bctx, NULL, 0);
1877     IBindCtx_Release(bctx);
1878     if(FAILED(hres))
1879         WARN("FAILED: %08x\n", hres);
1880 }
1881 
1882 static void check_codebase(HTMLInnerWindow *window, nsIDOMHTMLElement *nselem)
1883 {
1884     BOOL is_on_list = FALSE;
1885     install_entry_t *iter;
1886     const PRUnichar *val;
1887     nsAString val_str;
1888     IUri *uri = NULL;
1889     nsresult nsres;
1890     HRESULT hres;
1891 
1892     static const PRUnichar codebaseW[] = {'c','o','d','e','b','a','s','e',0};
1893 
1894     nsres = get_elem_attr_value(nselem, codebaseW, &val_str, &val);
1895     if(NS_SUCCEEDED(nsres)) {
1896         if(*val) {
1897             hres = CoInternetCombineUrlEx(window->base.outer_window->uri, val, 0, &uri, 0);
1898             if(FAILED(hres))
1899                 uri = NULL;
1900         }
1901         nsAString_Finish(&val_str);
1902     }
1903 
1904     if(!uri)
1905         return;
1906 
1907     EnterCriticalSection(&cs_install_list);
1908 
1909     LIST_FOR_EACH_ENTRY(iter, &install_list, install_entry_t, entry) {
1910         BOOL eq;
1911 
1912         hres = IUri_IsEqual(uri, iter->uri, &eq);
1913         if(SUCCEEDED(hres) && eq) {
1914             TRACE("already proceeded\n");
1915             is_on_list = TRUE;
1916             break;
1917         }
1918     }
1919 
1920     if(!is_on_list) {
1921         iter = heap_alloc(sizeof(*iter));
1922         if(iter) {
1923             IUri_AddRef(uri);
1924             iter->uri = uri;
1925 
1926             list_add_tail(&install_list, &iter->entry);
1927         }
1928     }
1929 
1930     LeaveCriticalSection(&cs_install_list);
1931 
1932     if(!is_on_list) {
1933         BSTR display_uri;
1934 
1935         hres = IUri_GetDisplayUri(uri, &display_uri);
1936         if(SUCCEEDED(hres)) {
1937             install_codebase(display_uri);
1938             SysFreeString(display_uri);
1939         }
1940     }
1941 
1942     IUri_Release(uri);
1943 }
1944 
1945 static IUnknown *create_activex_object(HTMLDocumentNode *doc, nsIDOMHTMLElement *nselem, CLSID *clsid)
1946 {
1947     IClassFactoryEx *cfex;
1948     IClassFactory *cf;
1949     IUnknown *obj;
1950     DWORD policy;
1951     HRESULT hres;
1952 
1953     if(!get_elem_clsid(nselem, clsid)) {
1954         WARN("Could not determine element CLSID\n");
1955         return NULL;
1956     }
1957 
1958     TRACE("clsid %s\n", debugstr_guid(clsid));
1959 
1960     policy = 0;
1961     hres = IInternetHostSecurityManager_ProcessUrlAction(&doc->IInternetHostSecurityManager_iface,
1962             URLACTION_ACTIVEX_RUN, (BYTE*)&policy, sizeof(policy), (BYTE*)clsid, sizeof(GUID), 0, 0);
1963     if(FAILED(hres) || policy != URLPOLICY_ALLOW) {
1964         WARN("ProcessUrlAction returned %08x %x\n", hres, policy);
1965         return NULL;
1966     }
1967 
1968     hres = CoGetClassObject(clsid, CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER, NULL, &IID_IClassFactory, (void**)&cf);
1969     if(hres == REGDB_E_CLASSNOTREG)
1970         check_codebase(doc->window, nselem);
1971     if(FAILED(hres))
1972         return NULL;
1973 
1974     hres = IClassFactory_QueryInterface(cf, &IID_IClassFactoryEx, (void**)&cfex);
1975     if(SUCCEEDED(hres)) {
1976         FIXME("Use IClassFactoryEx\n");
1977         IClassFactoryEx_Release(cfex);
1978     }
1979 
1980     hres = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void**)&obj);
1981     IClassFactory_Release(cf);
1982     if(FAILED(hres))
1983         return NULL;
1984 
1985     return obj;
1986 }
1987 
1988 void detach_plugin_host(PluginHost *host)
1989 {
1990     HRESULT hres;
1991 
1992     TRACE("%p\n", host);
1993 
1994     if(!host->doc)
1995         return;
1996 
1997     if(host->ip_object) {
1998         if(host->ui_active)
1999             IOleInPlaceObject_UIDeactivate(host->ip_object);
2000         IOleInPlaceObject_InPlaceDeactivate(host->ip_object);
2001     }
2002 
2003     if(host->plugin_unk) {
2004         IOleObject *ole_obj;
2005 
2006         hres = IUnknown_QueryInterface(host->plugin_unk, &IID_IOleObject, (void**)&ole_obj);
2007         if(SUCCEEDED(hres)) {
2008             if(!host->ip_object)
2009                 IOleObject_Close(ole_obj, OLECLOSE_NOSAVE);
2010             IOleObject_SetClientSite(ole_obj, NULL);
2011             IOleObject_Release(ole_obj);
2012         }
2013     }
2014 
2015     if(host->sink) {
2016         IConnectionPointContainer *cp_container;
2017         IConnectionPoint *cp;
2018 
2019         assert(host->plugin_unk != NULL);
2020 
2021         hres = IUnknown_QueryInterface(host->plugin_unk, &IID_IConnectionPointContainer, (void**)&cp_container);
2022         if(SUCCEEDED(hres)) {
2023             hres = IConnectionPointContainer_FindConnectionPoint(cp_container, &host->sink->iid, &cp);
2024             IConnectionPointContainer_Release(cp_container);
2025             if(SUCCEEDED(hres)) {
2026                 IConnectionPoint_Unadvise(cp, host->sink->cookie);
2027                 IConnectionPoint_Release(cp);
2028             }
2029         }
2030 
2031         host->sink->host = NULL;
2032         IDispatch_Release(&host->sink->IDispatch_iface);
2033         host->sink = NULL;
2034     }
2035 
2036     release_plugin_ifaces(host);
2037 
2038     if(host->element) {
2039         host->element->plugin_host = NULL;
2040         host->element = NULL;
2041     }
2042 
2043     list_remove(&host->entry);
2044     list_init(&host->entry);
2045     host->doc = NULL;
2046 }
2047 
2048 HRESULT create_plugin_host(HTMLDocumentNode *doc, HTMLPluginContainer *container)
2049 {
2050     PluginHost *host;
2051     IUnknown *unk;
2052     CLSID clsid;
2053 
2054     assert(!container->plugin_host);
2055 
2056     unk = create_activex_object(doc, container->element.nselem, &clsid);
2057     if(!unk)
2058         return E_FAIL;
2059 
2060     host = heap_alloc_zero(sizeof(*host));
2061     if(!host) {
2062         IUnknown_Release(unk);
2063         return E_OUTOFMEMORY;
2064     }
2065 
2066     host->IOleClientSite_iface.lpVtbl      = &OleClientSiteVtbl;
2067     host->IAdviseSinkEx_iface.lpVtbl       = &AdviseSinkExVtbl;
2068     host->IPropertyNotifySink_iface.lpVtbl = &PropertyNotifySinkVtbl;
2069     host->IDispatch_iface.lpVtbl           = &DispatchVtbl;
2070     host->IOleInPlaceSiteEx_iface.lpVtbl   = &OleInPlaceSiteExVtbl;
2071     host->IOleControlSite_iface.lpVtbl     = &OleControlSiteVtbl;
2072     host->IBindHost_iface.lpVtbl           = &BindHostVtbl;
2073     host->IServiceProvider_iface.lpVtbl    = &ServiceProviderVtbl;
2074 
2075     host->ref = 1;
2076 
2077     host->plugin_unk = unk;
2078     host->clsid = clsid;
2079 
2080     host->doc = doc;
2081     list_add_tail(&doc->plugin_hosts, &host->entry);
2082 
2083     container->plugin_host = host;
2084     host->element = container;
2085 
2086     initialize_plugin_object(host);
2087 
2088     return S_OK;
2089 }
2090