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