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 HttpSProtocolCF =
185 { &ClassFactoryVtbl, HttpSProtocol_Construct};
186 static const ClassFactory MkProtocolCF =
187 { &ClassFactoryVtbl, MkProtocol_Construct};
188 static const ClassFactory SecurityManagerCF =
189 { &ClassFactoryVtbl, SecManagerImpl_Construct};
190 static const ClassFactory ZoneManagerCF =
191 { &ClassFactoryVtbl, ZoneMgrImpl_Construct};
193 struct object_creation_info
200 static const WCHAR wszFile[] = {'f','i','l','e',0};
201 static const WCHAR wszFtp[] = {'f','t','p',0};
202 static const WCHAR wszHttp[] = {'h','t','t','p',0};
203 static const WCHAR wszHttps[] = {'h','t','t','p','s',0};
204 static const WCHAR wszMk[] = {'m','k',0};
206 static const struct object_creation_info object_creation[] =
208 { &CLSID_FileProtocol, CLASSFACTORY(&FileProtocolCF), wszFile },
209 { &CLSID_FtpProtocol, CLASSFACTORY(&FtpProtocolCF), wszFtp },
210 { &CLSID_HttpProtocol, CLASSFACTORY(&HttpProtocolCF), wszHttp },
211 { &CLSID_HttpSProtocol, CLASSFACTORY(&HttpSProtocolCF), wszHttps },
212 { &CLSID_MkProtocol, CLASSFACTORY(&MkProtocolCF), wszMk },
213 { &CLSID_InternetSecurityManager, CLASSFACTORY(&SecurityManagerCF), NULL },
214 { &CLSID_InternetZoneManager, CLASSFACTORY(&ZoneManagerCF), NULL }
217 static void init_session(BOOL init)
219 IInternetSession *session;
222 CoInternetGetSession(0, &session, 0);
224 for(i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++) {
225 if(object_creation[i].protocol) {
228 IInternetSession_RegisterNameSpace(session, object_creation[i].cf,
229 object_creation[i].clsid, object_creation[i].protocol, 0, NULL, 0);
230 /* make sure that the AddRef on the class factory doesn't keep us loaded */
231 URLMON_UnlockModule();
235 /* make sure that the Release on the class factory doesn't unload us */
237 IInternetSession_UnregisterNameSpace(session, object_creation[i].cf,
238 object_creation[i].protocol);
243 IInternetSession_Release(session);
246 /*******************************************************************************
247 * DllGetClassObject [URLMON.@]
248 * Retrieves class object from a DLL object
251 * Docs say returns STDAPI
254 * rclsid [I] CLSID for the class object
255 * riid [I] Reference to identifier of interface for class object
256 * ppv [O] Address of variable to receive interface pointer for riid
260 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
264 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
268 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
270 for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
272 if (IsEqualGUID(object_creation[i].clsid, rclsid))
273 return IClassFactory_QueryInterface(object_creation[i].cf, riid, ppv);
276 FIXME("%s: no class found.\n", debugstr_guid(rclsid));
277 return CLASS_E_CLASSNOTAVAILABLE;
281 /***********************************************************************
282 * DllRegisterServerEx (URLMON.@)
284 HRESULT WINAPI DllRegisterServerEx(void)
286 FIXME("(void): stub\n");
291 /**************************************************************************
292 * UrlMkSetSessionOption (URLMON.@)
294 HRESULT WINAPI UrlMkSetSessionOption(DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength,
297 FIXME("(%#x, %p, %#x): stub\n", dwOption, pBuffer, dwBufferLength);
302 static const CHAR Agent[] = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)";
304 /**************************************************************************
305 * ObtainUserAgentString (URLMON.@)
307 HRESULT WINAPI ObtainUserAgentString(DWORD dwOption, LPSTR pcszUAOut, DWORD *cbSize)
309 FIXME("(%d, %p, %p): stub\n", dwOption, pcszUAOut, cbSize);
311 if (pcszUAOut == NULL || cbSize == NULL)
314 if (*cbSize < sizeof(Agent))
316 *cbSize = sizeof(Agent);
317 return E_OUTOFMEMORY;
320 if (sizeof(Agent) < *cbSize)
321 *cbSize = sizeof(Agent);
322 lstrcpynA(pcszUAOut, Agent, *cbSize);
327 /**************************************************************************
328 * IsValidURL (URLMON.@)
330 * Determines if a specified string is a valid URL.
333 * pBC [I] ignored, must be NULL.
334 * szURL [I] string that represents the URL in question.
335 * dwReserved [I] reserved and must be zero.
340 * returns E_INVALIDARG if one or more of the args is invalid.
343 * test functionality against windows to see what a valid URL is.
345 HRESULT WINAPI IsValidURL(LPBC pBC, LPCWSTR szURL, DWORD dwReserved)
347 FIXME("(%p, %s, %d): stub\n", pBC, debugstr_w(szURL), dwReserved);
349 if (pBC != NULL || dwReserved != 0)
355 /**************************************************************************
356 * FaultInIEFeature (URLMON.@)
358 * Undocumented. Appears to be used by native shdocvw.dll.
360 HRESULT WINAPI FaultInIEFeature( HWND hwnd, uCLSSPEC * pClassSpec,
361 QUERYCONTEXT *pQuery, DWORD flags )
363 FIXME("%p %p %p %08x\n", hwnd, pClassSpec, pQuery, flags);
367 /**************************************************************************
368 * CoGetClassObjectFromURL (URLMON.@)
370 HRESULT WINAPI CoGetClassObjectFromURL( REFCLSID rclsid, LPCWSTR szCodeURL, DWORD dwFileVersionMS,
371 DWORD dwFileVersionLS, LPCWSTR szContentType,
372 LPBINDCTX pBindCtx, DWORD dwClsContext, LPVOID pvReserved,
373 REFIID riid, LPVOID *ppv )
375 FIXME("(%s %s %d %d %s %p %d %p %s %p) Stub!\n", debugstr_guid(rclsid), debugstr_w(szCodeURL),
376 dwFileVersionMS, dwFileVersionLS, debugstr_w(szContentType), pBindCtx, dwClsContext, pvReserved,
377 debugstr_guid(riid), ppv);
378 return E_NOINTERFACE;
381 /***********************************************************************
382 * ReleaseBindInfo (URLMON.@)
384 * Release the resources used by the specified BINDINFO structure.
387 * pbindinfo [I] BINDINFO to release.
392 void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo)
396 TRACE("(%p)\n", pbindinfo);
398 if(!pbindinfo || !(size = pbindinfo->cbSize))
401 CoTaskMemFree(pbindinfo->szExtraInfo);
402 ReleaseStgMedium(&pbindinfo->stgmedData);
404 if(offsetof(BINDINFO, szExtraInfo) < size)
405 CoTaskMemFree(pbindinfo->szCustomVerb);
408 if(pbindinfo->pUnk && offsetof(BINDINFO, pUnk) < size)
409 IUnknown_Release(pbindinfo->pUnk);
411 memset(pbindinfo, 0, size);
412 pbindinfo->cbSize = size;
415 static BOOL text_richtext_filter(const BYTE *b, DWORD size)
417 return size > 5 && !memcmp(b, "{\\rtf", 5);
420 static BOOL text_html_filter(const BYTE *b, DWORD size)
427 for(i=0; i < size-5; i++) {
429 && (b[i+1] == 'h' || b[i+1] == 'H')
430 && (b[i+2] == 't' || b[i+2] == 'T')
431 && (b[i+3] == 'm' || b[i+3] == 'M')
432 && (b[i+4] == 'l' || b[i+4] == 'L'))
439 static BOOL audio_wav_filter(const BYTE *b, DWORD size)
442 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
443 && b[8] == 'W' && b[9] == 'A' && b[10] == 'V' && b[11] == 'E';
446 static BOOL image_gif_filter(const BYTE *b, DWORD size)
449 && (b[0] == 'G' || b[0] == 'g')
450 && (b[1] == 'I' || b[1] == 'i')
451 && (b[2] == 'F' || b[2] == 'f')
453 && (b[4] == '7' || b[4] == '9')
454 && (b[5] == 'A' || b[5] == 'a');
457 static BOOL image_pjpeg_filter(const BYTE *b, DWORD size)
459 return size > 2 && b[0] == 0xff && b[1] == 0xd8;
462 static BOOL image_tiff_filter(const BYTE *b, DWORD size)
464 return size > 2 && b[0] == 0x4d && b[1] == 0x4d;
467 static BOOL image_xpng_filter(const BYTE *b, DWORD size)
469 static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a};
470 return size > sizeof(xpng_header) && !memcmp(b, xpng_header, sizeof(xpng_header));
473 static BOOL image_bmp_filter(const BYTE *b, DWORD size)
476 && b[0] == 0x42 && b[1] == 0x4d
477 && *(const DWORD *)(b+6) == 0;
480 static BOOL video_avi_filter(const BYTE *b, DWORD size)
483 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
484 && b[8] == 'A' && b[9] == 'V' && b[10] == 'I' && b[11] == 0x20;
487 static BOOL video_mpeg_filter(const BYTE *b, DWORD size)
490 && !b[0] && !b[1] && b[2] == 0x01
491 && (b[3] == 0xb3 || b[3] == 0xba);
494 static BOOL application_postscript_filter(const BYTE *b, DWORD size)
496 return size > 2 && b[0] == '%' && b[1] == '!';
499 static BOOL application_pdf_filter(const BYTE *b, DWORD size)
501 return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46;
504 static BOOL application_xzip_filter(const BYTE *b, DWORD size)
506 return size > 2 && b[0] == 0x50 && b[1] == 0x4b;
509 static BOOL application_xgzip_filter(const BYTE *b, DWORD size)
511 return size > 2 && b[0] == 0x1f && b[1] == 0x8b;
514 static BOOL application_java_filter(const BYTE *b, DWORD size)
516 return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe;
519 static BOOL application_xmsdownload(const BYTE *b, DWORD size)
521 return size > 2 && b[0] == 'M' && b[1] == 'Z';
524 static BOOL text_plain_filter(const BYTE *b, DWORD size)
528 for(ptr = b; ptr < b+size-1; ptr++) {
529 if(*ptr < 0x20 && *ptr != '\n' && *ptr != '\r' && *ptr != '\t')
536 static BOOL application_octet_stream_filter(const BYTE *b, DWORD size)
541 /***********************************************************************
542 * FindMimeFromData (URLMON.@)
544 * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
546 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
547 DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
548 LPWSTR* ppwzMimeOut, DWORD dwReserved)
550 TRACE("(%p,%s,%p,%d,%s,0x%x,%p,0x%x)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize,
551 debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved);
554 WARN("dwMimeFlags=%08x\n", dwMimeFlags);
556 WARN("dwReserved=%d\n", dwReserved);
558 /* pBC seams to not be used */
560 if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
563 if(pwzMimeProposed && (!pBuffer || (pBuffer && !cbSize))) {
569 len = strlenW(pwzMimeProposed)+1;
570 *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
571 memcpy(*ppwzMimeOut, pwzMimeProposed, len*sizeof(WCHAR));
576 const BYTE *buf = pBuffer;
581 static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};
582 static const WCHAR wszTextRichtext[] = {'t','e','x','t','/','r','i','c','h','t','e','x','t',0};
583 static const WCHAR wszAudioWav[] = {'a','u','d','i','o','/','w','a','v',0};
584 static const WCHAR wszImageGif[] = {'i','m','a','g','e','/','g','i','f',0};
585 static const WCHAR wszImagePjpeg[] = {'i','m','a','g','e','/','p','j','p','e','g',0};
586 static const WCHAR wszImageTiff[] = {'i','m','a','g','e','/','t','i','f','f',0};
587 static const WCHAR wszImageXPng[] = {'i','m','a','g','e','/','x','-','p','n','g',0};
588 static const WCHAR wszImageBmp[] = {'i','m','a','g','e','/','b','m','p',0};
589 static const WCHAR wszVideoAvi[] = {'v','i','d','e','o','/','a','v','i',0};
590 static const WCHAR wszVideoMpeg[] = {'v','i','d','e','o','/','m','p','e','g',0};
591 static const WCHAR wszAppPostscript[] =
592 {'a','p','p','l','i','c','a','t','i','o','n','/','p','o','s','t','s','c','r','i','p','t',0};
593 static const WCHAR wszAppPdf[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
595 static const WCHAR wszAppXZip[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
596 'x','-','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
597 static const WCHAR wszAppXGzip[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
598 'x','-','g','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
599 static const WCHAR wszAppJava[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
601 static const WCHAR wszAppXMSDownload[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
602 'x','-','m','s','d','o','w','n','l','o','a','d',0};
603 static const WCHAR wszTextPlain[] = {'t','e','x','t','/','p','l','a','i','n','\0'};
604 static const WCHAR wszAppOctetStream[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
605 'o','c','t','e','t','-','s','t','r','e','a','m','\0'};
607 static const struct {
609 BOOL (*filter)(const BYTE *,DWORD);
611 {wszTextHtml, text_html_filter},
612 {wszTextRichtext, text_richtext_filter},
613 {wszAudioWav, audio_wav_filter},
614 {wszImageGif, image_gif_filter},
615 {wszImagePjpeg, image_pjpeg_filter},
616 {wszImageTiff, image_tiff_filter},
617 {wszImageXPng, image_xpng_filter},
618 {wszImageBmp, image_bmp_filter},
619 {wszVideoAvi, video_avi_filter},
620 {wszVideoMpeg, video_mpeg_filter},
621 {wszAppPostscript, application_postscript_filter},
622 {wszAppPdf, application_pdf_filter},
623 {wszAppXZip, application_xzip_filter},
624 {wszAppXGzip, application_xgzip_filter},
625 {wszAppJava, application_java_filter},
626 {wszAppXMSDownload, application_xmsdownload},
627 {wszTextPlain, text_plain_filter},
628 {wszAppOctetStream, application_octet_stream_filter}
634 if(pwzMimeProposed && strcmpW(pwzMimeProposed, wszAppOctetStream)) {
635 for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) {
636 if(!strcmpW(pwzMimeProposed, mime_filters[i].mime))
640 if(i == sizeof(mime_filters)/sizeof(*mime_filters)
641 || mime_filters[i].filter(buf, cbSize)) {
642 len = strlenW(pwzMimeProposed)+1;
643 *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
644 memcpy(*ppwzMimeOut, pwzMimeProposed, len*sizeof(WCHAR));
651 if(mime_filters[i].filter(buf, cbSize))
652 ret = mime_filters[i].mime;
656 TRACE("found %s for data\n"
657 "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
658 debugstr_w(ret), buf[0],buf[1],buf[2],buf[3], buf[4],buf[5],buf[6],buf[7],
659 buf[8],buf[9],buf[10],buf[11], buf[12],buf[13],buf[14],buf[15]);
661 if(pwzMimeProposed) {
662 if(i == sizeof(mime_filters)/sizeof(*mime_filters))
663 ret = pwzMimeProposed;
665 /* text/html is a special case */
666 if(!strcmpW(pwzMimeProposed, wszTextHtml) && !strcmpW(ret, wszTextPlain))
670 len = strlenW(ret)+1;
671 *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
672 memcpy(*ppwzMimeOut, ret, len*sizeof(WCHAR));
682 static const WCHAR wszContentType[] =
683 {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
685 ptr = strrchrW(pwzUrl, '.');
689 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
690 if(res != ERROR_SUCCESS)
691 return HRESULT_FROM_WIN32(res);
694 res = RegQueryValueExW(hkey, wszContentType, NULL, NULL, (LPBYTE)mime, &size);
696 if(res != ERROR_SUCCESS)
697 return HRESULT_FROM_WIN32(res);
699 *ppwzMimeOut = CoTaskMemAlloc(size);
700 memcpy(*ppwzMimeOut, mime, size);
707 /***********************************************************************
708 * GetClassFileOrMime (URLMON.@)
710 * Determines the class ID from the bind context, file name or MIME type.
712 HRESULT WINAPI GetClassFileOrMime(LPBC pBC, LPCWSTR pszFilename,
713 LPVOID pBuffer, DWORD cbBuffer, LPCWSTR pszMimeType, DWORD dwReserved,
716 FIXME("(%p, %s, %p, %d, %p, 0x%08x, %p): stub\n", pBC,
717 debugstr_w(pszFilename), pBuffer, cbBuffer, debugstr_w(pszMimeType),
722 /***********************************************************************
725 HRESULT WINAPI Extract(void *dest, LPCSTR szCabName)
727 HRESULT (WINAPI *pExtract)(void *, LPCSTR);
730 hCabinet = LoadLibraryA("cabinet.dll");
732 if (!hCabinet) return HRESULT_FROM_WIN32(GetLastError());
733 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
734 if (!pExtract) return HRESULT_FROM_WIN32(GetLastError());
736 return pExtract(dest, szCabName);