Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenhtmllocation.c
Go to the documentation of this file.
00001 /* 00002 * Copyright 2008 Jacek Caban for CodeWeavers 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2.1 of the License, or (at your option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public 00015 * License along with this library; if not, write to the Free Software 00016 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00017 */ 00018 00019 #include <stdarg.h> 00020 00021 #define COBJMACROS 00022 00023 #include "windef.h" 00024 #include "winbase.h" 00025 #include "winuser.h" 00026 #include "winreg.h" 00027 #include "ole2.h" 00028 #include "wininet.h" 00029 #include "shlwapi.h" 00030 00031 #include "wine/debug.h" 00032 00033 #include "mshtml_private.h" 00034 #include "resource.h" 00035 00036 WINE_DEFAULT_DEBUG_CHANNEL(mshtml); 00037 00038 static HRESULT get_url(HTMLLocation *This, const WCHAR **ret) 00039 { 00040 if(!This->window || !This->window->url) { 00041 FIXME("No current URL\n"); 00042 return E_NOTIMPL; 00043 } 00044 00045 *ret = This->window->url; 00046 return S_OK; 00047 } 00048 00049 static HRESULT get_url_components(HTMLLocation *This, URL_COMPONENTSW *url) 00050 { 00051 const WCHAR *doc_url; 00052 HRESULT hres; 00053 00054 hres = get_url(This, &doc_url); 00055 if(FAILED(hres)) 00056 return hres; 00057 00058 if(!InternetCrackUrlW(doc_url, 0, 0, url)) { 00059 FIXME("InternetCrackUrlW failed: 0x%08x\n", GetLastError()); 00060 SetLastError(0); 00061 return E_FAIL; 00062 } 00063 00064 return S_OK; 00065 } 00066 00067 #define HTMLLOCATION_THIS(iface) DEFINE_THIS(HTMLLocation, HTMLLocation, iface) 00068 00069 static HRESULT WINAPI HTMLLocation_QueryInterface(IHTMLLocation *iface, REFIID riid, void **ppv) 00070 { 00071 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00072 00073 *ppv = NULL; 00074 00075 if(IsEqualGUID(&IID_IUnknown, riid)) { 00076 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); 00077 *ppv = HTMLLOCATION(This); 00078 }else if(IsEqualGUID(&IID_IHTMLLocation, riid)) { 00079 TRACE("(%p)->(IID_IHTMLLocation %p)\n", This, ppv); 00080 *ppv = HTMLLOCATION(This); 00081 }else if(dispex_query_interface(&This->dispex, riid, ppv)) { 00082 return *ppv ? S_OK : E_NOINTERFACE; 00083 } 00084 00085 if(*ppv) { 00086 IUnknown_AddRef((IUnknown*)*ppv); 00087 return S_OK; 00088 } 00089 00090 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); 00091 return E_NOINTERFACE; 00092 } 00093 00094 static ULONG WINAPI HTMLLocation_AddRef(IHTMLLocation *iface) 00095 { 00096 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00097 LONG ref = InterlockedIncrement(&This->ref); 00098 00099 TRACE("(%p) ref=%d\n", This, ref); 00100 00101 return ref; 00102 } 00103 00104 static ULONG WINAPI HTMLLocation_Release(IHTMLLocation *iface) 00105 { 00106 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00107 LONG ref = InterlockedDecrement(&This->ref); 00108 00109 TRACE("(%p) ref=%d\n", This, ref); 00110 00111 if(!ref) { 00112 if(This->window) 00113 This->window->location = NULL; 00114 release_dispex(&This->dispex); 00115 heap_free(This); 00116 } 00117 00118 return ref; 00119 } 00120 00121 static HRESULT WINAPI HTMLLocation_GetTypeInfoCount(IHTMLLocation *iface, UINT *pctinfo) 00122 { 00123 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00124 return IDispatchEx_GetTypeInfoCount(DISPATCHEX(&This->dispex), pctinfo); 00125 } 00126 00127 static HRESULT WINAPI HTMLLocation_GetTypeInfo(IHTMLLocation *iface, UINT iTInfo, 00128 LCID lcid, ITypeInfo **ppTInfo) 00129 { 00130 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00131 return IDispatchEx_GetTypeInfo(DISPATCHEX(&This->dispex), iTInfo, lcid, ppTInfo); 00132 } 00133 00134 static HRESULT WINAPI HTMLLocation_GetIDsOfNames(IHTMLLocation *iface, REFIID riid, 00135 LPOLESTR *rgszNames, UINT cNames, 00136 LCID lcid, DISPID *rgDispId) 00137 { 00138 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00139 return IDispatchEx_GetIDsOfNames(DISPATCHEX(&This->dispex), riid, rgszNames, cNames, lcid, rgDispId); 00140 } 00141 00142 static HRESULT WINAPI HTMLLocation_Invoke(IHTMLLocation *iface, DISPID dispIdMember, 00143 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, 00144 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) 00145 { 00146 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00147 return IDispatchEx_Invoke(DISPATCHEX(&This->dispex), dispIdMember, riid, lcid, 00148 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); 00149 } 00150 00151 static HRESULT WINAPI HTMLLocation_put_href(IHTMLLocation *iface, BSTR v) 00152 { 00153 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00154 00155 TRACE("(%p)->(%s)\n", This, debugstr_w(v)); 00156 00157 if(!This->window) { 00158 FIXME("No window available\n"); 00159 return E_FAIL; 00160 } 00161 00162 return navigate_url(This->window, v, This->window->url); 00163 } 00164 00165 static HRESULT WINAPI HTMLLocation_get_href(IHTMLLocation *iface, BSTR *p) 00166 { 00167 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00168 URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)}; 00169 WCHAR *buf = NULL, *url_path = NULL; 00170 HRESULT hres, ret; 00171 DWORD len = 0; 00172 int i; 00173 00174 TRACE("(%p)->(%p)\n", This, p); 00175 00176 if(!p) 00177 return E_POINTER; 00178 00179 url.dwSchemeLength = 1; 00180 url.dwHostNameLength = 1; 00181 url.dwUrlPathLength = 1; 00182 url.dwExtraInfoLength = 1; 00183 hres = get_url_components(This, &url); 00184 if(FAILED(hres)) 00185 return hres; 00186 00187 switch(url.nScheme) { 00188 case INTERNET_SCHEME_FILE: 00189 { 00190 /* prepend a slash */ 00191 url_path = HeapAlloc(GetProcessHeap(), 0, (url.dwUrlPathLength + 1) * sizeof(WCHAR)); 00192 if(!url_path) 00193 return E_OUTOFMEMORY; 00194 url_path[0] = '/'; 00195 memcpy(url_path + 1, url.lpszUrlPath, url.dwUrlPathLength * sizeof(WCHAR)); 00196 url.lpszUrlPath = url_path; 00197 url.dwUrlPathLength = url.dwUrlPathLength + 1; 00198 } 00199 break; 00200 00201 case INTERNET_SCHEME_HTTP: 00202 case INTERNET_SCHEME_HTTPS: 00203 case INTERNET_SCHEME_FTP: 00204 if(!url.dwUrlPathLength) { 00205 /* add a slash if it's blank */ 00206 url_path = url.lpszUrlPath = HeapAlloc(GetProcessHeap(), 0, 1 * sizeof(WCHAR)); 00207 if(!url.lpszUrlPath) 00208 return E_OUTOFMEMORY; 00209 url.lpszUrlPath[0] = '/'; 00210 url.dwUrlPathLength = 1; 00211 } 00212 break; 00213 00214 default: 00215 break; 00216 } 00217 00218 /* replace \ with / */ 00219 for(i = 0; i < url.dwUrlPathLength; ++i) 00220 if(url.lpszUrlPath[i] == '\\') 00221 url.lpszUrlPath[i] = '/'; 00222 00223 if(InternetCreateUrlW(&url, ICU_ESCAPE, NULL, &len)) { 00224 FIXME("InternetCreateUrl succeeded with NULL buffer?\n"); 00225 ret = E_FAIL; 00226 goto cleanup; 00227 } 00228 00229 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) { 00230 FIXME("InternetCreateUrl failed with error: %08x\n", GetLastError()); 00231 SetLastError(0); 00232 ret = E_FAIL; 00233 goto cleanup; 00234 } 00235 SetLastError(0); 00236 00237 buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 00238 if(!buf) { 00239 ret = E_OUTOFMEMORY; 00240 goto cleanup; 00241 } 00242 00243 if(!InternetCreateUrlW(&url, ICU_ESCAPE, buf, &len)) { 00244 FIXME("InternetCreateUrl failed with error: %08x\n", GetLastError()); 00245 SetLastError(0); 00246 ret = E_FAIL; 00247 goto cleanup; 00248 } 00249 00250 *p = SysAllocStringLen(buf, len); 00251 if(!*p) { 00252 ret = E_OUTOFMEMORY; 00253 goto cleanup; 00254 } 00255 00256 ret = S_OK; 00257 00258 cleanup: 00259 HeapFree(GetProcessHeap(), 0, buf); 00260 HeapFree(GetProcessHeap(), 0, url_path); 00261 00262 return ret; 00263 } 00264 00265 static HRESULT WINAPI HTMLLocation_put_protocol(IHTMLLocation *iface, BSTR v) 00266 { 00267 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00268 FIXME("(%p)->(%s)\n", This, debugstr_w(v)); 00269 return E_NOTIMPL; 00270 } 00271 00272 static HRESULT WINAPI HTMLLocation_get_protocol(IHTMLLocation *iface, BSTR *p) 00273 { 00274 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00275 URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)}; 00276 HRESULT hres; 00277 00278 TRACE("(%p)->(%p)\n", This, p); 00279 00280 if(!p) 00281 return E_POINTER; 00282 00283 url.dwSchemeLength = 1; 00284 hres = get_url_components(This, &url); 00285 if(FAILED(hres)) 00286 return hres; 00287 00288 if(!url.dwSchemeLength) { 00289 FIXME("Unexpected blank protocol\n"); 00290 return E_NOTIMPL; 00291 }else { 00292 WCHAR buf[url.dwSchemeLength + 1]; 00293 memcpy(buf, url.lpszScheme, url.dwSchemeLength * sizeof(WCHAR)); 00294 buf[url.dwSchemeLength] = ':'; 00295 *p = SysAllocStringLen(buf, url.dwSchemeLength + 1); 00296 } 00297 if(!*p) 00298 return E_OUTOFMEMORY; 00299 return S_OK; 00300 } 00301 00302 static HRESULT WINAPI HTMLLocation_put_host(IHTMLLocation *iface, BSTR v) 00303 { 00304 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00305 FIXME("(%p)->(%s)\n", This, debugstr_w(v)); 00306 return E_NOTIMPL; 00307 } 00308 00309 static HRESULT WINAPI HTMLLocation_get_host(IHTMLLocation *iface, BSTR *p) 00310 { 00311 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00312 URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)}; 00313 HRESULT hres; 00314 00315 TRACE("(%p)->(%p)\n", This, p); 00316 00317 if(!p) 00318 return E_POINTER; 00319 00320 url.dwHostNameLength = 1; 00321 hres = get_url_components(This, &url); 00322 if(FAILED(hres)) 00323 return hres; 00324 00325 if(!url.dwHostNameLength){ 00326 *p = NULL; 00327 return S_OK; 00328 } 00329 00330 if(url.nPort) { 00331 /* <hostname>:<port> */ 00332 const WCHAR format[] = {'%','d',0}; 00333 DWORD len = url.dwHostNameLength + 1 + 5 + 1; 00334 WCHAR buf[len]; 00335 00336 memcpy(buf, url.lpszHostName, url.dwHostNameLength * sizeof(WCHAR)); 00337 buf[url.dwHostNameLength] = ':'; 00338 snprintfW(buf + url.dwHostNameLength + 1, 6, format, url.nPort); 00339 *p = SysAllocString(buf); 00340 }else 00341 *p = SysAllocStringLen(url.lpszHostName, url.dwHostNameLength); 00342 00343 if(!*p) 00344 return E_OUTOFMEMORY; 00345 return S_OK; 00346 } 00347 00348 static HRESULT WINAPI HTMLLocation_put_hostname(IHTMLLocation *iface, BSTR v) 00349 { 00350 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00351 FIXME("(%p)->(%s)\n", This, debugstr_w(v)); 00352 return E_NOTIMPL; 00353 } 00354 00355 static HRESULT WINAPI HTMLLocation_get_hostname(IHTMLLocation *iface, BSTR *p) 00356 { 00357 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00358 URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)}; 00359 HRESULT hres; 00360 00361 TRACE("(%p)->(%p)\n", This, p); 00362 00363 if(!p) 00364 return E_POINTER; 00365 00366 url.dwHostNameLength = 1; 00367 hres = get_url_components(This, &url); 00368 if(FAILED(hres)) 00369 return hres; 00370 00371 if(!url.dwHostNameLength){ 00372 *p = NULL; 00373 return S_OK; 00374 } 00375 00376 *p = SysAllocStringLen(url.lpszHostName, url.dwHostNameLength); 00377 if(!*p) 00378 return E_OUTOFMEMORY; 00379 return S_OK; 00380 } 00381 00382 static HRESULT WINAPI HTMLLocation_put_port(IHTMLLocation *iface, BSTR v) 00383 { 00384 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00385 FIXME("(%p)->(%s)\n", This, debugstr_w(v)); 00386 return E_NOTIMPL; 00387 } 00388 00389 static HRESULT WINAPI HTMLLocation_get_port(IHTMLLocation *iface, BSTR *p) 00390 { 00391 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00392 URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)}; 00393 HRESULT hres; 00394 00395 TRACE("(%p)->(%p)\n", This, p); 00396 00397 if(!p) 00398 return E_POINTER; 00399 00400 hres = get_url_components(This, &url); 00401 if(FAILED(hres)) 00402 return hres; 00403 00404 if(url.nPort) { 00405 const WCHAR format[] = {'%','d',0}; 00406 WCHAR buf[6]; 00407 snprintfW(buf, 6, format, url.nPort); 00408 *p = SysAllocString(buf); 00409 }else { 00410 const WCHAR empty[] = {0}; 00411 *p = SysAllocString(empty); 00412 } 00413 00414 if(!*p) 00415 return E_OUTOFMEMORY; 00416 return S_OK; 00417 } 00418 00419 static HRESULT WINAPI HTMLLocation_put_pathname(IHTMLLocation *iface, BSTR v) 00420 { 00421 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00422 FIXME("(%p)->(%s)\n", This, debugstr_w(v)); 00423 return E_NOTIMPL; 00424 } 00425 00426 static HRESULT WINAPI HTMLLocation_get_pathname(IHTMLLocation *iface, BSTR *p) 00427 { 00428 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00429 URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)}; 00430 HRESULT hres; 00431 00432 TRACE("(%p)->(%p)\n", This, p); 00433 00434 if(!p) 00435 return E_POINTER; 00436 00437 url.dwUrlPathLength = 1; 00438 url.dwExtraInfoLength = 1; 00439 hres = get_url_components(This, &url); 00440 if(FAILED(hres)) 00441 return hres; 00442 00443 if(url.dwUrlPathLength && url.lpszUrlPath[0] == '/') 00444 *p = SysAllocStringLen(url.lpszUrlPath + 1, url.dwUrlPathLength - 1); 00445 else 00446 *p = SysAllocStringLen(url.lpszUrlPath, url.dwUrlPathLength); 00447 00448 if(!*p) 00449 return E_OUTOFMEMORY; 00450 return S_OK; 00451 } 00452 00453 static HRESULT WINAPI HTMLLocation_put_search(IHTMLLocation *iface, BSTR v) 00454 { 00455 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00456 FIXME("(%p)->(%s)\n", This, debugstr_w(v)); 00457 return E_NOTIMPL; 00458 } 00459 00460 static HRESULT WINAPI HTMLLocation_get_search(IHTMLLocation *iface, BSTR *p) 00461 { 00462 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00463 URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)}; 00464 HRESULT hres; 00465 const WCHAR hash[] = {'#',0}; 00466 00467 TRACE("(%p)->(%p)\n", This, p); 00468 00469 if(!p) 00470 return E_POINTER; 00471 00472 url.dwExtraInfoLength = 1; 00473 hres = get_url_components(This, &url); 00474 if(FAILED(hres)) 00475 return hres; 00476 00477 if(!url.dwExtraInfoLength){ 00478 *p = NULL; 00479 return S_OK; 00480 } 00481 00482 url.dwExtraInfoLength = strcspnW(url.lpszExtraInfo, hash); 00483 00484 *p = SysAllocStringLen(url.lpszExtraInfo, url.dwExtraInfoLength); 00485 00486 if(!*p) 00487 return E_OUTOFMEMORY; 00488 return S_OK; 00489 } 00490 00491 static HRESULT WINAPI HTMLLocation_put_hash(IHTMLLocation *iface, BSTR v) 00492 { 00493 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00494 FIXME("(%p)->(%s)\n", This, debugstr_w(v)); 00495 return E_NOTIMPL; 00496 } 00497 00498 static HRESULT WINAPI HTMLLocation_get_hash(IHTMLLocation *iface, BSTR *p) 00499 { 00500 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00501 URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)}; 00502 const WCHAR hash[] = {'#',0}; 00503 DWORD hash_pos = 0; 00504 HRESULT hres; 00505 00506 TRACE("(%p)->(%p)\n", This, p); 00507 00508 if(!p) 00509 return E_POINTER; 00510 00511 url.dwExtraInfoLength = 1; 00512 hres = get_url_components(This, &url); 00513 if(FAILED(hres)) 00514 return hres; 00515 00516 if(!url.dwExtraInfoLength){ 00517 *p = NULL; 00518 return S_OK; 00519 } 00520 00521 hash_pos = strcspnW(url.lpszExtraInfo, hash); 00522 url.dwExtraInfoLength -= hash_pos; 00523 00524 *p = SysAllocStringLen(url.lpszExtraInfo + hash_pos, url.dwExtraInfoLength); 00525 00526 if(!*p) 00527 return E_OUTOFMEMORY; 00528 return S_OK; 00529 } 00530 00531 static HRESULT WINAPI HTMLLocation_reload(IHTMLLocation *iface, VARIANT_BOOL flag) 00532 { 00533 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00534 FIXME("(%p)->(%x)\n", This, flag); 00535 return E_NOTIMPL; 00536 } 00537 00538 static HRESULT WINAPI HTMLLocation_replace(IHTMLLocation *iface, BSTR bstr) 00539 { 00540 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00541 FIXME("(%p)->(%s)\n", This, debugstr_w(bstr)); 00542 return E_NOTIMPL; 00543 } 00544 00545 static HRESULT WINAPI HTMLLocation_assign(IHTMLLocation *iface, BSTR bstr) 00546 { 00547 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00548 FIXME("(%p)->(%s)\n", This, debugstr_w(bstr)); 00549 return E_NOTIMPL; 00550 } 00551 00552 static HRESULT WINAPI HTMLLocation_toString(IHTMLLocation *iface, BSTR *String) 00553 { 00554 HTMLLocation *This = HTMLLOCATION_THIS(iface); 00555 FIXME("(%p)->(%p)\n", This, String); 00556 return E_NOTIMPL; 00557 } 00558 00559 #undef HTMLLOCATION_THIS 00560 00561 static const IHTMLLocationVtbl HTMLLocationVtbl = { 00562 HTMLLocation_QueryInterface, 00563 HTMLLocation_AddRef, 00564 HTMLLocation_Release, 00565 HTMLLocation_GetTypeInfoCount, 00566 HTMLLocation_GetTypeInfo, 00567 HTMLLocation_GetIDsOfNames, 00568 HTMLLocation_Invoke, 00569 HTMLLocation_put_href, 00570 HTMLLocation_get_href, 00571 HTMLLocation_put_protocol, 00572 HTMLLocation_get_protocol, 00573 HTMLLocation_put_host, 00574 HTMLLocation_get_host, 00575 HTMLLocation_put_hostname, 00576 HTMLLocation_get_hostname, 00577 HTMLLocation_put_port, 00578 HTMLLocation_get_port, 00579 HTMLLocation_put_pathname, 00580 HTMLLocation_get_pathname, 00581 HTMLLocation_put_search, 00582 HTMLLocation_get_search, 00583 HTMLLocation_put_hash, 00584 HTMLLocation_get_hash, 00585 HTMLLocation_reload, 00586 HTMLLocation_replace, 00587 HTMLLocation_assign, 00588 HTMLLocation_toString 00589 }; 00590 00591 static const tid_t HTMLLocation_iface_tids[] = { 00592 IHTMLLocation_tid, 00593 0 00594 }; 00595 static dispex_static_data_t HTMLLocation_dispex = { 00596 NULL, 00597 DispHTMLLocation_tid, 00598 NULL, 00599 HTMLLocation_iface_tids 00600 }; 00601 00602 00603 HRESULT HTMLLocation_Create(HTMLWindow *window, HTMLLocation **ret) 00604 { 00605 HTMLLocation *location; 00606 00607 location = heap_alloc(sizeof(*location)); 00608 if(!location) 00609 return E_OUTOFMEMORY; 00610 00611 location->lpHTMLLocationVtbl = &HTMLLocationVtbl; 00612 location->ref = 1; 00613 location->window = window; 00614 00615 init_dispex(&location->dispex, (IUnknown*)HTMLLOCATION(location), &HTMLLocation_dispex); 00616 00617 *ret = location; 00618 return S_OK; 00619 } Generated on Sun May 27 2012 04:24:57 for ReactOS by
1.7.6.1
|