4 * Copyright (c) 2000 Patrik Stridvall
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #define NO_SHLWAPI_REG
31 #include "wine/debug.h"
32 #include "wine/unicode.h"
36 #include "urlmon_main.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
41 LONG URLMON_refCount = 0;
43 HINSTANCE URLMON_hInstance = 0;
44 static HMODULE hCabinet = NULL;
46 static void init_session(BOOL);
48 /***********************************************************************
49 * DllMain (URLMON.init)
51 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
53 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
56 case DLL_PROCESS_ATTACH:
57 DisableThreadLibraryCalls(hinstDLL);
58 URLMON_hInstance = hinstDLL;
62 case DLL_PROCESS_DETACH:
64 FreeLibrary(hCabinet);
74 /***********************************************************************
75 * DllInstall (URLMON.@)
77 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
79 FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
85 /***********************************************************************
86 * DllCanUnloadNow (URLMON.@)
88 HRESULT WINAPI DllCanUnloadNow(void)
90 return URLMON_refCount != 0 ? S_FALSE : S_OK;
95 /******************************************************************************
99 const IClassFactoryVtbl *lpClassFactoryVtbl;
101 HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
104 #define CLASSFACTORY(x) ((IClassFactory*) &(x)->lpClassFactoryVtbl)
106 static HRESULT WINAPI CF_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppv)
110 if(IsEqualGUID(riid, &IID_IUnknown)) {
111 TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
113 }else if(IsEqualGUID(riid, &IID_IClassFactory)) {
114 TRACE("(%p)->(IID_IClassFactory %p)\n", iface, ppv);
119 IUnknown_AddRef((IUnknown*)*ppv);
123 WARN("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ppv);
124 return E_NOINTERFACE;
127 static ULONG WINAPI CF_AddRef(IClassFactory *iface)
133 static ULONG WINAPI CF_Release(IClassFactory *iface)
135 URLMON_UnlockModule();
140 static HRESULT WINAPI CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
141 REFIID riid, LPVOID *ppobj)
143 ClassFactory *This = (ClassFactory*)iface;
147 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
150 if(SUCCEEDED(hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk))) {
151 hres = IUnknown_QueryInterface(punk, riid, ppobj);
152 IUnknown_Release(punk);
157 static HRESULT WINAPI CF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
159 TRACE("(%d)\n", dolock);
164 URLMON_UnlockModule();
169 static const IClassFactoryVtbl ClassFactoryVtbl =
178 static const ClassFactory FileProtocolCF =
179 { &ClassFactoryVtbl, FileProtocol_Construct};
180 static const ClassFactory FtpProtocolCF =
181 { &ClassFactoryVtbl, FtpProtocol_Construct};
182 static const ClassFactory HttpProtocolCF =
183 { &ClassFactoryVtbl, HttpProtocol_Construct};
184 static const ClassFactory MkProtocolCF =
185 { &ClassFactoryVtbl, MkProtocol_Construct};
186 static const ClassFactory SecurityManagerCF =
187 { &ClassFactoryVtbl, SecManagerImpl_Construct};
188 static const ClassFactory ZoneManagerCF =
189 { &ClassFactoryVtbl, ZoneMgrImpl_Construct};
191 struct object_creation_info
198 static const WCHAR wszFile[] = {'f','i','l','e',0};
199 static const WCHAR wszFtp[] = {'f','t','p',0};
200 static const WCHAR wszHttp[] = {'h','t','t','p',0};
201 static const WCHAR wszMk[] = {'m','k',0};
203 static const struct object_creation_info object_creation[] =
205 { &CLSID_FileProtocol, CLASSFACTORY(&FileProtocolCF), wszFile },
206 { &CLSID_FtpProtocol, CLASSFACTORY(&FtpProtocolCF), wszFtp },
207 { &CLSID_HttpProtocol, CLASSFACTORY(&HttpProtocolCF), wszHttp },
208 { &CLSID_MkProtocol, CLASSFACTORY(&MkProtocolCF), wszMk },
209 { &CLSID_InternetSecurityManager, CLASSFACTORY(&SecurityManagerCF), NULL },
210 { &CLSID_InternetZoneManager, CLASSFACTORY(&ZoneManagerCF), NULL }
213 static void init_session(BOOL init)
215 IInternetSession *session;
218 CoInternetGetSession(0, &session, 0);
220 for(i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++) {
221 if(object_creation[i].protocol) {
224 IInternetSession_RegisterNameSpace(session, object_creation[i].cf,
225 object_creation[i].clsid, object_creation[i].protocol, 0, NULL, 0);
226 /* make sure that the AddRef on the class factory doesn't keep us loaded */
227 URLMON_UnlockModule();
231 /* make sure that the Release on the class factory doesn't unload us */
233 IInternetSession_UnregisterNameSpace(session, object_creation[i].cf,
234 object_creation[i].protocol);
239 IInternetSession_Release(session);
242 /*******************************************************************************
243 * DllGetClassObject [URLMON.@]
244 * Retrieves class object from a DLL object
247 * Docs say returns STDAPI
250 * rclsid [I] CLSID for the class object
251 * riid [I] Reference to identifier of interface for class object
252 * ppv [O] Address of variable to receive interface pointer for riid
256 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
260 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
264 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
266 for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
268 if (IsEqualGUID(object_creation[i].clsid, rclsid))
269 return IClassFactory_QueryInterface(object_creation[i].cf, riid, ppv);
272 FIXME("%s: no class found.\n", debugstr_guid(rclsid));
273 return CLASS_E_CLASSNOTAVAILABLE;
277 /***********************************************************************
278 * DllRegisterServerEx (URLMON.@)
280 HRESULT WINAPI DllRegisterServerEx(void)
282 FIXME("(void): stub\n");
287 /**************************************************************************
288 * UrlMkSetSessionOption (URLMON.@)
290 HRESULT WINAPI UrlMkSetSessionOption(DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength,
293 FIXME("(%#x, %p, %#x): stub\n", dwOption, pBuffer, dwBufferLength);
298 static const CHAR Agent[] = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)";
300 /**************************************************************************
301 * ObtainUserAgentString (URLMON.@)
303 HRESULT WINAPI ObtainUserAgentString(DWORD dwOption, LPSTR pcszUAOut, DWORD *cbSize)
305 FIXME("(%d, %p, %p): stub\n", dwOption, pcszUAOut, cbSize);
307 if (pcszUAOut == NULL || cbSize == NULL)
310 if (*cbSize < sizeof(Agent))
312 *cbSize = sizeof(Agent);
313 return E_OUTOFMEMORY;
316 if (sizeof(Agent) < *cbSize)
317 *cbSize = sizeof(Agent);
318 lstrcpynA(pcszUAOut, Agent, *cbSize);
323 /**************************************************************************
324 * IsValidURL (URLMON.@)
326 * Determines if a specified string is a valid URL.
329 * pBC [I] ignored, must be NULL.
330 * szURL [I] string that represents the URL in question.
331 * dwReserved [I] reserved and must be zero.
336 * returns E_INVALIDARG if one or more of the args is invalid.
339 * test functionality against windows to see what a valid URL is.
341 HRESULT WINAPI IsValidURL(LPBC pBC, LPCWSTR szURL, DWORD dwReserved)
343 FIXME("(%p, %s, %d): stub\n", pBC, debugstr_w(szURL), dwReserved);
345 if (pBC != NULL || dwReserved != 0)
351 /**************************************************************************
352 * FaultInIEFeature (URLMON.@)
354 * Undocumented. Appears to be used by native shdocvw.dll.
356 HRESULT WINAPI FaultInIEFeature( HWND hwnd, uCLSSPEC * pClassSpec,
357 QUERYCONTEXT *pQuery, DWORD flags )
359 FIXME("%p %p %p %08x\n", hwnd, pClassSpec, pQuery, flags);
363 /**************************************************************************
364 * CoGetClassObjectFromURL (URLMON.@)
366 HRESULT WINAPI CoGetClassObjectFromURL( REFCLSID rclsid, LPCWSTR szCodeURL, DWORD dwFileVersionMS,
367 DWORD dwFileVersionLS, LPCWSTR szContentType,
368 LPBINDCTX pBindCtx, DWORD dwClsContext, LPVOID pvReserved,
369 REFIID riid, LPVOID *ppv )
371 FIXME("(%s %s %d %d %s %p %d %p %s %p) Stub!\n", debugstr_guid(rclsid), debugstr_w(szCodeURL),
372 dwFileVersionMS, dwFileVersionLS, debugstr_w(szContentType), pBindCtx, dwClsContext, pvReserved,
373 debugstr_guid(riid), ppv);
374 return E_NOINTERFACE;
377 /***********************************************************************
378 * ReleaseBindInfo (URLMON.@)
380 * Release the resources used by the specified BINDINFO structure.
383 * pbindinfo [I] BINDINFO to release.
388 void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo)
392 TRACE("(%p)\n", pbindinfo);
394 if(!pbindinfo || !(size = pbindinfo->cbSize))
397 CoTaskMemFree(pbindinfo->szExtraInfo);
398 ReleaseStgMedium(&pbindinfo->stgmedData);
400 if(offsetof(BINDINFO, szExtraInfo) < size)
401 CoTaskMemFree(pbindinfo->szCustomVerb);
404 if(pbindinfo->pUnk && offsetof(BINDINFO, pUnk) < size)
405 IUnknown_Release(pbindinfo->pUnk);
407 memset(pbindinfo, 0, size);
408 pbindinfo->cbSize = size;
411 static BOOL text_richtext_filter(const BYTE *b, DWORD size)
413 return size > 5 && !memcmp(b, "{\\rtf", 5);
416 static BOOL text_html_filter(const BYTE *b, DWORD size)
423 for(i=0; i < size-5; i++) {
425 && (b[i+1] == 'h' || b[i+1] == 'H')
426 && (b[i+2] == 't' || b[i+2] == 'T')
427 && (b[i+3] == 'm' || b[i+3] == 'M')
428 && (b[i+4] == 'l' || b[i+4] == 'L'))
435 static BOOL audio_wav_filter(const BYTE *b, DWORD size)
438 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
439 && b[8] == 'W' && b[9] == 'A' && b[10] == 'V' && b[11] == 'E';
442 static BOOL image_gif_filter(const BYTE *b, DWORD size)
445 && (b[0] == 'G' || b[0] == 'g')
446 && (b[1] == 'I' || b[1] == 'i')
447 && (b[2] == 'F' || b[2] == 'f')
449 && (b[4] == '7' || b[4] == '9')
450 && (b[5] == 'A' || b[5] == 'a');
453 static BOOL image_pjpeg_filter(const BYTE *b, DWORD size)
455 return size > 2 && b[0] == 0xff && b[1] == 0xd8;
458 static BOOL image_tiff_filter(const BYTE *b, DWORD size)
460 return size > 2 && b[0] == 0x4d && b[1] == 0x4d;
463 static BOOL image_xpng_filter(const BYTE *b, DWORD size)
465 static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a};
466 return size > sizeof(xpng_header) && !memcmp(b, xpng_header, sizeof(xpng_header));
469 static BOOL image_bmp_filter(const BYTE *b, DWORD size)
472 && b[0] == 0x42 && b[1] == 0x4d
473 && *(const DWORD *)(b+6) == 0;
476 static BOOL video_avi_filter(const BYTE *b, DWORD size)
479 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
480 && b[8] == 'A' && b[9] == 'V' && b[10] == 'I' && b[11] == 0x20;
483 static BOOL video_mpeg_filter(const BYTE *b, DWORD size)
486 && !b[0] && !b[1] && b[2] == 0x01
487 && (b[3] == 0xb3 || b[3] == 0xba);
490 static BOOL application_postscript_filter(const BYTE *b, DWORD size)
492 return size > 2 && b[0] == '%' && b[1] == '!';
495 static BOOL application_pdf_filter(const BYTE *b, DWORD size)
497 return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46;
500 static BOOL application_xzip_filter(const BYTE *b, DWORD size)
502 return size > 2 && b[0] == 0x50 && b[1] == 0x4b;
505 static BOOL application_xgzip_filter(const BYTE *b, DWORD size)
507 return size > 2 && b[0] == 0x1f && b[1] == 0x8b;
510 static BOOL application_java_filter(const BYTE *b, DWORD size)
512 return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe;
515 static BOOL application_xmsdownload(const BYTE *b, DWORD size)
517 return size > 2 && b[0] == 'M' && b[1] == 'Z';
520 static BOOL text_plain_filter(const BYTE *b, DWORD size)
524 for(ptr = b; ptr < b+size-1; ptr++) {
525 if(*ptr < 0x20 && *ptr != '\n' && *ptr != '\r' && *ptr != '\t')
532 static BOOL application_octet_stream_filter(const BYTE *b, DWORD size)
537 /***********************************************************************
538 * FindMimeFromData (URLMON.@)
540 * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
542 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
543 DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
544 LPWSTR* ppwzMimeOut, DWORD dwReserved)
546 TRACE("(%p,%s,%p,%d,%s,0x%x,%p,0x%x)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize,
547 debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved);
550 WARN("dwMimeFlags=%08x\n", dwMimeFlags);
552 WARN("dwReserved=%d\n", dwReserved);
554 /* pBC seams to not be used */
556 if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
559 if(pwzMimeProposed && (!pBuffer || (pBuffer && !cbSize))) {
565 len = strlenW(pwzMimeProposed)+1;
566 *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
567 memcpy(*ppwzMimeOut, pwzMimeProposed, len*sizeof(WCHAR));
572 const BYTE *buf = pBuffer;
577 static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};
578 static const WCHAR wszTextRichtext[] = {'t','e','x','t','/','r','i','c','h','t','e','x','t',0};
579 static const WCHAR wszAudioWav[] = {'a','u','d','i','o','/','w','a','v',0};
580 static const WCHAR wszImageGif[] = {'i','m','a','g','e','/','g','i','f',0};
581 static const WCHAR wszImagePjpeg[] = {'i','m','a','g','e','/','p','j','p','e','g',0};
582 static const WCHAR wszImageTiff[] = {'i','m','a','g','e','/','t','i','f','f',0};
583 static const WCHAR wszImageXPng[] = {'i','m','a','g','e','/','x','-','p','n','g',0};
584 static const WCHAR wszImageBmp[] = {'i','m','a','g','e','/','b','m','p',0};
585 static const WCHAR wszVideoAvi[] = {'v','i','d','e','o','/','a','v','i',0};
586 static const WCHAR wszVideoMpeg[] = {'v','i','d','e','o','/','m','p','e','g',0};
587 static const WCHAR wszAppPostscript[] =
588 {'a','p','p','l','i','c','a','t','i','o','n','/','p','o','s','t','s','c','r','i','p','t',0};
589 static const WCHAR wszAppPdf[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
591 static const WCHAR wszAppXZip[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
592 'x','-','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
593 static const WCHAR wszAppXGzip[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
594 'x','-','g','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
595 static const WCHAR wszAppJava[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
597 static const WCHAR wszAppXMSDownload[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
598 'x','-','m','s','d','o','w','n','l','o','a','d',0};
599 static const WCHAR wszTextPlain[] = {'t','e','x','t','/','p','l','a','i','n','\0'};
600 static const WCHAR wszAppOctetStream[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
601 'o','c','t','e','t','-','s','t','r','e','a','m','\0'};
603 static const struct {
605 BOOL (*filter)(const BYTE *,DWORD);
607 {wszTextHtml, text_html_filter},
608 {wszTextRichtext, text_richtext_filter},
609 {wszAudioWav, audio_wav_filter},
610 {wszImageGif, image_gif_filter},
611 {wszImagePjpeg, image_pjpeg_filter},
612 {wszImageTiff, image_tiff_filter},
613 {wszImageXPng, image_xpng_filter},
614 {wszImageBmp, image_bmp_filter},
615 {wszVideoAvi, video_avi_filter},
616 {wszVideoMpeg, video_mpeg_filter},
617 {wszAppPostscript, application_postscript_filter},
618 {wszAppPdf, application_pdf_filter},
619 {wszAppXZip, application_xzip_filter},
620 {wszAppXGzip, application_xgzip_filter},
621 {wszAppJava, application_java_filter},
622 {wszAppXMSDownload, application_xmsdownload},
623 {wszTextPlain, text_plain_filter},
624 {wszAppOctetStream, application_octet_stream_filter}
630 if(pwzMimeProposed && strcmpW(pwzMimeProposed, wszAppOctetStream)) {
631 for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) {
632 if(!strcmpW(pwzMimeProposed, mime_filters[i].mime))
636 if(i == sizeof(mime_filters)/sizeof(*mime_filters)
637 || mime_filters[i].filter(buf, cbSize)) {
638 len = strlenW(pwzMimeProposed)+1;
639 *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
640 memcpy(*ppwzMimeOut, pwzMimeProposed, len*sizeof(WCHAR));
647 if(mime_filters[i].filter(buf, cbSize))
648 ret = mime_filters[i].mime;
652 TRACE("found %s for data\n"
653 "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
654 debugstr_w(ret), buf[0],buf[1],buf[2],buf[3], buf[4],buf[5],buf[6],buf[7],
655 buf[8],buf[9],buf[10],buf[11], buf[12],buf[13],buf[14],buf[15]);
657 if(pwzMimeProposed) {
658 if(i == sizeof(mime_filters)/sizeof(*mime_filters))
659 ret = pwzMimeProposed;
661 /* text/html is a special case */
662 if(!strcmpW(pwzMimeProposed, wszTextHtml) && !strcmpW(ret, wszTextPlain))
666 len = strlenW(ret)+1;
667 *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
668 memcpy(*ppwzMimeOut, ret, len*sizeof(WCHAR));
678 static const WCHAR wszContentType[] =
679 {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
681 ptr = strrchrW(pwzUrl, '.');
685 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
686 if(res != ERROR_SUCCESS)
687 return HRESULT_FROM_WIN32(res);
690 res = RegQueryValueExW(hkey, wszContentType, NULL, NULL, (LPBYTE)mime, &size);
692 if(res != ERROR_SUCCESS)
693 return HRESULT_FROM_WIN32(res);
695 *ppwzMimeOut = CoTaskMemAlloc(size);
696 memcpy(*ppwzMimeOut, mime, size);
703 /***********************************************************************
704 * GetClassFileOrMime (URLMON.@)
706 * Determines the class ID from the bind context, file name or MIME type.
708 HRESULT WINAPI GetClassFileOrMime(LPBC pBC, LPCWSTR pszFilename,
709 LPVOID pBuffer, DWORD cbBuffer, LPCWSTR pszMimeType, DWORD dwReserved,
712 FIXME("(%p, %s, %p, %d, %p, 0x%08x, %p): stub\n", pBC,
713 debugstr_w(pszFilename), pBuffer, cbBuffer, debugstr_w(pszMimeType),
718 /***********************************************************************
721 HRESULT WINAPI Extract(void *dest, LPCSTR szCabName)
723 HRESULT (WINAPI *pExtract)(void *, LPCSTR);
726 hCabinet = LoadLibraryA("cabinet.dll");
728 if (!hCabinet) return HRESULT_FROM_WIN32(GetLastError());
729 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
730 if (!pExtract) return HRESULT_FROM_WIN32(GetLastError());
732 return pExtract(dest, szCabName);