Release 1.5.29.
[wine] / dlls / mshtml / oleobj.c
1 /*
2  * Copyright 2005 Jacek Caban
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 "config.h"
20
21 #include <stdarg.h>
22 #include <stdio.h>
23
24 #define COBJMACROS
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "ole2.h"
30 #include "shlguid.h"
31 #include "shdeprecated.h"
32 #include "mshtmdid.h"
33 #include "idispids.h"
34
35 #include "wine/debug.h"
36
37 #include "mshtml_private.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
40
41 #define DOCHOST_DOCCANNAVIGATE  0
42
43 typedef struct {
44     IEnumUnknown IEnumUnknown_iface;
45     LONG ref;
46 } EnumUnknown;
47
48 static inline EnumUnknown *impl_from_IEnumUnknown(IEnumUnknown *iface)
49 {
50     return CONTAINING_RECORD(iface, EnumUnknown, IEnumUnknown_iface);
51 }
52
53 static HRESULT WINAPI EnumUnknown_QueryInterface(IEnumUnknown *iface, REFIID riid, void **ppv)
54 {
55     EnumUnknown *This = impl_from_IEnumUnknown(iface);
56
57     if(IsEqualGUID(&IID_IUnknown, riid)) {
58         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
59         *ppv = &This->IEnumUnknown_iface;
60     }else if(IsEqualGUID(&IID_IEnumUnknown, riid)) {
61         TRACE("(%p)->(IID_IEnumUnknown %p)\n", This, ppv);
62         *ppv = &This->IEnumUnknown_iface;
63     }else {
64         WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
65         *ppv = NULL;
66         return E_NOINTERFACE;
67     }
68
69     IUnknown_AddRef((IUnknown*)*ppv);
70     return S_OK;
71 }
72
73 static ULONG WINAPI EnumUnknown_AddRef(IEnumUnknown *iface)
74 {
75     EnumUnknown *This = impl_from_IEnumUnknown(iface);
76     LONG ref = InterlockedIncrement(&This->ref);
77
78     TRACE("(%p) ref=%d\n", This, ref);
79
80     return ref;
81 }
82
83 static ULONG WINAPI EnumUnknown_Release(IEnumUnknown *iface)
84 {
85     EnumUnknown *This = impl_from_IEnumUnknown(iface);
86     LONG ref = InterlockedDecrement(&This->ref);
87
88     TRACE("(%p) ref=%d\n", This, ref);
89
90     if(!ref)
91         heap_free(This);
92
93     return ref;
94 }
95
96 static HRESULT WINAPI EnumUnknown_Next(IEnumUnknown *iface, ULONG celt, IUnknown **rgelt, ULONG *pceltFetched)
97 {
98     EnumUnknown *This = impl_from_IEnumUnknown(iface);
99
100     TRACE("(%p)->(%u %p %p)\n", This, celt, rgelt, pceltFetched);
101
102     /* FIXME: It's not clear if we should ever return something here */
103     if(pceltFetched)
104         *pceltFetched = 0;
105     return S_FALSE;
106 }
107
108 static HRESULT WINAPI EnumUnknown_Skip(IEnumUnknown *iface, ULONG celt)
109 {
110     EnumUnknown *This = impl_from_IEnumUnknown(iface);
111     FIXME("(%p)->(%u)\n", This, celt);
112     return E_NOTIMPL;
113 }
114
115 static HRESULT WINAPI EnumUnknown_Reset(IEnumUnknown *iface)
116 {
117     EnumUnknown *This = impl_from_IEnumUnknown(iface);
118     FIXME("(%p)\n", This);
119     return E_NOTIMPL;
120 }
121
122 static HRESULT WINAPI EnumUnknown_Clone(IEnumUnknown *iface, IEnumUnknown **ppenum)
123 {
124     EnumUnknown *This = impl_from_IEnumUnknown(iface);
125     FIXME("(%p)->(%p)\n", This, ppenum);
126     return E_NOTIMPL;
127 }
128
129 static const IEnumUnknownVtbl EnumUnknownVtbl = {
130     EnumUnknown_QueryInterface,
131     EnumUnknown_AddRef,
132     EnumUnknown_Release,
133     EnumUnknown_Next,
134     EnumUnknown_Skip,
135     EnumUnknown_Reset,
136     EnumUnknown_Clone
137 };
138
139 /**********************************************************
140  * IOleObject implementation
141  */
142
143 static inline HTMLDocument *impl_from_IOleObject(IOleObject *iface)
144 {
145     return CONTAINING_RECORD(iface, HTMLDocument, IOleObject_iface);
146 }
147
148 static HRESULT WINAPI OleObject_QueryInterface(IOleObject *iface, REFIID riid, void **ppv)
149 {
150     HTMLDocument *This = impl_from_IOleObject(iface);
151     return htmldoc_query_interface(This, riid, ppv);
152 }
153
154 static ULONG WINAPI OleObject_AddRef(IOleObject *iface)
155 {
156     HTMLDocument *This = impl_from_IOleObject(iface);
157     return htmldoc_addref(This);
158 }
159
160 static ULONG WINAPI OleObject_Release(IOleObject *iface)
161 {
162     HTMLDocument *This = impl_from_IOleObject(iface);
163     return htmldoc_release(This);
164 }
165
166 static void update_hostinfo(HTMLDocumentObj *This, DOCHOSTUIINFO *hostinfo)
167 {
168     nsIScrollable *scrollable;
169     nsresult nsres;
170
171     if(!This->nscontainer)
172         return;
173
174     nsres = nsIWebBrowser_QueryInterface(This->nscontainer->webbrowser, &IID_nsIScrollable, (void**)&scrollable);
175     if(NS_SUCCEEDED(nsres)) {
176         nsres = nsIScrollable_SetDefaultScrollbarPreferences(scrollable, ScrollOrientation_Y,
177                 (hostinfo->dwFlags & DOCHOSTUIFLAG_SCROLL_NO) ? Scrollbar_Never : Scrollbar_Always);
178         if(NS_FAILED(nsres))
179             ERR("Could not set default Y scrollbar prefs: %08x\n", nsres);
180
181         nsres = nsIScrollable_SetDefaultScrollbarPreferences(scrollable, ScrollOrientation_X,
182                 hostinfo->dwFlags & DOCHOSTUIFLAG_SCROLL_NO ? Scrollbar_Never : Scrollbar_Auto);
183         if(NS_FAILED(nsres))
184             ERR("Could not set default X scrollbar prefs: %08x\n", nsres);
185
186         nsIScrollable_Release(scrollable);
187     }else {
188         ERR("Could not get nsIScrollable: %08x\n", nsres);
189     }
190 }
191
192 /* Calls undocumented 84 cmd of CGID_ShellDocView */
193 void call_docview_84(HTMLDocumentObj *doc)
194 {
195     IOleCommandTarget *olecmd;
196     VARIANT var;
197     HRESULT hres;
198
199     if(!doc->client)
200         return;
201
202     hres = IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&olecmd);
203     if(FAILED(hres))
204         return;
205
206     VariantInit(&var);
207     hres = IOleCommandTarget_Exec(olecmd, &CGID_ShellDocView, 84, 0, NULL, &var);
208     IOleCommandTarget_Release(olecmd);
209     if(SUCCEEDED(hres) && V_VT(&var) != VT_NULL)
210         FIXME("handle result\n");
211 }
212
213 static HRESULT WINAPI OleObject_SetClientSite(IOleObject *iface, IOleClientSite *pClientSite)
214 {
215     HTMLDocument *This = impl_from_IOleObject(iface);
216     IOleCommandTarget *cmdtrg = NULL;
217     IOleWindow *ole_window;
218     IBrowserService *browser_service;
219     BOOL hostui_setup;
220     VARIANT silent;
221     HWND hwnd;
222     HRESULT hres;
223
224     TRACE("(%p)->(%p)\n", This, pClientSite);
225
226     if(pClientSite == This->doc_obj->client)
227         return S_OK;
228
229     if(This->doc_obj->client) {
230         IOleClientSite_Release(This->doc_obj->client);
231         This->doc_obj->client = NULL;
232         This->doc_obj->usermode = UNKNOWN_USERMODE;
233     }
234
235     if(This->doc_obj->client_cmdtrg) {
236         IOleCommandTarget_Release(This->doc_obj->client_cmdtrg);
237         This->doc_obj->client_cmdtrg = NULL;
238     }
239
240     if(This->doc_obj->hostui && !This->doc_obj->custom_hostui) {
241         IDocHostUIHandler_Release(This->doc_obj->hostui);
242         This->doc_obj->hostui = NULL;
243     }
244
245     if(This->doc_obj->doc_object_service) {
246         IDocObjectService_Release(This->doc_obj->doc_object_service);
247         This->doc_obj->doc_object_service = NULL;
248     }
249
250     if(This->doc_obj->webbrowser) {
251         IUnknown_Release(This->doc_obj->webbrowser);
252         This->doc_obj->webbrowser = NULL;
253     }
254
255     if(This->doc_obj->browser_service) {
256         IUnknown_Release(This->doc_obj->browser_service);
257         This->doc_obj->browser_service = NULL;
258     }
259
260     if(This->doc_obj->travel_log) {
261         ITravelLog_Release(This->doc_obj->travel_log);
262         This->doc_obj->travel_log = NULL;
263     }
264
265     memset(&This->doc_obj->hostinfo, 0, sizeof(DOCHOSTUIINFO));
266
267     if(!pClientSite)
268         return S_OK;
269
270     IOleClientSite_AddRef(pClientSite);
271     This->doc_obj->client = pClientSite;
272
273     hostui_setup = This->doc_obj->hostui_setup;
274
275     if(!This->doc_obj->hostui) {
276         IDocHostUIHandler *uihandler;
277
278         This->doc_obj->custom_hostui = FALSE;
279
280         hres = IOleClientSite_QueryInterface(pClientSite, &IID_IDocHostUIHandler, (void**)&uihandler);
281         if(SUCCEEDED(hres))
282             This->doc_obj->hostui = uihandler;
283     }
284
285     if(This->doc_obj->hostui) {
286         DOCHOSTUIINFO hostinfo;
287         LPOLESTR key_path = NULL, override_key_path = NULL;
288         IDocHostUIHandler2 *uihandler2;
289
290         memset(&hostinfo, 0, sizeof(DOCHOSTUIINFO));
291         hostinfo.cbSize = sizeof(DOCHOSTUIINFO);
292         hres = IDocHostUIHandler_GetHostInfo(This->doc_obj->hostui, &hostinfo);
293         if(SUCCEEDED(hres)) {
294             TRACE("hostinfo = {%u %08x %08x %s %s}\n",
295                     hostinfo.cbSize, hostinfo.dwFlags, hostinfo.dwDoubleClick,
296                     debugstr_w(hostinfo.pchHostCss), debugstr_w(hostinfo.pchHostNS));
297             update_hostinfo(This->doc_obj, &hostinfo);
298             This->doc_obj->hostinfo = hostinfo;
299         }
300
301         if(!hostui_setup) {
302             hres = IDocHostUIHandler_GetOptionKeyPath(This->doc_obj->hostui, &key_path, 0);
303             if(hres == S_OK && key_path) {
304                 if(key_path[0]) {
305                     /* FIXME: use key_path */
306                     TRACE("key_path = %s\n", debugstr_w(key_path));
307                 }
308                 CoTaskMemFree(key_path);
309             }
310
311             hres = IDocHostUIHandler_QueryInterface(This->doc_obj->hostui, &IID_IDocHostUIHandler2,
312                     (void**)&uihandler2);
313             if(SUCCEEDED(hres)) {
314                 hres = IDocHostUIHandler2_GetOverrideKeyPath(uihandler2, &override_key_path, 0);
315                 if(hres == S_OK && override_key_path && override_key_path[0]) {
316                     if(override_key_path[0]) {
317                         /*FIXME: use override_key_path */
318                         TRACE("override_key_path = %s\n", debugstr_w(override_key_path));
319                     }
320                     CoTaskMemFree(override_key_path);
321                 }
322                 IDocHostUIHandler2_Release(uihandler2);
323             }
324
325             This->doc_obj->hostui_setup = TRUE;
326         }
327     }
328
329     /* Native calls here GetWindow. What is it for?
330      * We don't have anything to do with it here (yet). */
331     hres = IOleClientSite_QueryInterface(pClientSite, &IID_IOleWindow, (void**)&ole_window);
332     if(SUCCEEDED(hres)) {
333         IOleWindow_GetWindow(ole_window, &hwnd);
334         IOleWindow_Release(ole_window);
335     }
336
337     hres = do_query_service((IUnknown*)pClientSite, &IID_IShellBrowser,
338             &IID_IBrowserService, (void**)&browser_service);
339     if(SUCCEEDED(hres)) {
340         ITravelLog *travel_log;
341
342         This->doc_obj->browser_service = (IUnknown*)browser_service;
343
344         hres = IBrowserService_GetTravelLog(browser_service, &travel_log);
345         if(SUCCEEDED(hres))
346             This->doc_obj->travel_log = travel_log;
347     }else {
348         browser_service = NULL;
349     }
350
351     hres = IOleClientSite_QueryInterface(pClientSite, &IID_IOleCommandTarget, (void**)&cmdtrg);
352     if(SUCCEEDED(hres)) {
353         VARIANT var;
354         OLECMD cmd = {OLECMDID_SETPROGRESSTEXT, 0};
355
356         This->doc_obj->client_cmdtrg = cmdtrg;
357
358         if(!hostui_setup) {
359             IDocObjectService *doc_object_service;
360             IWebBrowser2 *wb;
361
362             V_VT(&var) = VT_UNKNOWN;
363             V_UNKNOWN(&var) = (IUnknown*)&This->window->base.IHTMLWindow2_iface;
364             IOleCommandTarget_Exec(cmdtrg, &CGID_DocHostCmdPriv, DOCHOST_DOCCANNAVIGATE, 0, &var, NULL);
365
366             if(browser_service) {
367                 hres = IBrowserService_QueryInterface(browser_service,
368                         &IID_IDocObjectService, (void**)&doc_object_service);
369                 if(SUCCEEDED(hres)) {
370                     This->doc_obj->doc_object_service = doc_object_service;
371
372                     /*
373                      * Some embedding routines, esp. in regards to use of IDocObjectService, differ if
374                      * embedder supports IWebBrowserApp.
375                      */
376                     hres = do_query_service((IUnknown*)pClientSite, &IID_IWebBrowserApp, &IID_IWebBrowser2, (void**)&wb);
377                     if(SUCCEEDED(hres))
378                         This->doc_obj->webbrowser = (IUnknown*)wb;
379                 }
380             }
381         }
382
383         call_docview_84(This->doc_obj);
384
385         IOleCommandTarget_QueryStatus(cmdtrg, NULL, 1, &cmd, NULL);
386
387         V_VT(&var) = VT_I4;
388         V_I4(&var) = 0;
389         IOleCommandTarget_Exec(cmdtrg, NULL, OLECMDID_SETPROGRESSMAX,
390                 OLECMDEXECOPT_DONTPROMPTUSER, &var, NULL);
391         IOleCommandTarget_Exec(cmdtrg, NULL, OLECMDID_SETPROGRESSPOS, 
392                 OLECMDEXECOPT_DONTPROMPTUSER, &var, NULL);
393     }
394
395     if(This->doc_obj->usermode == UNKNOWN_USERMODE)
396         IOleControl_OnAmbientPropertyChange(&This->IOleControl_iface, DISPID_AMBIENT_USERMODE);
397
398     IOleControl_OnAmbientPropertyChange(&This->IOleControl_iface,
399             DISPID_AMBIENT_OFFLINEIFNOTCONNECTED);
400
401     hres = get_client_disp_property(This->doc_obj->client, DISPID_AMBIENT_SILENT, &silent);
402     if(SUCCEEDED(hres)) {
403         if(V_VT(&silent) != VT_BOOL)
404             WARN("silent = %s\n", debugstr_variant(&silent));
405         else if(V_BOOL(&silent))
406             FIXME("silent == true\n");
407     }
408
409     IOleControl_OnAmbientPropertyChange(&This->IOleControl_iface, DISPID_AMBIENT_USERAGENT);
410     IOleControl_OnAmbientPropertyChange(&This->IOleControl_iface, DISPID_AMBIENT_PALETTE);
411
412     return S_OK;
413 }
414
415 static HRESULT WINAPI OleObject_GetClientSite(IOleObject *iface, IOleClientSite **ppClientSite)
416 {
417     HTMLDocument *This = impl_from_IOleObject(iface);
418
419     TRACE("(%p)->(%p)\n", This, ppClientSite);
420
421     if(!ppClientSite)
422         return E_INVALIDARG;
423
424     if(This->doc_obj->client)
425         IOleClientSite_AddRef(This->doc_obj->client);
426     *ppClientSite = This->doc_obj->client;
427
428     return S_OK;
429 }
430
431 static HRESULT WINAPI OleObject_SetHostNames(IOleObject *iface, LPCOLESTR szContainerApp, LPCOLESTR szContainerObj)
432 {
433     HTMLDocument *This = impl_from_IOleObject(iface);
434     FIXME("(%p)->(%s %s)\n", This, debugstr_w(szContainerApp), debugstr_w(szContainerObj));
435     return E_NOTIMPL;
436 }
437
438 static HRESULT WINAPI OleObject_Close(IOleObject *iface, DWORD dwSaveOption)
439 {
440     HTMLDocument *This = impl_from_IOleObject(iface);
441
442     TRACE("(%p)->(%08x)\n", This, dwSaveOption);
443
444     if(dwSaveOption == OLECLOSE_PROMPTSAVE)
445         FIXME("OLECLOSE_PROMPTSAVE not implemented\n");
446
447     if(This->doc_obj->in_place_active)
448         IOleInPlaceObjectWindowless_InPlaceDeactivate(&This->IOleInPlaceObjectWindowless_iface);
449
450     HTMLDocument_LockContainer(This->doc_obj, FALSE);
451
452     if(This->advise_holder)
453         IOleAdviseHolder_SendOnClose(This->advise_holder);
454     
455     return S_OK;
456 }
457
458 static HRESULT WINAPI OleObject_SetMoniker(IOleObject *iface, DWORD dwWhichMoniker, IMoniker *pmk)
459 {
460     HTMLDocument *This = impl_from_IOleObject(iface);
461     FIXME("(%p %d %p)->()\n", This, dwWhichMoniker, pmk);
462     return E_NOTIMPL;
463 }
464
465 static HRESULT WINAPI OleObject_GetMoniker(IOleObject *iface, DWORD dwAssign, DWORD dwWhichMoniker, IMoniker **ppmk)
466 {
467     HTMLDocument *This = impl_from_IOleObject(iface);
468     FIXME("(%p)->(%d %d %p)\n", This, dwAssign, dwWhichMoniker, ppmk);
469     return E_NOTIMPL;
470 }
471
472 static HRESULT WINAPI OleObject_InitFromData(IOleObject *iface, IDataObject *pDataObject, BOOL fCreation,
473                                         DWORD dwReserved)
474 {
475     HTMLDocument *This = impl_from_IOleObject(iface);
476     FIXME("(%p)->(%p %x %d)\n", This, pDataObject, fCreation, dwReserved);
477     return E_NOTIMPL;
478 }
479
480 static HRESULT WINAPI OleObject_GetClipboardData(IOleObject *iface, DWORD dwReserved, IDataObject **ppDataObject)
481 {
482     HTMLDocument *This = impl_from_IOleObject(iface);
483     FIXME("(%p)->(%d %p)\n", This, dwReserved, ppDataObject);
484     return E_NOTIMPL;
485 }
486
487 static HRESULT WINAPI OleObject_DoVerb(IOleObject *iface, LONG iVerb, LPMSG lpmsg, IOleClientSite *pActiveSite,
488                                         LONG lindex, HWND hwndParent, LPCRECT lprcPosRect)
489 {
490     HTMLDocument *This = impl_from_IOleObject(iface);
491     IOleDocumentSite *pDocSite;
492     HRESULT hres;
493
494     TRACE("(%p)->(%d %p %p %d %p %p)\n", This, iVerb, lpmsg, pActiveSite, lindex, hwndParent, lprcPosRect);
495
496     if(iVerb != OLEIVERB_SHOW && iVerb != OLEIVERB_UIACTIVATE && iVerb != OLEIVERB_INPLACEACTIVATE) { 
497         FIXME("iVerb = %d not supported\n", iVerb);
498         return E_NOTIMPL;
499     }
500
501     if(!pActiveSite)
502         pActiveSite = This->doc_obj->client;
503
504     hres = IOleClientSite_QueryInterface(pActiveSite, &IID_IOleDocumentSite, (void**)&pDocSite);
505     if(SUCCEEDED(hres)) {
506         HTMLDocument_LockContainer(This->doc_obj, TRUE);
507
508         /* FIXME: Create new IOleDocumentView. See CreateView for more info. */
509         hres = IOleDocumentSite_ActivateMe(pDocSite, &This->IOleDocumentView_iface);
510         IOleDocumentSite_Release(pDocSite);
511     }else {
512         hres = IOleDocumentView_UIActivate(&This->IOleDocumentView_iface, TRUE);
513         if(SUCCEEDED(hres)) {
514             if(lprcPosRect) {
515                 RECT rect; /* We need to pass rect as not const pointer */
516                 rect = *lprcPosRect;
517                 IOleDocumentView_SetRect(&This->IOleDocumentView_iface, &rect);
518             }
519             IOleDocumentView_Show(&This->IOleDocumentView_iface, TRUE);
520         }
521     }
522
523     return hres;
524 }
525
526 static HRESULT WINAPI OleObject_EnumVerbs(IOleObject *iface, IEnumOLEVERB **ppEnumOleVerb)
527 {
528     HTMLDocument *This = impl_from_IOleObject(iface);
529     FIXME("(%p)->(%p)\n", This, ppEnumOleVerb);
530     return E_NOTIMPL;
531 }
532
533 static HRESULT WINAPI OleObject_Update(IOleObject *iface)
534 {
535     HTMLDocument *This = impl_from_IOleObject(iface);
536     FIXME("(%p)\n", This);
537     return E_NOTIMPL;
538 }
539
540 static HRESULT WINAPI OleObject_IsUpToDate(IOleObject *iface)
541 {
542     HTMLDocument *This = impl_from_IOleObject(iface);
543     FIXME("(%p)\n", This);
544     return E_NOTIMPL;
545 }
546
547 static HRESULT WINAPI OleObject_GetUserClassID(IOleObject *iface, CLSID *pClsid)
548 {
549     HTMLDocument *This = impl_from_IOleObject(iface);
550
551     TRACE("(%p)->(%p)\n", This, pClsid);
552
553     if(!pClsid)
554         return E_INVALIDARG;
555
556     *pClsid = CLSID_HTMLDocument;
557     return S_OK;
558 }
559
560 static HRESULT WINAPI OleObject_GetUserType(IOleObject *iface, DWORD dwFormOfType, LPOLESTR *pszUserType)
561 {
562     HTMLDocument *This = impl_from_IOleObject(iface);
563     FIXME("(%p)->(%d %p)\n", This, dwFormOfType, pszUserType);
564     return E_NOTIMPL;
565 }
566
567 static HRESULT WINAPI OleObject_SetExtent(IOleObject *iface, DWORD dwDrawAspect, SIZEL *psizel)
568 {
569     HTMLDocument *This = impl_from_IOleObject(iface);
570     FIXME("(%p)->(%d %p)\n", This, dwDrawAspect, psizel);
571     return E_NOTIMPL;
572 }
573
574 static HRESULT WINAPI OleObject_GetExtent(IOleObject *iface, DWORD dwDrawAspect, SIZEL *psizel)
575 {
576     HTMLDocument *This = impl_from_IOleObject(iface);
577     FIXME("(%p)->(%d %p)\n", This, dwDrawAspect, psizel);
578     return E_NOTIMPL;
579 }
580
581 static HRESULT WINAPI OleObject_Advise(IOleObject *iface, IAdviseSink *pAdvSink, DWORD *pdwConnection)
582 {
583     HTMLDocument *This = impl_from_IOleObject(iface);
584     TRACE("(%p)->(%p %p)\n", This, pAdvSink, pdwConnection);
585
586     if(!pdwConnection)
587         return E_INVALIDARG;
588
589     if(!pAdvSink) {
590         *pdwConnection = 0;
591         return E_INVALIDARG;
592     }
593
594     if(!This->advise_holder) {
595         CreateOleAdviseHolder(&This->advise_holder);
596         if(!This->advise_holder)
597             return E_OUTOFMEMORY;
598     }
599
600     return IOleAdviseHolder_Advise(This->advise_holder, pAdvSink, pdwConnection);
601 }
602
603 static HRESULT WINAPI OleObject_Unadvise(IOleObject *iface, DWORD dwConnection)
604 {
605     HTMLDocument *This = impl_from_IOleObject(iface);
606     TRACE("(%p)->(%d)\n", This, dwConnection);
607
608     if(!This->advise_holder)
609         return OLE_E_NOCONNECTION;
610
611     return IOleAdviseHolder_Unadvise(This->advise_holder, dwConnection);
612 }
613
614 static HRESULT WINAPI OleObject_EnumAdvise(IOleObject *iface, IEnumSTATDATA **ppenumAdvise)
615 {
616     HTMLDocument *This = impl_from_IOleObject(iface);
617
618     if(!This->advise_holder) {
619         *ppenumAdvise = NULL;
620         return S_OK;
621     }
622
623     return IOleAdviseHolder_EnumAdvise(This->advise_holder, ppenumAdvise);
624 }
625
626 static HRESULT WINAPI OleObject_GetMiscStatus(IOleObject *iface, DWORD dwAspect, DWORD *pdwStatus)
627 {
628     HTMLDocument *This = impl_from_IOleObject(iface);
629     FIXME("(%p)->(%d %p)\n", This, dwAspect, pdwStatus);
630     return E_NOTIMPL;
631 }
632
633 static HRESULT WINAPI OleObject_SetColorScheme(IOleObject *iface, LOGPALETTE *pLogpal)
634 {
635     HTMLDocument *This = impl_from_IOleObject(iface);
636     FIXME("(%p)->(%p)\n", This, pLogpal);
637     return E_NOTIMPL;
638 }
639
640 static const IOleObjectVtbl OleObjectVtbl = {
641     OleObject_QueryInterface,
642     OleObject_AddRef,
643     OleObject_Release,
644     OleObject_SetClientSite,
645     OleObject_GetClientSite,
646     OleObject_SetHostNames,
647     OleObject_Close,
648     OleObject_SetMoniker,
649     OleObject_GetMoniker,
650     OleObject_InitFromData,
651     OleObject_GetClipboardData,
652     OleObject_DoVerb,
653     OleObject_EnumVerbs,
654     OleObject_Update,
655     OleObject_IsUpToDate,
656     OleObject_GetUserClassID,
657     OleObject_GetUserType,
658     OleObject_SetExtent,
659     OleObject_GetExtent,
660     OleObject_Advise,
661     OleObject_Unadvise,
662     OleObject_EnumAdvise,
663     OleObject_GetMiscStatus,
664     OleObject_SetColorScheme
665 };
666
667 /**********************************************************
668  * IOleDocument implementation
669  */
670
671 static inline HTMLDocument *impl_from_IOleDocument(IOleDocument *iface)
672 {
673     return CONTAINING_RECORD(iface, HTMLDocument, IOleDocument_iface);
674 }
675
676 static HRESULT WINAPI OleDocument_QueryInterface(IOleDocument *iface, REFIID riid, void **ppv)
677 {
678     HTMLDocument *This = impl_from_IOleDocument(iface);
679     return htmldoc_query_interface(This, riid, ppv);
680 }
681
682 static ULONG WINAPI OleDocument_AddRef(IOleDocument *iface)
683 {
684     HTMLDocument *This = impl_from_IOleDocument(iface);
685     return htmldoc_addref(This);
686 }
687
688 static ULONG WINAPI OleDocument_Release(IOleDocument *iface)
689 {
690     HTMLDocument *This = impl_from_IOleDocument(iface);
691     return htmldoc_release(This);
692 }
693
694 static HRESULT WINAPI OleDocument_CreateView(IOleDocument *iface, IOleInPlaceSite *pIPSite, IStream *pstm,
695                                    DWORD dwReserved, IOleDocumentView **ppView)
696 {
697     HTMLDocument *This = impl_from_IOleDocument(iface);
698     HRESULT hres;
699
700     TRACE("(%p)->(%p %p %d %p)\n", This, pIPSite, pstm, dwReserved, ppView);
701
702     if(!ppView)
703         return E_INVALIDARG;
704
705     /* FIXME:
706      * Windows implementation creates new IOleDocumentView when function is called for the
707      * first time and returns E_FAIL when it is called for the second time, but it doesn't matter
708      * if the application uses returned interfaces, passed to ActivateMe or returned by
709      * QueryInterface, so there is no reason to create new interface. This needs more testing.
710      */
711
712     if(pIPSite) {
713         hres = IOleDocumentView_SetInPlaceSite(&This->IOleDocumentView_iface, pIPSite);
714         if(FAILED(hres))
715             return hres;
716     }
717
718     if(pstm)
719         FIXME("pstm is not supported\n");
720
721     IOleDocumentView_AddRef(&This->IOleDocumentView_iface);
722     *ppView = &This->IOleDocumentView_iface;
723     return S_OK;
724 }
725
726 static HRESULT WINAPI OleDocument_GetDocMiscStatus(IOleDocument *iface, DWORD *pdwStatus)
727 {
728     HTMLDocument *This = impl_from_IOleDocument(iface);
729     FIXME("(%p)->(%p)\n", This, pdwStatus);
730     return E_NOTIMPL;
731 }
732
733 static HRESULT WINAPI OleDocument_EnumViews(IOleDocument *iface, IEnumOleDocumentViews **ppEnum,
734                                    IOleDocumentView **ppView)
735 {
736     HTMLDocument *This = impl_from_IOleDocument(iface);
737     FIXME("(%p)->(%p %p)\n", This, ppEnum, ppView);
738     return E_NOTIMPL;
739 }
740
741 static const IOleDocumentVtbl OleDocumentVtbl = {
742     OleDocument_QueryInterface,
743     OleDocument_AddRef,
744     OleDocument_Release,
745     OleDocument_CreateView,
746     OleDocument_GetDocMiscStatus,
747     OleDocument_EnumViews
748 };
749
750 /**********************************************************
751  * IOleControl implementation
752  */
753
754 static inline HTMLDocument *impl_from_IOleControl(IOleControl *iface)
755 {
756     return CONTAINING_RECORD(iface, HTMLDocument, IOleControl_iface);
757 }
758
759 static HRESULT WINAPI OleControl_QueryInterface(IOleControl *iface, REFIID riid, void **ppv)
760 {
761     HTMLDocument *This = impl_from_IOleControl(iface);
762     return htmldoc_query_interface(This, riid, ppv);
763 }
764
765 static ULONG WINAPI OleControl_AddRef(IOleControl *iface)
766 {
767     HTMLDocument *This = impl_from_IOleControl(iface);
768     return htmldoc_addref(This);
769 }
770
771 static ULONG WINAPI OleControl_Release(IOleControl *iface)
772 {
773     HTMLDocument *This = impl_from_IOleControl(iface);
774     return htmldoc_release(This);
775 }
776
777 static HRESULT WINAPI OleControl_GetControlInfo(IOleControl *iface, CONTROLINFO *pCI)
778 {
779     HTMLDocument *This = impl_from_IOleControl(iface);
780     FIXME("(%p)->(%p)\n", This, pCI);
781     return E_NOTIMPL;
782 }
783
784 static HRESULT WINAPI OleControl_OnMnemonic(IOleControl *iface, MSG *pMsg)
785 {
786     HTMLDocument *This = impl_from_IOleControl(iface);
787     FIXME("(%p)->(%p)\n", This, pMsg);
788     return E_NOTIMPL;
789 }
790
791 HRESULT get_client_disp_property(IOleClientSite *client, DISPID dispid, VARIANT *res)
792 {
793     IDispatch *disp = NULL;
794     DISPPARAMS dispparams = {NULL, 0};
795     UINT err;
796     HRESULT hres;
797
798     hres = IOleClientSite_QueryInterface(client, &IID_IDispatch, (void**)&disp);
799     if(FAILED(hres)) {
800         TRACE("Could not get IDispatch\n");
801         return hres;
802     }
803
804     VariantInit(res);
805
806     hres = IDispatch_Invoke(disp, dispid, &IID_NULL, LOCALE_SYSTEM_DEFAULT,
807             DISPATCH_PROPERTYGET, &dispparams, res, NULL, &err);
808
809     IDispatch_Release(disp);
810
811     return hres;
812 }
813
814 static HRESULT on_change_dlcontrol(HTMLDocument *This)
815 {
816     VARIANT res;
817     HRESULT hres;
818     
819     hres = get_client_disp_property(This->doc_obj->client, DISPID_AMBIENT_DLCONTROL, &res);
820     if(SUCCEEDED(hres))
821         FIXME("unsupported dlcontrol %08x\n", V_I4(&res));
822
823     return S_OK;
824 }
825
826 static HRESULT WINAPI OleControl_OnAmbientPropertyChange(IOleControl *iface, DISPID dispID)
827 {
828     HTMLDocument *This = impl_from_IOleControl(iface);
829     IOleClientSite *client;
830     VARIANT res;
831     HRESULT hres;
832
833     client = This->doc_obj->client;
834     if(!client) {
835         TRACE("client = NULL\n");
836         return S_OK;
837     }
838
839     switch(dispID) {
840     case DISPID_AMBIENT_USERMODE:
841         TRACE("(%p)->(DISPID_AMBIENT_USERMODE)\n", This);
842         hres = get_client_disp_property(client, DISPID_AMBIENT_USERMODE, &res);
843         if(FAILED(hres))
844             return S_OK;
845
846         if(V_VT(&res) == VT_BOOL) {
847             if(V_BOOL(&res)) {
848                 This->doc_obj->usermode = BROWSEMODE;
849             }else {
850                 FIXME("edit mode is not supported\n");
851                 This->doc_obj->usermode = EDITMODE;
852             }
853         }else {
854             FIXME("usermode=%s\n", debugstr_variant(&res));
855         }
856         return S_OK;
857     case DISPID_AMBIENT_DLCONTROL:
858         TRACE("(%p)->(DISPID_AMBIENT_DLCONTROL)\n", This);
859         return on_change_dlcontrol(This);
860     case DISPID_AMBIENT_OFFLINEIFNOTCONNECTED:
861         TRACE("(%p)->(DISPID_AMBIENT_OFFLINEIFNOTCONNECTED)\n", This);
862         on_change_dlcontrol(This);
863         hres = get_client_disp_property(client, DISPID_AMBIENT_OFFLINEIFNOTCONNECTED, &res);
864         if(FAILED(hres))
865             return S_OK;
866
867         if(V_VT(&res) == VT_BOOL) {
868             if(V_BOOL(&res)) {
869                 FIXME("offline connection is not supported\n");
870                 hres = E_FAIL;
871             }
872         }else {
873             FIXME("offlineconnected=%s\n", debugstr_variant(&res));
874         }
875         return S_OK;
876     case DISPID_AMBIENT_SILENT:
877         TRACE("(%p)->(DISPID_AMBIENT_SILENT)\n", This);
878         on_change_dlcontrol(This);
879         hres = get_client_disp_property(client, DISPID_AMBIENT_SILENT, &res);
880         if(FAILED(hres))
881             return S_OK;
882
883         if(V_VT(&res) == VT_BOOL) {
884             if(V_BOOL(&res)) {
885                 FIXME("silent mode is not supported\n");
886                 hres = E_FAIL;
887             }
888         }else {
889             FIXME("silent=%s\n", debugstr_variant(&res));
890         }
891         return S_OK;
892     case DISPID_AMBIENT_USERAGENT:
893         TRACE("(%p)->(DISPID_AMBIENT_USERAGENT)\n", This);
894         hres = get_client_disp_property(client, DISPID_AMBIENT_USERAGENT, &res);
895         if(FAILED(hres))
896             return S_OK;
897
898         FIXME("not supported AMBIENT_USERAGENT\n");
899         hres = E_FAIL;
900         return S_OK;
901     case DISPID_AMBIENT_PALETTE:
902         TRACE("(%p)->(DISPID_AMBIENT_PALETTE)\n", This);
903         hres = get_client_disp_property(client, DISPID_AMBIENT_PALETTE, &res);
904         if(FAILED(hres))
905             return S_OK;
906
907         FIXME("not supported AMBIENT_PALETTE\n");
908         hres = E_FAIL;
909         return S_OK;
910     }
911
912     FIXME("(%p) unsupported dispID=%d\n", This, dispID);
913     return E_FAIL;
914 }
915
916 static HRESULT WINAPI OleControl_FreezeEvents(IOleControl *iface, BOOL bFreeze)
917 {
918     HTMLDocument *This = impl_from_IOleControl(iface);
919     FIXME("(%p)->(%x)\n", This, bFreeze);
920     return E_NOTIMPL;
921 }
922
923 static const IOleControlVtbl OleControlVtbl = {
924     OleControl_QueryInterface,
925     OleControl_AddRef,
926     OleControl_Release,
927     OleControl_GetControlInfo,
928     OleControl_OnMnemonic,
929     OleControl_OnAmbientPropertyChange,
930     OleControl_FreezeEvents
931 };
932
933 /**********************************************************
934  * IObjectWithSite implementation
935  */
936
937 static inline HTMLDocument *impl_from_IObjectWithSite(IObjectWithSite *iface)
938 {
939     return CONTAINING_RECORD(iface, HTMLDocument, IObjectWithSite_iface);
940 }
941
942 static HRESULT WINAPI ObjectWithSite_QueryInterface(IObjectWithSite *iface, REFIID riid, void **ppv)
943 {
944     HTMLDocument *This = impl_from_IObjectWithSite(iface);
945     return htmldoc_query_interface(This, riid, ppv);
946 }
947
948 static ULONG WINAPI ObjectWithSite_AddRef(IObjectWithSite *iface)
949 {
950     HTMLDocument *This = impl_from_IObjectWithSite(iface);
951     return htmldoc_addref(This);
952 }
953
954 static ULONG WINAPI ObjectWithSite_Release(IObjectWithSite *iface)
955 {
956     HTMLDocument *This = impl_from_IObjectWithSite(iface);
957     return htmldoc_release(This);
958 }
959
960 static HRESULT WINAPI ObjectWithSite_SetSite(IObjectWithSite *iface, IUnknown *pUnkSite)
961 {
962     HTMLDocument *This = impl_from_IObjectWithSite(iface);
963     FIXME("(%p)->(%p)\n", This, pUnkSite);
964     return E_NOTIMPL;
965 }
966
967 static HRESULT WINAPI ObjectWithSite_GetSite(IObjectWithSite* iface, REFIID riid, PVOID *ppvSite)
968 {
969     HTMLDocument *This = impl_from_IObjectWithSite(iface);
970     FIXME("(%p)->(%p)\n", This, ppvSite);
971     return E_NOTIMPL;
972 }
973
974 static const IObjectWithSiteVtbl ObjectWithSiteVtbl = {
975     ObjectWithSite_QueryInterface,
976     ObjectWithSite_AddRef,
977     ObjectWithSite_Release,
978     ObjectWithSite_SetSite,
979     ObjectWithSite_GetSite
980 };
981
982 /**********************************************************
983  * IOleContainer implementation
984  */
985
986 static inline HTMLDocument *impl_from_IOleContainer(IOleContainer *iface)
987 {
988     return CONTAINING_RECORD(iface, HTMLDocument, IOleContainer_iface);
989 }
990
991 static HRESULT WINAPI OleContainer_QueryInterface(IOleContainer *iface, REFIID riid, void **ppv)
992 {
993     HTMLDocument *This = impl_from_IOleContainer(iface);
994     return htmldoc_query_interface(This, riid, ppv);
995 }
996
997 static ULONG WINAPI OleContainer_AddRef(IOleContainer *iface)
998 {
999     HTMLDocument *This = impl_from_IOleContainer(iface);
1000     return htmldoc_addref(This);
1001 }
1002
1003 static ULONG WINAPI OleContainer_Release(IOleContainer *iface)
1004 {
1005     HTMLDocument *This = impl_from_IOleContainer(iface);
1006     return htmldoc_release(This);
1007 }
1008
1009 static HRESULT WINAPI OleContainer_ParseDisplayName(IOleContainer *iface, IBindCtx *pbc, LPOLESTR pszDisplayName,
1010         ULONG *pchEaten, IMoniker **ppmkOut)
1011 {
1012     HTMLDocument *This = impl_from_IOleContainer(iface);
1013     FIXME("(%p)->(%p %s %p %p)\n", This, pbc, debugstr_w(pszDisplayName), pchEaten, ppmkOut);
1014     return E_NOTIMPL;
1015 }
1016
1017 static HRESULT WINAPI OleContainer_EnumObjects(IOleContainer *iface, DWORD grfFlags, IEnumUnknown **ppenum)
1018 {
1019     HTMLDocument *This = impl_from_IOleContainer(iface);
1020     EnumUnknown *ret;
1021
1022     TRACE("(%p)->(%x %p)\n", This, grfFlags, ppenum);
1023
1024     ret = heap_alloc(sizeof(*ret));
1025     if(!ret)
1026         return E_OUTOFMEMORY;
1027
1028     ret->IEnumUnknown_iface.lpVtbl = &EnumUnknownVtbl;
1029     ret->ref = 1;
1030
1031     *ppenum = &ret->IEnumUnknown_iface;
1032     return S_OK;
1033 }
1034
1035 static HRESULT WINAPI OleContainer_LockContainer(IOleContainer *iface, BOOL fLock)
1036 {
1037     HTMLDocument *This = impl_from_IOleContainer(iface);
1038     FIXME("(%p)->(%x)\n", This, fLock);
1039     return E_NOTIMPL;
1040 }
1041
1042 static const IOleContainerVtbl OleContainerVtbl = {
1043     OleContainer_QueryInterface,
1044     OleContainer_AddRef,
1045     OleContainer_Release,
1046     OleContainer_ParseDisplayName,
1047     OleContainer_EnumObjects,
1048     OleContainer_LockContainer
1049 };
1050
1051 static inline HTMLDocumentObj *impl_from_ITargetContainer(ITargetContainer *iface)
1052 {
1053     return CONTAINING_RECORD(iface, HTMLDocumentObj, ITargetContainer_iface);
1054 }
1055
1056 static HRESULT WINAPI TargetContainer_QueryInterface(ITargetContainer *iface, REFIID riid, void **ppv)
1057 {
1058     HTMLDocumentObj *This = impl_from_ITargetContainer(iface);
1059     return ICustomDoc_QueryInterface(&This->ICustomDoc_iface, riid, ppv);
1060 }
1061
1062 static ULONG WINAPI TargetContainer_AddRef(ITargetContainer *iface)
1063 {
1064     HTMLDocumentObj *This = impl_from_ITargetContainer(iface);
1065     return ICustomDoc_AddRef(&This->ICustomDoc_iface);
1066 }
1067
1068 static ULONG WINAPI TargetContainer_Release(ITargetContainer *iface)
1069 {
1070     HTMLDocumentObj *This = impl_from_ITargetContainer(iface);
1071     return ICustomDoc_Release(&This->ICustomDoc_iface);
1072 }
1073
1074 static HRESULT WINAPI TargetContainer_GetFrameUrl(ITargetContainer *iface, LPWSTR *ppszFrameSrc)
1075 {
1076     HTMLDocumentObj *This = impl_from_ITargetContainer(iface);
1077     FIXME("(%p)->(%p)\n", This, ppszFrameSrc);
1078     return E_NOTIMPL;
1079 }
1080
1081 static HRESULT WINAPI TargetContainer_GetFramesContainer(ITargetContainer *iface, IOleContainer **ppContainer)
1082 {
1083     HTMLDocumentObj *This = impl_from_ITargetContainer(iface);
1084
1085     TRACE("(%p)->(%p)\n", This, ppContainer);
1086
1087     /* NOTE: we should return wrapped interface here */
1088     IOleContainer_AddRef(&This->basedoc.IOleContainer_iface);
1089     *ppContainer = &This->basedoc.IOleContainer_iface;
1090     return S_OK;
1091 }
1092
1093 static const ITargetContainerVtbl TargetContainerVtbl = {
1094     TargetContainer_QueryInterface,
1095     TargetContainer_AddRef,
1096     TargetContainer_Release,
1097     TargetContainer_GetFrameUrl,
1098     TargetContainer_GetFramesContainer
1099 };
1100
1101 void TargetContainer_Init(HTMLDocumentObj *This)
1102 {
1103     This->ITargetContainer_iface.lpVtbl = &TargetContainerVtbl;
1104 }
1105
1106 /**********************************************************
1107  * IObjectSafety implementation
1108  */
1109
1110 static inline HTMLDocument *impl_from_IObjectSafety(IObjectSafety *iface)
1111 {
1112     return CONTAINING_RECORD(iface, HTMLDocument, IObjectSafety_iface);
1113 }
1114
1115 static HRESULT WINAPI ObjectSafety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
1116 {
1117     HTMLDocument *This = impl_from_IObjectSafety(iface);
1118     return htmldoc_query_interface(This, riid, ppv);
1119 }
1120
1121 static ULONG WINAPI ObjectSafety_AddRef(IObjectSafety *iface)
1122 {
1123     HTMLDocument *This = impl_from_IObjectSafety(iface);
1124     return htmldoc_addref(This);
1125 }
1126
1127 static ULONG WINAPI ObjectSafety_Release(IObjectSafety *iface)
1128 {
1129     HTMLDocument *This = impl_from_IObjectSafety(iface);
1130     return htmldoc_release(This);
1131 }
1132
1133 static HRESULT WINAPI ObjectSafety_GetInterfaceSafetyOptions(IObjectSafety *iface,
1134         REFIID riid, DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
1135 {
1136     HTMLDocument *This = impl_from_IObjectSafety(iface);
1137     FIXME("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), pdwSupportedOptions, pdwEnabledOptions);
1138     return E_NOTIMPL;
1139 }
1140
1141 static HRESULT WINAPI ObjectSafety_SetInterfaceSafetyOptions(IObjectSafety *iface,
1142         REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions)
1143 {
1144     HTMLDocument *This = impl_from_IObjectSafety(iface);
1145     FIXME("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), dwOptionSetMask, dwEnabledOptions);
1146
1147     if(IsEqualGUID(&IID_IPersistMoniker, riid) &&
1148             dwOptionSetMask==INTERFACESAFE_FOR_UNTRUSTED_DATA &&
1149             dwEnabledOptions==INTERFACESAFE_FOR_UNTRUSTED_DATA)
1150         return S_OK;
1151
1152     return E_NOTIMPL;
1153 }
1154
1155 static const IObjectSafetyVtbl ObjectSafetyVtbl = {
1156     ObjectSafety_QueryInterface,
1157     ObjectSafety_AddRef,
1158     ObjectSafety_Release,
1159     ObjectSafety_GetInterfaceSafetyOptions,
1160     ObjectSafety_SetInterfaceSafetyOptions
1161 };
1162
1163 void HTMLDocument_LockContainer(HTMLDocumentObj *This, BOOL fLock)
1164 {
1165     IOleContainer *container;
1166     HRESULT hres;
1167
1168     if(!This->client || This->container_locked == fLock)
1169         return;
1170
1171     hres = IOleClientSite_GetContainer(This->client, &container);
1172     if(SUCCEEDED(hres)) {
1173         IOleContainer_LockContainer(container, fLock);
1174         This->container_locked = fLock;
1175         IOleContainer_Release(container);
1176     }
1177 }
1178
1179 void HTMLDocument_OleObj_Init(HTMLDocument *This)
1180 {
1181     This->IOleObject_iface.lpVtbl = &OleObjectVtbl;
1182     This->IOleDocument_iface.lpVtbl = &OleDocumentVtbl;
1183     This->IOleControl_iface.lpVtbl = &OleControlVtbl;
1184     This->IObjectWithSite_iface.lpVtbl = &ObjectWithSiteVtbl;
1185     This->IOleContainer_iface.lpVtbl = &OleContainerVtbl;
1186     This->IObjectSafety_iface.lpVtbl = &ObjectSafetyVtbl;
1187 }