[MSHTA] Implement MSHTA.exe (#577) CORE-12813
[reactos.git] / dll / win32 / mshtml / htmllocation.c
1 /*
2 * Copyright 2008 Jacek Caban for CodeWeavers
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 "mshtml_private.h"
20
21 static HRESULT get_url(HTMLLocation *This, const WCHAR **ret)
22 {
23 if(!This->window || !This->window->base.outer_window || !This->window->base.outer_window->url) {
24 FIXME("No current URL\n");
25 return E_NOTIMPL;
26 }
27
28 *ret = This->window->base.outer_window->url;
29 return S_OK;
30 }
31
32 static IUri *get_uri(HTMLLocation *This)
33 {
34 if(!This->window || !This->window->base.outer_window)
35 return NULL;
36 return This->window->base.outer_window->uri;
37 }
38
39 static HRESULT get_url_components(HTMLLocation *This, URL_COMPONENTSW *url)
40 {
41 const WCHAR *doc_url;
42 HRESULT hres;
43
44 hres = get_url(This, &doc_url);
45 if(FAILED(hres))
46 return hres;
47
48 if(!InternetCrackUrlW(doc_url, 0, 0, url)) {
49 FIXME("InternetCrackUrlW failed: 0x%08x\n", GetLastError());
50 SetLastError(0);
51 return E_FAIL;
52 }
53
54 return S_OK;
55 }
56
57 static inline HTMLLocation *impl_from_IHTMLLocation(IHTMLLocation *iface)
58 {
59 return CONTAINING_RECORD(iface, HTMLLocation, IHTMLLocation_iface);
60 }
61
62 static HRESULT WINAPI HTMLLocation_QueryInterface(IHTMLLocation *iface, REFIID riid, void **ppv)
63 {
64 HTMLLocation *This = impl_from_IHTMLLocation(iface);
65
66 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
67
68 if(IsEqualGUID(&IID_IUnknown, riid)) {
69 *ppv = &This->IHTMLLocation_iface;
70 }else if(IsEqualGUID(&IID_IHTMLLocation, riid)) {
71 *ppv = &This->IHTMLLocation_iface;
72 }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
73 return *ppv ? S_OK : E_NOINTERFACE;
74 }else {
75 *ppv = NULL;
76 WARN("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
77 return E_NOINTERFACE;
78 }
79
80 IUnknown_AddRef((IUnknown*)*ppv);
81 return S_OK;
82 }
83
84 static ULONG WINAPI HTMLLocation_AddRef(IHTMLLocation *iface)
85 {
86 HTMLLocation *This = impl_from_IHTMLLocation(iface);
87 LONG ref = InterlockedIncrement(&This->ref);
88
89 TRACE("(%p) ref=%d\n", This, ref);
90
91 return ref;
92 }
93
94 static ULONG WINAPI HTMLLocation_Release(IHTMLLocation *iface)
95 {
96 HTMLLocation *This = impl_from_IHTMLLocation(iface);
97 LONG ref = InterlockedDecrement(&This->ref);
98
99 TRACE("(%p) ref=%d\n", This, ref);
100
101 if(!ref) {
102 if(This->window)
103 This->window->location = NULL;
104 release_dispex(&This->dispex);
105 heap_free(This);
106 }
107
108 return ref;
109 }
110
111 static HRESULT WINAPI HTMLLocation_GetTypeInfoCount(IHTMLLocation *iface, UINT *pctinfo)
112 {
113 HTMLLocation *This = impl_from_IHTMLLocation(iface);
114 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
115 }
116
117 static HRESULT WINAPI HTMLLocation_GetTypeInfo(IHTMLLocation *iface, UINT iTInfo,
118 LCID lcid, ITypeInfo **ppTInfo)
119 {
120 HTMLLocation *This = impl_from_IHTMLLocation(iface);
121 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
122 }
123
124 static HRESULT WINAPI HTMLLocation_GetIDsOfNames(IHTMLLocation *iface, REFIID riid,
125 LPOLESTR *rgszNames, UINT cNames,
126 LCID lcid, DISPID *rgDispId)
127 {
128 HTMLLocation *This = impl_from_IHTMLLocation(iface);
129 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
130 lcid, rgDispId);
131 }
132
133 static HRESULT WINAPI HTMLLocation_Invoke(IHTMLLocation *iface, DISPID dispIdMember,
134 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
135 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
136 {
137 HTMLLocation *This = impl_from_IHTMLLocation(iface);
138 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
139 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
140 }
141
142 static HRESULT WINAPI HTMLLocation_put_href(IHTMLLocation *iface, BSTR v)
143 {
144 HTMLLocation *This = impl_from_IHTMLLocation(iface);
145
146 TRACE("(%p)->(%s)\n", This, debugstr_w(v));
147
148 if(!This->window || !This->window->base.outer_window) {
149 FIXME("No window available\n");
150 return E_FAIL;
151 }
152
153 return navigate_url(This->window->base.outer_window, v, This->window->base.outer_window->uri, BINDING_NAVIGATED);
154 }
155
156 static HRESULT WINAPI HTMLLocation_get_href(IHTMLLocation *iface, BSTR *p)
157 {
158 HTMLLocation *This = impl_from_IHTMLLocation(iface);
159 URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
160 WCHAR *buf = NULL, *url_path = NULL;
161 HRESULT hres, ret;
162 DWORD len = 0;
163 int i;
164
165 TRACE("(%p)->(%p)\n", This, p);
166
167 if(!p)
168 return E_POINTER;
169
170 url.dwSchemeLength = 1;
171 url.dwHostNameLength = 1;
172 url.dwUrlPathLength = 1;
173 url.dwExtraInfoLength = 1;
174 hres = get_url_components(This, &url);
175 if(FAILED(hres))
176 return hres;
177
178 switch(url.nScheme) {
179 case INTERNET_SCHEME_FILE:
180 {
181 /* prepend a slash */
182 url_path = HeapAlloc(GetProcessHeap(), 0, (url.dwUrlPathLength + 1) * sizeof(WCHAR));
183 if(!url_path)
184 return E_OUTOFMEMORY;
185 url_path[0] = '/';
186 memcpy(url_path + 1, url.lpszUrlPath, url.dwUrlPathLength * sizeof(WCHAR));
187 url.lpszUrlPath = url_path;
188 url.dwUrlPathLength = url.dwUrlPathLength + 1;
189 }
190 break;
191
192 case INTERNET_SCHEME_HTTP:
193 case INTERNET_SCHEME_HTTPS:
194 case INTERNET_SCHEME_FTP:
195 if(!url.dwUrlPathLength) {
196 /* add a slash if it's blank */
197 url_path = url.lpszUrlPath = HeapAlloc(GetProcessHeap(), 0, 1 * sizeof(WCHAR));
198 if(!url.lpszUrlPath)
199 return E_OUTOFMEMORY;
200 url.lpszUrlPath[0] = '/';
201 url.dwUrlPathLength = 1;
202 }
203 break;
204
205 default:
206 break;
207 }
208
209 /* replace \ with / */
210 for(i = 0; i < url.dwUrlPathLength; ++i)
211 if(url.lpszUrlPath[i] == '\\')
212 url.lpszUrlPath[i] = '/';
213
214 if(InternetCreateUrlW(&url, ICU_ESCAPE, NULL, &len)) {
215 FIXME("InternetCreateUrl succeeded with NULL buffer?\n");
216 ret = E_FAIL;
217 goto cleanup;
218 }
219
220 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
221 FIXME("InternetCreateUrl failed with error: %08x\n", GetLastError());
222 SetLastError(0);
223 ret = E_FAIL;
224 goto cleanup;
225 }
226 SetLastError(0);
227
228 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
229 if(!buf) {
230 ret = E_OUTOFMEMORY;
231 goto cleanup;
232 }
233
234 if(!InternetCreateUrlW(&url, ICU_ESCAPE, buf, &len)) {
235 FIXME("InternetCreateUrl failed with error: %08x\n", GetLastError());
236 SetLastError(0);
237 ret = E_FAIL;
238 goto cleanup;
239 }
240
241 *p = SysAllocStringLen(buf, len);
242 if(!*p) {
243 ret = E_OUTOFMEMORY;
244 goto cleanup;
245 }
246
247 ret = S_OK;
248
249 cleanup:
250 HeapFree(GetProcessHeap(), 0, buf);
251 HeapFree(GetProcessHeap(), 0, url_path);
252
253 return ret;
254 }
255
256 static HRESULT WINAPI HTMLLocation_put_protocol(IHTMLLocation *iface, BSTR v)
257 {
258 HTMLLocation *This = impl_from_IHTMLLocation(iface);
259 FIXME("(%p)->(%s)\n", This, debugstr_w(v));
260 return E_NOTIMPL;
261 }
262
263 static HRESULT WINAPI HTMLLocation_get_protocol(IHTMLLocation *iface, BSTR *p)
264 {
265 HTMLLocation *This = impl_from_IHTMLLocation(iface);
266 BSTR protocol, ret;
267 unsigned len;
268 IUri *uri;
269 HRESULT hres;
270
271 TRACE("(%p)->(%p)\n", This, p);
272
273 if(!p)
274 return E_POINTER;
275
276 if(!(uri = get_uri(This))) {
277 FIXME("No current URI\n");
278 return E_NOTIMPL;
279 }
280
281 hres = IUri_GetSchemeName(uri, &protocol);
282 if(FAILED(hres))
283 return hres;
284 if(hres == S_FALSE) {
285 SysFreeString(protocol);
286 *p = NULL;
287 return S_OK;
288 }
289
290 len = SysStringLen(protocol);
291 ret = SysAllocStringLen(protocol, len+1);
292 SysFreeString(protocol);
293 if(!ret)
294 return E_OUTOFMEMORY;
295
296 ret[len] = ':';
297 *p = ret;
298 return S_OK;
299 }
300
301 static HRESULT WINAPI HTMLLocation_put_host(IHTMLLocation *iface, BSTR v)
302 {
303 HTMLLocation *This = impl_from_IHTMLLocation(iface);
304 FIXME("(%p)->(%s)\n", This, debugstr_w(v));
305 return E_NOTIMPL;
306 }
307
308 static HRESULT WINAPI HTMLLocation_get_host(IHTMLLocation *iface, BSTR *p)
309 {
310 HTMLLocation *This = impl_from_IHTMLLocation(iface);
311 URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
312 HRESULT hres;
313
314 TRACE("(%p)->(%p)\n", This, p);
315
316 if(!p)
317 return E_POINTER;
318
319 url.dwHostNameLength = 1;
320 hres = get_url_components(This, &url);
321 if(FAILED(hres))
322 return hres;
323
324 if(!url.dwHostNameLength){
325 *p = NULL;
326 return S_OK;
327 }
328
329 if(url.nPort) {
330 /* <hostname>:<port> */
331 const WCHAR format[] = {'%','u',0};
332 DWORD len = url.dwHostNameLength + 1 + 5;
333 WCHAR *buf;
334
335 buf = *p = SysAllocStringLen(NULL, len);
336 memcpy(buf, url.lpszHostName, url.dwHostNameLength * sizeof(WCHAR));
337 buf[url.dwHostNameLength] = ':';
338 snprintfW(buf + url.dwHostNameLength + 1, 6, format, url.nPort);
339 }else
340 *p = SysAllocStringLen(url.lpszHostName, url.dwHostNameLength);
341
342 if(!*p)
343 return E_OUTOFMEMORY;
344 return S_OK;
345 }
346
347 static HRESULT WINAPI HTMLLocation_put_hostname(IHTMLLocation *iface, BSTR v)
348 {
349 HTMLLocation *This = impl_from_IHTMLLocation(iface);
350 FIXME("(%p)->(%s)\n", This, debugstr_w(v));
351 return E_NOTIMPL;
352 }
353
354 static HRESULT WINAPI HTMLLocation_get_hostname(IHTMLLocation *iface, BSTR *p)
355 {
356 HTMLLocation *This = impl_from_IHTMLLocation(iface);
357 BSTR hostname;
358 IUri *uri;
359 HRESULT hres;
360
361 TRACE("(%p)->(%p)\n", This, p);
362
363 if(!p)
364 return E_POINTER;
365
366 if(!(uri = get_uri(This))) {
367 FIXME("No current URI\n");
368 return E_NOTIMPL;
369 }
370
371 hres = IUri_GetHost(uri, &hostname);
372 if(hres == S_OK) {
373 *p = hostname;
374 }else if(hres == S_FALSE) {
375 SysFreeString(hostname);
376 *p = NULL;
377 }else {
378 return hres;
379 }
380
381 return S_OK;
382 }
383
384 static HRESULT WINAPI HTMLLocation_put_port(IHTMLLocation *iface, BSTR v)
385 {
386 HTMLLocation *This = impl_from_IHTMLLocation(iface);
387 FIXME("(%p)->(%s)\n", This, debugstr_w(v));
388 return E_NOTIMPL;
389 }
390
391 static HRESULT WINAPI HTMLLocation_get_port(IHTMLLocation *iface, BSTR *p)
392 {
393 HTMLLocation *This = impl_from_IHTMLLocation(iface);
394 DWORD port;
395 IUri *uri;
396 HRESULT hres;
397
398 TRACE("(%p)->(%p)\n", This, p);
399
400 if(!p)
401 return E_POINTER;
402
403 if(!(uri = get_uri(This))) {
404 FIXME("No current URI\n");
405 return E_NOTIMPL;
406 }
407
408 hres = IUri_GetPort(uri, &port);
409 if(FAILED(hres))
410 return hres;
411
412 if(hres == S_OK) {
413 static const WCHAR formatW[] = {'%','u',0};
414 WCHAR buf[12];
415
416 sprintfW(buf, formatW, port);
417 *p = SysAllocString(buf);
418 }else {
419 *p = SysAllocStringLen(NULL, 0);
420 }
421
422 if(!*p)
423 return E_OUTOFMEMORY;
424 return S_OK;
425 }
426
427 static HRESULT WINAPI HTMLLocation_put_pathname(IHTMLLocation *iface, BSTR v)
428 {
429 HTMLLocation *This = impl_from_IHTMLLocation(iface);
430 FIXME("(%p)->(%s)\n", This, debugstr_w(v));
431 return E_NOTIMPL;
432 }
433
434 static HRESULT WINAPI HTMLLocation_get_pathname(IHTMLLocation *iface, BSTR *p)
435 {
436 HTMLLocation *This = impl_from_IHTMLLocation(iface);
437 URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
438 HRESULT hres;
439
440 TRACE("(%p)->(%p)\n", This, p);
441
442 if(!p)
443 return E_POINTER;
444
445 url.dwUrlPathLength = 1;
446 url.dwExtraInfoLength = 1;
447 hres = get_url_components(This, &url);
448 if(FAILED(hres))
449 return hres;
450
451 if(url.dwUrlPathLength && url.lpszUrlPath[0] == '/')
452 *p = SysAllocStringLen(url.lpszUrlPath + 1, url.dwUrlPathLength - 1);
453 else
454 *p = SysAllocStringLen(url.lpszUrlPath, url.dwUrlPathLength);
455
456 if(!*p)
457 return E_OUTOFMEMORY;
458 return S_OK;
459 }
460
461 static HRESULT WINAPI HTMLLocation_put_search(IHTMLLocation *iface, BSTR v)
462 {
463 HTMLLocation *This = impl_from_IHTMLLocation(iface);
464 FIXME("(%p)->(%s)\n", This, debugstr_w(v));
465 return E_NOTIMPL;
466 }
467
468 static HRESULT WINAPI HTMLLocation_get_search(IHTMLLocation *iface, BSTR *p)
469 {
470 HTMLLocation *This = impl_from_IHTMLLocation(iface);
471 BSTR query;
472 IUri *uri;
473 HRESULT hres;
474
475 TRACE("(%p)->(%p)\n", This, p);
476
477 if(!p)
478 return E_POINTER;
479
480 if(!(uri = get_uri(This))) {
481 FIXME("No current URI\n");
482 return E_NOTIMPL;
483 }
484
485 hres = IUri_GetQuery(uri, &query);
486 if(hres == S_OK) {
487 *p = query;
488 }else if(hres == S_FALSE) {
489 SysFreeString(query);
490 *p = NULL;
491 }else {
492 return hres;
493 }
494
495 return S_OK;
496 }
497
498 static HRESULT WINAPI HTMLLocation_put_hash(IHTMLLocation *iface, BSTR v)
499 {
500 HTMLLocation *This = impl_from_IHTMLLocation(iface);
501
502 TRACE("(%p)->(%s)\n", This, debugstr_w(v));
503
504 if(!This->window || !This->window->base.outer_window) {
505 FIXME("No window available\n");
506 return E_FAIL;
507 }
508
509 return navigate_url(This->window->base.outer_window, v, This->window->base.outer_window->uri, 0);
510 }
511
512 static HRESULT WINAPI HTMLLocation_get_hash(IHTMLLocation *iface, BSTR *p)
513 {
514 HTMLLocation *This = impl_from_IHTMLLocation(iface);
515 BSTR hash;
516 IUri *uri;
517 HRESULT hres;
518
519 TRACE("(%p)->(%p)\n", This, p);
520
521 if(!p)
522 return E_POINTER;
523
524 if(!(uri = get_uri(This))) {
525 FIXME("No current URI\n");
526 return E_NOTIMPL;
527 }
528
529 hres = IUri_GetFragment(uri, &hash);
530 if(hres == S_OK) {
531 *p = hash;
532 }else if(hres == S_FALSE) {
533 SysFreeString(hash);
534 *p = NULL;
535 }else {
536 return hres;
537 }
538
539 return S_OK;
540 }
541
542 static HRESULT WINAPI HTMLLocation_reload(IHTMLLocation *iface, VARIANT_BOOL flag)
543 {
544 HTMLLocation *This = impl_from_IHTMLLocation(iface);
545 FIXME("(%p)->(%x)\n", This, flag);
546 return E_NOTIMPL;
547 }
548
549 static HRESULT WINAPI HTMLLocation_replace(IHTMLLocation *iface, BSTR bstr)
550 {
551 HTMLLocation *This = impl_from_IHTMLLocation(iface);
552
553 TRACE("(%p)->(%s)\n", This, debugstr_w(bstr));
554
555 if(!This->window || !This->window->base.outer_window) {
556 FIXME("No window available\n");
557 return E_FAIL;
558 }
559
560 return navigate_url(This->window->base.outer_window, bstr, This->window->base.outer_window->uri,
561 BINDING_NAVIGATED|BINDING_REPLACE);
562 }
563
564 static HRESULT WINAPI HTMLLocation_assign(IHTMLLocation *iface, BSTR bstr)
565 {
566 HTMLLocation *This = impl_from_IHTMLLocation(iface);
567 TRACE("(%p)->(%s)\n", This, debugstr_w(bstr));
568 return IHTMLLocation_put_href(iface, bstr);
569 }
570
571 static HRESULT WINAPI HTMLLocation_toString(IHTMLLocation *iface, BSTR *String)
572 {
573 HTMLLocation *This = impl_from_IHTMLLocation(iface);
574
575 TRACE("(%p)->(%p)\n", This, String);
576
577 return IHTMLLocation_get_href(&This->IHTMLLocation_iface, String);
578 }
579
580 static const IHTMLLocationVtbl HTMLLocationVtbl = {
581 HTMLLocation_QueryInterface,
582 HTMLLocation_AddRef,
583 HTMLLocation_Release,
584 HTMLLocation_GetTypeInfoCount,
585 HTMLLocation_GetTypeInfo,
586 HTMLLocation_GetIDsOfNames,
587 HTMLLocation_Invoke,
588 HTMLLocation_put_href,
589 HTMLLocation_get_href,
590 HTMLLocation_put_protocol,
591 HTMLLocation_get_protocol,
592 HTMLLocation_put_host,
593 HTMLLocation_get_host,
594 HTMLLocation_put_hostname,
595 HTMLLocation_get_hostname,
596 HTMLLocation_put_port,
597 HTMLLocation_get_port,
598 HTMLLocation_put_pathname,
599 HTMLLocation_get_pathname,
600 HTMLLocation_put_search,
601 HTMLLocation_get_search,
602 HTMLLocation_put_hash,
603 HTMLLocation_get_hash,
604 HTMLLocation_reload,
605 HTMLLocation_replace,
606 HTMLLocation_assign,
607 HTMLLocation_toString
608 };
609
610 static const tid_t HTMLLocation_iface_tids[] = {
611 IHTMLLocation_tid,
612 0
613 };
614 static dispex_static_data_t HTMLLocation_dispex = {
615 NULL,
616 DispHTMLLocation_tid,
617 NULL,
618 HTMLLocation_iface_tids
619 };
620
621
622 HRESULT HTMLLocation_Create(HTMLInnerWindow *window, HTMLLocation **ret)
623 {
624 HTMLLocation *location;
625
626 location = heap_alloc(sizeof(*location));
627 if(!location)
628 return E_OUTOFMEMORY;
629
630 location->IHTMLLocation_iface.lpVtbl = &HTMLLocationVtbl;
631 location->ref = 1;
632 location->window = window;
633
634 init_dispex(&location->dispex, (IUnknown*)&location->IHTMLLocation_iface, &HTMLLocation_dispex);
635
636 *ret = location;
637 return S_OK;
638 }