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
23 #include "urlmon_main.h"
27 #define NO_SHLWAPI_REG
29 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
35 LONG URLMON_refCount = 0;
37 HINSTANCE URLMON_hInstance = 0;
38 static HMODULE hCabinet = NULL;
40 static void init_session(BOOL);
42 /***********************************************************************
43 * DllMain (URLMON.init)
45 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
47 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
50 case DLL_PROCESS_ATTACH:
51 DisableThreadLibraryCalls(hinstDLL);
52 URLMON_hInstance = hinstDLL;
56 case DLL_PROCESS_DETACH:
58 FreeLibrary(hCabinet);
68 /***********************************************************************
69 * DllInstall (URLMON.@)
71 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
73 FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE",
79 /***********************************************************************
80 * DllCanUnloadNow (URLMON.@)
82 HRESULT WINAPI DllCanUnloadNow(void)
84 return URLMON_refCount != 0 ? S_FALSE : S_OK;
89 /******************************************************************************
93 const IClassFactoryVtbl *lpClassFactoryVtbl;
95 HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
98 #define CLASSFACTORY(x) ((IClassFactory*) &(x)->lpClassFactoryVtbl)
100 static HRESULT WINAPI CF_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppv)
104 if(IsEqualGUID(riid, &IID_IUnknown)) {
105 TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
107 }else if(IsEqualGUID(riid, &IID_IClassFactory)) {
108 TRACE("(%p)->(IID_IClassFactory %p)\n", iface, ppv);
113 IUnknown_AddRef((IUnknown*)*ppv);
117 WARN("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ppv);
118 return E_NOINTERFACE;
121 static ULONG WINAPI CF_AddRef(IClassFactory *iface)
127 static ULONG WINAPI CF_Release(IClassFactory *iface)
129 URLMON_UnlockModule();
134 static HRESULT WINAPI CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
135 REFIID riid, LPVOID *ppobj)
137 ClassFactory *This = (ClassFactory*)iface;
141 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
144 if(SUCCEEDED(hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk))) {
145 hres = IUnknown_QueryInterface(punk, riid, ppobj);
146 IUnknown_Release(punk);
151 static HRESULT WINAPI CF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
153 TRACE("(%d)\n", dolock);
158 URLMON_UnlockModule();
163 static const IClassFactoryVtbl ClassFactoryVtbl =
172 static const ClassFactory FileProtocolCF =
173 { &ClassFactoryVtbl, FileProtocol_Construct};
174 static const ClassFactory FtpProtocolCF =
175 { &ClassFactoryVtbl, FtpProtocol_Construct};
176 static const ClassFactory HttpProtocolCF =
177 { &ClassFactoryVtbl, HttpProtocol_Construct};
178 static const ClassFactory HttpSProtocolCF =
179 { &ClassFactoryVtbl, HttpSProtocol_Construct};
180 static const ClassFactory MkProtocolCF =
181 { &ClassFactoryVtbl, MkProtocol_Construct};
182 static const ClassFactory SecurityManagerCF =
183 { &ClassFactoryVtbl, SecManagerImpl_Construct};
184 static const ClassFactory ZoneManagerCF =
185 { &ClassFactoryVtbl, ZoneMgrImpl_Construct};
187 struct object_creation_info
194 static const WCHAR wszFile[] = {'f','i','l','e',0};
195 static const WCHAR wszFtp[] = {'f','t','p',0};
196 static const WCHAR wszHttp[] = {'h','t','t','p',0};
197 static const WCHAR wszHttps[] = {'h','t','t','p','s',0};
198 static const WCHAR wszMk[] = {'m','k',0};
200 static const struct object_creation_info object_creation[] =
202 { &CLSID_FileProtocol, CLASSFACTORY(&FileProtocolCF), wszFile },
203 { &CLSID_FtpProtocol, CLASSFACTORY(&FtpProtocolCF), wszFtp },
204 { &CLSID_HttpProtocol, CLASSFACTORY(&HttpProtocolCF), wszHttp },
205 { &CLSID_HttpSProtocol, CLASSFACTORY(&HttpSProtocolCF), wszHttps },
206 { &CLSID_MkProtocol, CLASSFACTORY(&MkProtocolCF), wszMk },
207 { &CLSID_InternetSecurityManager, CLASSFACTORY(&SecurityManagerCF), NULL },
208 { &CLSID_InternetZoneManager, CLASSFACTORY(&ZoneManagerCF), NULL }
211 static void init_session(BOOL init)
213 IInternetSession *session;
216 CoInternetGetSession(0, &session, 0);
218 for(i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++) {
219 if(object_creation[i].protocol) {
222 IInternetSession_RegisterNameSpace(session, object_creation[i].cf,
223 object_creation[i].clsid, object_creation[i].protocol, 0, NULL, 0);
224 /* make sure that the AddRef on the class factory doesn't keep us loaded */
225 URLMON_UnlockModule();
229 /* make sure that the Release on the class factory doesn't unload us */
231 IInternetSession_UnregisterNameSpace(session, object_creation[i].cf,
232 object_creation[i].protocol);
237 IInternetSession_Release(session);
240 /*******************************************************************************
241 * DllGetClassObject [URLMON.@]
242 * Retrieves class object from a DLL object
245 * Docs say returns STDAPI
248 * rclsid [I] CLSID for the class object
249 * riid [I] Reference to identifier of interface for class object
250 * ppv [O] Address of variable to receive interface pointer for riid
254 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
258 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
262 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
264 for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
266 if (IsEqualGUID(object_creation[i].clsid, rclsid))
267 return IClassFactory_QueryInterface(object_creation[i].cf, riid, ppv);
270 FIXME("%s: no class found.\n", debugstr_guid(rclsid));
271 return CLASS_E_CLASSNOTAVAILABLE;
275 /***********************************************************************
276 * DllRegisterServerEx (URLMON.@)
278 HRESULT WINAPI DllRegisterServerEx(void)
280 FIXME("(void): stub\n");
285 /**************************************************************************
286 * UrlMkSetSessionOption (URLMON.@)
288 HRESULT WINAPI UrlMkSetSessionOption(DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength,
291 FIXME("(%#x, %p, %#x): stub\n", dwOption, pBuffer, dwBufferLength);
296 static const CHAR Agent[] = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)";
298 /**************************************************************************
299 * ObtainUserAgentString (URLMON.@)
301 HRESULT WINAPI ObtainUserAgentString(DWORD dwOption, LPSTR pcszUAOut, DWORD *cbSize)
303 FIXME("(%d, %p, %p): stub\n", dwOption, pcszUAOut, cbSize);
305 if (pcszUAOut == NULL || cbSize == NULL)
308 if (*cbSize < sizeof(Agent))
310 *cbSize = sizeof(Agent);
311 return E_OUTOFMEMORY;
314 if (sizeof(Agent) < *cbSize)
315 *cbSize = sizeof(Agent);
316 lstrcpynA(pcszUAOut, Agent, *cbSize);
321 /**************************************************************************
322 * IsValidURL (URLMON.@)
324 * Determines if a specified string is a valid URL.
327 * pBC [I] ignored, must be NULL.
328 * szURL [I] string that represents the URL in question.
329 * dwReserved [I] reserved and must be zero.
334 * returns E_INVALIDARG if one or more of the args is invalid.
337 * test functionality against windows to see what a valid URL is.
339 HRESULT WINAPI IsValidURL(LPBC pBC, LPCWSTR szURL, DWORD dwReserved)
341 FIXME("(%p, %s, %d): stub\n", pBC, debugstr_w(szURL), dwReserved);
343 if (pBC != NULL || dwReserved != 0)
349 /**************************************************************************
350 * FaultInIEFeature (URLMON.@)
352 * Undocumented. Appears to be used by native shdocvw.dll.
354 HRESULT WINAPI FaultInIEFeature( HWND hwnd, uCLSSPEC * pClassSpec,
355 QUERYCONTEXT *pQuery, DWORD flags )
357 FIXME("%p %p %p %08x\n", hwnd, pClassSpec, pQuery, flags);
361 /**************************************************************************
362 * CoGetClassObjectFromURL (URLMON.@)
364 HRESULT WINAPI CoGetClassObjectFromURL( REFCLSID rclsid, LPCWSTR szCodeURL, DWORD dwFileVersionMS,
365 DWORD dwFileVersionLS, LPCWSTR szContentType,
366 LPBINDCTX pBindCtx, DWORD dwClsContext, LPVOID pvReserved,
367 REFIID riid, LPVOID *ppv )
369 FIXME("(%s %s %d %d %s %p %d %p %s %p) Stub!\n", debugstr_guid(rclsid), debugstr_w(szCodeURL),
370 dwFileVersionMS, dwFileVersionLS, debugstr_w(szContentType), pBindCtx, dwClsContext, pvReserved,
371 debugstr_guid(riid), ppv);
372 return E_NOINTERFACE;
375 /***********************************************************************
376 * ReleaseBindInfo (URLMON.@)
378 * Release the resources used by the specified BINDINFO structure.
381 * pbindinfo [I] BINDINFO to release.
386 void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo)
390 TRACE("(%p)\n", pbindinfo);
392 if(!pbindinfo || !(size = pbindinfo->cbSize))
395 CoTaskMemFree(pbindinfo->szExtraInfo);
396 ReleaseStgMedium(&pbindinfo->stgmedData);
398 if(offsetof(BINDINFO, szExtraInfo) < size)
399 CoTaskMemFree(pbindinfo->szCustomVerb);
402 if(pbindinfo->pUnk && offsetof(BINDINFO, pUnk) < size)
403 IUnknown_Release(pbindinfo->pUnk);
405 memset(pbindinfo, 0, size);
406 pbindinfo->cbSize = size;
409 /***********************************************************************
410 * CopyStgMedium (URLMON.@)
412 HRESULT WINAPI CopyStgMedium(const STGMEDIUM *src, STGMEDIUM *dst)
414 TRACE("(%p %p)\n", src, dst);
419 memcpy(dst, src, sizeof(STGMEDIUM));
426 IStream_AddRef(dst->u.pstm);
430 IStorage_AddRef(dst->u.pstg);
433 FIXME("Unimplemented tymed %d\n", src->tymed);
436 if(dst->pUnkForRelease)
437 IUnknown_AddRef(dst->pUnkForRelease);
442 static BOOL text_richtext_filter(const BYTE *b, DWORD size)
444 return size > 5 && !memcmp(b, "{\\rtf", 5);
447 static BOOL text_html_filter(const BYTE *b, DWORD size)
454 for(i=0; i < size-5; i++) {
456 && (b[i+1] == 'h' || b[i+1] == 'H')
457 && (b[i+2] == 't' || b[i+2] == 'T')
458 && (b[i+3] == 'm' || b[i+3] == 'M')
459 && (b[i+4] == 'l' || b[i+4] == 'L'))
466 static BOOL audio_wav_filter(const BYTE *b, DWORD size)
469 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
470 && b[8] == 'W' && b[9] == 'A' && b[10] == 'V' && b[11] == 'E';
473 static BOOL image_gif_filter(const BYTE *b, DWORD size)
476 && (b[0] == 'G' || b[0] == 'g')
477 && (b[1] == 'I' || b[1] == 'i')
478 && (b[2] == 'F' || b[2] == 'f')
480 && (b[4] == '7' || b[4] == '9')
481 && (b[5] == 'A' || b[5] == 'a');
484 static BOOL image_pjpeg_filter(const BYTE *b, DWORD size)
486 return size > 2 && b[0] == 0xff && b[1] == 0xd8;
489 static BOOL image_tiff_filter(const BYTE *b, DWORD size)
491 return size > 2 && b[0] == 0x4d && b[1] == 0x4d;
494 static BOOL image_xpng_filter(const BYTE *b, DWORD size)
496 static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a};
497 return size > sizeof(xpng_header) && !memcmp(b, xpng_header, sizeof(xpng_header));
500 static BOOL image_bmp_filter(const BYTE *b, DWORD size)
503 && b[0] == 0x42 && b[1] == 0x4d
504 && *(const DWORD *)(b+6) == 0;
507 static BOOL video_avi_filter(const BYTE *b, DWORD size)
510 && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F'
511 && b[8] == 'A' && b[9] == 'V' && b[10] == 'I' && b[11] == 0x20;
514 static BOOL video_mpeg_filter(const BYTE *b, DWORD size)
517 && !b[0] && !b[1] && b[2] == 0x01
518 && (b[3] == 0xb3 || b[3] == 0xba);
521 static BOOL application_postscript_filter(const BYTE *b, DWORD size)
523 return size > 2 && b[0] == '%' && b[1] == '!';
526 static BOOL application_pdf_filter(const BYTE *b, DWORD size)
528 return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46;
531 static BOOL application_xzip_filter(const BYTE *b, DWORD size)
533 return size > 2 && b[0] == 0x50 && b[1] == 0x4b;
536 static BOOL application_xgzip_filter(const BYTE *b, DWORD size)
538 return size > 2 && b[0] == 0x1f && b[1] == 0x8b;
541 static BOOL application_java_filter(const BYTE *b, DWORD size)
543 return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe;
546 static BOOL application_xmsdownload(const BYTE *b, DWORD size)
548 return size > 2 && b[0] == 'M' && b[1] == 'Z';
551 static BOOL text_plain_filter(const BYTE *b, DWORD size)
555 for(ptr = b; ptr < b+size-1; ptr++) {
556 if(*ptr < 0x20 && *ptr != '\n' && *ptr != '\r' && *ptr != '\t')
563 static BOOL application_octet_stream_filter(const BYTE *b, DWORD size)
568 /***********************************************************************
569 * FindMimeFromData (URLMON.@)
571 * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
573 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
574 DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
575 LPWSTR* ppwzMimeOut, DWORD dwReserved)
577 TRACE("(%p,%s,%p,%d,%s,0x%x,%p,0x%x)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize,
578 debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved);
581 WARN("dwMimeFlags=%08x\n", dwMimeFlags);
583 WARN("dwReserved=%d\n", dwReserved);
585 /* pBC seams to not be used */
587 if(!ppwzMimeOut || (!pwzUrl && !pBuffer))
590 if(pwzMimeProposed && (!pBuffer || (pBuffer && !cbSize))) {
596 len = strlenW(pwzMimeProposed)+1;
597 *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
598 memcpy(*ppwzMimeOut, pwzMimeProposed, len*sizeof(WCHAR));
603 const BYTE *buf = pBuffer;
608 static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};
609 static const WCHAR wszTextRichtext[] = {'t','e','x','t','/','r','i','c','h','t','e','x','t',0};
610 static const WCHAR wszAudioWav[] = {'a','u','d','i','o','/','w','a','v',0};
611 static const WCHAR wszImageGif[] = {'i','m','a','g','e','/','g','i','f',0};
612 static const WCHAR wszImagePjpeg[] = {'i','m','a','g','e','/','p','j','p','e','g',0};
613 static const WCHAR wszImageTiff[] = {'i','m','a','g','e','/','t','i','f','f',0};
614 static const WCHAR wszImageXPng[] = {'i','m','a','g','e','/','x','-','p','n','g',0};
615 static const WCHAR wszImageBmp[] = {'i','m','a','g','e','/','b','m','p',0};
616 static const WCHAR wszVideoAvi[] = {'v','i','d','e','o','/','a','v','i',0};
617 static const WCHAR wszVideoMpeg[] = {'v','i','d','e','o','/','m','p','e','g',0};
618 static const WCHAR wszAppPostscript[] =
619 {'a','p','p','l','i','c','a','t','i','o','n','/','p','o','s','t','s','c','r','i','p','t',0};
620 static const WCHAR wszAppPdf[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
622 static const WCHAR wszAppXZip[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
623 'x','-','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
624 static const WCHAR wszAppXGzip[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
625 'x','-','g','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0};
626 static const WCHAR wszAppJava[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
628 static const WCHAR wszAppXMSDownload[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
629 'x','-','m','s','d','o','w','n','l','o','a','d',0};
630 static const WCHAR wszTextPlain[] = {'t','e','x','t','/','p','l','a','i','n','\0'};
631 static const WCHAR wszAppOctetStream[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
632 'o','c','t','e','t','-','s','t','r','e','a','m','\0'};
634 static const struct {
636 BOOL (*filter)(const BYTE *,DWORD);
638 {wszTextHtml, text_html_filter},
639 {wszTextRichtext, text_richtext_filter},
640 /* {wszAudioXAiff, audio_xaiff_filter}, */
641 /* {wszAudioBasic, audio_basic_filter}, */
642 {wszAudioWav, audio_wav_filter},
643 {wszImageGif, image_gif_filter},
644 {wszImagePjpeg, image_pjpeg_filter},
645 {wszImageTiff, image_tiff_filter},
646 {wszImageXPng, image_xpng_filter},
647 /* {wszImageXBitmap, image_xbitmap_filter}, */
648 {wszImageBmp, image_bmp_filter},
649 /* {wszImageXJg, image_xjg_filter}, */
650 /* {wszImageXEmf, image_xemf_filter}, */
651 /* {wszImageXWmf, image_xwmf_filter}, */
652 {wszVideoAvi, video_avi_filter},
653 {wszVideoMpeg, video_mpeg_filter},
654 {wszAppPostscript, application_postscript_filter},
655 /* {wszAppBase64, application_base64_filter}, */
656 /* {wszAppMacbinhex40, application_macbinhex40_filter}, */
657 {wszAppPdf, application_pdf_filter},
658 /* {wszAppXCompressed, application_xcompressed_filter}, */
659 {wszAppXZip, application_xzip_filter},
660 {wszAppXGzip, application_xgzip_filter},
661 {wszAppJava, application_java_filter},
662 {wszAppXMSDownload, application_xmsdownload},
663 {wszTextPlain, text_plain_filter},
664 {wszAppOctetStream, application_octet_stream_filter}
670 if(pwzMimeProposed && strcmpW(pwzMimeProposed, wszAppOctetStream)) {
671 for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) {
672 if(!strcmpW(pwzMimeProposed, mime_filters[i].mime))
676 if(i == sizeof(mime_filters)/sizeof(*mime_filters)
677 || mime_filters[i].filter(buf, cbSize)) {
678 len = strlenW(pwzMimeProposed)+1;
679 *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
680 memcpy(*ppwzMimeOut, pwzMimeProposed, len*sizeof(WCHAR));
687 if(mime_filters[i].filter(buf, cbSize))
688 ret = mime_filters[i].mime;
692 TRACE("found %s for data\n"
693 "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
694 debugstr_w(ret), buf[0],buf[1],buf[2],buf[3], buf[4],buf[5],buf[6],buf[7],
695 buf[8],buf[9],buf[10],buf[11], buf[12],buf[13],buf[14],buf[15]);
697 if(pwzMimeProposed) {
698 if(i == sizeof(mime_filters)/sizeof(*mime_filters))
699 ret = pwzMimeProposed;
701 /* text/html is a special case */
702 if(!strcmpW(pwzMimeProposed, wszTextHtml) && !strcmpW(ret, wszTextPlain))
706 len = strlenW(ret)+1;
707 *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR));
708 memcpy(*ppwzMimeOut, ret, len*sizeof(WCHAR));
718 static const WCHAR wszContentType[] =
719 {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
721 ptr = strrchrW(pwzUrl, '.');
725 res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey);
726 if(res != ERROR_SUCCESS)
727 return HRESULT_FROM_WIN32(res);
730 res = RegQueryValueExW(hkey, wszContentType, NULL, NULL, (LPBYTE)mime, &size);
732 if(res != ERROR_SUCCESS)
733 return HRESULT_FROM_WIN32(res);
735 *ppwzMimeOut = CoTaskMemAlloc(size);
736 memcpy(*ppwzMimeOut, mime, size);
743 /***********************************************************************
744 * GetClassFileOrMime (URLMON.@)
746 * Determines the class ID from the bind context, file name or MIME type.
748 HRESULT WINAPI GetClassFileOrMime(LPBC pBC, LPCWSTR pszFilename,
749 LPVOID pBuffer, DWORD cbBuffer, LPCWSTR pszMimeType, DWORD dwReserved,
752 FIXME("(%p, %s, %p, %d, %p, 0x%08x, %p): stub\n", pBC,
753 debugstr_w(pszFilename), pBuffer, cbBuffer, debugstr_w(pszMimeType),
758 /***********************************************************************
761 HRESULT WINAPI Extract(void *dest, LPCSTR szCabName)
763 HRESULT (WINAPI *pExtract)(void *, LPCSTR);
766 hCabinet = LoadLibraryA("cabinet.dll");
768 if (!hCabinet) return HRESULT_FROM_WIN32(GetLastError());
769 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
770 if (!pExtract) return HRESULT_FROM_WIN32(GetLastError());
772 return pExtract(dest, szCabName);