mshtml: Return INET_E_USE_DEFAULT_PROTOCOLHANDLER in ResProtocolInfo::CombineUrl.
[wine] / dlls / mshtml / protocol.c
1 /*
2  * Copyright 2005 Jacek Caban
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "config.h"
20
21 #include <stdarg.h>
22 #include <stdio.h>
23
24 #define COBJMACROS
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "ole2.h"
30
31 #include "wine/debug.h"
32 #include "wine/unicode.h"
33
34 #include "mshtml_private.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
37
38 /********************************************************************
39  * common ProtocolFactory implementation
40  */
41
42 #define PROTOCOLINFO(x) ((IInternetProtocolInfo*) &(x)->lpInternetProtocolInfoVtbl)
43 #define CLASSFACTORY(x) ((IClassFactory*)         &(x)->lpClassFactoryVtbl)
44 #define PROTOCOL(x)     ((IInternetProtocol*)     &(x)->lpInternetProtocolVtbl)
45
46 typedef struct {
47     const IInternetProtocolInfoVtbl *lpInternetProtocolInfoVtbl;
48     const IClassFactoryVtbl         *lpClassFactoryVtbl;
49 } ProtocolFactory;
50
51 #define PROTOCOLINFO_THIS(iface) DEFINE_THIS(ProtocolFactory, InternetProtocolInfo, iface)
52
53 static HRESULT WINAPI InternetProtocolInfo_QueryInterface(IInternetProtocolInfo *iface, REFIID riid, void **ppv)
54 {
55     ProtocolFactory *This = PROTOCOLINFO_THIS(iface);
56
57     *ppv = NULL;
58     if(IsEqualGUID(&IID_IUnknown, riid)) {
59         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
60         *ppv = PROTOCOLINFO(This);
61     }else if(IsEqualGUID(&IID_IInternetProtocolInfo, riid)) {
62         TRACE("(%p)->(IID_IInternetProtocolInfo %p)\n", This, ppv);
63         *ppv = PROTOCOLINFO(This);
64     }else if(IsEqualGUID(&IID_IClassFactory, riid)) {
65         TRACE("(%p)->(IID_IClassFactory %p)\n", This, ppv);
66         *ppv = CLASSFACTORY(This);
67     }
68
69     if(!*ppv) {
70         WARN("unknown interface %s\n", debugstr_guid(riid));
71         return E_NOINTERFACE;
72     }
73
74     IInternetProtocolInfo_AddRef(iface);
75     return S_OK;
76 }
77
78 static ULONG WINAPI InternetProtocolInfo_AddRef(IInternetProtocolInfo *iface)
79 {
80     ProtocolFactory *This = PROTOCOLINFO_THIS(iface);
81     TRACE("(%p)\n", This);
82     LOCK_MODULE();
83     return 2;
84 }
85
86 static ULONG WINAPI InternetProtocolInfo_Release(IInternetProtocolInfo *iface)
87 {
88     ProtocolFactory *This = PROTOCOLINFO_THIS(iface);
89     TRACE("(%p)\n", This);
90     UNLOCK_MODULE();
91     return 1;
92 }
93
94 #undef PROTOCOLINFO_THIS
95
96 #define CLASSFACTORY_THIS(iface) DEFINE_THIS(ProtocolFactory, ClassFactory, iface)
97
98 static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
99 {
100     ProtocolFactory *This = CLASSFACTORY_THIS(iface);
101     return IInternetProtocolInfo_QueryInterface(PROTOCOLINFO(This), riid, ppv);
102 }
103
104 static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
105 {
106     ProtocolFactory *This = CLASSFACTORY_THIS(iface);
107     return IInternetProtocolInfo_AddRef(PROTOCOLINFO(This));
108 }
109
110 static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
111 {
112     ProtocolFactory *This = CLASSFACTORY_THIS(iface);
113     return IInternetProtocolInfo_Release(PROTOCOLINFO(This));
114 }
115
116 static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock)
117 {
118     ProtocolFactory *This = CLASSFACTORY_THIS(iface);
119
120     TRACE("(%p)->(%x)\n", This, dolock);
121
122     if(dolock)
123         LOCK_MODULE();
124     else
125         UNLOCK_MODULE();
126
127     return S_OK;
128 }
129
130 #undef CLASSFACTORY_THIS
131
132 /********************************************************************
133  * AboutProtocol implementation
134  */
135
136 typedef struct {
137     const IInternetProtocolVtbl *lpInternetProtocolVtbl;
138
139     LONG ref;
140
141     BYTE *data;
142     ULONG data_len;
143     ULONG cur;
144
145     IUnknown *pUnkOuter;
146 } AboutProtocol;
147
148 #define PROTOCOL_THIS(iface) DEFINE_THIS(AboutProtocol, InternetProtocol, iface)
149
150 static HRESULT WINAPI AboutProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
151 {
152     AboutProtocol *This = PROTOCOL_THIS(iface);
153
154     *ppv = NULL;
155
156     if(IsEqualGUID(&IID_IUnknown, riid)) {
157         TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
158         if(This->pUnkOuter)
159             return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
160         *ppv = PROTOCOL(This);
161     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
162         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", iface, ppv);
163         *ppv = PROTOCOL(This);
164     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
165         TRACE("(%p)->(IID_IInternetProtocol %p)\n", iface, ppv);
166         *ppv = PROTOCOL(This);
167     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
168         FIXME("IServiceProvider is not implemented\n");
169         return E_NOINTERFACE;
170     }
171
172     if(!*ppv) {
173         TRACE("unknown interface %s\n", debugstr_guid(riid));
174         return E_NOINTERFACE;
175     }
176
177     IInternetProtocol_AddRef(iface);
178     return S_OK;
179 }
180
181 static ULONG WINAPI AboutProtocol_AddRef(IInternetProtocol *iface)
182 {
183     AboutProtocol *This = PROTOCOL_THIS(iface);
184     ULONG ref = InterlockedIncrement(&This->ref);
185     TRACE("(%p) ref=%ld\n", iface, ref);
186     return This->pUnkOuter ? IUnknown_AddRef(This->pUnkOuter) : ref;
187 }
188
189 static ULONG WINAPI AboutProtocol_Release(IInternetProtocol *iface)
190 {
191     AboutProtocol *This = PROTOCOL_THIS(iface);
192     IUnknown *pUnkOuter = This->pUnkOuter;
193     ULONG ref = InterlockedDecrement(&This->ref);
194
195     TRACE("(%p) ref=%lx\n", iface, ref);
196
197     if(!ref) {
198         mshtml_free(This->data);
199         mshtml_free(This);
200         UNLOCK_MODULE();
201     }
202
203     return pUnkOuter ? IUnknown_Release(pUnkOuter) : ref;
204 }
205
206 static HRESULT WINAPI AboutProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
207         IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo,
208         DWORD grfPI, DWORD dwReserved)
209 {
210     AboutProtocol *This = PROTOCOL_THIS(iface);
211     BINDINFO bindinfo;
212     DWORD grfBINDF = 0;
213     LPCWSTR text = NULL;
214
215     static const WCHAR html_begin[] = {0xfeff,'<','H','T','M','L','>',0};
216     static const WCHAR html_end[] = {'<','/','H','T','M','L','>',0};
217     static const WCHAR wszBlank[] = {'b','l','a','n','k',0};
218     static const WCHAR wszAbout[] = {'a','b','o','u','t',':'};
219     static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};
220
221     /* NOTE:
222      * the about protocol seems not to work as I would expect. It creates html document
223      * for a given url, eg. about:some_text -> <HTML>some_text</HTML> except for the case when
224      * some_text = "blank", when document is blank (<HTML></HMTL>). The same happens
225      * when the url does not have "about:" in the beginning.
226      */
227
228     TRACE("(%p)->(%s %p %p %08lx %ld)\n", This, debugstr_w(szUrl), pOIProtSink,
229             pOIBindInfo, grfPI, dwReserved);
230
231     memset(&bindinfo, 0, sizeof(bindinfo));
232     bindinfo.cbSize = sizeof(BINDINFO);
233     IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo);
234     ReleaseBindInfo(&bindinfo);
235
236     if(strlenW(szUrl)>=sizeof(wszAbout)/sizeof(WCHAR) && !memcmp(wszAbout, szUrl, sizeof(wszAbout))) {
237         text = szUrl + sizeof(wszAbout)/sizeof(WCHAR);
238         if(!strcmpW(wszBlank, text))
239             text = NULL;
240     }
241
242     This->data_len = sizeof(html_begin)+sizeof(html_end)-sizeof(WCHAR) 
243         + (text ? strlenW(text)*sizeof(WCHAR) : 0);
244     This->data = mshtml_alloc(This->data_len);
245
246     memcpy(This->data, html_begin, sizeof(html_begin));
247     if(text)
248         strcatW((LPWSTR)This->data, text);
249     strcatW((LPWSTR)This->data, html_end);
250     
251     This->cur = 0;
252
253     IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_MIMETYPEAVAILABLE, wszTextHtml);
254
255     IInternetProtocolSink_ReportData(pOIProtSink,
256             BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE,
257             This->data_len, This->data_len);
258
259     IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL);
260
261     return S_OK;
262 }
263
264 static HRESULT WINAPI AboutProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA* pProtocolData)
265 {
266     AboutProtocol *This = PROTOCOL_THIS(iface);
267     FIXME("(%p)->(%p)\n", This, pProtocolData);
268     return E_NOTIMPL;
269 }
270
271 static HRESULT WINAPI AboutProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
272         DWORD dwOptions)
273 {
274     AboutProtocol *This = PROTOCOL_THIS(iface);
275     FIXME("(%p)->(%08lx %08lx)\n", This, hrReason, dwOptions);
276     return E_NOTIMPL;
277 }
278
279 static HRESULT WINAPI AboutProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
280 {
281     AboutProtocol *This = PROTOCOL_THIS(iface);
282     TRACE("(%p)->(%08lx)\n", This, dwOptions);
283     return S_OK;
284 }
285
286 static HRESULT WINAPI AboutProtocol_Suspend(IInternetProtocol *iface)
287 {
288     AboutProtocol *This = PROTOCOL_THIS(iface);
289     FIXME("(%p)\n", This);
290     return E_NOTIMPL;
291 }
292
293 static HRESULT WINAPI AboutProtocol_Resume(IInternetProtocol *iface)
294 {
295     AboutProtocol *This = PROTOCOL_THIS(iface);
296     FIXME("(%p)\n", This);
297     return E_NOTIMPL;
298 }
299
300 static HRESULT WINAPI AboutProtocol_Read(IInternetProtocol *iface, void* pv, ULONG cb, ULONG* pcbRead)
301 {
302     AboutProtocol *This = PROTOCOL_THIS(iface);
303
304     TRACE("(%p)->(%p %lu %p)\n", This, pv, cb, pcbRead);
305
306     if(!This->data)
307         return E_FAIL;
308
309     *pcbRead = (cb > This->data_len-This->cur ? This->data_len-This->cur : cb);
310
311     if(!*pcbRead)
312         return S_FALSE;
313
314     memcpy(pv, This->data, *pcbRead);
315     This->cur += *pcbRead;
316
317     return S_OK;
318 }
319
320 static HRESULT WINAPI AboutProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
321         DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
322 {
323     AboutProtocol *This = PROTOCOL_THIS(iface);
324     FIXME("(%p)->(%ld %ld %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
325     return E_NOTIMPL;
326 }
327
328 static HRESULT WINAPI AboutProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
329 {
330     AboutProtocol *This = PROTOCOL_THIS(iface);
331
332     TRACE("(%p)->(%ld)\n", This, dwOptions);
333
334     return S_OK;
335 }
336
337 static HRESULT WINAPI AboutProtocol_UnlockRequest(IInternetProtocol *iface)
338 {
339     AboutProtocol *This = PROTOCOL_THIS(iface);
340
341     TRACE("(%p)\n", This);
342
343     return S_OK;
344 }
345
346 #undef PROTOCOL_THIS
347
348 static const IInternetProtocolVtbl AboutProtocolVtbl = {
349     AboutProtocol_QueryInterface,
350     AboutProtocol_AddRef,
351     AboutProtocol_Release,
352     AboutProtocol_Start,
353     AboutProtocol_Continue,
354     AboutProtocol_Abort,
355     AboutProtocol_Terminate,
356     AboutProtocol_Suspend,
357     AboutProtocol_Resume,
358     AboutProtocol_Read,
359     AboutProtocol_Seek,
360     AboutProtocol_LockRequest,
361     AboutProtocol_UnlockRequest
362 };
363
364 static HRESULT WINAPI AboutProtocolFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter,
365         REFIID riid, void **ppv)
366 {
367     AboutProtocol *ret;
368     HRESULT hres = S_OK;
369
370     TRACE("(%p)->(%p %s %p)\n", iface, pUnkOuter, debugstr_guid(riid), ppv);
371
372     ret = mshtml_alloc(sizeof(AboutProtocol));
373     ret->lpInternetProtocolVtbl = &AboutProtocolVtbl;
374     ret->ref = 0;
375
376     ret->data = NULL;
377     ret->data_len = 0;
378     ret->cur = 0;
379     ret->pUnkOuter = pUnkOuter;
380
381     if(pUnkOuter) {
382         ret->ref = 1;
383         if(IsEqualGUID(&IID_IUnknown, riid))
384             *ppv = PROTOCOL(ret);
385         else
386             hres = E_INVALIDARG;
387     }else {
388         hres = IInternetProtocol_QueryInterface(PROTOCOL(ret), riid, ppv);
389     }
390
391     if(SUCCEEDED(hres))
392         LOCK_MODULE();
393     else
394         mshtml_free(ret);
395
396     return hres;
397 }
398
399 static HRESULT WINAPI AboutProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
400         PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult,
401         DWORD* pcchResult, DWORD dwReserved)
402 {
403     TRACE("%p)->(%s %08x %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), ParseAction,
404             dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved);
405
406     if(ParseAction == PARSE_SECURITY_URL) {
407         int len = lstrlenW(pwzUrl);
408
409         if(len >= cchResult)
410             return S_FALSE;
411
412         memcpy(pwzResult, pwzUrl, (len+1)*sizeof(WCHAR));
413         return S_OK;
414     }
415
416     if(ParseAction == PARSE_DOMAIN) {
417         if(!pcchResult)
418             return E_POINTER;
419
420         if(pwzUrl)
421             *pcchResult = strlenW(pwzUrl)+1;
422         else
423             *pcchResult = 1;
424         return E_FAIL;
425     }
426
427     return INET_E_DEFAULT_ACTION;
428 }
429
430 static HRESULT WINAPI AboutProtocolInfo_CombineUrl(IInternetProtocolInfo *iface, LPCWSTR pwzBaseUrl,
431         LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult, DWORD cchResult,
432         DWORD* pcchResult, DWORD dwReserved)
433 {
434     FIXME("%p)->(%s %s %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzBaseUrl), debugstr_w(pwzRelativeUrl),
435             dwCombineFlags, pwzResult, cchResult, pcchResult, dwReserved);
436     return E_NOTIMPL;
437 }
438
439 static HRESULT WINAPI AboutProtocolInfo_CompareUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl1,
440         LPCWSTR pwzUrl2, DWORD dwCompareFlags)
441 {
442     FIXME("%p)->(%s %s %08lx)\n", iface, debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags);
443     return E_NOTIMPL;
444 }
445
446 static HRESULT WINAPI AboutProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
447         QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf,
448         DWORD dwReserved)
449 {
450     FIXME("%p)->(%s %08x %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer,
451             cbBuffer, pcbBuf, dwReserved);
452     return E_NOTIMPL;
453 }
454
455 static const IInternetProtocolInfoVtbl AboutProtocolInfoVtbl = {
456     InternetProtocolInfo_QueryInterface,
457     InternetProtocolInfo_AddRef,
458     InternetProtocolInfo_Release,
459     AboutProtocolInfo_ParseUrl,
460     AboutProtocolInfo_CombineUrl,
461     AboutProtocolInfo_CompareUrl,
462     AboutProtocolInfo_QueryInfo
463 };
464
465 static const IClassFactoryVtbl AboutProtocolFactoryVtbl = {
466     ClassFactory_QueryInterface,
467     ClassFactory_AddRef,
468     ClassFactory_Release,
469     AboutProtocolFactory_CreateInstance,
470     ClassFactory_LockServer
471 };
472
473 static ProtocolFactory AboutProtocolFactory = {
474     &AboutProtocolInfoVtbl,
475     &AboutProtocolFactoryVtbl
476 };
477
478 /********************************************************************
479  * ResProtocol implementation
480  */
481
482 typedef struct {
483     const IInternetProtocolVtbl *lpInternetProtocolVtbl;
484     LONG ref;
485
486     BYTE *data;
487     ULONG data_len;
488     ULONG cur;
489
490     IUnknown *pUnkOuter;
491 } ResProtocol;
492
493 #define PROTOCOL_THIS(iface) DEFINE_THIS(ResProtocol, InternetProtocol, iface)
494
495 static HRESULT WINAPI ResProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
496 {
497     ResProtocol *This = PROTOCOL_THIS(iface);
498
499     *ppv = NULL;
500
501     if(IsEqualGUID(&IID_IUnknown, riid)) {
502         TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
503         if(This->pUnkOuter)
504             return IUnknown_QueryInterface(This->pUnkOuter, &IID_IUnknown, ppv);
505         *ppv = PROTOCOL(This);
506     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
507         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", iface, ppv);
508         *ppv = PROTOCOL(This);
509     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
510         TRACE("(%p)->(IID_IInternetProtocol %p)\n", iface, ppv);
511         *ppv = PROTOCOL(This);
512     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
513         FIXME("IServiceProvider is not implemented\n");
514         return E_NOINTERFACE;
515     }
516
517     if(!*ppv) {
518         TRACE("unknown interface %s\n", debugstr_guid(riid));
519         return E_NOINTERFACE;
520     }
521
522     IInternetProtocol_AddRef(iface);
523     return S_OK;
524 }
525
526 static ULONG WINAPI ResProtocol_AddRef(IInternetProtocol *iface)
527 {
528     ResProtocol *This = PROTOCOL_THIS(iface);
529     ULONG ref = InterlockedIncrement(&This->ref);
530     TRACE("(%p) ref=%ld\n", iface, ref);
531     return This->pUnkOuter ? IUnknown_AddRef(This->pUnkOuter) : ref;
532 }
533
534 static ULONG WINAPI ResProtocol_Release(IInternetProtocol *iface)
535 {
536     ResProtocol *This = (ResProtocol*)iface;
537     IUnknown *pUnkOuter = This->pUnkOuter;
538     ULONG ref = InterlockedDecrement(&This->ref);
539
540     TRACE("(%p) ref=%lx\n", iface, ref);
541
542     if(!ref) {
543         mshtml_free(This->data);
544         mshtml_free(This);
545         UNLOCK_MODULE();
546     }
547
548     return pUnkOuter ? IUnknown_Release(pUnkOuter) : ref;
549 }
550
551 static HRESULT WINAPI ResProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
552         IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo,
553         DWORD grfPI, DWORD dwReserved)
554 {
555     ResProtocol *This = PROTOCOL_THIS(iface);
556     DWORD grfBINDF = 0, len;
557     BINDINFO bindinfo;
558     LPWSTR url_dll, url_file, url, mime;
559     HMODULE hdll;
560     HRSRC src;
561     HRESULT hres;
562
563     static const WCHAR wszRes[] = {'r','e','s',':','/','/'};
564
565     TRACE("(%p)->(%s %p %p %08lx %ld)\n", This, debugstr_w(szUrl), pOIProtSink,
566             pOIBindInfo, grfPI, dwReserved);
567
568     memset(&bindinfo, 0, sizeof(bindinfo));
569     bindinfo.cbSize = sizeof(BINDINFO);
570     IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo);
571     ReleaseBindInfo(&bindinfo);
572
573     len = strlenW(szUrl)+16;
574     url = mshtml_alloc(len*sizeof(WCHAR));
575     hres = CoInternetParseUrl(szUrl, PARSE_ENCODE, 0, url, len, &len, 0);
576     if(FAILED(hres)) {
577         WARN("CoInternetParseUrl failed: %08lx\n", hres);
578         mshtml_free(url);
579         IInternetProtocolSink_ReportResult(pOIProtSink, hres, 0, NULL);
580         return hres;
581     }
582
583     if(len < sizeof(wszRes)/sizeof(wszRes[0]) || memcmp(url, wszRes, sizeof(wszRes))) {
584         WARN("Wrong protocol of url: %s\n", debugstr_w(url));
585         IInternetProtocolSink_ReportResult(pOIProtSink, MK_E_SYNTAX, 0, NULL);
586         mshtml_free(url);
587         return MK_E_SYNTAX;
588     }
589
590     url_dll = url + sizeof(wszRes)/sizeof(wszRes[0]);
591     if(!(url_file = strrchrW(url_dll, '/'))) {
592         WARN("wrong url: %s\n", debugstr_w(url));
593         IInternetProtocolSink_ReportResult(pOIProtSink, MK_E_SYNTAX, 0, NULL);
594         mshtml_free(url);
595         return MK_E_SYNTAX;
596     }
597
598     *url_file++ = 0;
599     hdll = LoadLibraryExW(url_dll, NULL, LOAD_LIBRARY_AS_DATAFILE);
600     if(!hdll) {
601         WARN("Could not open dll: %s\n", debugstr_w(url_dll));
602         IInternetProtocolSink_ReportResult(pOIProtSink, HRESULT_FROM_WIN32(GetLastError()), 0, NULL);
603         return HRESULT_FROM_WIN32(GetLastError());
604     }
605
606     src = FindResourceW(hdll, url_file, (LPCWSTR)RT_HTML);
607     if(!src) {
608         LPWSTR endpoint = NULL;
609         DWORD file_id = strtolW(url_file, &endpoint, 10);
610         if(endpoint == url_file+strlenW(url_file))
611             src = FindResourceW(hdll, (LPCWSTR)file_id, (LPCWSTR)RT_HTML);
612
613         if(!src) {
614             WARN("Could not find resource\n");
615             IInternetProtocolSink_ReportResult(pOIProtSink,
616                     HRESULT_FROM_WIN32(GetLastError()), 0, NULL);
617             mshtml_free(url);
618             return HRESULT_FROM_WIN32(GetLastError());
619         }
620     }
621
622     if(This->data) {
623         WARN("data already loaded\n");
624         mshtml_free(This->data);
625     }
626
627     This->data_len = SizeofResource(hdll, src);
628     This->data = mshtml_alloc(This->data_len);
629     memcpy(This->data, LoadResource(hdll, src), This->data_len);
630     This->cur = 0;
631
632     FreeLibrary(hdll);
633
634     hres = FindMimeFromData(NULL, url_file, NULL, 0, NULL, 0, &mime, 0);
635     mshtml_free(url);
636     if(SUCCEEDED(hres)) {
637         IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_MIMETYPEAVAILABLE, mime);
638         CoTaskMemFree(mime);
639     }
640
641     IInternetProtocolSink_ReportData(pOIProtSink,
642             BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE,
643             This->data_len, This->data_len);
644
645     IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL);
646     
647     return S_OK;
648 }
649
650 static HRESULT WINAPI ResProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA* pProtocolData)
651 {
652     ResProtocol *This = PROTOCOL_THIS(iface);
653     FIXME("(%p)->(%p)\n", This, pProtocolData);
654     return E_NOTIMPL;
655 }
656
657 static HRESULT WINAPI ResProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
658         DWORD dwOptions)
659 {
660     ResProtocol *This = PROTOCOL_THIS(iface);
661     FIXME("(%p)->(%08lx %08lx)\n", This, hrReason, dwOptions);
662     return E_NOTIMPL;
663 }
664
665 static HRESULT WINAPI ResProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
666 {
667     ResProtocol *This = PROTOCOL_THIS(iface);
668
669     TRACE("(%p)->(%08lx)\n", This, dwOptions);
670
671     /* test show that we don't have to do anything here */
672     return S_OK;
673 }
674
675 static HRESULT WINAPI ResProtocol_Suspend(IInternetProtocol *iface)
676 {
677     ResProtocol *This = PROTOCOL_THIS(iface);
678     FIXME("(%p)\n", This);
679     return E_NOTIMPL;
680 }
681
682 static HRESULT WINAPI ResProtocol_Resume(IInternetProtocol *iface)
683 {
684     ResProtocol *This = PROTOCOL_THIS(iface);
685     FIXME("(%p)\n", This);
686     return E_NOTIMPL;
687 }
688
689 static HRESULT WINAPI ResProtocol_Read(IInternetProtocol *iface, void* pv, ULONG cb, ULONG* pcbRead)
690 {
691     ResProtocol *This = PROTOCOL_THIS(iface);
692
693     TRACE("(%p)->(%p %lu %p)\n", This, pv, cb, pcbRead);
694
695     if(!This->data)
696         return E_FAIL;
697
698     *pcbRead = (cb > This->data_len-This->cur ? This->data_len-This->cur : cb);
699
700     if(!*pcbRead)
701         return S_FALSE;
702
703     memcpy(pv, This->data, *pcbRead);
704     This->cur += *pcbRead;
705
706     return S_OK;
707 }
708
709 static HRESULT WINAPI ResProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
710         DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
711 {
712     ResProtocol *This = PROTOCOL_THIS(iface);
713     FIXME("(%p)->(%ld %ld %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
714     return E_NOTIMPL;
715 }
716
717 static HRESULT WINAPI ResProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
718 {
719     ResProtocol *This = PROTOCOL_THIS(iface);
720
721     TRACE("(%p)->(%ld)\n", This, dwOptions);
722
723     /* test show that we don't have to do anything here */
724     return S_OK;
725 }
726
727 static HRESULT WINAPI ResProtocol_UnlockRequest(IInternetProtocol *iface)
728 {
729     ResProtocol *This = PROTOCOL_THIS(iface);
730
731     TRACE("(%p)\n", This);
732
733     /* test show that we don't have to do anything here */
734     return S_OK;
735 }
736
737 #undef PROTOCOL_THIS
738
739 static const IInternetProtocolVtbl ResProtocolVtbl = {
740     ResProtocol_QueryInterface,
741     ResProtocol_AddRef,
742     ResProtocol_Release,
743     ResProtocol_Start,
744     ResProtocol_Continue,
745     ResProtocol_Abort,
746     ResProtocol_Terminate,
747     ResProtocol_Suspend,
748     ResProtocol_Resume,
749     ResProtocol_Read,
750     ResProtocol_Seek,
751     ResProtocol_LockRequest,
752     ResProtocol_UnlockRequest
753 };
754
755 static HRESULT WINAPI ResProtocolFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter,
756         REFIID riid, void **ppv)
757 {
758     ResProtocol *ret;
759     HRESULT hres = S_OK;
760
761     TRACE("(%p)->(%p %s %p)\n", iface, pUnkOuter, debugstr_guid(riid), ppv);
762
763     ret = mshtml_alloc(sizeof(ResProtocol));
764     ret->lpInternetProtocolVtbl = &ResProtocolVtbl;
765     ret->ref = 0;
766     ret->data = NULL;
767     ret->data_len = 0;
768     ret->cur = 0;
769     ret->pUnkOuter = pUnkOuter;
770
771     if(pUnkOuter) {
772         ret->ref = 1;
773         if(IsEqualGUID(&IID_IUnknown, riid))
774             *ppv = PROTOCOL(ret);
775         else
776             hres = E_FAIL;
777     }else {
778         hres = IInternetProtocol_QueryInterface(PROTOCOL(ret), riid, ppv);
779     }
780
781     if(SUCCEEDED(hres))
782         LOCK_MODULE();
783     else
784         mshtml_free(ret);
785
786     return hres;
787 }
788
789 static HRESULT WINAPI ResProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
790         PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult,
791         DWORD* pcchResult, DWORD dwReserved)
792 {
793     TRACE("%p)->(%s %d %lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), ParseAction,
794             dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved);
795
796     if(ParseAction == PARSE_SECURITY_URL) {
797         WCHAR *ptr;
798         DWORD size;
799
800         static const WCHAR wszFile[] = {'f','i','l','e',':','/','/'};
801         static const WCHAR wszRes[] = {'r','e','s',':','/','/'};
802
803         if(strlenW(pwzUrl) <= sizeof(wszRes)/sizeof(WCHAR) || memcmp(pwzUrl, wszRes, sizeof(wszRes)))
804             return MK_E_SYNTAX;
805
806         ptr = strchrW(pwzUrl + sizeof(wszRes)/sizeof(WCHAR), '/');
807         if(!ptr)
808             return MK_E_SYNTAX;
809
810         size = ptr-pwzUrl + sizeof(wszFile)/sizeof(WCHAR) - sizeof(wszRes)/sizeof(WCHAR);
811         if(size >= cchResult)
812             return S_FALSE;
813
814         /* FIXME: return full path */
815         memcpy(pwzResult, wszFile, sizeof(wszFile));
816         memcpy(pwzResult + sizeof(wszFile)/sizeof(WCHAR),
817                 pwzUrl + sizeof(wszRes)/sizeof(WCHAR),
818                 size*sizeof(WCHAR) - sizeof(wszFile));
819         pwzResult[size] = 0;
820
821         if(pcchResult)
822             *pcchResult = size;
823         return S_OK;
824     }
825
826     if(ParseAction == PARSE_DOMAIN) {
827         if(!pcchResult)
828             return E_POINTER;
829
830         if(pwzUrl)
831             *pcchResult = strlenW(pwzUrl)+1;
832         else
833             *pcchResult = 1;
834         return E_FAIL;
835     }
836
837     return INET_E_DEFAULT_ACTION;
838 }
839
840 static HRESULT WINAPI ResProtocolInfo_CombineUrl(IInternetProtocolInfo *iface, LPCWSTR pwzBaseUrl,
841         LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult, DWORD cchResult,
842         DWORD* pcchResult, DWORD dwReserved)
843 {
844     TRACE("%p)->(%s %s %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzBaseUrl), debugstr_w(pwzRelativeUrl),
845             dwCombineFlags, pwzResult, cchResult, pcchResult, dwReserved);
846
847     return INET_E_USE_DEFAULT_PROTOCOLHANDLER;
848 }
849
850 static HRESULT WINAPI ResProtocolInfo_CompareUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl1,
851         LPCWSTR pwzUrl2, DWORD dwCompareFlags)
852 {
853     FIXME("%p)->(%s %s %08lx)\n", iface, debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags);
854     return E_NOTIMPL;
855 }
856
857 static HRESULT WINAPI ResProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl,
858         QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf,
859         DWORD dwReserved)
860 {
861     FIXME("%p)->(%s %08x %08lx %p %ld %p %ld)\n", iface, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer,
862             cbBuffer, pcbBuf, dwReserved);
863     return E_NOTIMPL;
864 }
865
866 static const IInternetProtocolInfoVtbl ResProtocolInfoVtbl = {
867     InternetProtocolInfo_QueryInterface,
868     InternetProtocolInfo_AddRef,
869     InternetProtocolInfo_Release,
870     ResProtocolInfo_ParseUrl,
871     ResProtocolInfo_CombineUrl,
872     ResProtocolInfo_CompareUrl,
873     ResProtocolInfo_QueryInfo
874 };
875
876 static const IClassFactoryVtbl ResProtocolFactoryVtbl = {
877     ClassFactory_QueryInterface,
878     ClassFactory_AddRef,
879     ClassFactory_Release,
880     ResProtocolFactory_CreateInstance,
881     ClassFactory_LockServer
882 };
883
884 static ProtocolFactory ResProtocolFactory = {
885     &ResProtocolInfoVtbl,
886     &ResProtocolFactoryVtbl
887 };
888
889 HRESULT ProtocolFactory_Create(REFCLSID rclsid, REFIID riid, void **ppv)
890 {
891     ProtocolFactory *cf = NULL;
892
893     if(IsEqualGUID(&CLSID_AboutProtocol, rclsid))
894         cf = &AboutProtocolFactory;
895     else if(IsEqualGUID(&CLSID_ResProtocol, rclsid))
896         cf = &ResProtocolFactory;
897
898     if(!cf) {
899         FIXME("not implemented protocol %s\n", debugstr_guid(rclsid));
900         return CLASS_E_CLASSNOTAVAILABLE;
901     }
902  
903     return IUnknown_QueryInterface((IUnknown*)cf, riid, ppv);
904 }