mshtml: Add a space before ellipses in the Slovenian translation.
[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*)HTMLWINDOW2(This->window);
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 #define PERSISTMON_THIS(iface) DEFINE_THIS(HTMLDocument, PersistMoniker, iface)
343
344 static HRESULT WINAPI PersistMoniker_QueryInterface(IPersistMoniker *iface, REFIID riid,
345                                                             void **ppvObject)
346 {
347     HTMLDocument *This = PERSISTMON_THIS(iface);
348     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppvObject);
349 }
350
351 static ULONG WINAPI PersistMoniker_AddRef(IPersistMoniker *iface)
352 {
353     HTMLDocument *This = PERSISTMON_THIS(iface);
354     return IHTMLDocument2_AddRef(HTMLDOC(This));
355 }
356
357 static ULONG WINAPI PersistMoniker_Release(IPersistMoniker *iface)
358 {
359     HTMLDocument *This = PERSISTMON_THIS(iface);
360     return IHTMLDocument2_Release(HTMLDOC(This));
361 }
362
363 static HRESULT WINAPI PersistMoniker_GetClassID(IPersistMoniker *iface, CLSID *pClassID)
364 {
365     HTMLDocument *This = PERSISTMON_THIS(iface);
366     return IPersist_GetClassID(PERSIST(This), pClassID);
367 }
368
369 static HRESULT WINAPI PersistMoniker_IsDirty(IPersistMoniker *iface)
370 {
371     HTMLDocument *This = PERSISTMON_THIS(iface);
372
373     TRACE("(%p)\n", This);
374
375     return IPersistStreamInit_IsDirty(PERSTRINIT(This));
376 }
377
378 static HRESULT WINAPI PersistMoniker_Load(IPersistMoniker *iface, BOOL fFullyAvailable,
379         IMoniker *pimkName, LPBC pibc, DWORD grfMode)
380 {
381     HTMLDocument *This = PERSISTMON_THIS(iface);
382     HRESULT hres;
383
384     TRACE("(%p)->(%x %p %p %08x)\n", This, fFullyAvailable, pimkName, pibc, grfMode);
385
386     if(pibc) {
387         IUnknown *unk = NULL;
388
389         /* FIXME:
390          * Use params:
391          * "__PrecreatedObject"
392          * "BIND_CONTEXT_PARAM"
393          * "__HTMLLOADOPTIONS"
394          * "__DWNBINDINFO"
395          * "URL Context"
396          * "_ITransData_Object_"
397          * "_EnumFORMATETC_"
398          */
399
400         IBindCtx_GetObjectParam(pibc, (LPOLESTR)SZ_HTML_CLIENTSITE_OBJECTPARAM, &unk);
401         if(unk) {
402             IOleClientSite *client = NULL;
403
404             hres = IUnknown_QueryInterface(unk, &IID_IOleClientSite, (void**)&client);
405             if(SUCCEEDED(hres)) {
406                 TRACE("Got client site %p\n", client);
407                 IOleObject_SetClientSite(OLEOBJ(This), client);
408                 IOleClientSite_Release(client);
409             }
410
411             IUnknown_Release(unk);
412         }
413     }
414
415     hres = set_moniker(This, pimkName, pibc, NULL, TRUE);
416     if(FAILED(hres))
417         return hres;
418
419     return start_binding(This->window, NULL, (BSCallback*)This->window->bscallback, pibc);
420 }
421
422 static HRESULT WINAPI PersistMoniker_Save(IPersistMoniker *iface, IMoniker *pimkName,
423         LPBC pbc, BOOL fRemember)
424 {
425     HTMLDocument *This = PERSISTMON_THIS(iface);
426     FIXME("(%p)->(%p %p %x)\n", This, pimkName, pbc, fRemember);
427     return E_NOTIMPL;
428 }
429
430 static HRESULT WINAPI PersistMoniker_SaveCompleted(IPersistMoniker *iface, IMoniker *pimkName, LPBC pibc)
431 {
432     HTMLDocument *This = PERSISTMON_THIS(iface);
433     FIXME("(%p)->(%p %p)\n", This, pimkName, pibc);
434     return E_NOTIMPL;
435 }
436
437 static HRESULT WINAPI PersistMoniker_GetCurMoniker(IPersistMoniker *iface, IMoniker **ppimkName)
438 {
439     HTMLDocument *This = PERSISTMON_THIS(iface);
440
441     TRACE("(%p)->(%p)\n", This, ppimkName);
442
443     if(!This->window || !This->window->mon)
444         return E_UNEXPECTED;
445
446     IMoniker_AddRef(This->window->mon);
447     *ppimkName = This->window->mon;
448     return S_OK;
449 }
450
451 static const IPersistMonikerVtbl PersistMonikerVtbl = {
452     PersistMoniker_QueryInterface,
453     PersistMoniker_AddRef,
454     PersistMoniker_Release,
455     PersistMoniker_GetClassID,
456     PersistMoniker_IsDirty,
457     PersistMoniker_Load,
458     PersistMoniker_Save,
459     PersistMoniker_SaveCompleted,
460     PersistMoniker_GetCurMoniker
461 };
462
463 /**********************************************************
464  * IMonikerProp implementation
465  */
466
467 #define MONPROP_THIS(iface) DEFINE_THIS(HTMLDocument, MonikerProp, iface)
468
469 static HRESULT WINAPI MonikerProp_QueryInterface(IMonikerProp *iface, REFIID riid, void **ppvObject)
470 {
471     HTMLDocument *This = MONPROP_THIS(iface);
472     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppvObject);
473 }
474
475 static ULONG WINAPI MonikerProp_AddRef(IMonikerProp *iface)
476 {
477     HTMLDocument *This = MONPROP_THIS(iface);
478     return IHTMLDocument2_AddRef(HTMLDOC(This));
479 }
480
481 static ULONG WINAPI MonikerProp_Release(IMonikerProp *iface)
482 {
483     HTMLDocument *This = MONPROP_THIS(iface);
484     return IHTMLDocument_Release(HTMLDOC(This));
485 }
486
487 static HRESULT WINAPI MonikerProp_PutProperty(IMonikerProp *iface, MONIKERPROPERTY mkp, LPCWSTR val)
488 {
489     HTMLDocument *This = MONPROP_THIS(iface);
490
491     TRACE("(%p)->(%d %s)\n", This, mkp, debugstr_w(val));
492
493     switch(mkp) {
494     case MIMETYPEPROP:
495         heap_free(This->doc_obj->mime);
496         This->doc_obj->mime = heap_strdupW(val);
497         break;
498
499     case CLASSIDPROP:
500         break;
501
502     default:
503         FIXME("mkp %d\n", mkp);
504         return E_NOTIMPL;
505     }
506
507     return S_OK;
508 }
509
510 static const IMonikerPropVtbl MonikerPropVtbl = {
511     MonikerProp_QueryInterface,
512     MonikerProp_AddRef,
513     MonikerProp_Release,
514     MonikerProp_PutProperty
515 };
516
517 /**********************************************************
518  * IPersistFile implementation
519  */
520
521 #define PERSISTFILE_THIS(iface) DEFINE_THIS(HTMLDocument, PersistFile, iface)
522
523 static HRESULT WINAPI PersistFile_QueryInterface(IPersistFile *iface, REFIID riid, void **ppvObject)
524 {
525     HTMLDocument *This = PERSISTFILE_THIS(iface);
526     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppvObject);
527 }
528
529 static ULONG WINAPI PersistFile_AddRef(IPersistFile *iface)
530 {
531     HTMLDocument *This = PERSISTFILE_THIS(iface);
532     return IHTMLDocument2_AddRef(HTMLDOC(This));
533 }
534
535 static ULONG WINAPI PersistFile_Release(IPersistFile *iface)
536 {
537     HTMLDocument *This = PERSISTFILE_THIS(iface);
538     return IHTMLDocument2_Release(HTMLDOC(This));
539 }
540
541 static HRESULT WINAPI PersistFile_GetClassID(IPersistFile *iface, CLSID *pClassID)
542 {
543     HTMLDocument *This = PERSISTFILE_THIS(iface);
544
545     TRACE("(%p)->(%p)\n", This, pClassID);
546
547     if(!pClassID)
548         return E_INVALIDARG;
549
550     *pClassID = CLSID_HTMLDocument;
551     return S_OK;
552 }
553
554 static HRESULT WINAPI PersistFile_IsDirty(IPersistFile *iface)
555 {
556     HTMLDocument *This = PERSISTFILE_THIS(iface);
557
558     TRACE("(%p)\n", This);
559
560     return IPersistStreamInit_IsDirty(PERSTRINIT(This));
561 }
562
563 static HRESULT WINAPI PersistFile_Load(IPersistFile *iface, LPCOLESTR pszFileName, DWORD dwMode)
564 {
565     HTMLDocument *This = PERSISTFILE_THIS(iface);
566     FIXME("(%p)->(%s %08x)\n", This, debugstr_w(pszFileName), dwMode);
567     return E_NOTIMPL;
568 }
569
570 static HRESULT WINAPI PersistFile_Save(IPersistFile *iface, LPCOLESTR pszFileName, BOOL fRemember)
571 {
572     HTMLDocument *This = PERSISTFILE_THIS(iface);
573     char *str;
574     DWORD written=0;
575     HANDLE file;
576     HRESULT hres;
577
578     TRACE("(%p)->(%s %x)\n", This, debugstr_w(pszFileName), fRemember);
579
580     file = CreateFileW(pszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
581                        FILE_ATTRIBUTE_NORMAL, NULL);
582     if(file == INVALID_HANDLE_VALUE) {
583         WARN("Could not create file: %u\n", GetLastError());
584         return E_FAIL;
585     }
586
587     hres = get_doc_string(This->doc_node, &str);
588     if(SUCCEEDED(hres))
589         WriteFile(file, str, strlen(str), &written, NULL);
590
591     CloseHandle(file);
592     return hres;
593 }
594
595 static HRESULT WINAPI PersistFile_SaveCompleted(IPersistFile *iface, LPCOLESTR pszFileName)
596 {
597     HTMLDocument *This = PERSISTFILE_THIS(iface);
598     FIXME("(%p)->(%s)\n", This, debugstr_w(pszFileName));
599     return E_NOTIMPL;
600 }
601
602 static HRESULT WINAPI PersistFile_GetCurFile(IPersistFile *iface, LPOLESTR *pszFileName)
603 {
604     HTMLDocument *This = PERSISTFILE_THIS(iface);
605     FIXME("(%p)->(%p)\n", This, pszFileName);
606     return E_NOTIMPL;
607 }
608
609 static const IPersistFileVtbl PersistFileVtbl = {
610     PersistFile_QueryInterface,
611     PersistFile_AddRef,
612     PersistFile_Release,
613     PersistFile_GetClassID,
614     PersistFile_IsDirty,
615     PersistFile_Load,
616     PersistFile_Save,
617     PersistFile_SaveCompleted,
618     PersistFile_GetCurFile
619 };
620
621 #define PERSTRINIT_THIS(iface) DEFINE_THIS(HTMLDocument, PersistStreamInit, iface)
622
623 static HRESULT WINAPI PersistStreamInit_QueryInterface(IPersistStreamInit *iface,
624                                                        REFIID riid, void **ppv)
625 {
626     HTMLDocument *This = PERSTRINIT_THIS(iface);
627     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppv);
628 }
629
630 static ULONG WINAPI PersistStreamInit_AddRef(IPersistStreamInit *iface)
631 {
632     HTMLDocument *This = PERSTRINIT_THIS(iface);
633     return IHTMLDocument2_AddRef(HTMLDOC(This));
634 }
635
636 static ULONG WINAPI PersistStreamInit_Release(IPersistStreamInit *iface)
637 {
638     HTMLDocument *This = PERSTRINIT_THIS(iface);
639     return IHTMLDocument2_Release(HTMLDOC(This));
640 }
641
642 static HRESULT WINAPI PersistStreamInit_GetClassID(IPersistStreamInit *iface, CLSID *pClassID)
643 {
644     HTMLDocument *This = PERSTRINIT_THIS(iface);
645     return IPersist_GetClassID(PERSIST(This), pClassID);
646 }
647
648 static HRESULT WINAPI PersistStreamInit_IsDirty(IPersistStreamInit *iface)
649 {
650     HTMLDocument *This = PERSTRINIT_THIS(iface);
651
652     TRACE("(%p)\n", This);
653
654     if(This->doc_obj->usermode == EDITMODE)
655         return editor_is_dirty(This);
656
657     return S_FALSE;
658 }
659
660 static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, LPSTREAM pStm)
661 {
662     HTMLDocument *This = PERSTRINIT_THIS(iface);
663     IMoniker *mon;
664     HRESULT hres;
665
666     static const WCHAR about_blankW[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
667
668     TRACE("(%p)->(%p)\n", This, pStm);
669
670     hres = CreateURLMoniker(NULL, about_blankW, &mon);
671     if(FAILED(hres)) {
672         WARN("CreateURLMoniker failed: %08x\n", hres);
673         return hres;
674     }
675
676     hres = set_moniker(This, mon, NULL, NULL, TRUE);
677     IMoniker_Release(mon);
678     if(FAILED(hres))
679         return hres;
680
681     return channelbsc_load_stream(This->window->bscallback, pStm);
682 }
683
684 static HRESULT WINAPI PersistStreamInit_Save(IPersistStreamInit *iface, LPSTREAM pStm,
685                                              BOOL fClearDirty)
686 {
687     HTMLDocument *This = PERSTRINIT_THIS(iface);
688     char *str;
689     DWORD written=0;
690     HRESULT hres;
691
692     TRACE("(%p)->(%p %x)\n", This, pStm, fClearDirty);
693
694     hres = get_doc_string(This->doc_node, &str);
695     if(FAILED(hres))
696         return hres;
697
698     hres = IStream_Write(pStm, str, strlen(str), &written);
699     if(FAILED(hres))
700         FIXME("Write failed: %08x\n", hres);
701
702     heap_free(str);
703
704     if(fClearDirty)
705         set_dirty(This, VARIANT_FALSE);
706
707     return S_OK;
708 }
709
710 static HRESULT WINAPI PersistStreamInit_GetSizeMax(IPersistStreamInit *iface,
711                                                    ULARGE_INTEGER *pcbSize)
712 {
713     HTMLDocument *This = PERSTRINIT_THIS(iface);
714     FIXME("(%p)->(%p)\n", This, pcbSize);
715     return E_NOTIMPL;
716 }
717
718 static HRESULT WINAPI PersistStreamInit_InitNew(IPersistStreamInit *iface)
719 {
720     HTMLDocument *This = PERSTRINIT_THIS(iface);
721     IMoniker *mon;
722     HRESULT hres;
723
724     static const WCHAR about_blankW[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
725
726     TRACE("(%p)\n", This);
727
728     hres = CreateURLMoniker(NULL, about_blankW, &mon);
729     if(FAILED(hres)) {
730         WARN("CreateURLMoniker failed: %08x\n", hres);
731         return hres;
732     }
733
734     hres = set_moniker(This, mon, NULL, NULL, FALSE);
735     IMoniker_Release(mon);
736     if(FAILED(hres))
737         return hres;
738
739     return channelbsc_load_stream(This->window->bscallback, NULL);
740 }
741
742 #undef PERSTRINIT_THIS
743
744 static const IPersistStreamInitVtbl PersistStreamInitVtbl = {
745     PersistStreamInit_QueryInterface,
746     PersistStreamInit_AddRef,
747     PersistStreamInit_Release,
748     PersistStreamInit_GetClassID,
749     PersistStreamInit_IsDirty,
750     PersistStreamInit_Load,
751     PersistStreamInit_Save,
752     PersistStreamInit_GetSizeMax,
753     PersistStreamInit_InitNew
754 };
755
756 /**********************************************************
757  * IPersistHistory implementation
758  */
759
760 #define PERSISTHIST_THIS(iface) DEFINE_THIS(HTMLDocument, PersistHistory, iface)
761
762 static HRESULT WINAPI PersistHistory_QueryInterface(IPersistHistory *iface, REFIID riid, void **ppvObject)
763 {
764     HTMLDocument *This = PERSISTHIST_THIS(iface);
765     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppvObject);
766 }
767
768 static ULONG WINAPI PersistHistory_AddRef(IPersistHistory *iface)
769 {
770     HTMLDocument *This = PERSISTHIST_THIS(iface);
771     return IHTMLDocument2_AddRef(HTMLDOC(This));
772 }
773
774 static ULONG WINAPI PersistHistory_Release(IPersistHistory *iface)
775 {
776     HTMLDocument *This = PERSISTHIST_THIS(iface);
777     return IHTMLDocument2_Release(HTMLDOC(This));
778 }
779
780 static HRESULT WINAPI PersistHistory_GetClassID(IPersistHistory *iface, CLSID *pClassID)
781 {
782     HTMLDocument *This = PERSISTHIST_THIS(iface);
783     return IPersist_GetClassID(PERSIST(This), pClassID);
784 }
785
786 static HRESULT WINAPI PersistHistory_LoadHistory(IPersistHistory *iface, IStream *pStream, IBindCtx *pbc)
787 {
788     HTMLDocument *This = PERSISTHIST_THIS(iface);
789     FIXME("(%p)->(%p %p)\n", This, pStream, pbc);
790     return E_NOTIMPL;
791 }
792
793 static HRESULT WINAPI PersistHistory_SaveHistory(IPersistHistory *iface, IStream *pStream)
794 {
795     HTMLDocument *This = PERSISTHIST_THIS(iface);
796     FIXME("(%p)->(%p)\n", This, pStream);
797     return E_NOTIMPL;
798 }
799
800 static HRESULT WINAPI PersistHistory_SetPositionCookie(IPersistHistory *iface, DWORD dwPositioncookie)
801 {
802     HTMLDocument *This = PERSISTHIST_THIS(iface);
803     FIXME("(%p)->(%x)\n", This, dwPositioncookie);
804     return E_NOTIMPL;
805 }
806
807 static HRESULT WINAPI PersistHistory_GetPositionCookie(IPersistHistory *iface, DWORD *pdwPositioncookie)
808 {
809     HTMLDocument *This = PERSISTHIST_THIS(iface);
810     FIXME("(%p)->(%p)\n", This, pdwPositioncookie);
811     return E_NOTIMPL;
812 }
813
814 #undef PERSISTHIST_THIS
815
816 static const IPersistHistoryVtbl PersistHistoryVtbl = {
817     PersistHistory_QueryInterface,
818     PersistHistory_AddRef,
819     PersistHistory_Release,
820     PersistHistory_GetClassID,
821     PersistHistory_LoadHistory,
822     PersistHistory_SaveHistory,
823     PersistHistory_SetPositionCookie,
824     PersistHistory_GetPositionCookie
825 };
826
827 void HTMLDocument_Persist_Init(HTMLDocument *This)
828 {
829     This->lpPersistMonikerVtbl = &PersistMonikerVtbl;
830     This->lpPersistFileVtbl = &PersistFileVtbl;
831     This->lpMonikerPropVtbl = &MonikerPropVtbl;
832     This->lpPersistStreamInitVtbl = &PersistStreamInitVtbl;
833     This->lpPersistHistoryVtbl = &PersistHistoryVtbl;
834 }