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 } 639