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