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