shdocvw: Added InternetExplorer object tests.
[wine] / dlls / mshtml / persist.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 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "ole2.h"
32 #include "shlguid.h"
33 #include "idispids.h"
34
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37
38 #include "mshtml_private.h"
39 #include "htmlevent.h"
40 #include "resource.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
43
44 typedef struct {
45     task_t header;
46     HTMLDocumentObj *doc;
47     BOOL set_download;
48     LPOLESTR url;
49 } download_proc_task_t;
50
51 static BOOL use_gecko_script(LPCWSTR url)
52 {
53     static const WCHAR fileW[] = {'f','i','l','e',':'};
54     static const WCHAR aboutW[] = {'a','b','o','u','t',':'};
55     static const WCHAR resW[] = {'r','e','s',':'};
56
57     return strncmpiW(fileW, url, sizeof(fileW)/sizeof(WCHAR))
58         && strncmpiW(aboutW, url, sizeof(aboutW)/sizeof(WCHAR))
59         && strncmpiW(resW, url, sizeof(resW)/sizeof(WCHAR));
60 }
61
62 void set_current_mon(HTMLWindow *This, IMoniker *mon)
63 {
64     HRESULT hres;
65
66     if(This->mon) {
67         IMoniker_Release(This->mon);
68         This->mon = NULL;
69     }
70
71     if(This->url) {
72         CoTaskMemFree(This->url);
73         This->url = NULL;
74     }
75
76     if(!mon)
77         return;
78
79     IMoniker_AddRef(mon);
80     This->mon = mon;
81
82     hres = IMoniker_GetDisplayName(mon, NULL, NULL, &This->url);
83     if(FAILED(hres))
84         WARN("GetDisplayName failed: %08x\n", hres);
85
86     set_script_mode(This, use_gecko_script(This->url) ? SCRIPTMODE_GECKO : SCRIPTMODE_ACTIVESCRIPT);
87 }
88
89 static void set_progress_proc(task_t *_task)
90 {
91     docobj_task_t *task = (docobj_task_t*)_task;
92     IOleCommandTarget *olecmd = NULL;
93     HTMLDocumentObj *doc = task->doc;
94     HRESULT hres;
95
96     TRACE("(%p)\n", doc);
97
98     if(doc->client)
99         IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&olecmd);
100
101     if(olecmd) {
102         VARIANT progress_max, progress;
103
104         V_VT(&progress_max) = VT_I4;
105         V_I4(&progress_max) = 0; /* FIXME */
106         IOleCommandTarget_Exec(olecmd, NULL, OLECMDID_SETPROGRESSMAX, OLECMDEXECOPT_DONTPROMPTUSER,
107                                &progress_max, NULL);
108
109         V_VT(&progress) = VT_I4;
110         V_I4(&progress) = 0; /* FIXME */
111         IOleCommandTarget_Exec(olecmd, NULL, OLECMDID_SETPROGRESSPOS, OLECMDEXECOPT_DONTPROMPTUSER,
112                                &progress, NULL);
113         IOleCommandTarget_Release(olecmd);
114     }
115
116     if(doc->usermode == EDITMODE && doc->hostui) {
117         DOCHOSTUIINFO hostinfo;
118
119         memset(&hostinfo, 0, sizeof(DOCHOSTUIINFO));
120         hostinfo.cbSize = sizeof(DOCHOSTUIINFO);
121         hres = IDocHostUIHandler_GetHostInfo(doc->hostui, &hostinfo);
122         if(SUCCEEDED(hres))
123             /* FIXME: use hostinfo */
124             TRACE("hostinfo = {%u %08x %08x %s %s}\n",
125                     hostinfo.cbSize, hostinfo.dwFlags, hostinfo.dwDoubleClick,
126                     debugstr_w(hostinfo.pchHostCss), debugstr_w(hostinfo.pchHostNS));
127     }
128 }
129
130 static void set_downloading_proc(task_t *_task)
131 {
132     download_proc_task_t *task = (download_proc_task_t*)_task;
133     HTMLDocumentObj *doc = task->doc;
134     IOleCommandTarget *olecmd;
135     HRESULT hres;
136
137     TRACE("(%p)\n", doc);
138
139     set_statustext(doc, IDS_STATUS_DOWNLOADINGFROM, task->url);
140     CoTaskMemFree(task->url);
141
142     if(!doc->client)
143         return;
144
145     if(task->set_download) {
146         hres = IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&olecmd);
147         if(SUCCEEDED(hres)) {
148             VARIANT var;
149
150             V_VT(&var) = VT_I4;
151             V_I4(&var) = 1;
152
153             IOleCommandTarget_Exec(olecmd, NULL, OLECMDID_SETDOWNLOADSTATE,
154                     OLECMDEXECOPT_DONTPROMPTUSER, &var, NULL);
155             IOleCommandTarget_Release(olecmd);
156         }
157
158         doc->download_state = 1;
159     }
160
161     if(doc->view_sink)
162         IAdviseSink_OnViewChange(doc->view_sink, DVASPECT_CONTENT, -1);
163
164     if(doc->hostui) {
165         IDropTarget *drop_target = NULL;
166
167         hres = IDocHostUIHandler_GetDropTarget(doc->hostui, NULL /* FIXME */, &drop_target);
168         if(drop_target) {
169             FIXME("Use IDropTarget\n");
170             IDropTarget_Release(drop_target);
171         }
172     }
173 }
174
175 HRESULT set_moniker(HTMLDocument *This, IMoniker *mon, IBindCtx *pibc, nsChannelBSC *async_bsc, BOOL set_download)
176 {
177     nsChannelBSC *bscallback;
178     docobj_task_t *task;
179     download_proc_task_t *download_task;
180     nsWineURI *nsuri;
181     LPOLESTR url;
182     HRESULT hres;
183
184     hres = IMoniker_GetDisplayName(mon, pibc, NULL, &url);
185     if(FAILED(hres)) {
186         WARN("GetDiaplayName failed: %08x\n", hres);
187         return hres;
188     }
189
190     TRACE("got url: %s\n", debugstr_w(url));
191
192     if(This->doc_obj->client) {
193         VARIANT silent, offline;
194
195         hres = get_client_disp_property(This->doc_obj->client, DISPID_AMBIENT_SILENT, &silent);
196         if(SUCCEEDED(hres)) {
197             if(V_VT(&silent) != VT_BOOL)
198                 WARN("V_VT(silent) = %d\n", V_VT(&silent));
199             else if(V_BOOL(&silent))
200                 FIXME("silent == true\n");
201         }
202
203         hres = get_client_disp_property(This->doc_obj->client,
204                 DISPID_AMBIENT_OFFLINEIFNOTCONNECTED, &offline);
205         if(SUCCEEDED(hres)) {
206             if(V_VT(&silent) != VT_BOOL)
207                 WARN("V_VT(offline) = %d\n", V_VT(&silent));
208             else if(V_BOOL(&silent))
209                 FIXME("offline == true\n");
210         }
211     }
212
213     if(This->window->mon) {
214         update_doc(This, UPDATE_TITLE|UPDATE_UI);
215     }else {
216         update_doc(This, UPDATE_TITLE);
217         set_current_mon(This->window, mon);
218     }
219
220     set_ready_state(This->window, READYSTATE_LOADING);
221
222     if(This->doc_obj->client) {
223         IOleCommandTarget *cmdtrg = NULL;
224
225         hres = IOleClientSite_QueryInterface(This->doc_obj->client, &IID_IOleCommandTarget,
226                 (void**)&cmdtrg);
227         if(SUCCEEDED(hres)) {
228             VARIANT var, out;
229
230             if(!async_bsc) {
231                 V_VT(&var) = VT_I4;
232                 V_I4(&var) = 0;
233                 IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 37, 0, &var, NULL);
234             }else {
235                 V_VT(&var) = VT_UNKNOWN;
236                 V_UNKNOWN(&var) = (IUnknown*)&This->window->IHTMLWindow2_iface;
237                 V_VT(&out) = VT_EMPTY;
238                 hres = IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 63, 0, &var, &out);
239                 if(SUCCEEDED(hres))
240                     VariantClear(&out);
241             }
242
243             IOleCommandTarget_Release(cmdtrg);
244         }
245     }
246
247     hres = create_doc_uri(This->window, url, &nsuri);
248
249     if(SUCCEEDED(hres))
250     {
251         if(async_bsc) {
252             bscallback = async_bsc;
253         }else {
254             hres = create_channelbsc(mon, NULL, NULL, 0, &bscallback);
255         }
256     }
257
258     if(SUCCEEDED(hres))
259     {
260         hres = load_nsuri(This->window, nsuri, bscallback, LOAD_INITIAL_DOCUMENT_URI);
261         nsISupports_Release((nsISupports*)nsuri); /* FIXME */
262         if(SUCCEEDED(hres))
263             set_window_bscallback(This->window, bscallback);
264         if(bscallback != async_bsc)
265             IUnknown_Release((IUnknown*)bscallback);
266     }
267
268     if(FAILED(hres))
269     {
270         CoTaskMemFree(url);
271         return hres;
272     }
273
274     HTMLDocument_LockContainer(This->doc_obj, TRUE);
275
276     if(This->doc_obj->frame) {
277         task = heap_alloc(sizeof(docobj_task_t));
278         task->doc = This->doc_obj;
279         push_task(&task->header, set_progress_proc, This->doc_obj->basedoc.task_magic);
280     }
281
282     download_task = heap_alloc(sizeof(download_proc_task_t));
283     download_task->doc = This->doc_obj;
284     download_task->set_download = set_download;
285     download_task->url = url;
286     push_task(&download_task->header, set_downloading_proc, This->doc_obj->basedoc.task_magic);
287
288     return S_OK;
289 }
290
291 void set_ready_state(HTMLWindow *window, READYSTATE readystate)
292 {
293     window->readystate = readystate;
294
295     if(window->doc_obj && window->doc_obj->basedoc.window == window)
296         call_property_onchanged(&window->doc_obj->basedoc.cp_propnotif, DISPID_READYSTATE);
297
298     fire_event(window->doc, EVENTID_READYSTATECHANGE, FALSE, window->doc->node.nsnode, NULL);
299
300     if(window->frame_element)
301         fire_event(window->frame_element->element.node.doc, EVENTID_READYSTATECHANGE,
302                    TRUE, window->frame_element->element.node.nsnode, NULL);
303 }
304
305 static HRESULT get_doc_string(HTMLDocumentNode *This, char **str)
306 {
307     nsIDOMNode *nsnode;
308     LPCWSTR strw;
309     nsAString nsstr;
310     nsresult nsres;
311
312     if(!This->nsdoc) {
313         WARN("NULL nsdoc\n");
314         return E_UNEXPECTED;
315     }
316
317     nsres = nsIDOMHTMLDocument_QueryInterface(This->nsdoc, &IID_nsIDOMNode, (void**)&nsnode);
318     if(NS_FAILED(nsres)) {
319         ERR("Could not get nsIDOMNode failed: %08x\n", nsres);
320         return E_FAIL;
321     }
322
323     nsAString_Init(&nsstr, NULL);
324     nsnode_to_nsstring(nsnode, &nsstr);
325     nsIDOMNode_Release(nsnode);
326
327     nsAString_GetData(&nsstr, &strw);
328     TRACE("%s\n", debugstr_w(strw));
329
330     *str = heap_strdupWtoA(strw);
331
332     nsAString_Finish(&nsstr);
333
334     return S_OK;
335 }
336
337
338 /**********************************************************
339  * IPersistMoniker implementation
340  */
341
342 static inline HTMLDocument *impl_from_IPersistMoniker(IPersistMoniker *iface)
343 {
344     return CONTAINING_RECORD(iface, HTMLDocument, IPersistMoniker_iface);
345 }
346
347 static HRESULT WINAPI PersistMoniker_QueryInterface(IPersistMoniker *iface, REFIID riid, void **ppv)
348 {
349     HTMLDocument *This = impl_from_IPersistMoniker(iface);
350     return htmldoc_query_interface(This, riid, ppv);
351 }
352
353 static ULONG WINAPI PersistMoniker_AddRef(IPersistMoniker *iface)
354 {
355     HTMLDocument *This = impl_from_IPersistMoniker(iface);
356     return htmldoc_addref(This);
357 }
358
359 static ULONG WINAPI PersistMoniker_Release(IPersistMoniker *iface)
360 {
361     HTMLDocument *This = impl_from_IPersistMoniker(iface);
362     return htmldoc_release(This);
363 }
364
365 static HRESULT WINAPI PersistMoniker_GetClassID(IPersistMoniker *iface, CLSID *pClassID)
366 {
367     HTMLDocument *This = impl_from_IPersistMoniker(iface);
368     return IPersist_GetClassID(&This->IPersistFile_iface, pClassID);
369 }
370
371 static HRESULT WINAPI PersistMoniker_IsDirty(IPersistMoniker *iface)
372 {
373     HTMLDocument *This = impl_from_IPersistMoniker(iface);
374
375     TRACE("(%p)\n", This);
376
377     return IPersistStreamInit_IsDirty(&This->IPersistStreamInit_iface);
378 }
379
380 static HRESULT WINAPI PersistMoniker_Load(IPersistMoniker *iface, BOOL fFullyAvailable,
381         IMoniker *pimkName, LPBC pibc, DWORD grfMode)
382 {
383     HTMLDocument *This = impl_from_IPersistMoniker(iface);
384     HRESULT hres;
385
386     TRACE("(%p)->(%x %p %p %08x)\n", This, fFullyAvailable, pimkName, pibc, grfMode);
387
388     if(pibc) {
389         IUnknown *unk = NULL;
390
391         /* FIXME:
392          * Use params:
393          * "__PrecreatedObject"
394          * "BIND_CONTEXT_PARAM"
395          * "__HTMLLOADOPTIONS"
396          * "__DWNBINDINFO"
397          * "URL Context"
398          * "_ITransData_Object_"
399          * "_EnumFORMATETC_"
400          */
401
402         IBindCtx_GetObjectParam(pibc, (LPOLESTR)SZ_HTML_CLIENTSITE_OBJECTPARAM, &unk);
403         if(unk) {
404             IOleClientSite *client = NULL;
405
406             hres = IUnknown_QueryInterface(unk, &IID_IOleClientSite, (void**)&client);
407             if(SUCCEEDED(hres)) {
408                 TRACE("Got client site %p\n", client);
409                 IOleObject_SetClientSite(&This->IOleObject_iface, client);
410                 IOleClientSite_Release(client);
411             }
412
413             IUnknown_Release(unk);
414         }
415     }
416
417     hres = set_moniker(This, pimkName, pibc, NULL, TRUE);
418     if(FAILED(hres))
419         return hres;
420
421     return start_binding(This->window, NULL, (BSCallback*)This->window->bscallback, pibc);
422 }
423
424 static HRESULT WINAPI PersistMoniker_Save(IPersistMoniker *iface, IMoniker *pimkName,
425         LPBC pbc, BOOL fRemember)
426 {
427     HTMLDocument *This = impl_from_IPersistMoniker(iface);
428     FIXME("(%p)->(%p %p %x)\n", This, pimkName, pbc, fRemember);
429     return E_NOTIMPL;
430 }
431
432 static HRESULT WINAPI PersistMoniker_SaveCompleted(IPersistMoniker *iface, IMoniker *pimkName, LPBC pibc)
433 {
434     HTMLDocument *This = impl_from_IPersistMoniker(iface);
435     FIXME("(%p)->(%p %p)\n", This, pimkName, pibc);
436     return E_NOTIMPL;
437 }
438
439 static HRESULT WINAPI PersistMoniker_GetCurMoniker(IPersistMoniker *iface, IMoniker **ppimkName)
440 {
441     HTMLDocument *This = impl_from_IPersistMoniker(iface);
442
443     TRACE("(%p)->(%p)\n", This, ppimkName);
444
445     if(!This->window || !This->window->mon)
446         return E_UNEXPECTED;
447
448     IMoniker_AddRef(This->window->mon);
449     *ppimkName = This->window->mon;
450     return S_OK;
451 }
452
453 static const IPersistMonikerVtbl PersistMonikerVtbl = {
454     PersistMoniker_QueryInterface,
455     PersistMoniker_AddRef,
456     PersistMoniker_Release,
457     PersistMoniker_GetClassID,
458     PersistMoniker_IsDirty,
459     PersistMoniker_Load,
460     PersistMoniker_Save,
461     PersistMoniker_SaveCompleted,
462     PersistMoniker_GetCurMoniker
463 };
464
465 /**********************************************************
466  * IMonikerProp implementation
467  */
468
469 static inline HTMLDocument *impl_from_IMonikerProp(IMonikerProp *iface)
470 {
471     return CONTAINING_RECORD(iface, HTMLDocument, IMonikerProp_iface);
472 }
473
474 static HRESULT WINAPI MonikerProp_QueryInterface(IMonikerProp *iface, REFIID riid, void **ppv)
475 {
476     HTMLDocument *This = impl_from_IMonikerProp(iface);
477     return htmldoc_query_interface(This, riid, ppv);
478 }
479
480 static ULONG WINAPI MonikerProp_AddRef(IMonikerProp *iface)
481 {
482     HTMLDocument *This = impl_from_IMonikerProp(iface);
483     return htmldoc_addref(This);
484 }
485
486 static ULONG WINAPI MonikerProp_Release(IMonikerProp *iface)
487 {
488     HTMLDocument *This = impl_from_IMonikerProp(iface);
489     return htmldoc_release(This);
490 }
491
492 static HRESULT WINAPI MonikerProp_PutProperty(IMonikerProp *iface, MONIKERPROPERTY mkp, LPCWSTR val)
493 {
494     HTMLDocument *This = impl_from_IMonikerProp(iface);
495
496     TRACE("(%p)->(%d %s)\n", This, mkp, debugstr_w(val));
497
498     switch(mkp) {
499     case MIMETYPEPROP:
500         heap_free(This->doc_obj->mime);
501         This->doc_obj->mime = heap_strdupW(val);
502         break;
503
504     case CLASSIDPROP:
505         break;
506
507     default:
508         FIXME("mkp %d\n", mkp);
509         return E_NOTIMPL;
510     }
511
512     return S_OK;
513 }
514
515 static const IMonikerPropVtbl MonikerPropVtbl = {
516     MonikerProp_QueryInterface,
517     MonikerProp_AddRef,
518     MonikerProp_Release,
519     MonikerProp_PutProperty
520 };
521
522 /**********************************************************
523  * IPersistFile implementation
524  */
525
526 static inline HTMLDocument *impl_from_IPersistFile(IPersistFile *iface)
527 {
528     return CONTAINING_RECORD(iface, HTMLDocument, IPersistFile_iface);
529 }
530
531 static HRESULT WINAPI PersistFile_QueryInterface(IPersistFile *iface, REFIID riid, void **ppv)
532 {
533     HTMLDocument *This = impl_from_IPersistFile(iface);
534     return htmldoc_query_interface(This, riid, ppv);
535 }
536
537 static ULONG WINAPI PersistFile_AddRef(IPersistFile *iface)
538 {
539     HTMLDocument *This = impl_from_IPersistFile(iface);
540     return htmldoc_addref(This);
541 }
542
543 static ULONG WINAPI PersistFile_Release(IPersistFile *iface)
544 {
545     HTMLDocument *This = impl_from_IPersistFile(iface);
546     return htmldoc_release(This);
547 }
548
549 static HRESULT WINAPI PersistFile_GetClassID(IPersistFile *iface, CLSID *pClassID)
550 {
551     HTMLDocument *This = impl_from_IPersistFile(iface);
552
553     TRACE("(%p)->(%p)\n", This, pClassID);
554
555     if(!pClassID)
556         return E_INVALIDARG;
557
558     *pClassID = CLSID_HTMLDocument;
559     return S_OK;
560 }
561
562 static HRESULT WINAPI PersistFile_IsDirty(IPersistFile *iface)
563 {
564     HTMLDocument *This = impl_from_IPersistFile(iface);
565
566     TRACE("(%p)\n", This);
567
568     return IPersistStreamInit_IsDirty(&This->IPersistStreamInit_iface);
569 }
570
571 static HRESULT WINAPI PersistFile_Load(IPersistFile *iface, LPCOLESTR pszFileName, DWORD dwMode)
572 {
573     HTMLDocument *This = impl_from_IPersistFile(iface);
574     FIXME("(%p)->(%s %08x)\n", This, debugstr_w(pszFileName), dwMode);
575     return E_NOTIMPL;
576 }
577
578 static HRESULT WINAPI PersistFile_Save(IPersistFile *iface, LPCOLESTR pszFileName, BOOL fRemember)
579 {
580     HTMLDocument *This = impl_from_IPersistFile(iface);
581     char *str;
582     DWORD written=0;
583     HANDLE file;
584     HRESULT hres;
585
586     TRACE("(%p)->(%s %x)\n", This, debugstr_w(pszFileName), fRemember);
587
588     file = CreateFileW(pszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
589                        FILE_ATTRIBUTE_NORMAL, NULL);
590     if(file == INVALID_HANDLE_VALUE) {
591         WARN("Could not create file: %u\n", GetLastError());
592         return E_FAIL;
593     }
594
595     hres = get_doc_string(This->doc_node, &str);
596     if(SUCCEEDED(hres))
597         WriteFile(file, str, strlen(str), &written, NULL);
598
599     CloseHandle(file);
600     return hres;
601 }
602
603 static HRESULT WINAPI PersistFile_SaveCompleted(IPersistFile *iface, LPCOLESTR pszFileName)
604 {
605     HTMLDocument *This = impl_from_IPersistFile(iface);
606     FIXME("(%p)->(%s)\n", This, debugstr_w(pszFileName));
607     return E_NOTIMPL;
608 }
609
610 static HRESULT WINAPI PersistFile_GetCurFile(IPersistFile *iface, LPOLESTR *pszFileName)
611 {
612     HTMLDocument *This = impl_from_IPersistFile(iface);
613     FIXME("(%p)->(%p)\n", This, pszFileName);
614     return E_NOTIMPL;
615 }
616
617 static const IPersistFileVtbl PersistFileVtbl = {
618     PersistFile_QueryInterface,
619     PersistFile_AddRef,
620     PersistFile_Release,
621     PersistFile_GetClassID,
622     PersistFile_IsDirty,
623     PersistFile_Load,
624     PersistFile_Save,
625     PersistFile_SaveCompleted,
626     PersistFile_GetCurFile
627 };
628
629 static inline HTMLDocument *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
630 {
631     return CONTAINING_RECORD(iface, HTMLDocument, IPersistStreamInit_iface);
632 }
633
634 static HRESULT WINAPI PersistStreamInit_QueryInterface(IPersistStreamInit *iface,
635                                                        REFIID riid, void **ppv)
636 {
637     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
638     return htmldoc_query_interface(This, riid, ppv);
639 }
640
641 static ULONG WINAPI PersistStreamInit_AddRef(IPersistStreamInit *iface)
642 {
643     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
644     return htmldoc_addref(This);
645 }
646
647 static ULONG WINAPI PersistStreamInit_Release(IPersistStreamInit *iface)
648 {
649     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
650     return htmldoc_release(This);
651 }
652
653 static HRESULT WINAPI PersistStreamInit_GetClassID(IPersistStreamInit *iface, CLSID *pClassID)
654 {
655     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
656     return IPersist_GetClassID(&This->IPersistFile_iface, pClassID);
657 }
658
659 static HRESULT WINAPI PersistStreamInit_IsDirty(IPersistStreamInit *iface)
660 {
661     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
662
663     TRACE("(%p)\n", This);
664
665     if(This->doc_obj->usermode == EDITMODE)
666         return editor_is_dirty(This);
667
668     return S_FALSE;
669 }
670
671 static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, LPSTREAM pStm)
672 {
673     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
674     IMoniker *mon;
675     HRESULT hres;
676
677     static const WCHAR about_blankW[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
678
679     TRACE("(%p)->(%p)\n", This, pStm);
680
681     hres = CreateURLMoniker(NULL, about_blankW, &mon);
682     if(FAILED(hres)) {
683         WARN("CreateURLMoniker failed: %08x\n", hres);
684         return hres;
685     }
686
687     hres = set_moniker(This, mon, NULL, NULL, TRUE);
688     IMoniker_Release(mon);
689     if(FAILED(hres))
690         return hres;
691
692     return channelbsc_load_stream(This->window->bscallback, pStm);
693 }
694
695 static HRESULT WINAPI PersistStreamInit_Save(IPersistStreamInit *iface, LPSTREAM pStm,
696                                              BOOL fClearDirty)
697 {
698     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
699     char *str;
700     DWORD written=0;
701     HRESULT hres;
702
703     TRACE("(%p)->(%p %x)\n", This, pStm, fClearDirty);
704
705     hres = get_doc_string(This->doc_node, &str);
706     if(FAILED(hres))
707         return hres;
708
709     hres = IStream_Write(pStm, str, strlen(str), &written);
710     if(FAILED(hres))
711         FIXME("Write failed: %08x\n", hres);
712
713     heap_free(str);
714
715     if(fClearDirty)
716         set_dirty(This, VARIANT_FALSE);
717
718     return S_OK;
719 }
720
721 static HRESULT WINAPI PersistStreamInit_GetSizeMax(IPersistStreamInit *iface,
722                                                    ULARGE_INTEGER *pcbSize)
723 {
724     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
725     FIXME("(%p)->(%p)\n", This, pcbSize);
726     return E_NOTIMPL;
727 }
728
729 static HRESULT WINAPI PersistStreamInit_InitNew(IPersistStreamInit *iface)
730 {
731     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
732     IMoniker *mon;
733     HRESULT hres;
734
735     static const WCHAR about_blankW[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
736
737     TRACE("(%p)\n", This);
738
739     hres = CreateURLMoniker(NULL, about_blankW, &mon);
740     if(FAILED(hres)) {
741         WARN("CreateURLMoniker failed: %08x\n", hres);
742         return hres;
743     }
744
745     hres = set_moniker(This, mon, NULL, NULL, FALSE);
746     IMoniker_Release(mon);
747     if(FAILED(hres))
748         return hres;
749
750     return channelbsc_load_stream(This->window->bscallback, NULL);
751 }
752
753 static const IPersistStreamInitVtbl PersistStreamInitVtbl = {
754     PersistStreamInit_QueryInterface,
755     PersistStreamInit_AddRef,
756     PersistStreamInit_Release,
757     PersistStreamInit_GetClassID,
758     PersistStreamInit_IsDirty,
759     PersistStreamInit_Load,
760     PersistStreamInit_Save,
761     PersistStreamInit_GetSizeMax,
762     PersistStreamInit_InitNew
763 };
764
765 /**********************************************************
766  * IPersistHistory implementation
767  */
768
769 static inline HTMLDocument *impl_from_IPersistHistory(IPersistHistory *iface)
770 {
771     return CONTAINING_RECORD(iface, HTMLDocument, IPersistHistory_iface);
772 }
773
774 static HRESULT WINAPI PersistHistory_QueryInterface(IPersistHistory *iface, REFIID riid, void **ppv)
775 {
776     HTMLDocument *This = impl_from_IPersistHistory(iface);
777     return htmldoc_query_interface(This, riid, ppv);
778 }
779
780 static ULONG WINAPI PersistHistory_AddRef(IPersistHistory *iface)
781 {
782     HTMLDocument *This = impl_from_IPersistHistory(iface);
783     return htmldoc_addref(This);
784 }
785
786 static ULONG WINAPI PersistHistory_Release(IPersistHistory *iface)
787 {
788     HTMLDocument *This = impl_from_IPersistHistory(iface);
789     return htmldoc_release(This);
790 }
791
792 static HRESULT WINAPI PersistHistory_GetClassID(IPersistHistory *iface, CLSID *pClassID)
793 {
794     HTMLDocument *This = impl_from_IPersistHistory(iface);
795     return IPersist_GetClassID(&This->IPersistFile_iface, pClassID);
796 }
797
798 static HRESULT WINAPI PersistHistory_LoadHistory(IPersistHistory *iface, IStream *pStream, IBindCtx *pbc)
799 {
800     HTMLDocument *This = impl_from_IPersistHistory(iface);
801     FIXME("(%p)->(%p %p)\n", This, pStream, pbc);
802     return E_NOTIMPL;
803 }
804
805 static HRESULT WINAPI PersistHistory_SaveHistory(IPersistHistory *iface, IStream *pStream)
806 {
807     HTMLDocument *This = impl_from_IPersistHistory(iface);
808     FIXME("(%p)->(%p)\n", This, pStream);
809     return E_NOTIMPL;
810 }
811
812 static HRESULT WINAPI PersistHistory_SetPositionCookie(IPersistHistory *iface, DWORD dwPositioncookie)
813 {
814     HTMLDocument *This = impl_from_IPersistHistory(iface);
815     FIXME("(%p)->(%x)\n", This, dwPositioncookie);
816     return E_NOTIMPL;
817 }
818
819 static HRESULT WINAPI PersistHistory_GetPositionCookie(IPersistHistory *iface, DWORD *pdwPositioncookie)
820 {
821     HTMLDocument *This = impl_from_IPersistHistory(iface);
822     FIXME("(%p)->(%p)\n", This, pdwPositioncookie);
823     return E_NOTIMPL;
824 }
825
826 static const IPersistHistoryVtbl PersistHistoryVtbl = {
827     PersistHistory_QueryInterface,
828     PersistHistory_AddRef,
829     PersistHistory_Release,
830     PersistHistory_GetClassID,
831     PersistHistory_LoadHistory,
832     PersistHistory_SaveHistory,
833     PersistHistory_SetPositionCookie,
834     PersistHistory_GetPositionCookie
835 };
836
837 void HTMLDocument_Persist_Init(HTMLDocument *This)
838 {
839     This->IPersistMoniker_iface.lpVtbl = &PersistMonikerVtbl;
840     This->IPersistFile_iface.lpVtbl = &PersistFileVtbl;
841     This->IMonikerProp_iface.lpVtbl = &MonikerPropVtbl;
842     This->IPersistStreamInit_iface.lpVtbl = &PersistStreamInitVtbl;
843     This->IPersistHistory_iface.lpVtbl = &PersistHistoryVtbl;
844 }