Revert "kernel32: Exit from initial thread with ExitThread not by ExitProcess."
[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
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
36
37 #include "mshtml_private.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
40
41 /**********************************************************
42  * IPersistMoniker implementation
43  */
44
45 #define PERSISTMON_THIS(iface) DEFINE_THIS(HTMLDocument, PersistMoniker, iface)
46
47 static HRESULT WINAPI PersistMoniker_QueryInterface(IPersistMoniker *iface, REFIID riid,
48                                                             void **ppvObject)
49 {
50     HTMLDocument *This = PERSISTMON_THIS(iface);
51     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppvObject);
52 }
53
54 static ULONG WINAPI PersistMoniker_AddRef(IPersistMoniker *iface)
55 {
56     HTMLDocument *This = PERSISTMON_THIS(iface);
57     return IHTMLDocument2_AddRef(HTMLDOC(This));
58 }
59
60 static ULONG WINAPI PersistMoniker_Release(IPersistMoniker *iface)
61 {
62     HTMLDocument *This = PERSISTMON_THIS(iface);
63     return IHTMLDocument2_Release(HTMLDOC(This));
64 }
65
66 static HRESULT WINAPI PersistMoniker_GetClassID(IPersistMoniker *iface, CLSID *pClassID)
67 {
68     HTMLDocument *This = PERSISTMON_THIS(iface);
69     return IPersist_GetClassID(PERSIST(This), pClassID);
70 }
71
72 static HRESULT WINAPI PersistMoniker_IsDirty(IPersistMoniker *iface)
73 {
74     HTMLDocument *This = PERSISTMON_THIS(iface);
75     FIXME("(%p)\n", This);
76     return E_NOTIMPL;
77 }
78
79 static nsIInputStream *get_post_data_stream(IBindCtx *bctx)
80 {
81     nsIInputStream *ret = NULL;
82     IBindStatusCallback *callback;
83     IHttpNegotiate *http_negotiate;
84     BINDINFO bindinfo;
85     DWORD bindf = 0;
86     DWORD post_len = 0, headers_len = 0;
87     LPWSTR headers = NULL;
88     WCHAR emptystr[] = {0};
89     char *data;
90     HRESULT hres;
91
92     static WCHAR _BSCB_Holder_[] =
93         {'_','B','S','C','B','_','H','o','l','d','e','r','_',0};
94
95
96     /* FIXME: This should be done in URLMoniker */
97     if(!bctx)
98         return NULL;
99
100     hres = IBindCtx_GetObjectParam(bctx, _BSCB_Holder_, (IUnknown**)&callback);
101     if(FAILED(hres))
102         return NULL;
103
104     hres = IBindStatusCallback_QueryInterface(callback, &IID_IHttpNegotiate,
105                                               (void**)&http_negotiate);
106     if(SUCCEEDED(hres)) {
107         hres = IHttpNegotiate_BeginningTransaction(http_negotiate, emptystr,
108                                                    emptystr, 0, &headers);
109         IHttpNegotiate_Release(http_negotiate);
110
111         if(SUCCEEDED(hres) && headers)
112             headers_len = WideCharToMultiByte(CP_ACP, 0, headers, -1, NULL, 0, NULL, NULL);
113     }
114
115     memset(&bindinfo, 0, sizeof(bindinfo));
116     bindinfo.cbSize = sizeof(bindinfo);
117
118     hres = IBindStatusCallback_GetBindInfo(callback, &bindf, &bindinfo);
119
120     if(SUCCEEDED(hres) && bindinfo.dwBindVerb == BINDVERB_POST)
121         post_len = bindinfo.cbstgmedData;
122
123     if(headers_len || post_len) {
124         int len = headers_len ? headers_len-1 : 0;
125
126         static const char content_length[] = "Content-Length: %u\r\n\r\n";
127
128         data = mshtml_alloc(headers_len+post_len+sizeof(content_length)+8);
129
130         if(headers_len) {
131             WideCharToMultiByte(CP_ACP, 0, headers, -1, data, -1, NULL, NULL);
132             CoTaskMemFree(headers);
133         }
134
135         if(post_len) {
136             sprintf(data+len, content_length, post_len);
137             len = strlen(data);
138
139             memcpy(data+len, bindinfo.stgmedData.u.hGlobal, post_len);
140         }
141
142         TRACE("data = %s\n", debugstr_an(data, len+post_len));
143
144         ret = create_nsstream(data, len+post_len);
145     }
146
147     ReleaseBindInfo(&bindinfo);
148     IBindStatusCallback_Release(callback);
149
150     return ret;
151 }
152
153 static HRESULT WINAPI PersistMoniker_Load(IPersistMoniker *iface, BOOL fFullyAvailable,
154         IMoniker *pimkName, LPBC pibc, DWORD grfMode)
155 {
156     HTMLDocument *This = PERSISTMON_THIS(iface);
157     BSCallback *bscallback;
158     LPOLESTR url = NULL;
159     task_t *task;
160     HRESULT hres;
161     nsresult nsres;
162
163     TRACE("(%p)->(%x %p %p %08x)\n", This, fFullyAvailable, pimkName, pibc, grfMode);
164
165     if(pibc) {
166         IUnknown *unk = NULL;
167
168         /* FIXME:
169          * Use params:
170          * "__PrecreatedObject"
171          * "BIND_CONTEXT_PARAM"
172          * "__HTMLLOADOPTIONS"
173          * "__DWNBINDINFO"
174          * "URL Context"
175          * "CBinding Context"
176          * "_ITransData_Object_"
177          * "_EnumFORMATETC_"
178          */
179
180         IBindCtx_GetObjectParam(pibc, (LPOLESTR)SZ_HTML_CLIENTSITE_OBJECTPARAM, &unk);
181         if(unk) {
182             IOleClientSite *client = NULL;
183
184             hres = IUnknown_QueryInterface(unk, &IID_IOleClientSite, (void**)&client);
185             if(SUCCEEDED(hres)) {
186                 TRACE("Got client site %p\n", client);
187                 IOleObject_SetClientSite(OLEOBJ(This), client);
188                 IOleClientSite_Release(client);
189             }
190
191             IUnknown_Release(unk);
192         }
193     }
194
195     This->readystate = READYSTATE_LOADING;
196     call_property_onchanged(This->cp_propnotif, DISPID_READYSTATE);
197
198     HTMLDocument_LockContainer(This, TRUE);
199     
200     hres = IMoniker_GetDisplayName(pimkName, pibc, NULL, &url);
201     if(FAILED(hres)) {
202         WARN("GetDiaplayName failed: %08x\n", hres);
203         return hres;
204     }
205
206     TRACE("got url: %s\n", debugstr_w(url));
207
208     if(This->client) {
209         IOleCommandTarget *cmdtrg = NULL;
210
211         hres = IOleClientSite_QueryInterface(This->client, &IID_IOleCommandTarget,
212                 (void**)&cmdtrg);
213         if(SUCCEEDED(hres)) {
214             VARIANT var;
215
216             V_VT(&var) = VT_I4;
217             V_I4(&var) = 0;
218             IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 37, 0, &var, NULL);
219         }
220     }
221
222     bscallback = create_bscallback(pimkName);
223
224     task = mshtml_alloc(sizeof(task_t));
225
226     task->doc = This;
227     task->task_id = TASK_SETDOWNLOADSTATE;
228     task->next = NULL;
229
230     push_task(task);
231
232     if(This->nscontainer) {
233         nsIInputStream *post_data_stream = get_post_data_stream(pibc);
234
235         This->nscontainer->bscallback = bscallback;
236         nsres = nsIWebNavigation_LoadURI(This->nscontainer->navigation, url,
237                 LOAD_FLAGS_NONE, NULL, post_data_stream, NULL);
238         This->nscontainer->bscallback = NULL;
239
240         if(post_data_stream)
241             nsIInputStream_Release(post_data_stream);
242
243         if(!bscallback->nschannel)
244             ERR("bscallback->nschannel == NULL\n");
245
246         if(NS_SUCCEEDED(nsres)) {
247             /* FIXME: don't return here (URL Moniker needs to be good enough) */
248
249             IBindStatusCallback_Release(STATUSCLB(bscallback));
250             CoTaskMemFree(url);
251             return S_OK;
252         }else if(nsres != WINE_NS_LOAD_FROM_MONIKER) {
253             WARN("LoadURI failed: %08x\n", nsres);
254         }
255     }
256
257     set_document_bscallback(This, bscallback);
258     hres = start_binding(bscallback);
259
260     IBindStatusCallback_Release(STATUSCLB(bscallback));
261     CoTaskMemFree(url);
262
263     return hres;
264 }
265
266 static HRESULT WINAPI PersistMoniker_Save(IPersistMoniker *iface, IMoniker *pimkName,
267         LPBC pbc, BOOL fRemember)
268 {
269     HTMLDocument *This = PERSISTMON_THIS(iface);
270     FIXME("(%p)->(%p %p %x)\n", This, pimkName, pbc, fRemember);
271     return E_NOTIMPL;
272 }
273
274 static HRESULT WINAPI PersistMoniker_SaveCompleted(IPersistMoniker *iface, IMoniker *pimkName, LPBC pibc)
275 {
276     HTMLDocument *This = PERSISTMON_THIS(iface);
277     FIXME("(%p)->(%p %p)\n", This, pimkName, pibc);
278     return E_NOTIMPL;
279 }
280
281 static HRESULT WINAPI PersistMoniker_GetCurMoniker(IPersistMoniker *iface, IMoniker **ppimkName)
282 {
283     HTMLDocument *This = PERSISTMON_THIS(iface);
284     FIXME("(%p)->(%p)\n", This, ppimkName);
285     return E_NOTIMPL;
286 }
287
288 static const IPersistMonikerVtbl PersistMonikerVtbl = {
289     PersistMoniker_QueryInterface,
290     PersistMoniker_AddRef,
291     PersistMoniker_Release,
292     PersistMoniker_GetClassID,
293     PersistMoniker_IsDirty,
294     PersistMoniker_Load,
295     PersistMoniker_Save,
296     PersistMoniker_SaveCompleted,
297     PersistMoniker_GetCurMoniker
298 };
299
300 /**********************************************************
301  * IMonikerProp implementation
302  */
303
304 #define MONPROP_THIS(iface) DEFINE_THIS(HTMLDocument, MonikerProp, iface)
305
306 static HRESULT WINAPI MonikerProp_QueryInterface(IMonikerProp *iface, REFIID riid, void **ppvObject)
307 {
308     HTMLDocument *This = MONPROP_THIS(iface);
309     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppvObject);
310 }
311
312 static ULONG WINAPI MonikerProp_AddRef(IMonikerProp *iface)
313 {
314     HTMLDocument *This = MONPROP_THIS(iface);
315     return IHTMLDocument2_AddRef(HTMLDOC(This));
316 }
317
318 static ULONG WINAPI MonikerProp_Release(IMonikerProp *iface)
319 {
320     HTMLDocument *This = MONPROP_THIS(iface);
321     return IHTMLDocument_Release(HTMLDOC(This));
322 }
323
324 static HRESULT WINAPI MonikerProp_PutProperty(IMonikerProp *iface, MONIKERPROPERTY mkp, LPCWSTR val)
325 {
326     HTMLDocument *This = MONPROP_THIS(iface);
327     FIXME("(%p)->(%d %s)\n", This, mkp, debugstr_w(val));
328     return E_NOTIMPL;
329 }
330
331 static const IMonikerPropVtbl MonikerPropVtbl = {
332     MonikerProp_QueryInterface,
333     MonikerProp_AddRef,
334     MonikerProp_Release,
335     MonikerProp_PutProperty
336 };
337
338 /**********************************************************
339  * IPersistFile implementation
340  */
341
342 #define PERSISTFILE_THIS(iface) DEFINE_THIS(HTMLDocument, PersistFile, iface)
343
344 static HRESULT WINAPI PersistFile_QueryInterface(IPersistFile *iface, REFIID riid, void **ppvObject)
345 {
346     HTMLDocument *This = PERSISTFILE_THIS(iface);
347     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppvObject);
348 }
349
350 static ULONG WINAPI PersistFile_AddRef(IPersistFile *iface)
351 {
352     HTMLDocument *This = PERSISTFILE_THIS(iface);
353     return IHTMLDocument2_AddRef(HTMLDOC(This));
354 }
355
356 static ULONG WINAPI PersistFile_Release(IPersistFile *iface)
357 {
358     HTMLDocument *This = PERSISTFILE_THIS(iface);
359     return IHTMLDocument2_Release(HTMLDOC(This));
360 }
361
362 static HRESULT WINAPI PersistFile_GetClassID(IPersistFile *iface, CLSID *pClassID)
363 {
364     HTMLDocument *This = PERSISTFILE_THIS(iface);
365
366     TRACE("(%p)->(%p)\n", This, pClassID);
367
368     if(!pClassID)
369         return E_INVALIDARG;
370
371     memcpy(pClassID, &CLSID_HTMLDocument, sizeof(CLSID));
372     return S_OK;
373 }
374
375 static HRESULT WINAPI PersistFile_IsDirty(IPersistFile *iface)
376 {
377     HTMLDocument *This = PERSISTFILE_THIS(iface);
378     FIXME("(%p)\n", This);
379     return E_NOTIMPL;
380 }
381
382 static HRESULT WINAPI PersistFile_Load(IPersistFile *iface, LPCOLESTR pszFileName, DWORD dwMode)
383 {
384     HTMLDocument *This = PERSISTFILE_THIS(iface);
385     FIXME("(%p)->(%s %08x)\n", This, debugstr_w(pszFileName), dwMode);
386     return E_NOTIMPL;
387 }
388
389 static HRESULT WINAPI PersistFile_Save(IPersistFile *iface, LPCOLESTR pszFileName, BOOL fRemember)
390 {
391     HTMLDocument *This = PERSISTFILE_THIS(iface);
392     FIXME("(%p)->(%s %x)\n", This, debugstr_w(pszFileName), fRemember);
393     return E_NOTIMPL;
394 }
395
396 static HRESULT WINAPI PersistFile_SaveCompleted(IPersistFile *iface, LPCOLESTR pszFileName)
397 {
398     HTMLDocument *This = PERSISTFILE_THIS(iface);
399     FIXME("(%p)->(%s)\n", This, debugstr_w(pszFileName));
400     return E_NOTIMPL;
401 }
402
403 static HRESULT WINAPI PersistFile_GetCurFile(IPersistFile *iface, LPOLESTR *pszFileName)
404 {
405     HTMLDocument *This = PERSISTFILE_THIS(iface);
406     FIXME("(%p)->(%p)\n", This, pszFileName);
407     return E_NOTIMPL;
408 }
409
410 static const IPersistFileVtbl PersistFileVtbl = {
411     PersistFile_QueryInterface,
412     PersistFile_AddRef,
413     PersistFile_Release,
414     PersistFile_GetClassID,
415     PersistFile_IsDirty,
416     PersistFile_Load,
417     PersistFile_Save,
418     PersistFile_SaveCompleted,
419     PersistFile_GetCurFile
420 };
421
422 #define PERSTRINIT_THIS(iface) DEFINE_THIS(HTMLDocument, PersistStreamInit, iface)
423
424 static HRESULT WINAPI PersistStreamInit_QueryInterface(IPersistStreamInit *iface,
425                                                        REFIID riid, void **ppv)
426 {
427     HTMLDocument *This = PERSTRINIT_THIS(iface);
428     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppv);
429 }
430
431 static ULONG WINAPI PersistStreamInit_AddRef(IPersistStreamInit *iface)
432 {
433     HTMLDocument *This = PERSTRINIT_THIS(iface);
434     return IHTMLDocument2_AddRef(HTMLDOC(This));
435 }
436
437 static ULONG WINAPI PersistStreamInit_Release(IPersistStreamInit *iface)
438 {
439     HTMLDocument *This = PERSTRINIT_THIS(iface);
440     return IHTMLDocument2_AddRef(HTMLDOC(This));
441 }
442
443 static HRESULT WINAPI PersistStreamInit_GetClassID(IPersistStreamInit *iface, CLSID *pClassID)
444 {
445     HTMLDocument *This = PERSTRINIT_THIS(iface);
446     return IPersist_GetClassID(PERSIST(This), pClassID);
447 }
448
449 static HRESULT WINAPI PersistStreamInit_IsDirty(IPersistStreamInit *iface)
450 {
451     HTMLDocument *This = PERSTRINIT_THIS(iface);
452     FIXME("(%p)\n", This);
453     return E_NOTIMPL;
454 }
455
456 static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, LPSTREAM pStm)
457 {
458     HTMLDocument *This = PERSTRINIT_THIS(iface);
459     FIXME("(%p)->(%p)\n", This, pStm);
460     return E_NOTIMPL;
461 }
462
463 static HRESULT WINAPI PersistStreamInit_Save(IPersistStreamInit *iface, LPSTREAM pStm,
464                                              BOOL fClearDirty)
465 {
466     HTMLDocument *This = PERSTRINIT_THIS(iface);
467     nsIDOMDocument *nsdoc;
468     nsIDOMNode *nsnode;
469     nsAString nsstr;
470     LPCWSTR strw;
471     char *str;
472     DWORD len, written=0;
473     nsresult nsres;
474     HRESULT hres;
475
476     WARN("(%p)->(%p %x) needs more work\n", This, pStm, fClearDirty);
477
478     if(!This->nscontainer)
479         return S_OK;
480
481     nsres = nsIWebNavigation_GetDocument(This->nscontainer->navigation, &nsdoc);
482     if(NS_FAILED(nsres)) {
483         ERR("GetDocument failed: %08x\n", nsres);
484         return E_FAIL;
485     }
486
487     nsres = nsIDOMDocument_QueryInterface(nsdoc, &IID_nsIDOMNode, (void**)&nsnode);
488     nsIDOMDocument_Release(nsdoc);
489     if(NS_FAILED(nsres)) {
490         ERR("Could not get nsIDOMNode failed: %08x\n", nsres);
491         return E_FAIL;
492     }
493
494     nsAString_Init(&nsstr, NULL);
495     nsnode_to_nsstring(nsnode, &nsstr);
496     nsIDOMNode_Release(nsnode);
497
498     nsAString_GetData(&nsstr, &strw, NULL);
499
500     len = WideCharToMultiByte(CP_ACP, 0, strw, -1, NULL, 0, NULL, NULL);
501     str = mshtml_alloc(len);
502     WideCharToMultiByte(CP_ACP, 0, strw, -1, str, len, NULL, NULL);
503
504     nsAString_Finish(&nsstr);
505
506     ERR("%s\n", debugstr_a(str));
507
508     hres = IStream_Write(pStm, str, len, &written);
509     if(FAILED(hres))
510         FIXME("Write failed: %08x\n", hres);
511
512     mshtml_free(str);
513
514     return S_OK;
515 }
516
517 static HRESULT WINAPI PersistStreamInit_GetSizeMax(IPersistStreamInit *iface,
518                                                    ULARGE_INTEGER *pcbSize)
519 {
520     HTMLDocument *This = PERSTRINIT_THIS(iface);
521     FIXME("(%p)->(%p)\n", This, pcbSize);
522     return E_NOTIMPL;
523 }
524
525 static HRESULT WINAPI PersistStreamInit_InitNew(IPersistStreamInit *iface)
526 {
527     HTMLDocument *This = PERSTRINIT_THIS(iface);
528     FIXME("(%p)\n", This);
529     return E_NOTIMPL;
530 }
531
532 #undef PERSTRINIT_THIS
533
534 static const IPersistStreamInitVtbl PersistStreamInitVtbl = {
535     PersistStreamInit_QueryInterface,
536     PersistStreamInit_AddRef,
537     PersistStreamInit_Release,
538     PersistStreamInit_GetClassID,
539     PersistStreamInit_IsDirty,
540     PersistStreamInit_Load,
541     PersistStreamInit_Save,
542     PersistStreamInit_GetSizeMax,
543     PersistStreamInit_InitNew
544 };
545
546 void HTMLDocument_Persist_Init(HTMLDocument *This)
547 {
548     This->lpPersistMonikerVtbl = &PersistMonikerVtbl;
549     This->lpPersistFileVtbl = &PersistFileVtbl;
550     This->lpMonikerPropVtbl = &MonikerPropVtbl;
551     This->lpPersistStreamInitVtbl = &PersistStreamInitVtbl;
552
553     This->bscallback = NULL;
554 }