mshtml: Moved bscallback to HTMLWindow.
[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
40 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
41
42 static BOOL use_gecko_script(LPCWSTR url)
43 {
44     static const WCHAR fileW[] = {'f','i','l','e',':'};
45     static const WCHAR aboutW[] = {'a','b','o','u','t',':'};
46
47     return strncmpiW(fileW, url, sizeof(fileW)/sizeof(WCHAR))
48         && strncmpiW(aboutW, url, sizeof(aboutW)/sizeof(WCHAR));
49 }
50
51 void set_current_mon(HTMLDocument *This, IMoniker *mon)
52 {
53     HRESULT hres;
54
55     if(This->doc_obj->mon) {
56         IMoniker_Release(This->doc_obj->mon);
57         This->doc_obj->mon = NULL;
58     }
59
60     if(This->doc_obj->url) {
61         CoTaskMemFree(This->doc_obj->url);
62         This->doc_obj->url = NULL;
63     }
64
65     if(!mon)
66         return;
67
68     IMoniker_AddRef(mon);
69     This->doc_obj->mon = mon;
70
71     hres = IMoniker_GetDisplayName(mon, NULL, NULL, &This->doc_obj->url);
72     if(FAILED(hres))
73         WARN("GetDisplayName failed: %08x\n", hres);
74
75     set_script_mode(This->window, use_gecko_script(This->doc_obj->url) ? SCRIPTMODE_GECKO : SCRIPTMODE_ACTIVESCRIPT);
76 }
77
78 static HRESULT set_moniker(HTMLDocument *This, IMoniker *mon, IBindCtx *pibc, BOOL *bind_complete)
79 {
80     nsChannelBSC *bscallback;
81     LPOLESTR url = NULL;
82     task_t *task;
83     HRESULT hres;
84     nsresult nsres;
85
86     if(pibc) {
87         IUnknown *unk = NULL;
88
89         /* FIXME:
90          * Use params:
91          * "__PrecreatedObject"
92          * "BIND_CONTEXT_PARAM"
93          * "__HTMLLOADOPTIONS"
94          * "__DWNBINDINFO"
95          * "URL Context"
96          * "CBinding Context"
97          * "_ITransData_Object_"
98          * "_EnumFORMATETC_"
99          */
100
101         IBindCtx_GetObjectParam(pibc, (LPOLESTR)SZ_HTML_CLIENTSITE_OBJECTPARAM, &unk);
102         if(unk) {
103             IOleClientSite *client = NULL;
104
105             hres = IUnknown_QueryInterface(unk, &IID_IOleClientSite, (void**)&client);
106             if(SUCCEEDED(hres)) {
107                 TRACE("Got client site %p\n", client);
108                 IOleObject_SetClientSite(OLEOBJ(This), client);
109                 IOleClientSite_Release(client);
110             }
111
112             IUnknown_Release(unk);
113         }
114     }
115
116     This->doc_obj->readystate = READYSTATE_LOADING;
117     call_property_onchanged(&This->cp_propnotif, DISPID_READYSTATE);
118     update_doc(This, UPDATE_TITLE);
119
120     HTMLDocument_LockContainer(This->doc_obj, TRUE);
121     
122     hres = IMoniker_GetDisplayName(mon, pibc, NULL, &url);
123     if(FAILED(hres)) {
124         WARN("GetDiaplayName failed: %08x\n", hres);
125         return hres;
126     }
127
128     TRACE("got url: %s\n", debugstr_w(url));
129
130     set_current_mon(This, mon);
131
132     if(This->doc_obj->client) {
133         VARIANT silent, offline;
134         IOleCommandTarget *cmdtrg = NULL;
135
136         hres = get_client_disp_property(This->doc_obj->client, DISPID_AMBIENT_SILENT, &silent);
137         if(SUCCEEDED(hres)) {
138             if(V_VT(&silent) != VT_BOOL)
139                 WARN("V_VT(silent) = %d\n", V_VT(&silent));
140             else if(V_BOOL(&silent))
141                 FIXME("silent == true\n");
142         }
143
144         hres = get_client_disp_property(This->doc_obj->client,
145                 DISPID_AMBIENT_OFFLINEIFNOTCONNECTED, &offline);
146         if(SUCCEEDED(hres)) {
147             if(V_VT(&silent) != VT_BOOL)
148                 WARN("V_VT(offline) = %d\n", V_VT(&silent));
149             else if(V_BOOL(&silent))
150                 FIXME("offline == true\n");
151         }
152
153         hres = IOleClientSite_QueryInterface(This->doc_obj->client, &IID_IOleCommandTarget,
154                 (void**)&cmdtrg);
155         if(SUCCEEDED(hres)) {
156             VARIANT var;
157
158             V_VT(&var) = VT_I4;
159             V_I4(&var) = 0;
160             IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 37, 0, &var, NULL);
161
162             IOleCommandTarget_Release(cmdtrg);
163         }
164     }
165
166     bscallback = create_channelbsc(mon);
167
168     if(This->doc_obj->frame) {
169         task = heap_alloc(sizeof(task_t));
170
171         task->doc = This;
172         task->task_id = TASK_SETPROGRESS;
173         task->next = NULL;
174
175         push_task(task);
176     }
177
178     task = heap_alloc(sizeof(task_t));
179
180     task->doc = This;
181     task->task_id = TASK_SETDOWNLOADSTATE;
182     task->next = NULL;
183
184     push_task(task);
185
186     if(This->doc_obj->nscontainer) {
187         This->doc_obj->nscontainer->bscallback = bscallback;
188         nsres = nsIWebNavigation_LoadURI(This->doc_obj->nscontainer->navigation, url,
189                 LOAD_FLAGS_NONE, NULL, NULL, NULL);
190         This->doc_obj->nscontainer->bscallback = NULL;
191         if(NS_FAILED(nsres)) {
192             WARN("LoadURI failed: %08x\n", nsres);
193             IUnknown_Release((IUnknown*)bscallback);
194             CoTaskMemFree(url);
195             return E_FAIL;
196         }
197     }
198
199     set_window_bscallback(This->window, bscallback);
200     IUnknown_Release((IUnknown*)bscallback);
201     CoTaskMemFree(url);
202
203     if(bind_complete)
204         *bind_complete = FALSE;
205     return S_OK;
206 }
207
208 static HRESULT get_doc_string(HTMLDocumentNode *This, char **str)
209 {
210     nsIDOMNode *nsnode;
211     LPCWSTR strw;
212     nsAString nsstr;
213     nsresult nsres;
214
215     if(!This->nsdoc) {
216         WARN("NULL nsdoc\n");
217         return E_UNEXPECTED;
218     }
219
220     nsres = nsIDOMHTMLDocument_QueryInterface(This->nsdoc, &IID_nsIDOMNode, (void**)&nsnode);
221     if(NS_FAILED(nsres)) {
222         ERR("Could not get nsIDOMNode failed: %08x\n", nsres);
223         return E_FAIL;
224     }
225
226     nsAString_Init(&nsstr, NULL);
227     nsnode_to_nsstring(nsnode, &nsstr);
228     nsIDOMNode_Release(nsnode);
229
230     nsAString_GetData(&nsstr, &strw);
231     TRACE("%s\n", debugstr_w(strw));
232
233     *str = heap_strdupWtoA(strw);
234
235     nsAString_Finish(&nsstr);
236
237     return S_OK;
238 }
239
240
241 /**********************************************************
242  * IPersistMoniker implementation
243  */
244
245 #define PERSISTMON_THIS(iface) DEFINE_THIS(HTMLDocument, PersistMoniker, iface)
246
247 static HRESULT WINAPI PersistMoniker_QueryInterface(IPersistMoniker *iface, REFIID riid,
248                                                             void **ppvObject)
249 {
250     HTMLDocument *This = PERSISTMON_THIS(iface);
251     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppvObject);
252 }
253
254 static ULONG WINAPI PersistMoniker_AddRef(IPersistMoniker *iface)
255 {
256     HTMLDocument *This = PERSISTMON_THIS(iface);
257     return IHTMLDocument2_AddRef(HTMLDOC(This));
258 }
259
260 static ULONG WINAPI PersistMoniker_Release(IPersistMoniker *iface)
261 {
262     HTMLDocument *This = PERSISTMON_THIS(iface);
263     return IHTMLDocument2_Release(HTMLDOC(This));
264 }
265
266 static HRESULT WINAPI PersistMoniker_GetClassID(IPersistMoniker *iface, CLSID *pClassID)
267 {
268     HTMLDocument *This = PERSISTMON_THIS(iface);
269     return IPersist_GetClassID(PERSIST(This), pClassID);
270 }
271
272 static HRESULT WINAPI PersistMoniker_IsDirty(IPersistMoniker *iface)
273 {
274     HTMLDocument *This = PERSISTMON_THIS(iface);
275
276     TRACE("(%p)\n", This);
277
278     return IPersistStreamInit_IsDirty(PERSTRINIT(This));
279 }
280
281 static HRESULT WINAPI PersistMoniker_Load(IPersistMoniker *iface, BOOL fFullyAvailable,
282         IMoniker *pimkName, LPBC pibc, DWORD grfMode)
283 {
284     HTMLDocument *This = PERSISTMON_THIS(iface);
285     BOOL bind_complete = FALSE;
286     HRESULT hres;
287
288     TRACE("(%p)->(%x %p %p %08x)\n", This, fFullyAvailable, pimkName, pibc, grfMode);
289
290     hres = set_moniker(This, pimkName, pibc, &bind_complete);
291     if(FAILED(hres))
292         return hres;
293
294     if(!bind_complete)
295         return start_binding(This, (BSCallback*)This->window->bscallback, pibc);
296
297     return S_OK;
298 }
299
300 static HRESULT WINAPI PersistMoniker_Save(IPersistMoniker *iface, IMoniker *pimkName,
301         LPBC pbc, BOOL fRemember)
302 {
303     HTMLDocument *This = PERSISTMON_THIS(iface);
304     FIXME("(%p)->(%p %p %x)\n", This, pimkName, pbc, fRemember);
305     return E_NOTIMPL;
306 }
307
308 static HRESULT WINAPI PersistMoniker_SaveCompleted(IPersistMoniker *iface, IMoniker *pimkName, LPBC pibc)
309 {
310     HTMLDocument *This = PERSISTMON_THIS(iface);
311     FIXME("(%p)->(%p %p)\n", This, pimkName, pibc);
312     return E_NOTIMPL;
313 }
314
315 static HRESULT WINAPI PersistMoniker_GetCurMoniker(IPersistMoniker *iface, IMoniker **ppimkName)
316 {
317     HTMLDocument *This = PERSISTMON_THIS(iface);
318
319     TRACE("(%p)->(%p)\n", This, ppimkName);
320
321     if(!This->doc_obj->mon)
322         return E_UNEXPECTED;
323
324     IMoniker_AddRef(This->doc_obj->mon);
325     *ppimkName = This->doc_obj->mon;
326     return S_OK;
327 }
328
329 static const IPersistMonikerVtbl PersistMonikerVtbl = {
330     PersistMoniker_QueryInterface,
331     PersistMoniker_AddRef,
332     PersistMoniker_Release,
333     PersistMoniker_GetClassID,
334     PersistMoniker_IsDirty,
335     PersistMoniker_Load,
336     PersistMoniker_Save,
337     PersistMoniker_SaveCompleted,
338     PersistMoniker_GetCurMoniker
339 };
340
341 /**********************************************************
342  * IMonikerProp implementation
343  */
344
345 #define MONPROP_THIS(iface) DEFINE_THIS(HTMLDocument, MonikerProp, iface)
346
347 static HRESULT WINAPI MonikerProp_QueryInterface(IMonikerProp *iface, REFIID riid, void **ppvObject)
348 {
349     HTMLDocument *This = MONPROP_THIS(iface);
350     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppvObject);
351 }
352
353 static ULONG WINAPI MonikerProp_AddRef(IMonikerProp *iface)
354 {
355     HTMLDocument *This = MONPROP_THIS(iface);
356     return IHTMLDocument2_AddRef(HTMLDOC(This));
357 }
358
359 static ULONG WINAPI MonikerProp_Release(IMonikerProp *iface)
360 {
361     HTMLDocument *This = MONPROP_THIS(iface);
362     return IHTMLDocument_Release(HTMLDOC(This));
363 }
364
365 static HRESULT WINAPI MonikerProp_PutProperty(IMonikerProp *iface, MONIKERPROPERTY mkp, LPCWSTR val)
366 {
367     HTMLDocument *This = MONPROP_THIS(iface);
368
369     TRACE("(%p)->(%d %s)\n", This, mkp, debugstr_w(val));
370
371     switch(mkp) {
372     case MIMETYPEPROP:
373         heap_free(This->doc_obj->mime);
374         This->doc_obj->mime = heap_strdupW(val);
375         break;
376
377     case CLASSIDPROP:
378         break;
379
380     default:
381         FIXME("mkp %d\n", mkp);
382         return E_NOTIMPL;
383     }
384
385     return S_OK;
386 }
387
388 static const IMonikerPropVtbl MonikerPropVtbl = {
389     MonikerProp_QueryInterface,
390     MonikerProp_AddRef,
391     MonikerProp_Release,
392     MonikerProp_PutProperty
393 };
394
395 /**********************************************************
396  * IPersistFile implementation
397  */
398
399 #define PERSISTFILE_THIS(iface) DEFINE_THIS(HTMLDocument, PersistFile, iface)
400
401 static HRESULT WINAPI PersistFile_QueryInterface(IPersistFile *iface, REFIID riid, void **ppvObject)
402 {
403     HTMLDocument *This = PERSISTFILE_THIS(iface);
404     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppvObject);
405 }
406
407 static ULONG WINAPI PersistFile_AddRef(IPersistFile *iface)
408 {
409     HTMLDocument *This = PERSISTFILE_THIS(iface);
410     return IHTMLDocument2_AddRef(HTMLDOC(This));
411 }
412
413 static ULONG WINAPI PersistFile_Release(IPersistFile *iface)
414 {
415     HTMLDocument *This = PERSISTFILE_THIS(iface);
416     return IHTMLDocument2_Release(HTMLDOC(This));
417 }
418
419 static HRESULT WINAPI PersistFile_GetClassID(IPersistFile *iface, CLSID *pClassID)
420 {
421     HTMLDocument *This = PERSISTFILE_THIS(iface);
422
423     TRACE("(%p)->(%p)\n", This, pClassID);
424
425     if(!pClassID)
426         return E_INVALIDARG;
427
428     *pClassID = CLSID_HTMLDocument;
429     return S_OK;
430 }
431
432 static HRESULT WINAPI PersistFile_IsDirty(IPersistFile *iface)
433 {
434     HTMLDocument *This = PERSISTFILE_THIS(iface);
435
436     TRACE("(%p)\n", This);
437
438     return IPersistStreamInit_IsDirty(PERSTRINIT(This));
439 }
440
441 static HRESULT WINAPI PersistFile_Load(IPersistFile *iface, LPCOLESTR pszFileName, DWORD dwMode)
442 {
443     HTMLDocument *This = PERSISTFILE_THIS(iface);
444     FIXME("(%p)->(%s %08x)\n", This, debugstr_w(pszFileName), dwMode);
445     return E_NOTIMPL;
446 }
447
448 static HRESULT WINAPI PersistFile_Save(IPersistFile *iface, LPCOLESTR pszFileName, BOOL fRemember)
449 {
450     HTMLDocument *This = PERSISTFILE_THIS(iface);
451     char *str;
452     DWORD written=0;
453     HANDLE file;
454     HRESULT hres;
455
456     TRACE("(%p)->(%s %x)\n", This, debugstr_w(pszFileName), fRemember);
457
458     file = CreateFileW(pszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
459                        FILE_ATTRIBUTE_NORMAL, NULL);
460     if(file == INVALID_HANDLE_VALUE) {
461         WARN("Could not create file: %u\n", GetLastError());
462         return E_FAIL;
463     }
464
465     hres = get_doc_string(This->doc_node, &str);
466     if(SUCCEEDED(hres))
467         WriteFile(file, str, strlen(str), &written, NULL);
468
469     CloseHandle(file);
470     return hres;
471 }
472
473 static HRESULT WINAPI PersistFile_SaveCompleted(IPersistFile *iface, LPCOLESTR pszFileName)
474 {
475     HTMLDocument *This = PERSISTFILE_THIS(iface);
476     FIXME("(%p)->(%s)\n", This, debugstr_w(pszFileName));
477     return E_NOTIMPL;
478 }
479
480 static HRESULT WINAPI PersistFile_GetCurFile(IPersistFile *iface, LPOLESTR *pszFileName)
481 {
482     HTMLDocument *This = PERSISTFILE_THIS(iface);
483     FIXME("(%p)->(%p)\n", This, pszFileName);
484     return E_NOTIMPL;
485 }
486
487 static const IPersistFileVtbl PersistFileVtbl = {
488     PersistFile_QueryInterface,
489     PersistFile_AddRef,
490     PersistFile_Release,
491     PersistFile_GetClassID,
492     PersistFile_IsDirty,
493     PersistFile_Load,
494     PersistFile_Save,
495     PersistFile_SaveCompleted,
496     PersistFile_GetCurFile
497 };
498
499 #define PERSTRINIT_THIS(iface) DEFINE_THIS(HTMLDocument, PersistStreamInit, iface)
500
501 static HRESULT WINAPI PersistStreamInit_QueryInterface(IPersistStreamInit *iface,
502                                                        REFIID riid, void **ppv)
503 {
504     HTMLDocument *This = PERSTRINIT_THIS(iface);
505     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppv);
506 }
507
508 static ULONG WINAPI PersistStreamInit_AddRef(IPersistStreamInit *iface)
509 {
510     HTMLDocument *This = PERSTRINIT_THIS(iface);
511     return IHTMLDocument2_AddRef(HTMLDOC(This));
512 }
513
514 static ULONG WINAPI PersistStreamInit_Release(IPersistStreamInit *iface)
515 {
516     HTMLDocument *This = PERSTRINIT_THIS(iface);
517     return IHTMLDocument2_Release(HTMLDOC(This));
518 }
519
520 static HRESULT WINAPI PersistStreamInit_GetClassID(IPersistStreamInit *iface, CLSID *pClassID)
521 {
522     HTMLDocument *This = PERSTRINIT_THIS(iface);
523     return IPersist_GetClassID(PERSIST(This), pClassID);
524 }
525
526 static HRESULT WINAPI PersistStreamInit_IsDirty(IPersistStreamInit *iface)
527 {
528     HTMLDocument *This = PERSTRINIT_THIS(iface);
529
530     TRACE("(%p)\n", This);
531
532     if(This->doc_obj->usermode == EDITMODE)
533         return editor_is_dirty(This);
534
535     return S_FALSE;
536 }
537
538 static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, LPSTREAM pStm)
539 {
540     HTMLDocument *This = PERSTRINIT_THIS(iface);
541     IMoniker *mon;
542     HRESULT hres;
543
544     static const WCHAR about_blankW[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
545
546     TRACE("(%p)->(%p)\n", This, pStm);
547
548     hres = CreateURLMoniker(NULL, about_blankW, &mon);
549     if(FAILED(hres)) {
550         WARN("CreateURLMoniker failed: %08x\n", hres);
551         return hres;
552     }
553
554     hres = set_moniker(This, mon, NULL, NULL);
555     IMoniker_Release(mon);
556     if(FAILED(hres))
557         return hres;
558
559     return channelbsc_load_stream(This->window->bscallback, pStm);
560 }
561
562 static HRESULT WINAPI PersistStreamInit_Save(IPersistStreamInit *iface, LPSTREAM pStm,
563                                              BOOL fClearDirty)
564 {
565     HTMLDocument *This = PERSTRINIT_THIS(iface);
566     char *str;
567     DWORD written=0;
568     HRESULT hres;
569
570     TRACE("(%p)->(%p %x)\n", This, pStm, fClearDirty);
571
572     hres = get_doc_string(This->doc_node, &str);
573     if(FAILED(hres))
574         return hres;
575
576     hres = IStream_Write(pStm, str, strlen(str), &written);
577     if(FAILED(hres))
578         FIXME("Write failed: %08x\n", hres);
579
580     heap_free(str);
581
582     if(fClearDirty)
583         set_dirty(This, VARIANT_FALSE);
584
585     return S_OK;
586 }
587
588 static HRESULT WINAPI PersistStreamInit_GetSizeMax(IPersistStreamInit *iface,
589                                                    ULARGE_INTEGER *pcbSize)
590 {
591     HTMLDocument *This = PERSTRINIT_THIS(iface);
592     FIXME("(%p)->(%p)\n", This, pcbSize);
593     return E_NOTIMPL;
594 }
595
596 static HRESULT WINAPI PersistStreamInit_InitNew(IPersistStreamInit *iface)
597 {
598     HTMLDocument *This = PERSTRINIT_THIS(iface);
599     FIXME("(%p)\n", This);
600     return E_NOTIMPL;
601 }
602
603 #undef PERSTRINIT_THIS
604
605 static const IPersistStreamInitVtbl PersistStreamInitVtbl = {
606     PersistStreamInit_QueryInterface,
607     PersistStreamInit_AddRef,
608     PersistStreamInit_Release,
609     PersistStreamInit_GetClassID,
610     PersistStreamInit_IsDirty,
611     PersistStreamInit_Load,
612     PersistStreamInit_Save,
613     PersistStreamInit_GetSizeMax,
614     PersistStreamInit_InitNew
615 };
616
617 /**********************************************************
618  * IPersistHistory implementation
619  */
620
621 #define PERSISTHIST_THIS(iface) DEFINE_THIS(HTMLDocument, PersistHistory, iface)
622
623 static HRESULT WINAPI PersistHistory_QueryInterface(IPersistHistory *iface, REFIID riid, void **ppvObject)
624 {
625     HTMLDocument *This = PERSISTHIST_THIS(iface);
626     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppvObject);
627 }
628
629 static ULONG WINAPI PersistHistory_AddRef(IPersistHistory *iface)
630 {
631     HTMLDocument *This = PERSISTHIST_THIS(iface);
632     return IHTMLDocument2_AddRef(HTMLDOC(This));
633 }
634
635 static ULONG WINAPI PersistHistory_Release(IPersistHistory *iface)
636 {
637     HTMLDocument *This = PERSISTHIST_THIS(iface);
638     return IHTMLDocument2_Release(HTMLDOC(This));
639 }
640
641 static HRESULT WINAPI PersistHistory_GetClassID(IPersistHistory *iface, CLSID *pClassID)
642 {
643     HTMLDocument *This = PERSISTHIST_THIS(iface);
644     return IPersist_GetClassID(PERSIST(This), pClassID);
645 }
646
647 static HRESULT WINAPI PersistHistory_LoadHistory(IPersistHistory *iface, IStream *pStream, IBindCtx *pbc)
648 {
649     HTMLDocument *This = PERSISTHIST_THIS(iface);
650     FIXME("(%p)->(%p %p)\n", This, pStream, pbc);
651     return E_NOTIMPL;
652 }
653
654 static HRESULT WINAPI PersistHistory_SaveHistory(IPersistHistory *iface, IStream *pStream)
655 {
656     HTMLDocument *This = PERSISTHIST_THIS(iface);
657     FIXME("(%p)->(%p)\n", This, pStream);
658     return E_NOTIMPL;
659 }
660
661 static HRESULT WINAPI PersistHistory_SetPositionCookie(IPersistHistory *iface, DWORD dwPositioncookie)
662 {
663     HTMLDocument *This = PERSISTHIST_THIS(iface);
664     FIXME("(%p)->(%x)\n", This, dwPositioncookie);
665     return E_NOTIMPL;
666 }
667
668 static HRESULT WINAPI PersistHistory_GetPositionCookie(IPersistHistory *iface, DWORD *pdwPositioncookie)
669 {
670     HTMLDocument *This = PERSISTHIST_THIS(iface);
671     FIXME("(%p)->(%p)\n", This, pdwPositioncookie);
672     return E_NOTIMPL;
673 }
674
675 #undef PERSISTHIST_THIS
676
677 static const IPersistHistoryVtbl PersistHistoryVtbl = {
678     PersistHistory_QueryInterface,
679     PersistHistory_AddRef,
680     PersistHistory_Release,
681     PersistHistory_GetClassID,
682     PersistHistory_LoadHistory,
683     PersistHistory_SaveHistory,
684     PersistHistory_SetPositionCookie,
685     PersistHistory_GetPositionCookie
686 };
687
688 void HTMLDocument_Persist_Init(HTMLDocument *This)
689 {
690     This->lpPersistMonikerVtbl = &PersistMonikerVtbl;
691     This->lpPersistFileVtbl = &PersistFileVtbl;
692     This->lpMonikerPropVtbl = &MonikerPropVtbl;
693     This->lpPersistStreamInitVtbl = &PersistStreamInitVtbl;
694     This->lpPersistHistoryVtbl = &PersistHistoryVtbl;
695 }