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;
412 static BOOL text_html_filter(const BYTE *b, DWORD size)
419 for(i=0; i < size-5; i++) {
421 && (b[i+1] == 'h' || b[i+1] == 'H')
422 && (b[i+2] == 't' || b[i+2] == 'T')
423 && (b[i+3] == 'm' || b[i+3] == 'M')
424 && (b[i+4] == 'l' || b[i+4] == 'L'))
431 static BOOL image_gif_filter(const BYTE *b, DWORD size)
434 && (b[0] == 'G' || b[0] == 'g')
435 && (b[1] == 'I' || b[1] == 'i')
436 && (b[2] == 'F' || b[2] == 'f')
438 && (b[4] == '7' || b[4] == '9')
439 && (b[5] == 'A' || b[5] == 'a');
442 static BOOL image_pjpeg_filter(const BYTE *b, DWORD size)
444 return size > 2 && b[0] == 0xff && b[1] == 0xd8;
447 static BOOL image_tiff_filter(const BYTE *b, DWORD size)
449 return size > 2 && b[0] == 0x4d && b[1] == 0x4d;
452 static BOOL image_xpng_filter(const BYTE *b, DWORD size)
454 static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a};
455 return size > sizeof(xpng_header) && !memcmp(b, xpng_header, sizeof(xpng_header));
458 static BOOL image_bmp_filter(const BYTE *b, DWORD size)
461 && b[0] == 0x42 && b[1] == 0x4d
462 && *(const DWORD *)(b+6) == 0;
465 static BOOL video_avi_filter(const BYTE *b, DWORD size)
468 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
469 && b[8] == 'A' && b[9] == 'V' && b[10] == 'I' && b[11] == 0x20;
472 static BOOL video_mpeg_filter(const BYTE *b, DWORD size)
475 && !b[0] && !b[1] && b[2] == 0x01
476 && (b[3] == 0xb3 || b[3] == 0xba);
479 static BOOL application_pdf_filter(const BYTE *b, DWORD size)
481 return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46;
484 static BOOL application_xzip_filter(const BYTE *b, DWORD size)
486 return size > 2 && b[0] == 0x50 && b[1] == 0x4b;
489 static BOOL application_xgzip_filter(const BYTE *b, DWORD size)
491 return size > 2 && b[0] == 0x1f && b[1] == 0x8b;
494 static BOOL application_java_filter(const BYTE *b, DWORD size)
496 return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe;
499 static BOOL application_xmsdownload(const BYTE *b, DWORD size)
501 return size > 2 && b[0] == 'M' && b[1] == 'Z';
504 static BOOL text_plain_filter(const BYTE *b, DWORD size)
508 for(ptr = b; ptr < b+size-1; ptr++) {
509 if(*ptr < 0x20 && *ptr != '\n' && *ptr != '\r' && *ptr != '\t')
516 static BOOL application_octet_stream_filter(const BYTE *b, DWORD size)
521 /***********************************************************************
522 * FindMimeFromData (URLMON.@)
524 * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
526 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
527 DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
528 LPWSTR* ppwzMimeOut, DWORD dwReserved)
530 TRACE("(%p,%s,%p,%d,%s,0x%x,%p,0x%x)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize,
531 debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved);
534 WARN("dwMimeFlags=%08x\n", dwMimeFlags);
536 WARN("dwReserved=%d\n", dwReserved);
538 /* pBC seams to not be used */
540 if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
543 if(pwzMimeProposed && (!pBuffer || (pBuffer && !cbSize))) {
549 len = strlenW(pwzMimeProposed)+1;
550 *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
551 memcpy(*ppwzMimeOut, pwzMimeProposed, len*sizeof(WCHAR));
556 const BYTE *buf = pBuffer;
561 static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};
562 static const WCHAR wszImageGif[] = {'i','m','a','g','e','/','g','i','f',0};
563 static const WCHAR wszImagePjpeg[] = {'i','m','a','g','e','/','p','j','p','e','g',0};
564 static const WCHAR wszImageTiff[] = {'i','m','a','g','e','/','t','i','f','f',0};
565 static const WCHAR wszImageXPng[] = {'i','m','a','g','e','/','x','-','p','n','g',0};
566 static const WCHAR wszImageBmp[] = {'i','m','a','g','e','/','b','m','p',0};
567 static const WCHAR wszVideoAvi[] = {'v','i','d','e','o','/','a','v','i',0};
568 static const WCHAR wszVideoMpeg[] = {'v','i','d','e','o','/','m','p','e','g',0};
569 static const WCHAR wszAppPdf[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
571 static const WCHAR wszAppXZip[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
572 'x','-','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
573 static const WCHAR wszAppXGzip[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
574 'x','-','g','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
575 static const WCHAR wszAppJava[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
577 static const WCHAR wszAppXMSDownload[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
578 'x','-','m','s','d','o','w','n','l','o','a','d',0};
579 static const WCHAR wszTextPlain[] = {'t','e','x','t','/','p','l','a','i','n','\0'};
580 static const WCHAR wszAppOctetStream[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
581 'o','c','t','e','t','-','s','t','r','e','a','m','\0'};
583 static const struct {
585 BOOL (*filter)(const BYTE *,DWORD);
587 {wszTextHtml, text_html_filter},
588 {wszImageGif, image_gif_filter},
589 {wszImagePjpeg, image_pjpeg_filter},
590 {wszImageTiff, image_tiff_filter},
591 {wszImageXPng, image_xpng_filter},
592 {wszImageBmp, image_bmp_filter},
593 {wszVideoAvi, video_avi_filter},
594 {wszVideoMpeg, video_mpeg_filter},
595 {wszAppPdf, application_pdf_filter},
596 {wszAppXZip, application_xzip_filter},
597 {wszAppXGzip, application_xgzip_filter},
598 {wszAppJava, application_java_filter},
599 {wszAppXMSDownload, application_xmsdownload},
600 {wszTextPlain, text_plain_filter},
601 {wszAppOctetStream, application_octet_stream_filter}
607 if(pwzMimeProposed && strcmpW(pwzMimeProposed, wszAppOctetStream)) {
608 for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) {
609 if(!strcmpW(pwzMimeProposed, mime_filters[i].mime))
613 if(i == sizeof(mime_filters)/sizeof(*mime_filters)
614 || mime_filters[i].filter(buf, cbSize)) {
615 len = strlenW(pwzMimeProposed)+1;
616 *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
617 memcpy(*ppwzMimeOut, pwzMimeProposed, len*sizeof(WCHAR));
624 if(mime_filters[i].filter(buf, cbSize))
625 ret = mime_filters[i].mime;
629 TRACE("found %s for data\n"
630 "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
631 debugstr_w(ret), buf[0],buf[1],buf[2],buf[3], buf[4],buf[5],buf[6],buf[7],
632 buf[8],buf[9],buf[10],buf[11], buf[12],buf[13],buf[14],buf[15]);
634 if(pwzMimeProposed) {
635 if(i == sizeof(mime_filters)/sizeof(*mime_filters))
636 ret = pwzMimeProposed;
638 /* text/html is a special case */
639 if(!strcmpW(pwzMimeProposed, wszTextHtml) && !strcmpW(ret, wszTextPlain))
643 len = strlenW(ret)+1;
644 *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
645 memcpy(*ppwzMimeOut, ret, len*sizeof(WCHAR));
655 static const WCHAR wszContentType[] =
656 {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
658 ptr = strrchrW(pwzUrl, '.');
662 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
663 if(res != ERROR_SUCCESS)
664 return HRESULT_FROM_WIN32(res);
667 res = RegQueryValueExW(hkey, wszContentType, NULL, NULL, (LPBYTE)mime, &size);
669 if(res != ERROR_SUCCESS)
670 return HRESULT_FROM_WIN32(res);
672 *ppwzMimeOut = CoTaskMemAlloc(size);
673 memcpy(*ppwzMimeOut, mime, size);
680 /***********************************************************************
681 * GetClassFileOrMime (URLMON.@)
683 * Determines the class ID from the bind context, file name or MIME type.
685 HRESULT WINAPI GetClassFileOrMime(LPBC pBC, LPCWSTR pszFilename,
686 LPVOID pBuffer, DWORD cbBuffer, LPCWSTR pszMimeType, DWORD dwReserved,
689 FIXME("(%p, %s, %p, %d, %p, 0x%08x, %p): stub\n", pBC,
690 debugstr_w(pszFilename), pBuffer, cbBuffer, debugstr_w(pszMimeType),
695 /***********************************************************************
698 HRESULT WINAPI Extract(void *dest, LPCSTR szCabName)
700 HRESULT (WINAPI *pExtract)(void *, LPCSTR);
703 hCabinet = LoadLibraryA("cabinet.dll");
705 if (!hCabinet) return HRESULT_FROM_WIN32(GetLastError());
706 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
707 if (!pExtract) return HRESULT_FROM_WIN32(GetLastError());
709 return pExtract(dest, szCabName);